Monitor errors and performance issues with

#380: 7 lessons from building a modern TUI framework Transcript

Recorded on Monday, Sep 5, 2022.

00:00 Terminals seem like the very lowest common denominator for software platforms. They have to work over SSH. They only show texts. You can't do much with them. Or can you? Will McGugan and team are building Textual based on Rich, which each looks more like an animated web app than a terminal app. And he has learned a bunch of lessons trying to maximize terminal based apps. He's here to share his seven lessons he's learned while building a modern TUI that is Text User Interface Framework. This is Talk Python to Me episode 380, recorded September 5, 2022. Welcome to Talk Python to Me, a weekly podcast on Python. This is your host, Michael Kennedy. Follow me on Twitter, where I'm @mkennedy, and keep up with the show and listen to past episodes at and follow the show on Twitter via @talkpython. We've started streaming most of our episodes live on YouTube. Subscribe to our YouTube channel over at Talkpython.FM/YouTube to get notified about upcoming shows and be part of that episode.

01:14 This episode is sponsored by Microsoft for startups foundershub. Check them out at Talkpython. Fm/foundershub to get early support for your startup. And it's brought to you by Sentry. Don't let those errors go unnoticed. Use Sentry. Get Started at Transcripts for this and all of our episodes are brought to you by Assembly AI. Do you need a great automatic speech to Text API? Get human level accuracy in just a few lines of code? Visit 'talkpython.FM/AssemblyAI'. Will welcome back to talk python to me.

01:47 Thank you. It's good to be here.

01:48 Yeah, it's fantastic to have you here. Really looking forward to talking about the progress you've made on Rich and Textual and your company, which is pretty fantastic. The show is not specifically about that. It's more about all these fantastic lessons that you've learned while building it. But of course, we'll get a chance to talk about it and give some updates, too, I'm sure.

02:09 Cool. Sounds good to me.

02:10 Yeah, well, normally I asked folks how they got into programming, and people, if they want to hear that story, they can go back and check out your episode 336 on Talk Python. Way back. Way back. Last year. About a year ago.

02:25 It's a lifetime ago. So what just happened in terms of.

02:29 What's happened with your projects and stuff? It really is kind of a lifetime ago. So what I want to ask you instead is what have you been up to the last year? Give us an update.

02:37 Yeah, okay. So I founded Textualize.IO a new start up. I've hired developers, and we're very busy working on Textual, and it's come on really well. It's amazing. There's more than I thought it would do, to be honest with you. textualize.IO.

02:56 Yeah, textualize. There we go.

02:59 The other one's for sale if you want it.

03:03 I get that all the time. Sorry. So you've been working on textualize and you actually got some investments and you're hiring and amazing.

03:11 I'm so happy for you.

03:13 Thank you. Yes.

03:14 When I first heard that, I'm like, well, what is the business model? What is the business model here? What are you all working towards? Like really trying to just leverage the terminal, right? Even more.

03:24 Yeah, that's right. So it's a very reasonable question that everyone asks. So the first part is textual, which will be open source and distributed just like any other open source project.

03:35 But we will add on this commercial service where you can take those textual apps and then you can put them in the web. And then when they're on the web, we can charge companies and organizations a monthly fee for various services such as accounts and things and payment portals and things. But it will be a very generous free tier for hobbyists and for open source projects that want to do the same.

04:01 Fantastic. So we have SaaS for software as a service. We have PaaS for platform as a service. And the whole style of apps from textual and to a lesser degree rich often go under the terminology of TUI, a text user interface. Right. So TUI as a service, Tas Ti as a service. Are you creating a new as a service?

04:27 Yeah, I kind of like it. Tas in tech, we love our acronyms, so if I don't invent at least one, I'll be disappointed.

04:35 That's right. And if they can have multiple cases right, like a capital TAS, then I think it's going to be great. Yeah, it's one of the better types of acronyms.

04:46 Yeah.

04:48 Fantastic. I think this is great.

04:51 One of the things I'm really fascinated about, and for a long time I've been trying to pay attention to and highlight is how do people go from open source project to business? And when I first started the podcast and really started to think about these things, it seemed like there was not that many great answers. It felt like a lot of, well, here's my PayPal donation link or something.

05:13 Yeah.

05:13 And it just seemed like, okay, that might feel good as a thanks, but you cannot make that your job to say, buy me a coffee most of the time.

05:22 There's a lot of progress lately, isn't there?

05:24 Yeah. Some GitHub sponsors and similar programs, you can get sponsorship and it can be enough to live on. It's not easy. The type of projects that get sponsored are the ones which are super critical to businesses. And in that case, companies don't mind donating $300 a month. And if you get enough of those, you could live on it. And some people certainly do, but I don't think it's practical for most people. Even if your open source project is widely used and popular, it might not bring in enough sponsorship to live on, unfortunately.

06:04 Yeah, unfortunately. And so I do think GitHub sponsors really is kind of that done right.

06:12 It's recurring. It's automatic.

06:15 It has a social signal benefit. Right. Like you can see who is sponsoring which projects. So if you're an organization, you could say, oh, look, our company sponsors that project, or whatever.

06:28 Yeah, it's very well done, actually. I've got no problems with it done.

06:33 Like I said, you can contribute every month or you can contribute a one off and you can get your name mentioned on the project, and the author of the project can offer various perks.

06:44 I think it's nicely done.

06:46 The other one that I see really, this might be the most popular one, is take an open source thing and then help alleviate or completely solve the operational side of things. Right. For example, we have MongoDB and then they have Atlas, which lets you push a button and manage your cluster automatically inside your own AWS or Azure account. We've got Streamlit, which just got acquired, has a lot of similarities to what you're doing. It's like it's got an open source version. You can create these dashboards. It's really cool. But then how do you put them on the Internet? How do you maintain them? Right. Well, guess what? There's a paid tier that just runs it in our cloud for you. Right. So it seems like a really great path to proceed down for what you're doing here.

07:34 Yeah, that's right.

07:35 They've got term for it's called open core.

07:38 So you use the open source part to drive adoption, and then you can use that to sell some related services, which will just make life easier for businesses and things. Because there's a long history of businesses making use of open source projects and making a lot of money out of it, but they haven't really put that money into the business. So if the people that are building and maintaining these open source projects can also build side businesses around the open source project, then everyone benefits because your code gets maintained for the indefinite future and people can make a living from it. Yeah.

08:17 If you would otherwise have to hire somebody to manage a Kubernetes cluster or whatever, and instead you can pay $20 a month. That's a real good deal.

08:26 Exactly. And you don't want to have to solve all these problems individually for everyone that uses it. It's actually far better for someone to solve it once and for all or at least reduce the footprint for maintenance.

