Have you heard of the package rich?
This library allows you to create, well, rich terminal-based UIs in Python.
When you think of what you can typically build with basic print statements,
they may seem quite limited.
But with rich, imagine justified tables, progress bars,
rendering of markdown, and way more.
This is one of the fastest-growing projects in the Python space these days,
and the creator, Will McGoogan, is here to give us the whole history
and even a peek at the future of rich and a follow-on library called Textual.
This is Talk Python to Me, episode 336, recorded October 13th, 2021.
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 talkpython.fm.
And follow the show on Twitter via at Talk Python.
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.
This episode is brought to you by Shortcut, formerly known as clubhouse.io,
and us over at Talk Python Training.
And the transcripts are brought to you by Assembly AI.
Will, welcome to Talk Python to Me.
Thank you.
It's fantastic to finally have you on the show.
I feel like we've talked a lot about the work that you've been doing many times.
Not so much on Talk Python because we're more focused on a single topic.
But even so, I believe, you know, at the end, I always ask for some project that needs attention,
needs some sort of shout out.
And, you know, I believe Rich has come up more than once.
I think Textual has come up at least once there.
So the prior guests of the show have been fans.
And I know the audience is a big fan.
So, yeah, congrats on all the progress there.
Great. Thanks.
Yeah, I really appreciate the coverage.
You probably increased my star count by a few thousand.
Well, I do want to talk about that because this project is super popular.
And as we get into it, I think it's going to be fun to explore some of the things that you felt were key to that.
And if this is the first time people are hearing about Rich, you definitely want to check out some of the screenshots.
Maybe I'll do something fun, like make part of the show, have the show notes or the podcast player have some screenshots from the various sections.
Like as I said, I'll see if I can make that happen.
But before we get to all that, before we dive into Rich and Textual and all the other things, let's talk about you.
How did you get into programming and how did you find yourself doing all this open source Python?
How did I get into programming?
Oh, OK.
So as a kid in the 80s, I guess, I had a Spectrum 48K computer.
It was a little plastic thing you plugged into your TV and you could create very simple animations and little games.
And I think from there I was hooked.
Oh, fantastic.
That's just something about me that connected with programming, I guess.
What's interesting is those games were so basic, right?
They weren't like 3D, VR, oh my gosh, I'm there.
Or some of the flashy, even the flashy mobile apps, mobile games these days.
But something about those early, early games really captured the imagination, didn't they?
Yeah.
And the fact that they were so limiting had to make you a little bit creative.
So it encouraged creativity because you couldn't do much of anything.
So you had to make the best of what you got.
So it encouraged you to experiment.
And I think it was a great way to get people into programming again, I think.
Yeah.
Until recently, we haven't had that.
And I think the Raspberry Pi does that to some extent, which is a great thing.
Yeah.
It sort of reaches out to the real world in a more simplistic way, kind of repeating that cycle, right?
Yeah.
And it just allows people access to programming in a very kind of accessible form for children, I guess.
So I think the next generation in 20 years will be citing Raspberry Pi as how they got into programming.
Interesting.
Yeah.
I built a robot the first time around or something like that, right?
Yeah.
Instead of wanting to play a game or script a game out or something like that.
Interesting.
And, you know, a lot of times I ask people, okay, well, what are you doing now?
They're like, oh, I'm, you know, head of data science at a company such and such.
You've taken a very interesting, and I suspect a lot of people will be quite jealous of what you're up to these days, right?
What are you doing now?
Yeah.
So up until recently, I was contracting.
But I ended my contract.
I'm going to take a year out.
Well, possibly a year.
It depends how much.
It depends how things go.
But the idea is to work on open source, specifically rich and textual.
There are other projects that take my fancy as well.
Anything that I can contribute to might try my hand at it.
It's not entirely selfless because I do think there might be commercial applications for textual down the line.
But certainly for this first six months, it'll be just focusing on just making it the best thing you can.
Making it a super solid foundation.
Yeah, absolutely.
Well, I don't think it's going to take that much to get some things in place to make this long term for you.
You know, people can go, if their company or individually they're finding huge value, they could go to GitHub and sponsor you.
There's enterprise stuff that can be set up.
We'll dive a little bit into that more possibly later as well.
But I wish you a lot of luck.
But I think with the traction that you're getting and the new things like I really find GitHub's sponsor feature to be something of a game changer.
Yeah.
I remember looking back, you'd see, oh, here's a popular project.
Maybe it's not even an open source library, but it's like an app.
And it's like, click here to thank the developer on PayPal.
Right.
And just.
There was a little bit of a barrier to entry.
Yeah.
And maybe you do it once.
Right.
But with GitHub, you can say, I just kind of want to say, I want this to keep going.
So here's two dollars a month.
And if, you know, not that many people who find it valuable send in a couple of bucks a month, all of a sudden it starts to be a foundation that you can really build from.
Yeah.
It could build up and be something which is sustainable and sustain open source because so many people benefit from open source, including big companies, big corporations.
But a lot of these developers are doing it in their spare time for the love of it.
And they haven't asked for funding before, but a lot of them deserve funding.
Certainly lots of projects which could really use funding to make sure they keep going, to make sure that the software that we all use is still available in a year, two years and five years down the line.
Yeah.
Otherwise, we're going to end up in a place with like open SSL where there's one person who maintains it and a quarter of the world seems to be built directly upon it.
Right.
Remember that?
Yeah.
It was a huge problem.
Heartbleed, was it called?
Which is a Heartbleed?
Yeah.
Heartbleed, that's right.
Yeah.
Which is a great name for a bug.
It really is.
Why wasn't this fixed?
Well, there's one person who does it in their spare time, but everything depends on it.
Yeah, but there's still one person who does it in their spare time.
Yeah.
And yeah, it's just really hard to put that kind of energy and responsiveness into it.
All right.
Fantastic.
So let's start with textual, which I had on the screen, but let's start with rich.
Rich is where things got started amongst rich and textual, right?
If I remember the history.
Yeah.
Rich was first.
That's about two years ago that I started that.
Yeah.
Cool.
So tell people, you know, a lot of people have heard of rich, but maybe tell folks out there,
how would you describe it?
You know, it's, we've had ways to sort of print stuff nicer.
We've got pretty print Python.
We've got colorama where you can put color into your, your terminal, but this takes it
to an absolutely new level.
So tell us, tell us about rich.
Yeah.
Um, that makes it difficult to describe sometimes when people ask me what it does, because it
does quite a lot of things.
Um, but it's all under the umbrella of writing more sophisticated outputs to the terminal.
At the basic level is you can set colors and you can set styles like bold and italic.
the next level up, it'll do word wrap and it'll also word wrap the, the style.
So you can apply bold and then, then word wrap it.
And then we have things like tables.
There's quite sophisticated table support, which are quite close to HTML tables.
You can, you know, put things in cells.
You've got a header row, you've got a little divider, and then you've got the data.
Yeah.
And then you can draw lines around it and change the styles.
And, it's, it's all, you even have like alternating rows, right?
So it kind of helps you line across, which is pretty neat.
Exactly.
Yeah.
So it's, it's quite sophisticated.
It's all composable.
So if I've got a table, I can obviously put text inside it, but I can put another
table inside it, or I could put a progress bar inside it or syntax highlighting inside
it.
So the idea is that, rather than like lots of separate libraries, which don't work
well together, which I think was a situation that we had previously.
Now they all work together.
They fit inside each other and they integrate quite well.
Right.
So you could take your formatting and put it in your word wrap and put it inside of a
table cell or something like that.
Exactly.
Yeah.
So one of the things that struck me, well, there's a couple of things, but one of them
is just how popular Rich is.
Right.
It's almost 30,000 GitHub stars.
That's, that's close to FastAPI level of popularity and not that far behind Flask and
Django.
That's a really, really popular.
When did you create this?
Two years ago.
Yeah.
So I guess on the timeline, similar age to FastAPI, but much younger than Flask and Django,
if I'm comparing them to those.
And over here, it says on your page, you have 2 million downloads a month.
That's pretty incredible.
Yeah.
That's, that's, that's pretty crazy.
I think quite a few of those are automated.
They're from CI systems.
Yeah.
But I do see that, that rising quite, quite steadily.
Yeah.
I wonder how many of the CI systems just in general out there do caching at some level where it
wouldn't register.
Right.
you know, I pip install a thing I've already installed and it's a certain version.
And it'll just say using cached version.
Mm-hmm.
Right.
versus if you create a brand new Docker image and then the next thing you do is install
your, you know, pip install your dependencies inside of your Docker.
That's a true download, right?
Because that machine is totally fresh.
Yeah.
So it's, it's hard to tell.
Yeah.
I don't know.
Do you have any feel for what that breakdown is?
To be honest, I'm not sure.
That site doesn't give you the breakdown.
To be honest, what I would be interested in is how many developers typed pip install rich
in that month.
You know, how many human beings played with it.
That would interest me more.
But suffice to say, quite a lot of people have used it.
It is quite a lot.
Downloading it.
Yeah.
I'm sure it's changed the way that you think about working on the library and whatnot.
Right.
You know, it's, oh, maybe this might, might destable it.
This might cause a problem or this might cause confusion.
It's one thing to do that for a thousand people.
It's another to do that for two million.
That's right.
Right.
It's, I am.
You're going to hear about it, I bet.
Absolutely.
I didn't follow Semver very strictly originally.
I always plan to use Semver and people are starting to use it.
And I made, I made a breaking change.
And I didn't think anyone was using this particular feature.
So I didn't increase the major version number.
And then a couple of days later, I got an issue, someone telling me off.
Quite rightly so.
Oh man.
For not warning them about a breaking feature.
So since then, I've been very, very strict.
It's a version 10.
And that's because I've made 10 changes, breaking changes to the API.
They're actually quite small.
You know, it might just be one signature and one method, but that requires a major version
change.
Right.
But at that scale, obviously, that's still going to affect it.
That people, you're going to hear about it and whatnot, right?
Exactly.
I don't want to break anyone's code.
I don't want to give them a bad day.
So I'm very strict about that kind of thing.
Yeah.
Fantastic.
And also people should pin their versions, right?
So on the flip side, they can also make sure that what they're working on is nice and stable,
right?
Yeah.
A lot of people don't.
I do search GitHub sometimes for rich and I look at their PyTummel.
What is it?
PyProjectTummel.
Yeah.
PyProjectTummel.
Yeah.
And a lot of people don't pin their rich version.
They'll just be rich and it shouldn't break too much.
And often it's a hobby project, so it's not the biggest deal.
Right.
It really depends.
Like it's one of the things I struggle with.
So I do a lot of course development, right?
And I don't necessarily want to pin people to the oldest version.
I'd rather let them have the newest stuff so it exactly matches the documentation.
If they go check it these days and stuff, if they go back, you know, six months and watch
the video or check out the demo app.
But at the same time, there's a chance of that instability.
There's always this tension, right?
And I guess it depends on what the use case of that app or that library is.
Yeah.
It's tricky to say.
The less critical it is for your business or your project, the more you can relax.
If it's a tutorial, maybe it doesn't matter quite so much.
But if it's critical infrastructure, then you want to pin.
Yeah.
For my web apps, versions are pinned.
Super strict.
Even the dependencies of the dependencies, like the transitive closure of the dependencies
are all pinned.
Yeah.
On like little demo apps and stuff.
Like it's just wide open.
So I think it depends.
All right.
So out in the audience, we have Hybotics says, Will, this looks really good to me.
I'm looking at repo now.
So not everyone has previously heard of Rich, which is awesome.
Oh, it's good to know there's a few people left.
That's right.
Yeah.
I suspect there's actually a lot of people.
So who haven't heard it before.
Again, check out the screenshots because if you think, oh, here's something that sort of
enhances terminal output that completely undersells the level of what you've pulled off here.
And that's only before we even talk about textual, right?
Let's talk about compatibility because one of the things I find with these sort of nicer
terminal output things is like, this works fantastic on POSIX systems.
Oh, but you better not be on Windows.
Or if you're a data scientist, you like Jupyter Notebooks, you can forget about it.
But if you really want to run this thing, like, so what's the story?
Like, where can I use this?
Just about everywhere.
Linux, OSX, Windows, and Jupyter.
It started out, it was Linux OSX because that is the easiest platform to develop this kind
of stuff for.
Windows is a bit of a black sheep.
It didn't quite work as is.
Windows is getting better though, right?
I mean, when it was cmd.exe, it was like, oh boy, this is really different.
But the new Windows terminal, I'm really digging it.
You know, the new PowerShell, the things like, oh, my Posh extensions.
I can feel much more at home on Windows on the terminal than I used to.
Yeah, yeah.
So the new Windows terminal is much better.
Rich doesn't have to do quite so many, doesn't have to jump so many hoops to get Windows support.
In fact, it just runs kind of as is.
It still supports the older Windows terminal, which does have a few issues.
It doesn't, it has very limited colors.
That's brave.
Yeah.
But I guess maybe you want to, right?
If you're going to give the app to somebody, you can't really package up the terminal they're going to run it in.
So you probably want to have your best possible experience on.
To be honest, most people are still going to be running cmd.exe, even if they shouldn't.
Yeah, exactly.
Yeah.
I mean, I could just tell them to install Windows terminal, but that kind of goes against the ethos of this library.
I just want it to work so that people don't have to think about what it runs on.
Yeah.
Put a lot of work initially into.
Yeah, so Linux, macOS, and Windows with good support for the new Windows terminal, very limited support for the old command prompt.
That's still pretty good.
I think it's fantastic, actually.
If people are really passionate about their terminal and they're on Windows, they probably know about Windows terminal anyway.
So they're probably good.
That's true.
Yeah.
The one that I thought was interesting and nice is Jupyter Notebooks.
What's the support there?
So it works quite, quite well.
So I wasn't a big Jupyter user at the time.
I was obviously aware of it, but I didn't use it myself.
And people asked me for Jupyter support.
And I thought, it doesn't do that.
It just works in the terminal.
But then I looked into it.
And it wasn't too bad because I already had functionality to export terminal content to HTML.
So I could put a little wrapper around that, export it to HTML, and then insert it into Jupyter.
They've got an API which allows you to write content into a notebook.
And so I got Jupyter support up quite quickly, quite easily.
And it works quite nicely, which people appreciate.
It means that you can write code which writes to terminal mostly.
But if you do happen to run it in a Jupyter notebook, then it'll write the same thing there as well.
It just knows, it detects that it's running in the Jupyter environment.
And then it just, all right, output is not print.
Output is generate HTML.
Exactly, yeah.
And Jupyter does have support for that.
It will capture standard output and it will convert the colors and everything.
But the problem is it wrapped the lines.
So if you expanded the window, it would break any kind of neat formatting.
If you've got like a grid or a table, it would break that.
So I had to do the HTML export within Rich as well.
Yeah.
Basically, most anywhere people do Python with a UI of some sort, this works is the takeaway.
Yeah.
This portion of Talk Python to Me is brought to you by Shortcut, formerly known as Clubhouse.io.
Happy with your project management tool?
Most tools are either too simple for a growing engineering team to manage everything,
or way too complex for anyone to want to use them without constant prodding.
Shortcut is different though, because it's worse.
No, wait, no, I mean it's better.
Shortcut is project management built specifically for software teams.
It's fast, intuitive, flexible, powerful, and many other nice, positive adjectives.
Key features include team-based workflows.
Individual teams can use default workflows or customize them to match the
the way they work.
Org-wide goals and roadmaps.
The work in these workflows is automatically tied into larger company goals.
It takes one click to move from a roadmap to a team's work to individual updates and back.
Tight version control integration.
Whether you use GitHub, GitLab, or Bitbucket, Clubhouse ties directly into them,
so you can update progress from the command line.
Keyboard-friendly interface.
The rest of Shortcut is just as friendly as their power bar, allowing you to do virtually
anything without touching your mouse.
Throw that thing in the trash.
Iteration planning.
Set weekly priorities and let Shortcut run the schedule for you with accompanying burndown
charts and other reporting.
Give it a try over at talkpython.fm/shortcut.
Again, that's talkpython.fm/shortcut.
Choose shortcut because you shouldn't have to project manage your project management.
Just going back to the pip-pinning version stuff, Wayland on the livestream says pip-compile.
Pip-tools is a game changer for pin dependencies and pip-compile specifically for managing pin
dependencies.
That's what I've switched to as well.
So I just run a script, checks for all the new versions, regenerates all the pip-compiled
stuff.
And I'm really enjoying that.
I think that's fantastic.
Okay.
I've not used pip-compile.
I'll have to check that out.
All right.
You basically define a requirements file that has what you actually would have pip-typed,
pip install, and then it will generate a requirements.txt that is the transitive closure of all of
those dependencies, which are pinned.
And then you can ask any time for it to update the versions, the pinned versions of that.
Okay.
Is that like Poetry's log files?
I think it's similar.
Yeah.
I'm not 100% sure, but I think so.
All right.
So let's talk about various features here.
I think just going through, I mean, we touched on them, but let's dive into it a little bit,
maybe talk a little bit about the code you write.
Sure.
So Kim Van Wake is here to kick us off on the first one.
Try something as simple as from rich import print in your next project, and you will be
amazed.
So Will, tell us why we'll be amazed.
Like what's this alternate print?
When I first wrote this as a console class, you have to construct a class and that's got
a print method.
But I figured I could just overwrite the existing, the built-in print because it's a, it's a function
in Python three.
I can just replace it with my own version.
So that's what I've done here.
I'll give, there's a version of print that you can import from rich, which has the same
signature as a built-in print, but it supports the console markup.
So you can insert these little square brackets with a style like, here we've got bold magenta
and it'll do emojis, colon, vampire, colon.
And these styles, like the square bracket, bold magenta slash bold magenta, this is specific
to rich.
This is something that you came up with.
Yeah, that's right.
It's called, I call it console markup and the syntax is very BB code like.
I don't know if you ever used BB code.
Yeah.
It's quite simple.
It's just like a markup where the tags have square brackets.
Yeah.
I like this a lot because one of the things that I'll use a lot still is, which maybe I
need to start switching to what you're doing here, is Colorama.
But for Colorama, you'll do things like you'll import the foreground settings or styles and then
you can say foreground dot green plus the text.
Yeah.
Foreground reset to go back to normal, but you don't have the bold.
And then all of that stuff has to happen in code, right?
If I wanted to say import some text and then show it on the screen, that text could have
these styles in it, right?
That's right.
Yeah.
So you can embed it in code easier or read it from a file, et cetera.
I think it's a bit easier to read rather than doing lots of string concatenations.
And also the benefit over the Colorama approach.
Colorama is a very good bit of software.
I've relied on it for years.
But the problem is when you concatenate strings like that, you insert these ANSI codes.
Once you've built that string, you can't do anything with it really.
You can't word wrap it.
You can't format it.
So with console markup, you can do.
You can markup bits of text with color and style, et cetera.
And then you can further do operations on them like word wrap and centering text and putting
it inside the table, et cetera.
Right.
Two other things that jump out here that are interesting is you have emoji support.
So you can say colon vampire colon, which is pretty awesome.
You can technically, if the file format supports it, you could actually put a vampire emoji
in the string.
Yeah.
But it's still kind of nice that you have this sort of emoji lookup, right?
Exactly.
Because if you want to insert the Unicode character, you'd have to go and find it and then cut and
paste it.
Yeah.
You can just do colon.
You can set that into console markup, just colon vampire colon or colon smiley colon.
I think there's a couple of thousand emojis you can use there now.
Fantastic.
Then another thing that jumps out is you're printing hello, bold magenta world.
So that's the word world, bold and magenta.
And then the vampire.
But then you're also printing out a dictionary.
And the dictionary is like pretty printed, but also syntax highlighted.
So if you print a container, like a dictionary, a list, or like an atomic Python type, it'll
run the pretty printer over it.
So it will format it in kind of the style that people like.
In code, you'd probably format.
This is how black would format it.
So it looks much the same.
Then it runs the syntax highlighting over it.
There's a few regular expressions.
So in which you can say anything between two quotes is a string and therefore it's green.
Anything in angle of brackets is a tag-like thing.
So I'll bold the brackets and change the tag name to bright red or whatever it is.
And so that the output you get is quite readable and looks like something that came out of VS Code or your editor.
Yeah.
The more I look at this, the more I think maybe just every project, I'm going to follow Kim's advice and just from rich import print.
Because why not?
This looks, it has all this cool auto formatting.
Does it look actually at the type that it's printing to make any determination?
Or does it just look and see if it's source code and then try to format it?
It looks at the type.
Like if it gets a dictionary or it gets an object versus getting it like a true string.
It'll do both.
It'll syntax highlight a string.
But if it's a container, if it knows that the type, it'll do some syntax highlighting there.
There's also a simple protocol you can add to your own objects if you want them pretty printed and formatted.
Oh, okay.
But not dunder stir, dunder repper, but something else.
Dunder rich.
It is dunder rich repper.
Right.
You can specify the arguments and parameters and the indentation.
It'll render something that's very much like a pretty printed dict.
That sounds like something that would be fantastic to add to some intermediate library that people use.
So I, sure, I could create a class and add it to mine.
But so often what I want to do is print out a Mongo Engine model or a SQLAlchemy model or a Pydantic model.
Yeah.
Pydantic could add that.
Or, you know what I mean?
Like these like intermediate SQLAlchemy could add something like that.
Oh, this is how you describe.
Like this one has an index and whatnot.
I think that'd be fantastic.
Yeah.
So I've added to Attrs.
So it'll pretty print objects from the Attrs library.
I have a PR for Pydantic as well.
So hopefully in the future, you print a Pydantic object and it will format it quite similar to the built-in data structures.
Yeah.
Okay.
Fantastic.
I love it.
Before we move on to this, I do want to talk about some other things because we're just scratching the surface here.
But one of the things that I think has both impressed me and, you know, Brian and I over on Python Bytes on our podcast we do there,
we've been continuously impressed at how fast you're adding new features and still kind of keeping the ethos of this library together.
So how, maybe give people a little hint on just the velocity here.
Like how's that work?
Well, I'm not convinced that it's been that fast.
I mean, bear in mind Rich is...
It felt like a lot of work.
It didn't feel that fast.
When I add new stuff to Rich, I'm not starting from scratch.
There's several layers which are already built and well tested.
The bit that I add might not be as large as it, maybe it looks.
I see.
So you've already got a lot of structure and architecture that makes adding a new feature...
Yeah.
...from scratch sort of thing, right?
So a good design basically.
I hope so, yeah.
And it seems to be working quite well because, you know, I did build a core feature set and then I added some things to it.
And admittedly, those things came quite fast because it wasn't that hard to implement.
And I've got to a point now where Rich is quite large.
I'd be resistant to adding any more stuff to it unless it is very useful for like a broad selection of users.
Sure.
Do you have a sense of how many lines of code it is?
I know you don't mean large in that sense.
You mean large in sort of feature set.
But do you have a sense of how many lines of code?
You know what?
I've never checked.
I couldn't guess.
By the time we're done with this recording, someone out in the audience will have like already downloaded and checked for us.
Who knows?
Probably.
All right.
So the next thing let's talk about is the REPL.
So I can create a REPL redevelop print loop by typing the word Python on the terminal.
And that opens it up.
But it looks just...
It's probably the least possibly good experiences you can have in Python, right?
There's no color.
There's no feedback on sort of what's happening, right?
But then I can say from rich import pretty, pretty.install.
And then all of a sudden, basically the output of the REPL, like if I'd set a variable name, it'll print it out.
Like that becomes rich printed, right?
That's right.
Yeah.
So yeah, you call pretty.install.
And then everything you put into the...
After the prompt will be pretty printed.
So previously, if you print a dict without rich, it'll just smash it onto a few lines.
It's quite hard to visually parse.
It's all one line except for the word wrapping, which doesn't even break on words.
And there's zero color, right?
Yeah.
Exactly.
So it's quite difficult to read.
I'm quite a visual person, so I always had difficulty with this.
If it was more than two lines, it'd be quite difficult for me to figure out where the keys and the values are.
But if you do it with rich, it'll pretty print it onto lines and it'll indent it like you would code and then it'll highlight it.
So it makes things just much more readable.
Yeah.
A lot of people will put it in their startup file, so they just get this ripple by default.
Oh, interesting.
Yeah, that's a good idea.
Have you tried this on the more advanced repls like PT Python or BT Python or those where you kind of get an Emacs E or Vim experience?
I haven't.
No, I've tried it on IPython and it works quite nicely on IPython, but I haven't tried it on other repls.
Yeah, it probably works on PT Python, but I haven't tried it.
Cool.
All right.
Now, another thing that you can do a lot with is sort of taking it up to the next level is the console.
Tell us about this.
Yeah, so the console class gives you more kind of advanced features.
There's more options, more things to specify.
Typically, you'd have a single console per project.
You'd keep it in your top level object or as a global.
It has a print method and there's also some other methods like there's a log method and there's a whole bunch of features you can do when you construct the console.
Things like exporting the output to HTML.
Okay.
Nice.
That's fantastic.
Yeah.
So one of the things you can do with the console, for example, is you can set a style on console.print and set some styles.
And then it'll come out in that style as opposed to embedding this console markup into the text itself, right?
Yeah.
So sometimes you might not want the console markup, especially if there's going to be square brackets in the output.
You don't want them to be confused with.
Right.
Or even if you're receiving a string and you just need to put it on the screen, but you haven't generated the string or it was generated by some other part of the app.
Like here's a message I need to log this that I got.
Exactly.
You don't want to parse the string to try to put text into it or more text, right?
Yeah.
Exactly.
So you can disable the highlighting and you can still set a style globally for that string if you want it in red or cyan, whatever.
You can still get that, but you can disable the console markup.
Nice.
And then we have the inspect, rich inspect.
What is this one?
This is my favorite function in rich and it came quite late.
But what it does is you call it with any object and it'll inspect the object and it'll pull out doc strings and it'll pull out methods.
And then it'll render it in quite a nice little table that's quite easy to read.
And I find this terrific for exploring APIs.
Sometimes it's better than documentation.
You know, if you get an object back from an API, you don't quite know what methods it supports.
You just call rich.inspect.
I could have typed something like dir, my, you know, print dir, my object.
And I get a list of dictionary objects which are representing, you know, fields and methods and whatnot.
Exactly.
But they're all jammed together.
There's no like help.
This is fantastic.
So it's like almost a table version of that with one line of help next to it, right?
Yeah.
So it does the same kind of thing as dir or help.
But way, way nicer, yeah.
It makes it easier, easier to read.
There's also two things.
I see there's a block of stuff that has, it's like a list of, I guess those are field names.
And then it has the methods.
It's sort of called out separately as well.
So you're like, these are the fields or properties or these are the fields.
And then here's the probably methods and properties, right?
That's right.
Yeah.
So it basically shows you the signature of all the methods and the first line of the doc string.
There's an option to show you the full details.
But I find just that abbreviated information is generally as much as I need.
Oh, this is fantastic.
So it says things like copy equals def, copy, bracket, bracket.
Would it say async def if it was an async method?
Or what's the alternative of def there?
Is it just to show it's a method?
That's just to show it's a method.
That's a good point about async.
I don't think it does do async def.
And that's a good idea.
It'd be pretty dope to throw in an async def or maybe a property if it's a getter method, right?
You're right.
Yeah.
I think they probably should do that.
They should inspect the method and see whether it's async and then emphasize that.
Yeah.
It's a good idea.
Yeah, sure.
We'll open a PR on that podcast here.
No problem.
All right.
So those are ones that you've got like graphics calling them out as some of the really main
things.
There's so much happening here.
That's that's amazing.
But like Waylon out in the live stream points out like mention rich tracebacks.
They're so good.
I have my ipython automatically start up with that.
And yeah, you've got a whole section down here under the library of things like logging,
log handlers, progress bars, status, tree views, like crazy.
You have tree views in the terminal that can expand and collapse with the mouse.
You know, there's there's more going on here than just the stuff we've touched on.
Right.
There's a bunch of cool features.
There's a lot going on.
Yeah.
Well, Rich will render the tree view.
It's textual, which provides the collapsing and navigation features.
Yeah.
Ah, got it.
Got it.
Okay.
So we'll get to the interactive bits.
But yeah, so I can still draw a tree view even with like little your example here.
You've got emoji icons for say folders and files.
And then even in the file, you've got an embedded syntax highlighted bit of code that comes out
of one of the files and a markdown with some of the markdown rendered as a rich markdown.
Yeah.
Just a markdown.
Like not, not rich the library, but like just colorized and formatted.
Yeah.
So it goes back to the composability of rich, rich objects.
I call them renderables, but you can use them in various contexts.
So in here, you can set a renderable per node on the tree.
So you can like do what we've done here, add a table next to a tree item or some syntax highlighting
or render some markdown.
It doesn't really matter to rich what you ask it to render.
You can just do it in various contexts.
Yeah.
Very cool.
Okay.
So we've got the tree, which is amazing.
Let's, you know, since Waylon mentioned it, let's talk tracebacks real quick.
I mean, one of the things that really is tricky with the tracebacks is, you know, a lot of
times you've got to go to like one end of them to see sort of the error.
And then like, there's no color.
There's just a lot of stuff dropping in there.
Maybe sometimes it'll show the variable values, but they're not really got to kind of pull
them out.
Right.
Things like that.
And what you get here is, is ridiculous.
First of all, what do I do to make this happen with the beautiful tracebacks?
You can do from rich import traceback, traceback.install.
Oh, good.
Yeah.
From then on, if you don't, if you don't handle an exception, it'll be printed with rich
or you can explicitly.
All right.
There's the second thing I got.
I just put on all my apps.
Yeah.
It's a piece of cake to add.
So yeah, it's easy to do.
Yeah.
So tell me what people who are not seeing this necessarily on the screen, like what is this
alternative traceback style look like here?
Okay.
So it actually follows much the same format as a regular Python traceback.
It's just underneath the file, you'll see some syntax highlighted code showing you that
the line where the exception happened for each frame and underneath each block of code,
it'll show you the locals at that point in the frame.
So you can see the local variables.
Right.
And these are called out in a nice table with a nice formatting that we've already talked
about.
So kind of as if you had done print, you know, from rich import print and then printed out
the locals into a table.
Yeah.
And it's all, it's all pretty printed.
So it's quite easy to read.
I find with regular Python tracebacks is it, it takes quite a bit of skill to read them.
Yeah.
Particularly for beginners and even for intermediates.
You've got to sit down and analyze the tracebacks, but I'm hoping, but this, this just kind of
presents the information in a more readable way and you can like get more of the context
of the error.
Yeah.
I think this is fantastic.
This definitely super interesting.
I guess one more thing here to really dive into, maybe two, two.
I think the log handler is really nice.
People should check that out, but maybe tables.
I know it's, it doesn't sound as appealing and amazing as necessarily as what we've been
talking about.
But if I want to have a nice formatted table in a text output, I basically just don't do
that.
I'm like, that is way too much work.
Yeah.
to worry about this.
Right.
But with using rich here, you can have almost HTML level formatting styles, you know, borders
on border off, just header content divider, like alternating rows.
Like I said, a right align, left align.
There's all sorts of amazing stuff here.
Tell us about the tables.
I didn't realize how hard tables would be to implement when I started it or I might
not have.
You might not have done it, huh?
Tables are quite complicated because you've got to calculate optimal column widths and that
gets really complicated when you've got text, which can, can wrap and other like renderables
that can go in those cells.
It does work quite nicely now and it can handle just about anything you can throw at it and
it will scale the table nicely and elegantly if, if it doesn't fit into the, you know,
the width of the terminal.
And it's also quite a good layout tool.
You can switch the borders off entirely and then use it to lay out other things.
You know, one thing that comes to mind right away is I think of some of the nice progress
bar type things for the terminal, like TQDM and stuff.
And they're great, but I'm always like the stuff on the right, it'll have like what it's
doing and then it'll have a progress bar and then it'll have maybe, you know, how fast
is it operating or how much time has it got to go or something.
And those are always kind of like doing like a little pulsing, like, cause the thing on
the right is always changing and they don't never quite line up.
You could just, you could do that here, but have a table and put the progress bar and one
of the center fill bits, right?
Yeah.
So you can do lots of things regarding alignment to fit everything together.
And like you said, stop that effect where bits of content will flicker because they're
using less characters because it goes from a hundred and into 99 and then.
Yeah, exactly.
Yeah.
It's a very good layout tool and also just a good way of presenting tabular information,
which is kind of what it was designed for.
Yeah.
It is a table, right?
All right.
So last one, I've got some content and probably a most common way that it's in a lightweight
format, but you want to turn it into something full featured in terms of text is Markdown,
right?
So for example, the Python bytes website is almost like entire, like the vast majority
of the content there is Markdown, talk by on training, like all the stuff we've got, the
CMS we built in the back end, it's all Markdown.
Rich has Markdown support too, right?
That's right.
Yeah.
There's a Markdown class.
And basically I took common Mark library, which parses the Markdown.
Okay.
I substituted the bits which were generating HTML with something which generates rich output.
And it turns out there's a reasonable job of things like headers and does the style just
fine.
And there's also syntax highlighting.
It'll actually call out to the syntax highlighting code.
So if you've got a Python code block, it'll actually highlight that Python code block.
Yeah.
You have support for inline code with the backtick thing, backtick.
Yeah.
And the blocks of code, which are the triple backslashes or triple backticks or four spaces
or whatever.
Yeah.
So it supports much of the basic common Mark syntax and does a reasonable job of rendering.
It won't look quite as good as a web browser, but I find it quite readable.
But it's in the terminal and I didn't have to do anything to get it there, right?
So that's pretty fantastic.
Yeah.
Really, really nice.
All right.
So I think this is probably as much of the details of rich we want to dive into in terms
of like the feature set and stuff, but there's still more to go.
There's a lot to love out of this library, which is great.
Maybe just give us a sense of the internals.
Like, how did you make this happen?
How do you make it work?
Is this curses to the nth degree or what's happening?
There's no curses.
There's a layer, which what makes most of it work, where I render everything into, and that's
a list of what I call segments.
The segment consists of a bit of text plus a style.
And the thing about having that intermediate layer before you actually render it to the
terminal is you can manipulate it afterwards.
So I can apply color and style and then do word wrapping and then I can render it onto the terminal.
So everything is built on that and a protocol.
So objects can add a couple of methods.
They can add a Dunder rich or a Dunder rich console method.
Then they can themselves be renderable.
So you can print your own custom objects and that will use that intermediate layer of segments
to render everything onto the terminal.
Nice.
Okay.
Yeah.
It sounds like a really good separation.
And you could probably also, if you need to do something specific for one platform versus
another, that layer, you can make a decision on how to do that without.
That's exactly it.
Yeah.
Having to put it all over the place, right?
Yeah.
So I render onto the segments and that's platform independent.
But there's another bit of code which will convert those segments onto the appropriate format
of the platform.
And the platform might be the number of colors that's supported by terminals because some will
support 16.7 million colors.
Some will support 256 and then some will support 16.
Yeah.
But because of that intermediate layer, I can make sure that no matter what you write, we'll
work on the terminal on the given platform.
Yeah.
Fantastic.
One of the things I do want to circle back to is this idea of you're taking a year off
to continue to work on this project, to grow it even further and already has and also do
other things in this general realm.
And so there's a couple of ways which people can support you, right?
If you're a large bank that depends on this kind of stuff, one of the good options is Tidelift,
right?
People can get a Tidelift subscription for Rich and that gives, what do they get with that?
So I don't think you get a subscription for Rich per se, but you can get a Tidelift subscription.
I see.
And that means that that money is divided amongst all the open source projects that you use that
are signed up to Tidelift.
In return, you get more responsive developers and developers which will handle security issues,
et cetera.
It takes the risk of open source code for big organizations because there is a little bit of
risk in that if you're relying on someone's hobby project, are they going to be around in
six months to your time?
Yeah.
So Tidelift ensures that developers will be around in the future to support your code
going forward.
Absolutely.
The other one is right up at the top here.
I could click sponsor and then come over here.
Also, that pulls up a link to the external funding for Tidelift.
But I could hit sponsor.
Do you have like plans or anything like that?
I know some projects have, you know, there's like a gold sponsor and here's just a sort
of keep it going sponsor.
Yeah.
Do you have anything like that or is it just, you know, what people want?
GitHub sponsors supports tiers.
So depending on how much you want to sponsor, I will help you with your projects.
I'm always happy to help people actually open source projects.
Always happy to do that.
But for the larger tiers, I will do code reviews or I will help you with your project on a more
more formal basis.
I might even write code for you.
It's up to what you want to sponsor.
If you just want to say thanks, that's very much appreciated.
You know, if I've solved, if I fixed a bug for you and just want to say thanks, then that's
fantastic.
But if you're a company which is benefiting from the work that I do or the work that other
open source developers do, you can sponsor a bit more to ensure that it keeps the work
going.
Right on.
Yeah.
And I encourage people if they're depending heavily upon this, you know, help you keep going
strong, especially as you're transitioning to just working on this.
So yeah.
Also, notice someone's forked it since we even pulled it up here.
How cool.
So the other, the next step that maybe you would, would take this, you talked about not
wanting to add too many insane features to rich to keep growing that, right?
Keep it focused on target is you also have this project called textual.
Textual is a TUI.
We've all heard of a GUI, but a TUI is a text user interface instead of a graphical user
interface, right?
Yeah.
I think it's a bit of a misnomer.
I mean, because the interface is constructed with text, granted, but it's still a graphical
thing you're looking at.
Yeah.
I think of it as a GUI, but with kind of like a fairly retro aesthetic.
Yeah.
It does have a bit of a retro aesthetic.
I would say maybe if you built something with like Colorama or something, that would be maybe
more TUI-esque, right?
Where there's, where you look at what you build with textual, it's got scroll bars, it's got
banners, it's got icons.
It's, it's closer by far.
Looks a bit more, a bit more graphical.
Yeah.
So tell us about textual and why not just more features on Rich.
Rich has some kind of dynamic features.
There are progress bars and they're updating live dashboards.
And I've been asked quite, quite a lot if I could add keyboard support and mouse support.
And I've resisted for quite a while because I want to keep the focus of Rich onto just generating
mostly static output.
But then, then I saw a project called GH top, which is kind of like H top, but it would take
information from the GitHub API and it would show you like real-time events.
And they used, oh, there we go.
And they used Rich for that.
And when I saw that, I realized, oh, I've got to do this.
There's a lot of potential there.
And I put it off a little bit, but then, then I started on it and I kind of realized that,
yeah, there's quite a lot you can do with a terminal these days.
This is one of the things that blew my mind.
Maybe, you know, give us a sense of, I'm trying to pull a particular picture.
Maybe this is just one I could sort of leave on the screen.
But one of the things I remember from my early days of GUI type development is how do you
resize stuff on the screen, right?
So I want to put something where like the main window is here, but then I want the status
bar thing, but I want it to stick to the bottom.
And then I want some other stuff on the left.
And it sounds like that would be pretty tricky to just dynamically try to generate with Rich.
But with Textual, you can say like this thing docks to the left and this docks to the bottom.
And here, this fills the main content.
And then those bits in the middle, are those basically rendered either more of these containers
and these widgets?
Or is that Rich directly?
Or give people a sense of like what they build with this.
So Rich does the rendering, which is responsible for getting stuff onto the screen, but Textual
handles the dynamic stuff.
At the most atomic layer, there's something called a widget.
And a widget is almost like a software component in itself.
It's built on AsyncIO.
So each widget has its own AsyncIO task and it's constantly processing events.
And Textual will change the size of that and change the layout in response to resizing the terminal.
And you can tell it how the widgets fit together within the given dimensions of the terminal.
Right.
So you've got like the layout elements that handle docking and whatnot.
Yeah.
Very cool.
So one of the examples you have on the Textual readme is building one of these widgets.
So you just create a class that drives from widget.
Here you have a hover example and it has a way to render itself.
And then it very much like traditional, you know, I'm thinking of building like VB6 apps
or Windows Forms apps, like these traditional ones where you have drag and drop widgets.
They have these events, right?
And one of the events here, you wouldn't think of this as a terminal thing.
You've got like, you know, on mouse, you know, on enter, on leave and, you know, mouse over
and things like that.
Right.
Like those are regular UI types of interactions that you would not expect to see in a text-based
app.
Right.
Yeah.
That's fantastic.
It's based partially on my knowledge of writing desktop applications, which is quite old now.
Oh yeah.
What did you write them in?
WX widgets mostly.
Yeah.
It's a C++ framework.
I think it's got a Python layer.
Yeah.
There's WX Python.
I think that might be the next, the Python wrapper.
That's right.
Yeah.
But in the last 10 years, I haven't done any desktop applications.
I've been working mostly in the web.
So it's mostly influenced by web development with modern frameworks, particularly Vue, which
I've used a few times.
Vue's nice.
Yeah.
Vue's very nice.
So I'm trying to replicate some of the best features, I think, of you into the terminal.
I'm surprised how well some of these features translate.
Yeah.
This is incredible.
It really does build these interactive things.
Now, another thing to talk about is how do you control the look and feel, right?
Like the way you might do it in Rich is you might have one of these console markups or markdown,
or you could use a console and set a style.
But if you're inspired by the web, you know, like dot main container hash thing I want to
style, right?
Like it's some sort of CSS selector, right?
Yeah.
So you've read my mind.
I've been last few days working on CSS.
Okay.
It's going to work very much like...
Is it actual CSS or CSS-like stuff?
Like what do you have in mind here?
It's probably not actual CSS.
A lot of the stuff just wouldn't apply to terminal.
Yeah, it makes sense.
Sure.
But essentially, it's the selectors.
So I will have selectors where you can select an ID and then a child with a class name,
et cetera.
I mean, that's basically what I was thinking when I was saying real CSS, right?
Like is it...
Right.
Or will I say like hash container dot children type and I would write that or is it like...
It's exactly like that, but it's...
Exactly like that.
Yeah.
Oh, beautiful.
And the only thing that differs is the...
I don't know what you call them.
The bit that goes inside the curly brackets, the actual rules, they will be different.
Sure.
Yeah, yeah.
Yeah.
They render different things, but very much like CSS.
If you come from the web, you see this, you'd be very much at home.
Nice.
I could probably even use less and transpile that down to CSS and put the odds...
Yeah, maybe.
Who knows?
Yeah, maybe.
I was thinking, should I just do CSS, which is hard enough in itself?
Or should I try to implement less or SAS or one of these things?
Well, I'm going to try CSS first of all.
If you get it working with CSS, then you probably can get the less compiler to generate the right CSS out of it somehow.
Yeah, maybe.
But actually, one of the worst things I think of JavaScript and web app development is all those pre-processors.
I know.
I'm 100% with you.
Yeah.
When you've got to run all these tasks and all these CLI things just to get it so you can start using your app, it's like, there's something kind of broken about this.
Can I just include a file here and go?
It's gotten so complicated that JavaScript is one of the more complicated ways to write code rather than one of the simplest, I think.
Exactly.
Yeah.
There was a time where front-end development was seen as kind of like the baby brother of real development.
You and your QJ query.
That's not true anymore.
I don't think it's been true for a while.
I think front-end development requires just the same type of thinking as back-ends.
You've got to organize all these different processes together and mental models.
And it's actually more complicated because there's so much going on.
There's so many little things you've got to remember.
Yeah.
You're taking so much of modern software development and squishing it down to this narrow little bit that is like run it in JavaScript on the browser.
Yeah.
It's kind of got to fit into this historically what used to be like a narrow-focused environment, and now it's definitely not.
Yeah.
So I'm trying to take what I think are the good things about front-end development and apply them to the terminal and hopefully leave out the things which I don't like so much.
Yeah.
That sounds great.
So maybe for this one, I think what people should probably do is they should check out the examples, right?
The examples from Textual.
They can clone the repo and just run these, and it's super easy.
There's also a way to see them, I guess, on the developer video log here.
Are these you doing these videos here?
That's me, yeah.
It's just using a short demo of each.
Nice.
This is my ad apparently I'm getting.
No.
All right.
We'll not play that.
Go YouTube.
All right.
So, yeah, but people can go and check these out because I think seeing it in action is really what you need to appreciate Textual.
And it can demonstrate the features which Textual can do, which I don't see in other 2E frameworks.
I'm thinking particularly of animation.
Yeah.
I was just thinking like the CSS easing functions and those types of animations.
Yeah.
I was surprised how well that worked.
I was animating things at 60 frames a second, and it can go up to 120 frames per second.
Terminals these days, they're built on the same technology as video games.
They use hardware accelerated graphics under the hood, so they can actually render terminal updates very, very quickly.
I don't think people have taken advantage of that.
How long until someone re-implements Doom on Rich or on Textual?
I'm sure it's possible.
You could render it and then, you know, render it onto text.
I don't know how you do it, but various ways of rendering images.
So, in theory, you could put Doom in the middle of a Textual application.
I would say start with really, really small fonts in a big terminal window so you get higher resolution.
Yeah.
But, yeah, you've got the color.
You've got the emojis.
I bet you could make it happen.
Awesome.
All right.
Well, we're getting pretty short on time here, Will.
Anything else you want to sort of throw in about Textual or even Rich before we wrap it up?
Just to say that I like getting feedback and input.
So, if you have any suggestions, jump onto Textual discussion board.
Or if you find any bugs, let me know.
Or connect with me on Twitter and I'm happy to talk about these things.
Yeah.
Fantastic.
Also, I want to give a shout out to one of your other projects real quick.
Great.
Yeah.
So, this is PAL file system.
I've been working on that for well over 10 years now.
I've handed it over to some very talented developers.
But, essentially, the idea is that there's an abstraction there for file systems.
So, the same code can write to your disk drive or an FTP server or a zip file.
And it just all works exactly the same way.
Nice.
Do you have, like, cloud format support, like S3 and things like that?
Yeah.
Exactly.
Yeah.
So, there's an S3 version and there's a Google Cloud version and there's dozens of other implementations.
Any database stuff?
Can I, like, treat a table as a directory or something like that?
I wouldn't be surprised if there is.
I don't know of any off the top of my head.
But some people have done some quite creative things where they've made something which is not a file system look like a file system.
Oh, look at this.
Dropbox FS.
Dropbox as a file system.
Okay.
That's pretty amazing.
Okay.
Here's the index of file systems.
Let's see.
We've got application data, FTP in memory.
Oh, that's pretty slick.
So, you can read and write files, like, say, for tests and not care.
Or temp files, maybe.
Tem files would be fantastic, right?
Yeah.
So, you can use temp files and, like you said, for testing.
So, you can write it into memory without bothering to write it onto your hard drive.
Okay.
The multi-file system.
So, you could multiplex reads and writes.
That's pretty killer.
Yeah.
That's more, I remember correctly, you can layer several file systems.
So, you could have one to write and then several to read.
And depending on where the file is, it'll just make it appear like a single file system.
Yeah.
A lot of neat stuff here.
So, you know, people, they got a lot of file reading and writing to do.
They can check that out.
Also, I want to give a quick shout out.
I saw Paul Everett on the live stream out there.
So, Paul and you dove inside in a more visual way into textual, right?
So, I'll link to a live stream you all did over there together.
Great.
Cool.
Yeah, that was fun.
Yeah.
Awesome.
All right.
Well, I think that pretty much wraps it up.
So, I'll give you the final two questions before we get out of here, though.
So, Will, if you're going to write some Python code, what editor do you use these days?
I use VS Code.
I've used that for quite a while.
Quite happy with it.
But I do try other editors from time to time.
Nice.
And then, in addition to pip install rich and pip install textual, any other packages out
there you want to give a shout out to that you think you use some eyeballs and some attention?
Anything that's impressed you lately?
I'm drawing a blank.
There's so many.
It is hard to choose, isn't it?
There's a project I saw.
Can I mention one that uses rich?
It was quite cool.
Of course.
Yeah, absolutely.
It's called Object Explorer.
It's a terminal user interface, but it's not.
I think it's OBJ Explorer, which is quite nice.
You could create an, you explore a Python object and you can navigate into it in a visual way
and it will show you the attributes, et cetera.
Oh, fantastic.
Yeah, that sounds really fun.
Is this for like in-memory Python objects or database objects or what is it?
Oh, in-memory Python objects.
So, I think it's like a debugging tool.
It's kind of like, it's a bit like rich.inspect, but it's more visual.
Okay.
Yeah, fantastic.
We'll have to link to that one.
All right, Will.
So, thank you for being here.
This has been really great.
Congratulations on both of these projects and all the momentum you've gotten.
Thank you.
Final call to action.
People want to check out Rich or Textual.
Maybe want to support you.
Whatever else you want to give a final shout out for or call to action before we call it a show.
Just connect with me on Twitter.
My handle is at Will McGuggan.
Say hi.
I'm happy to talk on Twitter.
Right on.
Be sure to put the link in the show notes.
Thanks for being here, Will.
Thank you.
It's been great.
Bye.
Bye-bye.
This has been another episode of Talk Python to Me.
Our guest on this episode was Will McGuggan.
It's been brought to you by Shortcut.
And us over at Talk Python Training.
And the transcripts are brought to you by Assembly AI.
Choose Shortcut, formerly Clubhouse.io, for tracking all of your project's work.
Because you shouldn't have to project manage your project management.
Visit talkpython.fm/shortcut.
Do you need a great automatic speech-to-text API?
Get human-level accuracy in just a few lines of code.
Visit talkpython.fm/assembly AI.
Want to 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 sight.
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 Google Play feed at /play,
and the direct RSS feed at /rss on talkpython.fm.
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.fm/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.
I'll see you next time.