08:39 Yeah. Who else? Better to figure out how to put it in the cloud than people who are creating it, right?

08:44 Yeah, exactly.

08:45 For sure. Okay, so fantastic. I'm looking forward to Tui as a service to come on strong here. That's great. So maybe before we jump into the lessons learned, just tell people about what textual is and then textual is built upon rich. So give us a quick rundown on whichever order you think is better to go first, rich or textual.

09:09 I think rich.

09:11 I'll go in chronological order so I started Rich.

09:14 Gosh, it must be like three years now. And the idea was to be able to write color text the terminal in a nice, elegant way and also be able to build on that with larger components. We've got things like tables, we've got progress bars, got log messages, panels, all sorts of things. And they're all using the same core rendering technology, which basically takes your objects and then turns it into ANSI codes and text that got fairly popular, shall we say. I was surprised. I would say, yeah, it's in Pip now, which still blows me away because that means that virtually every Python developer is running my code with Charm. So it scares me just a little bit better.

10:01 This is nuts, right? Because if you have Python, you have Pip, so you have Rich. Is it packaged with Pip as a dependency or is it vendored in it's?

10:11 Vendor because you've got a chicken and.

10:13 Egg problem with Pip is how you get the things, right?

10:16 Exactly. So everything is vendor. Pip is just one project with lots of vendor projects inside of it.

10:23 Rich for people who haven't seen it in action. It's not just like colorama or something, which I'm a big fan of Colorama, but that's just about how do I make this line this color or whatever. But you're talking about like tables with auto ellipsing and all sorts of really powerful content, right?

10:43 Yeah. And some things which you might take for granted in the browser, like text wrapping, that wasn't easy to do prior to Rich.

10:51 It's more complex. You might think things like emoji and Chinese characters, those take up two cells in the terminal. If you use the built in text wrap module, that won't account for that and your text trapping will be misaligned. So I want to solve those kind of problems. I just want it to be effortless. You just say, print this text and it'll wrap it for you, which generally makes it a lot more readable.

11:16 Yeah, absolutely.

11:18 There's a lot going on there.

11:19 I would say so. And I don't know how many projects are using Rich now, but they constantly seems to be like and now this has Rich support, so it has much better output or it's more understandable or whatever. Right. A lot of cool things happening because of it.

11:36 I'm delighted every time I read one of those.

11:39 I do try to make it quite easy to drop things in. For instance, if you're printing out Python data structures, you can use a Rich method and you'll get pretty printing and colorizing built in and things like exception handling. We've got very pretty exceptions that show you snippets of code and can highlight the line where the error occurred, and you can add those just a few lines. So I think that's kind of pushing adoption is the fact that there is very low barrier to entry. Yeah.

12:09 And it's just beautiful, right? It's easy to make beautiful UI, and if you make it easy for people to make nice looking things, they want to use it. It's not as used as much these days, but think of when Bootstrap came on the scene eight years ago, or ten years, whatever it was ten years ago, everything started to look like Bootstrap because you could just apply this magic and like, oh, everything looks like professional, but we're not professional. And I feel like Rich is a little bit like that for TUI's.

12:36 I think so, because it's very difficult to add pretty formatting prior to Rich, I mean, there were libraries that existed, but they didn't integrate very well. And Rich kind of combines all of that functionality together.

12:49 So it's very easy to add pretty content. And it's not just pretty for pretty sake. Pretty can also mean more readable developers. We get presented with pages and pages of content that we learn to decipher and pick out meaning, but we can do that much quicker if there's been some forethought thought into how it's presented and rendered in the terminal, and Rich does give you that capability.

13:16 This portion of Talk Python to me is brought to you by Microsoft for Startups Founders Hub, starting a business is hard. By some estimates, over 90% of startups will go out of business in just their first year. With that in mind, Microsoft for Startups set out to understand what startups need to be successful and to create a digital platform to help them overcome those challenges. Microsoft for startups founders hub was born. Founders Hub provides all founders at any stage with free resources to solve their startup challenges. The platform provides technology benefits, access to expert guidance and skilled resources, mentorship and networking connections, and much more. Unlike others in the industry, Microsoft for Startups founders Hub doesn't require startups to be investor backed or third party validated to participate. Founders Hub is truly open to all. So what do you get if you join them? You speed up your development with free access to GitHub and Microsoft cloud computing resources and the ability to unlock more credits over time. To help your startup innovate, Founders Hub is partnering with innovative companies like OpenAI, a global leader in AI research and development to provide exclusive benefits and discounts through Microsoft for Startups Founders Hub, becoming a founder is no longer about who you know. You'll have access to their mentorship network, giving you a pool of hundreds of mentors across a range of disciplines and areas like idea validation, fundraising, management and coaching, sales and marketing, as well as specific technical stress points. You'll be able to book a one on one meeting with the mentors, many of whom are former founders themselves. Make your idea a reality today with a critical support you'll get from foundershub. To join the program, just visit Talkpython.FM/foundershub all one word the links in your show notes thank you to Microsoft for supporting the show.

15:07 Jamie on the audience says I love Rich. Trace back is so helpful. Maybe just quickly touch on the trace back. And then also Demetrius is asking about is this for Jupyter? Is it only a thing for Linux terminals and maybe sort of touching those two things? Then we'll talk textual. Trace backs.

15:23 Yeah, you can install a trace back handler and it will capture unhandled trace backs and present them nicely in the terminal. What was the other question?

15:35 Where does this apply? Like, can you use this on Windows? Can you use it on Mac? Is it for Jupyter? What is this?

15:40 Pretty much everywhere. So you can use it on all the major platforms linux, Mac and Windows. And yes, it does work in jupyter, so it will convert the ANSI codes to HTML automatically.

15:53 That's not actually the most impressive thing to me. That must be a lot of work to maintain all these different output destinations and whatnot.

16:01 The terminal is not too bad. So macOS and Linux are frankly the same as far as I'm concerned.

16:07 Windows has a number of tweaks and hacks because there are two Windows, basically newer. Windows has virtual Terminal sequences which make it just like the Linux and Mac Terminal. And that's terrific. But we also support the older style terminal, which is quite limited and the.

16:27 Referral CMD exe is not nearly as powerful as the new general.

16:32 It's not. So we have to make some compromises and some sacrifices.

16:38 It works, it's usable, it won't look quite as pretty, but there's a lot of people using that out there. So it's important to maintain.

16:46 Yeah, you can't really drop it. No, you can't drop it. Okay. And then the other thing that's more directly related to your article and to your business, although obviously one is a building block same. It's textual.

17:01 Yeah. So Rich was for writing kind of static content into your kind of terminal or scrollback buffer. What type of does is it uses Rich, but it completely takes over your terminal to create an application. You don't see a command prompt, but textual will handle key presses and mouse movements and it will render quite sophisticated applications which look more like web apps than the previous generation of tui's. Yes, but under the hood it's using the same code that renders tables enriched.

17:33 I call it a rendering engine. It's designed to take some of abstract data and then turn it into what I call segments, which are basically a piece of text.

17:42 The style, it's pretty amazing. If you look at the UI, it really does feel a bit like a web app. It has, say, like a title bar across the top. And this isn't just like text you printed out at the top of the output, it's stuck to the top like a NAV bar, I guess is the right where you have these different widgets you can put in line like code highlighting. You've got text widgets, like scrolling within scrolling. You've got animated sidebars that pop out all these cool different aspects. Right. Even hotkey support for like D to toggle dark and light mode if you want.

18:16 Yeah, we even got data tables now which are pretty cool. They look kind of like little Excel Windows tablet spreadsheets, which is fantastic.

18:27 My background is a web developer, basically.

18:30 So I want to make something which anyone who knows how to use the web, which is pretty much everyone, they would be comfortable using one of these applications. You could just sit in front of it and they'll know exactly what to do. They'll know that this is a menu. Can click that here's a scroll bar. Not use a scroll bar. It'll work with a mouse wheel or two fingers, scroll on a trackpad. It'll just be very familiar.

18:54 At the same time. I also want to keep it keyboard focused because one of the benefits of Tui is it doesn't interrupt your flow.

19:02 You can be at the terminal typing commands, enter into a tui and you could work with that and use the keyboard and you can drop back straight into the command line. So it's kind of this manage of the command line and more sophisticated applications which work a lot like desktop and web.

19:21 Previously, when people wanted to create apps like this one, it was very difficult to do.

19:26 But if they wanted to come somewhat close to these types of things, they would use a library called Curses or something like that. Right?

19:33 Yeah. And Cursors has been around for a long time, I think decades I can't remember off the top of my head. But I think in the 90s it came around and people have done some very cool things with it and have been attempts to improve upon it. But I think still it does take you have to be very well motivated to create an application with Cursors because you're going to have to deal with some quite archaic issues.

19:59 Yeah, I haven't done a ton with it, but it feels to me like the equivalent of, say, like textual versus Cursors would be like you could either use something like Py game where you can give some sprites and they can move around the screen, or you could fire up OpenGL or direct X or Metal and you could start rendering pixels on your own. You could accomplish the same UI, but one is tremendously difficult. The other one kind of gives you much higher level building blocks to accomplish the same thing.

20:30 Yeah, exactly. So a textual is more abstract. You don't have to plot individual characters. You just say, put a text box this part of the screen and a button on this part of the screen, and textual handles the rest. So there's less archaic aspects of terminals that go back decades that you have to think about.

20:52 Let the framework handle it and handle the differences. Right.

20:55 Yeah, exactly. That's what computing should be. It should make your life easier. You shouldn't have to think about decades.

21:02 Or you hear in science people talking about standing on the shoulders of giants, of like building an Einstein or whatever. There's nothing else that stands on the shoulders of previous work like software. Right. It's just like layers and layers and layers.

21:18 We don't have to think about that anymore. We now have a different set of concepts to think and now let's go build.

21:25 Yes. Which is fine for the most part, as long as you don't ever have to look behind the curtain.

21:31 It's the same with them in any piece of computing. It presents nice clean interface, but there's a lot of effort to get there. It's like an iceberg. You only see the very top of it, but two thirds are below the water level.

21:45 Basically, if it becomes a leaky abstraction right. And then you've got to deal with the underlying layer, but not exactly anyway.

21:52 Exactly.

21:52 All right, last question and then we'll move off, talk about the lessons. Lucas asks will textual you have a polyfill for blink, like manual text, blinking terminals which don't support it. But basically it gets more interesting because it has polyfills and other ways to make stuff happen that's not naturally supported.

22:13 You know, I could quite easily you could set up a timer called set interval which would toggle something to show the blank or hide the blank. I don't think I want to support in textual because I don't want textual to be blinking. It's a terrible user interface for the most part. The exception would be a cursor. Sometimes you want a cursor to flash so you can see where it is. I think I might leave that one up to developer to implement. And it probably is like a two line job.

22:40 I can see a future where some movie has a fake hacker UI implemented and textual and they probably have a blinking about when something is going to blow up going on. All right, let's move on. Let's go through your lessons. So this is what you've been building, what you're building. And obviously you worked on Rich for a long time. You've worked you and your colleagues at the company for a year now. So tell us about the lessons. Let's go through these.

23:09 Yeah, okay. So terminals are fast.

23:12 This might surprise people and I can.

23:14 Understand why it surprised me.

23:15 Yeah, because when you use the terminal, you type a few characters and the characters appear on screen. You hit Return half a second later, you'll get a response with some text. And you don't think of terminals as being fast. But nowadays they're built on the same technology that runs video games. So it uses the GPU to update the terminal with new characters which have a background and foreground. And it turns out that if you can write updates at 60 frames second from the python code, the terminal will happily display it.

23:48 I was surprised at how smooth it was. And we had 60 frames per second animation of something moving across the screen and it looked silky smooth. And that was updating the entire screen, like every frame.

24:01 Wow. I'm really impressed with the fact that so many of these terminals are hardware accelerated, like GPU accelerated. And I'm just poking around, what am I running here? Right now? I'm running item and it has all these settings for GPU render redraws and basically the maximum frame rate.

24:20 And so things like this, you would never expect to go find hardware acceleration features inside the terminals. But they have them.

24:30 They do, yeah. And it's quite strange because not much software takes advantage of that. I mean, your day to day work at the terminal, it doesn't need to be fast, it really doesn't. As long as it can add new data within a second, you're probably quite happy. So these terminals have been getting faster and faster and faster, and some of them I use Kitty, and something called West Term, and those are incredibly fast. They're really optimized at getting things on the screen.

25:02 Yeah, Kitty is excellent, it's super fast, but most software doesn't need it. It's like you use them or top updates once a second.

25:13 So it's like the developers of these terminals are making it faster and faster and faster, but there's very little software that makes use of it, except for hobbyist demos where they do video to text things. So you see like, your face that's made up with ASCII characters, which is fun, right, but you don't think that's not really productivity software. So I was very pleased that when I started working on textual, that it wasn't a bottleneck.

25:40 If I could write things fast enough, the terminal, the terminal would happily accept it and render it.

25:47 That opens the possibility for so many things. If you can get high frame rates, the iterms default was limit frames to 60 frames a second. 60 frames a second, that's plenty fine for really smooth animations. Yeah, I think it's probably what my LCD monitor is stuck at. Right. So that's as fast as you're going to see it, basically. Anyway, that's it.

26:09 And there's not much use in it being any faster because in order to see greater than 60 frames a second, you have to have something that's moving greater than 60 frames a second. And generally you don't want things flying about your terminal, unless maybe you're making a video game. We use animation quite sparingly for nice kind of things, like when a panel slides in, sidebar pops in, it's quite smooth. We can also use it for fades, so we can set the opacity of block of text and have it fade away and fade in again. And that's sometimes quite useful if you want to draw the user's attention to the fact that you've added a new item rather than having it appear immediately. It'll fade in. So we can use animation in those places.

27:00 But again, it doesn't need to be anywhere near 60 frames a second.

27:05 No, it doesn't have to. But I do agree that little bits of animation are super important for highlighting things that people need to pay attention to without much effort. And it doesn't have to be so bright colored or right in the way. Right. If you just have a little thing slide down that says this job has finished while the other work is happening, or whatever, that's really nice. And you have a video here on this article, the Seven Things article that we'll link to, obviously. And it shows you running this thing called basic py. Is this included with textuall or is.

27:38 It yeah, that's one of our sandbox apps. So whenever we're testing something, we just put it in basic .py. So that shows off like a number of the features we've got. I think that video is quite old. They've got some more cool stuff.

27:51 I'm sure you do.

27:53 But one of the things that's really nice is it shows a lot of the animations. And one of the animations is changing the theme. Another one is to pop out the side navigation. And those are really nice. Right. The fact that that happens at a frame rate fast enough that it looks completely smooth means it doesn't just look like some terminal app where I think clicks in and then it clicks out. It actually feels really nice and polished.

28:18 Yeah, we've kind of identified it's like a sliding scale of animation. At one end you've got like the scroll bars. It might not be obvious, but those animate. So if you click below, it will scroll smoothly downwards and also filter. When you click and drag, it will filter frames between the motion of the mouse and it makes the scrolling look a lot more smooth. That's not obvious, but that is a use of animation. And at that end of the scale, I think most people would agree that's good, that's a bonus. The other end of the scale, we've got things which are a bit gratuitous, like the sidebar. I like it, but some people might think, I don't want to be distracted by this animation. I just want it to appear instantly. I want it to feel more snappy rather than animated. So I think what we're going to do is we're going to have like a switch where you can decide as a user what kind of animation you like.

29:10 If you just want the scroll bar so you can set it to be quite low and that would make the sidebar pop in instantly and disappear instantly.

29:19 But if you love the animation, you can just whack it up to the maximum and then it will use animation wherever it can for fading and sliding, et cetera.

29:27 For example, with a scroll bar that's not actually the. Terminal scrolling it that's textual redrawing the screen and reprocessing it. If it's not smooth, if it just goes clunk, clunk, clunk, it's super hard to track. When I scroll down, where do I continue from? And that kind of stuff, right?

29:46 Yes.

29:46 It's not just there to make it feel good or feel smooth, really. It's not just important, I bet. Yeah.

29:54 Page down. If it was to jump down instantly, you wouldn't be able to find your place in the text again.

30:01 Your eye would just have to focus in to find where you're reading. But if it scrolls in over 300 milliseconds, your eye tends to follow where you are reading. So you move your eye, you follow the animation, and then you're sort of reading again from the top. And that's actually beneficial. It's not just eye candy, it's not just gratuitous use of a feature.

30:23 Absolutely. It's very helpful. So you talked about all of this happening without flickering in the terminal. We already discussed the GPU accelerated hardware, accelerated aspects, but you said also that's not necessarily enough. So there's a couple of tricks that you highlight here.

30:40 The protocol of terminals came about over many decades, and it wasn't designed to avoid flickering. I think when people build, they never.

30:49 Imagined what you would be trying to do with it.

30:51 No, they didn't think someone's going to be animating it at 60 frames a second.

30:58 Well, there's very little help to reduce flicker, so there's a few things that you can do. One I discovered is better to overwrite content without clearing it. So if you want to animate, say, a piece of text, make it move, you might think, I'll clear this text and it'll draw on top of it. But what that does is it will introduce a potential for a frame where you see where it's cleared and then you see the frame where it's updated and that will cause flicker. So if you just overwrite the content without clearing it, then that reduces the chance of flickering. Yeah.

31:32 I've also seen sometimes some of these, like, progress bars or the little tables updating, they seem to write new whole sections. And it's like filling your history with every frame. Your terminal history is like full of every frame and stuff like that. If you start to resize it. And there's all this weird stuff that happens if you're not actually overriding it.

31:53 Textuall goes into what's called application mode.

31:56 This is a feature of terminals. So when you're in application mode, you don't have a scrollback buffer.

32:02 The scrollback buffer has that problem. It will tend to fill up with garbage if you're trying to animate things. And it's also quicker because the terminal doesn't have to worry about appending data and moving it, etcetera. So textual goes into application mode and it's generally much faster and able to reduce that flickering. Trick two, trick two. One of the problems with the protocol is that it's not aware of flickering. It doesn't know when to paint the screen. So you're sending a data. It needs to know when to update the screen.

32:36 If you write lots of small pieces of data, so you're going to update a character over here, you're going to update a progress bar here. It might update a few of them and then paint the screen and then update some others and paint the screen. And it's that brief moment where you've got half an update, which is what causes flicker. What I've discovered is if you batch all your updates into one, right, so you just write standard output, the ones rather than several rights, that will reduce the potential of flicker quite a bit.

33:05 Interesting. Of course it would. And I've never really thought about it. When you're doing regular pixel based graphics programming, OpenGL, DirectX, those types of things, they often set up what's called a double buffered mode, where you actually draw the screen on like a hidden piece, and then you swap that to be in one V sync to be the screen, so you don't see the pieces streaming in as it goes. And this is the same equivalent thing for terminals. It's like double buffered. You write to it like a whole thing, and then you make it the screen.

33:36 It's a very similar concept. The terminal doesn't give you that. It doesn't have an invisible buffer that you can take your time to draw to. So you have to implement that yourself. But, yeah, essentially we're implementing a double.

33:47 Buffer and the third one has to do with synchronized output.

33:51 Doing the one right thing, that's very helpful. But there's also a fairly recent addition to the protocol, which helps with us. Basically, you write an escape code which says, I'm beginning an update, and then you write your data and then you write another escape code which says, I finished the update. And between those two escape codes, the terminal won't update. It only update at the very last moment.

34:12 So that's kind of accomplishing the same thing as the double buffer.

34:18 So we do both because not all terminals support these new escape cods. So by doing both, we can ensure that it's flicker free on newer terminals and older terminals.

34:29 Yeah. Fantastic. Speaking of different terminals, kim in the audience asked, is application mode that you talked about earlier with the buffer a universal across all the terminals?

34:40 It is, yeah. It's been around for a long time. If you've used H Top or anything like it, or a full screen terminal app that will use application mode.

34:50 This portion of Talk Python to Me is brought to you by Sentry, you know, Sentry. As a longtime sponsor of this podcast, they offer great air monitoring software that I've told you about many times. It's even software that we use on our own web apps. But this time, I want to tell you about a fun conference they have coming up. Deploying new code can be a lot like making a really great sandwich, taking a bite and then having all the contents fall out. Exciting, chaotic and maddening. If you know the feeling, then DEX by Sentry might be for you. This is a free conference by developers, for developers, where you sort through the madness and look for ways to improve your workflow productivity. Join Sentry for this event in San Francisco or virtually on September 28 and discover new ways to make your life a little easier. Save your seat now at That's Talkdex. The link is in your show notes. Thank you to Sentry for supporting Talk Python to me.

35:50 Final question while we're on this performance thing, when will we see Doom implemented?

35:56 People keep asking that. I don't know. It might happen. I think it has to happen. I mean, Doom runs virtually everywhere.

36:03 It does.

36:05 Maybe the first Doom, maybe not Doom eternal.

36:07 Yes, we're thinking the original Doom. That really was amazing. Right after Castle Wolfenstein. Very good stuff.

36:13 Yeah, I love it.

36:14 All right, so that was also really interesting stuff about terminals, but we also have some other recommendations and discoveries that are pretty awesome even if you're doing other types of programming. And one of them is Dict views. Apparently I used Dict Views a lot, but I didn't really know they had a special name. Tell us, what are Dict Views and then why are they useful?

36:34 So Dict Views are the object returned from a dictionary when you call items or keys. And I think almost all Python developers have used this, but we tend to use them to iterate over to get the keys and the items. What you might not know is these are special objects. They're not just simple iterables. And they act a lot like set, which kind of makes sense because if you've got a dictionary, the keys are all unique, so you can't have a repeating key. So if you've got a key view, it's set like which means you can do set like operations on it right.

37:08 After a quick question, like, is this thing I'm about to add in here or not? Something like that, right?

37:13 Yeah. And you can take two different you can take a set and key view and combine them and see the intersection and see what keys are common in both or neither. And those type of operations turned out to be very useful for what I was using it for. And to be honest, I think this might be the first time ever used that in anger. It's one of the things that you read about in the notes for the latest Python, and you think, I can't imagine I'll ever use that.

37:42 And I didn't for years. But then I had a problem where in Textual, when we do a new update via CSS, we've got two different data structures. One with the old positions of things and then one with the new positions of things. What we want to do is compare those two data structures and find the things which have moved or have changed size. And I started writing code for this. And it wasn't straightforward code, it was a couple of hours in. I had written a lot of code and I think that's a bit too slow, it's a bit too awkward. And only then did I remember the fact that you could use these key views set operations.

38:18 And the code turned out to be almost a one liner. And I was so happy about this, I forgot the fact that spent 2 hours writing code that I just deleted.

38:29 Let me give people an example here who are listening. So if you check out the blog post, there's a nice code example. And the UI of textual is made up of all these widgets. They've got names like header, footer and sidebar. And they have boundaries and regions rectangles. And as the UI changes, you might only want to redraw the delta, not the whole thing for performance reason. Right. And so, given the old view and the new view, the question is, well, what widgets have changed? And so you just say items carrot or symmetric different with other newer frame.items. And that tells you these are the pieces that have to be redrawn, right?

39:07 Yeah, that gets exactly information needed. That tells me which things are new, which things have been removed, and then which things have changed position. And those three types of things are the things that I need to redraw on the screen. And it's a one liner. And I get that information for free because it is very fast, it runs at sea level and produces just information that I need.

39:31 Honestly, this surprises me that this is possible. I would totally expect that was dot keys, because keys have to be set like but items, you could have the same item assigned to different keys all over the place and stuff. So it's a little interesting here.

39:44 The item is obviously that the key plus the value.

39:48 So together they're unique. The values are not oh, I see.

39:52 That's right. Because that's a tuple of the key. I see. Got it. Okay.

39:56 So.

39:59 Therefore yeah, whatever you add to it's not going to make it less unique by adding stuff, more possible differences. All right, so not totally related to this, but I got to ask it because it's just so meta. Andrew out of the audience asked, can you embed a terminal within a textual app?

40:15 I can. I've been asked this a few times. I'm just wondering what people want to use this for. But in theory, it should be possible.

40:21 It means I'd have to write a software layer which interpreted all the escape codes and then translated that to a region of textual app. But in theory, yes, it's possible. We'll be do it maybe one day. It's not the highest on the priority, but maybe.

40:38 Yes, maybe. Okay. Very interesting. Is there something like a textual contribute that people put in? Like there's Django contribute and there's other contributes?

40:49 Yeah, not currently, but I'm really hoping that the community takes it and starts building things. So you could search PyPy for textual underscore and get lots of widget libraries and various add ons.

41:01 Is there like a plug in or extension aspect, anything special like that?

41:07 Yes. So the widgets are designed to be built that way. Widgets are like independent portions of the screen that can handle events and things and updates, and those are bundled up into separate libraries, third party libraries. So that would be the easiest way to implement something. You could implement anything you wish, like a full ID if you wanted to, and just import it as a Python library.

41:30 Sure. Related to using dict views for speed.

41:35 It's really hard to beat Caching for speed, isn't it?

41:38 Yeah, caching is awesome. And it's one of the things which allows textual to be fast. So LRU cache, I think a lot of people have used it, but maybe not appreciate how fast it is. Caching and generating the key is done at the C level, so it's super fast and you can use it for quite small functions. We've got a lot of calculations which are pretty quick.

41:59 They're well under milliseconds, like fractions of a millisecond, but we do them a lot of times, so we might do them like 10,000 times. But if we introduce the Lru cache, the time it takes to do those function calls becomes time it takes to essentially do an diction look up, then they become very fast. So that led to quite surprising speed ups.

42:22 Yeah. So you have an example here that you talk about where you're given a couple of regions and you do the intersection of those two, a region being like a rectangle thing. So you've got to figure out, well, which is the top left most, and there's a bunch of comparisons to find the overlapping rectangle, if it exists. Right.

42:47 It's not very complicated, it's not very slow. It's just doing sort of arithmetic and it's working on local variables. That's generally the fastest kind of code you can expect from Python.

42:57 You create a region object which has to reserve some memory, but if you put the LRU cache on it, that becomes a dict look up, so it becomes very fast. And the type of calculations we're doing, we often do the same ones many, many times. So we use the same two values to find intersection like that. The first time you update the screen, you calculate some intersections, and then the second time maybe one or two items has moved, but most of the same calculations are done again.

43:26 So Lru cache ensures that you don't do those calculations again. You just pick them out of the dictionary and yeah, big wins. And it's so easy to just copy that one line and everything works. Yeah.

43:37 Also it's kind of related to what we're going to get to here. But this kind of code is fantastic because in terms of Caching, because it doesn't really depend on something that could change behind the scenes, it doesn't have hold of weird pointers that other could change in other ways. And so it's very deterministic. It's going to give you the same answer every time and it's not like the cache is going to get weirdly stale.

44:04 Right, yeah, exactly. So it's an Immutable object, I think region is actually a named tuple and you get all those benefits. There's no side effects.

44:15 You can write these functions. I've got an input and an output and it doesn't depend on any other state. And when you have that kind of function, I think they call it a pure function, is Caching. Works beautifully, there's no hidden surprises. And also I think makes your code more easy to reason about. You can trace it just manually. You can tell what's going on just by looking at one function.

44:40 You can see the full story.

44:42 Sure, yeah. Immutable objects. If your codes can use a mutual object, I think you should pave it. It doesn't always make sense, but a mutual is definitely best.

44:51 Yeah, definitely easy to reason about. Kim and the audience says presumably the memory cost of Caching many frequently called functions isn't a big issue on a reasonable machine. And maybe it's worth pointing out the max size perimeter you pass to the LRU cache.

45:07 That's right. So you set a maximum size and if you add more items than that, it will throw out the oldest one. So you can define the set, the maximum size that you record and it depends on how you use it.

45:21 You tend to have a common set of calculations which are the doing repeatedly and those will kind of be in the cache most of the time. And then you might have some calculations which happen infrequently combinations of input and output and then those get recalculated occasionally, but it's still a big win. And 4096 items for that. The region's name Tuple is quite small, so that keeps the memory usage to something reasonable.

45:50 I did want to highlight this project called Async Cache because I haven't checked lately, but I think the LRU cache is only for synchronous functions.

46:02 I think so.

46:03 Yeah, I think so, too. Maybe it's been upgraded and I haven't checked, but if it's still true, there's this project called Async cache which has nearly the same UI but applies to Async functions. So basically the decorator has to return a function which is first checks the cache and then calls the function for the Async version. That has to be an Async function returned out of the decorator, hence the difference. Right. And so this Async cache has something very similar where you can have a Lru cache where you set the max size. Or you can also have a time to live, like, only want these results to stick around for 60 seconds.

46:43 It also has a bunch of other interesting features that you can bring in, like works on ORM objects, request objects, bunch of other things. It has sort of custom support for custom types that are one of the things that this needs here is, I think, hashable. I think you have to have hashable arguments for LRU cache.

47:04 Yeah. That strikes me as something very useful. If you've got a calculation which does Summer Wait and you want to catch it, then, yeah, that looks like a fantastic project.

47:13 Not super popular. People can check it out, but it looks pretty useful. Okay, we kind of touched on this already, so maybe we won't go too much into it. But just one of the actual lessons you said is immutability is definitely a good thing. So we can get this from named tuples, which are, like, better tuples. You can address them by name of variable type or frozen data classes.

47:37 I tend to think mutable first, so I'll prefer to make my objects mutable, and only when I think that's going to become a hindrance do I make them mutable. And I think I started doing that a few years ago, and I think that's benefited my code. So I'd recommend mutable objects.

47:53 Yeah. And then if you're out there doing Pydantic, which many of us are these days, it has faux mutability, which is kind of like it. It takes a shot at making things immutable, and you could just, say, allow mutation False as the config for your pydantic model, which is pretty fantastic.

48:11 Yeah, I think Python doesn't support true mutability.

48:16 If you really wanted to, you could do some horrible hack to change an object which should be immutable. But, you know, like, we're all adults here, right? So don't do crazy things like that.

48:28 And even for languages to have the word const and stuff, it still doesn't necessarily mean what you think it means. There's a little bit of Monty Python going on. No Princess Bride sort of thing going on there, where, okay, so this object says it can't be mutable, and it has pointers to other objects. And so, sure, you can't reassign those pointers, but that thing points to something which points to something which internally you call a function which changes to get true immutability is super hard and super restrictive.

48:58 Super hard, yeah. Python isn't too bad in that respect. It's definitely safer than C, C++.

49:05 Etcetera, that's for sure. Okay. Immutability is good. So is Unicode art. What the heck is this?

49:13 In the textual code, there's quite a lot of functions like this which are kind of geometric, so it might divide something into two.

49:21 Yeah, it's always doing visual things. Right?

49:23 Quite a lot of visual things. So here we got an example as a function which takes a region and splits it into four by making two or making a horizontal on the vertical cut. And that's quite hard to express in English. Succinctly I mean, you can do it, but I'll take it like a big paragraph. But if you create something like this, this kind of Unicode art using various box characters, you can draw a diagram to show what you're doing. And if you're coming to that quote later, that just makes it really obvious at a glance what it's doing.

49:57 Yeah, It's Fantastic.

49:58 I'm a big fan of that kind of unicorn art, and I use an application called Monodraw, which is Mac OS only. But there are similar applications for other platforms. And yes, I use it wherever I can also, because it's kind of fun.

50:14 It Is Cool. A powerful ASCII art editor designed for the Mac.

50:19 It Costs money, $10. I Love that. Has educational pricing, but it only costs $10.

50:27 That's Kind Of Cool. But yeah, it's pretty neat, I guess. You have, like, little arrows and boxes and just like, you might draw with PowerPoint or keynote or something like that. As, like, kind of your let me put together a visual graphic. But then output is ASCII art.

50:44 Yeah. And it's kind of like a vector graphic type thing. So if you draw a box, you can click on the box and drag it. It's not like a bit map. That's Fantastic. Yeah, it's Quite Powerful. I hope the authors made a fortune out of it, frankly, because I love it.

51:00 So what is the output like? You Output To Clipboard.

51:03 Yeah, you can cut and paste it output to the clipboard. You can write it to a text file. Easy. Cut and paste it directly into Python code.

51:11 Yeah, Of Course. So That's really Cool. It also made me think of something that's not exactly the same purpose, but balsamic. I don't know if you're familiar with Balsamiq, which is really great for developing UIs. I don't know if they have a gallery or something. They need some more graphics on this thing here.

51:27 Yeah, I've Used It. Wow. It's been around for a long time, hasn't it?

51:31 It's Been Around Forever. Yeah. But it basically lets you create UIs that look almost like as if they were created using ASCII art. Not quite, but it's an interesting goal. I did also want to highlight the most useful piece of ASCII. And to be clear, all of this discussion is what goes in the comments, right? What goes in the code comments or the doc strings? The one for the object. Allocator in Python. So If You Look In Pymalloc, C and CPython, there's all this fairly Intense looking code for It, like Allocating Memory when It's Particular c python Objects, like A Py Object or Py Long Or Whatever. Right. If you scroll down to the section here around line 777, it has a paragraph as an object. Allocator for Python. Here's an introduction to the layers of Python memory, architecture, etc. and instead of having an essay in here, it has this incredible graphic that is like vertically aligned, shows you here's where we allocate things like integers and lists. And here's Python core non object memory allocation. And here's how it relates down to the OS and to actual hardware. What do you think of this?

52:47 That's pretty awesome. A lot of respect to the author because I'm fairly sure they didn't use mono draw. I think they did that by hand typing the character spaces and everything.

52:58 That's pretty awesome.

52:59 Yeah, I think this is really fantastic. I was trying to piece together I did a course on Python memory, and I was trying to piece together like, well, how do I visually represent how it is described that the memory works? And I'm like, well, let me go look in the source code. And I was looking at this like, there's an actual picture here. This is amazing. I can't believe it.

53:18 Yeah. So anyway, if people need a concrete example of the type of stuff you're talking about, here's one that's pretty close to home. We all use it every day and we didn't know. Fractions I was always amazed at the fact that zero one plus zero one plus .1 is not equal to zero three. I learned that in the school. And it was but for some reason it's not. What do you think?

53:36 Yeah. So this is a problem that goes it's not just Python. It's pretty much any language which uses floats and doubles, which is like, almost all of them. And it trips up beginners and experienced developers. It tripped up me when I was working on Textual. We have lots of code which will divide the screen into various proportions. So you might have a third and then a two thirds, and you might divide the height into 7th.

53:59 And what I found was that when I use floats, I got a lot of rounding error. Not actually not a lot of rounding error, but occasionally rounding error, which means it wouldn't draw a line or it wouldn't draw a column, because this kind of issue where the rounding error is compounded and it's been rounded down to the nearest character right.

54:17 Because you've got to talk in, like, little block pieces anyway. And if it just misses it right?

54:22 If it just misses it by .001, then you'll be a whole character out. And I did come up with various ways of solving this where I used integers rather than floats and kept track of the error, which I think is the standard approach of doing it. But it's quite tricky code, and I get it wrong too frequently, but then I remembered fractions.

54:45 So fractions, they behave just like numbers, but they start at life as a numerator and denominator. So now fraction one comma two equals a half. And the great thing about fractions in the standard library is they don't suffer from that rounding error. So if you have 3110, they'll add up to 310 exactly. With the rounding error. And it makes that kind of code, which I do a lot of integral, to be much simpler. So I was very happy when I re remembered it because I must have known years ago and thought, why do I need fractions?

55:19 Yeah, exactly.

55:21 This is not elementary school. I don't need this. Come on.

55:25 Yeah, you learn that, you think, well, that's probably useful to mathematicians or something, or someone else. Not to me.

55:33 But if you work long enough, you'll eventually find a problem where that is actually the perfect solution for it.

55:38 I didn't know about these either. I see comments in the audience as well, like fractions. What is this madness?

55:45 So you're telling us that you can only work in rational numbers, not irrational numbers like py and e? We can't have columns that are e wide.

55:55 No, you can't.

55:57 Or py high.

56:00 It's py by e. No, it's cut off. Darn it.

56:05 The cool thing is that fractions, you can drop in replacements to floats. If you've written some code which was previously using floats, and then you pass in fractions, everything will work as normal, except you'll not get the rounding error. It's really kind of beautiful.

56:18 Okay, so you're saying the fraction library supports things like division, multiplication, additions and basically, what, duck typing behave the same?

56:27 Yes, duck typing is a rational number. So anywhere we use a float, fractional work.

56:32 Okay. I learned about that. Amazing. Let's see. Emojis are hard. You talked a little bit about things that take up different sizes and Unicode and whatnot.

56:41 Yeah.

56:43 So when I started Textualize and I got my first employee, I thought, this is a problem that I want to tackle because it has been bugging me for two whole years. And the problem is basically this, that some characters will take up two cells in the terminal or double wide, and some characters will take up one cell. And if you want to do any kind of formatting, say, to draw a line or panel around it, you need to know exactly how many cells a piece of text will take up. And it sounds like a simple problem. All you need to do is know how many cells a character will take off. So you might have a function which takes a character and returns either one or two. And in essence, that's what Rich does. But some characters you can't know because it will render differently on different terminals. They'll render differently on Item and Windows and Linux. And it gets even more complicated. You can get multiple characters, multiple code points, the characters. So you might have something like a flag. And a flag has a two letter character code and another character code which tells you this is a flag.

57:49 If you iterate over that, you get three good points.

57:52 So you have to know. First of all, how everything works together, and there's quite a lot of those type of characters.

57:58 I can't imagine how tricky it is to be down inside unicode.

58:02 Yeah, this is crazy. It's very complex. And we thought, well, we'll just do it, we'll just apply some engineering effort and just do it. But we discovered that it was impossible to know because you can't tell how the terminal is going to render these unicode. It might do it correctly, it might actually render a single character. If the terminal is not aware of multi code point emojis, then you might get three characters they might render as nothing, or they might render three double width characters they might not even render properly. So they might overlap following character and.

58:38 Some number of boxes.

58:39 Yeah, it's just every terminal did it differently. Not only the terminal, it was platform dependent. So if the terminal used the unicode database on the operating system, then you'd get different results. If it shipped its own copy of the unicode database, and it just turned out it was impossible to know how many characters.

58:59 So what do you do?

59:00 Well, there's a subset up to about unicode nine where things seem to be mostly sane, most terminal support, so if you use those, those are fine, but after that, it becomes unreliable. If you have flags and multi code point characters, then it might not work. It might cause the alignment of tables and panels to be out. The end carter might be shifted out by one, and it just comes up so frequently, and I would solve it if I could, but as far as I can tell, there is no reasonable solution which will work across all platforms.

59:36 And too many unknowns, right, too many unknowns.

59:40 Yeah, it's a crazy thing, but it kind of makes sense because these unique code characters came out in the last few years, and operating systems and terminals haven't caught up and they haven't agreed on how to render them. So it's a frustrating situation.

59:55 I'm sure that there is yeah. If you look at some of the nerd fonts, for, you look at some of these, what is possible? I think here you have these colored arrows. And they have if you go over to oh my Posh. I which I don't really have time to talk about. But if you look at the themes that are in here. The different themes that you can pick. And just some of the effects. Like a character that looks like a git branch with an arrow in it.

01:00:29 How are you supposed to decide how big that is? Or how is some of this stuff accomplished?

01:00:34 It's just I don't represent those characters. I wonder if they reuse existing characters.

01:00:41 When I saw that, I was like, okay, I don't know how this is possible. Right. Rounded edges and all sorts of stuff. So I'm trying to find one where it's like a sparkly fade from one character to the next.

01:00:53 These things over in the themes, if I thought about your job to figure out, like, what is that supposed to look like, I don't know, I would just give up.

01:01:03 I mean, they're really impressive and really useful. But this one, for example, the Cert theme where it's got like little dots that fade from one to the next, I just amazing. But mostly, how are you supposed to know, right?

01:01:17 So those are your lessons.

01:01:20 Very cool stuff. I really appreciate you coming on to talk about the seven lessons.

01:01:25 Terminals are fast, dict views are amazing. LRU cache is fast. Immutable is good. Unicode art is good. Fractions are good. Emojis bad.

01:01:35 Does that summarize it in a nutshell?

01:01:39 Let's wrap it up with one more thing real quick here. Let me see if I can find it. This one. There we go. So one of the sort of bring it full circle back around. One of the cool things to make terminals nicer that you've talked about recently is Rich-CLI. You want to close out the show? Just tell us what Rich CLI is.

01:01:58 Sure. Okay. So as you know, Rich is a library, and Rich CLI is a CLI interface for that library. So most of what Rich can do is exposed by Rich CLI. So you can get most file formats and it'll be nicely syntax highlighted. You'll have line numbers and guidelines, those sorts of things. And you can do things like panels, you can format text.

01:02:22 Well, there's a whole bunch of other features.

01:02:25 Yeah.

01:02:26 So, for example, if I had a JSON document on the terminal, I could type, I could open it in some terminal based editor SSH somewhere, or I could just type more or cat the name of it and it would print out just plain text of whatever is on the inside. Or now I could type Rich the file name and I get highlighted colorized formatted content for like, CSV and JSON and all those kinds of things, right?

01:02:53 Yeah. So Json example is quite good because that will decode the Json. So if you've got like compressed Json with no white space, it makes it impossible to read. Rich will decode it and also format it and like, pretty printed, pretty prints it. Exactly. Yeah. And it'll do markdown. It'll do a reasonable job of rendering markdown, and it will take CSV files and it'll turn those into nice rich tables. And if your output is quite large, you can add pager and that will put it in a nice pager where you can scroll up and down with scrollbars and do page up, page down, etcetera. It's kind of like a toolbox for fancy rich formatting of all sorts of different data types.

01:03:36 Definitely a cool project. And I know you're concerned about emojis, but Paul in the audience says, fortunately, Doom does not require emojis, so it's still on the table.

01:03:46 It was not yes.

01:03:49 That's right.

01:03:51 All right, well, fantastic lessons. Thanks for sharing all of your experience.

01:03:55 Final two questions before you get out of here. If you're going to write some Python code, work on Rich, what editor are you using these days? It's not so meta that you're using textual to write textual yet, is it?

01:04:04 No, maybe one day, but I use Vs code, and I quite like it. I'm comfortable with it. My colleague uses.

01:04:12 What's?

01:04:12 The editor by Jet brains.

01:04:14 PyCharm.

01:04:15 PyCharm. And he's very proficient at PyCharm. And to be honest with you, I am jealous of some of the features of PyCharm. It does some really cool things, so I'm kind of tempted to try PyCharm.

01:04:25 Looking over the shoulder. Awesome. Yeah, very cool. And then notable PyPI package. I mean, we've touched on some good ones that start or end with Rich, but anything else you run across that you're like, oh, this is fantastic, people should check this out.

01:04:38 Oh, gosh, there's so many advice. I'm drawing a blank.

01:04:43 I should have heard one in advance.

01:04:45 How about one that you use that makes Rich work well or something?

01:04:48 Well, there's Prompt Toolkit, so I owe Prompt Toolkit I'm a big debt of gratitude because when I was figuring out the textual stuff, I looked at the Prompt Toolkit source code, which is a great thing about open source that you can look at other people's code. And it's very good to help me understand things, and it still does things which textual doesn't do yet. So I think Prompt Toolkit is an excellent project, and if you haven't used it, you should definitely check it out.

01:05:13 Yeah, prompt toolkit is interesting. You'll be typing along and all of a sudden there's like a combo drop down box, like a select right in the middle of your terminal. Then you just carry on.

01:05:23 Yeah. It makes things like I think it's used in I Python. It makes that much nicer, much more friendly.

01:05:29 Absolutely. All right, well, final call to action. People want to do stuff with rich textual and maybe take some of these lessons and run with them. What do you tell them, Will?

01:05:38 Yeah. Check out the website and check out my Twitter profile, and if you have any questions, feel free to ping them over to me. I'm always happy to talk to people about Python related things.

01:05:48 Yeah, fantastic. And of course, I'll link to the article with your list of topics there so people can check that out. Thank you so much for being here. It's been great to catch up with you.

01:05:57 Thank you. You bet.

01:05:58 Take care. Bye bye.

01:05:58 Bye.

01:05:59 This has been another episode of Talk Python to me. Thank you to our sponsors. Be sure to check out what they're offering. It really helps support the show. Starting a business is hard. Microsoft for Startups Founders hub provides all founders at any stage with free resources and connections to solve startup challenges. Apply for free today at Talkpython.FM/foundershub. Join sentry at their conference Sort the Madness. The conference for every developer to join as they investigate the movement and trends for better and more reliable developer experiences. Save your seat now at Talkpython.Fm/dex. Want you level up your Python. We have one of the largest catalogs of Python video courses over at Talk Python. Our content ranges from true beginners to deeply advanced topics like memory and Async. And best of all, there's not a subscription in site. Check it out for yourself at training.talkpython.FM be sure to subscribe to the show, open your favorite podcast app and search for Python. We should be right at the top. You can also find the itunes feed at /itunes, the GooglePlay feed at /Play and the Direct rss feed at rss on talkpython FM.

01:07:09 We're live streaming most of our recordings these days. If you want to be part of the show and have your comments featured on the air, be sure to subscribe to our YouTube channel at talkpython/YouTube. This is your host, Michael Kennedy. Thanks so much for listening. I really appreciate it. Now get out there and write some Python code.

Back to show page
Talk Python's Mastodon Michael Kennedy's Mastodon