#469: PuePy: Reactive frontend framework in Python Transcript
00:00 Python is one of the most popular languages of the current era. It dominates data science.
00:05 It's an incredible choice for web development and it's many people's first language.
00:10 But it's not super great for front-end programming, is it? Frameworks like React, Vue, and other
00:16 JavaScript frameworks rule the browsers, and few other languages even get a chance to play there.
00:22 But with PyScript, which I've covered a couple times on this show, we have the possibility of Python on the front-end. Yet PyScript is not really a front-end framework,
00:32 it's just a runtime in the browser. That's why I'm excited to have Ken Kinder on the podcast
00:38 to talk about his project, PuePy, a reactive front-end framework in Python.
00:43 This is Talk Python To Me, episode 469, recorded June 20th, 2024.
00:51 Are you ready for your host, Darius? You're listening to Michael Kennedy on
00:55 Talk Python to Me. Live from Portland, Oregon, and this segment was made with Python.
01:00 Welcome to Talk Python to Me, a weekly podcast on Python. This is your host, Michael Kennedy.
01:08 Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython,
01:14 both on fosstodon.org. Keep up with the show and listen to over seven years of past episodes
01:19 at talkpython.fm. We've started streaming most of our episodes live on YouTube. Subscribe to
01:25 our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and be part
01:31 of that episode. This episode is brought to you by Sentry. Don't let those errors go unnoticed.
01:37 Use Sentry like we do here at Talk Python. Sign up at talkpython.fm/sentry. And it's brought to you
01:43 by Code Comments, an original podcast from Red Hat. This podcast covers stories from technologists
01:49 who've been through tough tech transitions and share how their teams survived the journey.
01:55 Episodes are available everywhere you listen to your podcast and at talkpython.fm/code-comments.
02:01 Hey, before we talk about PuePy, I have an announcement. I'm sure that you know I have
02:06 many online courses that you could take at Talk Python, but before I went down this online
02:11 courses path, I did years of in-person courses for software developers. So it's back to these
02:17 roots for my next event. But with a truly adventurous twist, I'll be doing a six half
02:23 day course on all sorts of modern Python topics, like FastAPI for building web apps and APIs.
02:30 And the amazing part is that the course will be held in a castle in Tuscany, Italy. That's right,
02:36 it's Code in a Castle, one half developer course and one half dream vacation. We'll spend the
02:42 mornings learning Python and the afternoon on excursions to amazing venues and vineyards.
02:46 Places are super limited and I'd love to have you join me. So check out talkpython.fm/castle
02:53 and see what it's all about. I hope you can join me for an adventure in Italy this fall.
02:57 Ken, welcome to Talk Python to me.
03:00 Hi, good to be here.
03:01 Excellent to have you here. It's a topic that's near and dear to my heart and I know for many
03:07 people as well, building cool websites, but more Python, less JavaScript, not hating on JavaScript,
03:13 but why do we need to learn a sixth language to work on websites? There's already so many
03:17 HTML, CSS, et cetera, et cetera. In the world, we should be able to pick the language we like
03:22 and build websites with it. But somehow it's gotten itself into a place where you pick part
03:26 of the language you like and then the rest you do in JavaScript, but we'll see how long that lasts.
03:30 Yeah. Running Python in the browser has always kind of been a little dream of mine
03:34 ever since I first started programming in JavaScript.
03:38 Yeah, that's awesome. We had traditionally things like ECMAScript and some of those transpilers, right? Like Sculpt and others.
03:47 Sculpt, Transcript, Brython, not Transpiler, but Transpiler. Brython. And it does the same
03:55 thing as PyScript. It just runs the whole CPython in JavaScript, which is wild.
04:01 Yeah, it's super wild. And I guess there's a requisite shout out to the birth and death
04:07 of JavaScript talk, which gives you a really good insight. It seems like you've seen that
04:11 talk as well. No, but I have heard about it.
04:13 It's worth the 15 minutes. It's both funny, but also very insightful. All right. So we're going
04:18 to talk about a front end framework that you've built that is Vue.js-like, but runs on top of
04:26 Python in the browser, which is awesome. On the client side.
04:29 On the client side.
04:30 Which is awesome. On the client side. Very important. That's the big thing. Before we
04:34 get to that though, just tell people a bit about yourself. Who's Ken?
04:37 Yeah, my name's Ken Kinder. I've been developing Python software for 24, 25 years,
04:44 something like that. Ever since Red Hat's installer crashed and I saw the stack trace
04:50 and opened up a file and I could just read the code. That was my introduction to Python and I
04:54 never looked back. Mostly I've been writing kind of line of business, software as a service,
04:59 kind of code. And I've always wanted to kind of short circuit and bring it to the browser.
05:05 Yeah. What are you using now for the line of business stuff? Is that like Flask on the
05:09 backend or is it Node on the backend or what are we talking here?
05:13 RealJab. It's all Python on the backend. And then our front end is actually a Vue.js app
05:19 that I wrote originally. And then some professional front end developers kind of took it over and
05:25 rewrote it.
05:27 Yeah, cool. Now it has eight compilation steps.
05:30 Yes. But I mean, it compiles into like a semi-native apps for mobile and there's
05:38 like a Chrome extension involved. So you're doing a good job with it.
05:42 Yeah, that's awesome. Look, there's a ton of websites built primarily with JavaScript and
05:47 many of them are good, some of them are bad, but there's also plenty of bad websites written in
05:51 Python. But like I said, not hating on JavaScript so much as just saying, why does every programmer
05:57 in language have to reduce to JavaScript? That seems like a weird situation. There's other
06:02 frameworks that are making progress here. For example, Blazor in the .NET C# space is actually,
06:08 I haven't done anything with it, but it's a super interesting idea and it's not that different.
06:12 Yeah.
06:12 Not the only crazy person.
06:13 Blazor uses WebAssembly just like PyScript, which is what I built my stuff on top of. And Web
06:20 Assembly is about what it sounds like. It's mature enough now and it's supported by all major
06:26 modern browsers. And since there is no JavaScript layer, really, I mean, there's some kind of
06:32 JavaScript shims involved. You want to think of it that way, but it's not like your Python code is
06:38 being transpiled to JavaScript. It's actual Python.
06:41 Right, right, right. And we're going to talk about that. It's super interesting. There's
06:44 interop in the sense that there's kind of like there's C interop in Python now back into the
06:50 JavaScript layer that you can have, but that's not the same as this other language is interpreting,
06:55 is running the interpreter, right? So it's kind of natively as much as you get in the front end,
06:59 natively there. I kind of want to walk people through some of the technologies to get us
07:04 started here. So we've already given a shout out to PyScript. We talked about Vue. I think
07:10 PyScript is the foundation. Vue is maybe the motivation. Let's start with PyScript. Got their
07:15 website pull up here. And what I'm learning is that I can have a REPL on my homepage. Actually,
07:20 I know I can do more than that, but that's sort of what they're demonstrating right now.
07:24 Yeah, you can do a lot more than that. You have kind of two choices with PyScript.
07:28 You can run PyOdide, which is lower level if you want to think of it that way, Python in the
07:33 browser project. And that is basically full CPython with some minor changes necessary, but you
07:43 get basically the whole standard library. You can install packages from PyPy or PyPI, however you
07:50 pronounce it. And those download just as you download the website. That's probably your best
07:56 bet if you just want a true Python experience. PyScript, though, also includes a micro Python
08:03 version. And the micro Python, if you're not familiar with it, it's mostly designed for
08:09 micro controllers or like Raspberry Py kind of environments where you have very limited resources
08:15 because it is so truncated relative to real Python. It downloads very nicely in the browser.
08:22 It's actually it plus PyScript ends up being smaller than a lot of JavaScript front end
08:28 frameworks. Yeah, which is incredible. And this is a huge thing that is unlocked. Honestly,
08:34 kind of the stuff that you're pursuing a much bigger scale, I think. Micro Python,
08:39 as the name suggests, and I've had Damien and others on to talk about micro Python.
08:44 It's real micro, like this, I'll hold up a little device here, like this thing in my hand,
08:48 this little chip that is probably the size of my thumb, costs like 20 bucks. And this runs
08:55 full micro Python, manages the DNS on my network and stuff like that, like ad blockers and that
09:01 little tiny thing. But the restriction is, you know, how much storage does it have? A couple
09:05 of megs. How much RAM does it have? Probably similar. I don't know. The goal was to be a
09:12 very small kernel of Python with micro Python, not let you do Tkinter, pandas, etc, etc, etc.
09:20 And so PyScript choosing to support both of these means you can kind of take PyOdide and get full
09:26 Python in a sense, as much as you can. Or you can do micro Python and restrict yourself to a smaller
09:32 set, but you get a much lighter weight experience, right? Yeah. If you've ever used transpiling,
09:39 micro Python is still a real big upgrade over that because you are getting almost all the Python
09:44 syntax and most of the libraries that you're likely to use just rendering a website.
09:49 Right. Okay. So a lot of the standard library is still there, but maybe things like networking or
09:54 whatever that don't make sense. I wouldn't say a lot of it is like a good example is the regular
09:59 expression module is there. But when I first wrote the router for PuePy, the regular expressions
10:04 that I was using weren't supported in the micro Python version module.
10:09 And there's a limited, limited regular expression. You went too big on your regular expressions.
10:13 I did. Yeah.
10:14 I see. Okay. Interesting. Yeah. We'll talk about routing. That'll be fun. Okay. So if somebody
10:20 were to, which we're on the topic of these two, like if someone were to think about building a
10:24 website, maybe internally for their company, would you suggest that they use Pyodide as the foundation
10:30 or micro Python? Cause you can pick when you run PyScript.
10:33 If it's for your company and it's an internal tool, probably most, most users downloading it are going to have plenty of bandwidth and normal machines. So
10:43 there's really no reason not to use Pyodide. Yeah, sure.
10:45 You get better errors with it. There's little things that'll just, you're used to coding,
10:50 like data classes are missing from micro Python, but you could use either.
10:54 Okay. Yeah. Let's see if it, well, if it'll show us how big is this thing. It doesn't want to,
10:59 I could just get this. It's a jQuery terminal. How about that? If I click on the link in
11:04 Pyodide, very cool. But yeah, how big is maybe 10 megs? Is that, would you say that's right?
11:09 Like I made a little example app for our purposes and I used Pyodide. Now I am pulling in SQLite,
11:17 which is part of it. That adds some space. One of the benefits though of using Pyodide is you
11:22 can just grab a lot of the libraries and that'll work, right?
11:25 Yeah. I don't know if it's PyScript doing it or Pyodide upstream, but they do make you say that
11:31 you need certain libraries and then they're available for import after you kind of declare
11:37 them. Right. And when you initially set up the PyScript environment, there's a way where you
11:41 kind of set the environment as it loads, right? Yeah.
11:44 Yeah. Okay.
11:44 You can do it at runtime too.
11:45 All right, cool. So we've got PyScript, which lets us do Python in the browser, which is awesome.
11:52 And we've got these two foundations. We've got Pyodide, which is great for its compatibility,
11:58 I guess. But PyScript, which if I was going to build a SaaS product where lots and lots of people
12:04 were visiting kind of interactive bits, maybe you consider writing that in MicroPython because it's
12:10 just less overhead for the world. I don't know. Depends.
12:13 I would especially consider MicroPython for a page that loads as a normal webpage.
12:18 Yeah. If it loads, yeah. If it's a landing page sort of thing. Yeah, absolutely.
12:23 Or even just if it's like one of the CRUD pages, like let's say that you have a traditional sort
12:29 of Django app or whatever, where you've done server side routing and you only want interactivity
12:35 on the edit page. And for the view and the list, you're fine with normal templates. You could just
12:40 use MicroPython where you need it then. But if you're building a single page app and you want
12:46 everything downloaded up front, maybe that 10 megs is worth it.
12:49 Yeah. You know, perhaps because you can put aggressive caching on it, put it over CDN.
12:54 A lot of times when you pull it up, it'll say, you know, loaded from cache, things like that. Right?
12:59 Yeah.
12:59 Let's see if I can on PyScript. Let's see what happens here. If we go to the network and pull
13:04 this in. Oh, look at that. They're using MicroPython there, but yeah, all this stuff is coming out of
13:08 disk cache, seven milliseconds to pull that up. Right. So another thing I just saw looking at
13:14 the PyScript source there is that it had a service worker and service workers kind of indicate maybe
13:20 progressive web app. Right. See if I click on this, but partially a progressive web app on
13:25 PyScript.net. I know you're a fan of these and it might be an interesting way to deploy. You know,
13:30 you talked about the internal apps, right? Instead of just putting links, maybe you
13:33 install it as a progressive web app. Right?
13:35 Yeah. I haven't made a progressive web app in PyScript yet, but there's others who have done it.
13:41 Yeah, I've done it. And I have an example up where I don't think it runs anymore because
13:45 PyScript's changed so much, but I even got it to install as an app on the home screen of my iPad.
13:52 You click it, it launches. It looks like a full blown app. Nobody would know the difference,
13:57 but it's PyScript based. Yeah. I'll try to link the video about that in the show notes.
14:03 Yeah. If you're running a SaaS, that's a really compelling option because then you also
14:08 skip out on the app store review process.
14:10 Oh my gosh.
14:11 Forking over so many people.
14:12 If people see, you got to carve off a piece of your soul to get through app store review. It's
14:16 not a fun, it's not a fun experience. Let me tell you, I've been through the ringer four or five
14:22 times, mostly in the Apple app store, but also in the Google app store with our courses app and
14:27 not fun. So progressive web app, letting you skip that a hundred percent behind that idea.
14:33 This portion of Talk Python to me is brought to you by Sentry. Code breaks. It's a fact of life.
14:38 With Sentry, you can fix it faster. As I've told you all before, we use Sentry on many of our apps
14:44 and APIs here at Talk Python. I recently used Sentry to help me track down one of the weirdest
14:49 bugs I've run into in a long time. Here's what happened. When signing up for our mailing list,
14:55 it would crash under a non-common execution paths, like situations where someone was already
15:00 subscribed or entered an invalid email address or something like this. The bizarre part was that our
15:06 logging of that unusual condition itself was crashing. How is it possible for her log to crash?
15:13 It's basically a glorified print statement. Well, Sentry to the rescue. I'm looking at the crash
15:19 report right now, and I see way more information than you'd expect to find in any log statement.
15:24 And because it's production, debuggers are out of the question. I see the traceback of the
15:29 crash report, but also the browser version, client OS, server OS, server OS version, whether it's
15:36 production or Q&A, the email and name of the person signing up, that's the person who actually
15:41 experienced the crash, dictionaries of data on the call stack, and so much more. What was the
15:46 problem? I initialized the logger with the string info for the level rather than the enumeration
15:52 dot info, which was an integer-based enum. So the logging statement would crash, saying that I could
15:59 not use less than or equal to between strings and ints. Crazy town. But with Sentry, I captured it,
16:07 fixed it, and I even helped the user who experienced that crash. Don't fly blind. Fix
16:12 code faster with Sentry. Create your Sentry account now at talkpython.fm/Sentry. And if you
16:18 sign up with the code TALKPYTHON, all capital, no spaces, it's good for two free months of Sentry's
16:25 business plan, which will give you up to 20 times as many monthly events as well as other features.
16:29 That's PyScript, which is super awesome. But let me just make a comment here to get your
16:35 thoughts about this. When I go to PyScript.net, I'm a big fan of this project, the people behind it.
16:40 But when I get here, what it shows me and what it encourages, what it basically communicates to me,
16:47 at least, is you, dear visitor, can have Python in your browser. And so, for example, here's your
16:55 REPL. You just type Python in the terminal, that thing that comes up, that redevelopment loop. You
17:00 just get the REPL. And now I can type. I could do x equals seven, y equals two, x plus y is nine.
17:07 That's interesting, and it shows the power. But as a web developer, I don't want to develop a
17:13 REPL. I want to develop web applications like input boxes and images and grids. And if I interact
17:20 with this, it changes that and so on. I want a front-end UI experience with my Python in the
17:27 browser, not just the equivalent of the console in JavaScript. That's my desire too. Something I
17:34 really like about Vue, React does this, but I don't have as much React experience, is reactivity,
17:40 where if the state of your page or your component changes, it redraws the UI and patches the DOM,
17:50 the elements in the browser, in real time, where you don't need to think about, oh, let's say one
17:57 state changed, and that affects five widgets, so I need to go redraw those five widgets. It all
18:02 just kind of happens automatically. And there's nothing like that built into PyScript itself.
18:08 So PuePy kind of lives on top of PyScript and adds that layer and just other conveniences
18:14 that I would want. Yeah, absolutely. And event handlers, right, as well. Yeah. So really a lot
18:21 of neat stuff. And that is very nice about Vue. I like that as well, the data binding and the
18:25 reactivity where you can just say, here's a dictionary. I make changes to the values of
18:30 that dictionary, that JSON object, and other parts of my UI are using it, just also make those change.
18:36 Or if I bound it to an input and somebody starts typing, propagate that back to the rest of the
18:40 app, right? Right. And you've got reusable components. So if you make like the perfect
18:46 foreign key lookup widget, you can just reuse it all over your application. And reusing it is
18:52 really easy. Like it just becomes a little HTML tag in Vue. Kind of like web components, if you've
18:56 used those. But I think... Those didn't really catch on that well, did they, compared to how...
19:01 I think they should have caught on better, maybe. I think there's kind of a little movement behind
19:05 them now. Maybe because people are so... I mean, not to come down on any projects, but I think
19:11 there's a desire to have more stable development tools. And all the JavaScript stuff changes one
19:19 day to the next. Like you go get a cup of coffee and then you need to upgrade all your node
19:25 dependencies. So with web components, you really only need to upgrade the components you use.
19:31 And web components are how I see you using PuePy too.
19:35 Okay. Very interesting. So that brings us to PuePy. The name is like Vue, but for Python. So
19:42 Pew and then pie, right? Is that where the origin is? Am I getting this right?
19:46 That is the origin.
19:47 Awesome. Okay. So here I land on Puepy.dev and I see a red button with a minus and a green button
19:53 with a plus. And I can just click on these and it does the reactivity and it does the changing.
19:58 There's no navigation, but there's not really directly much JavaScript is there.
20:02 What is happening here? Tell us about this project.
20:04 On your screen, if you have it pulled up, you'll see code directly below the counter.
20:10 And that is the code that is running the site you're seeing with just a little bit of boiler
20:14 plate that's missing.
20:15 And it sounds very, yeah, just a tiny, tiny... It looks very familiar to a Vue.js app startup,
20:21 right? How you would get that.
20:22 Yeah, especially Vue 2. I never upgraded to Vue 3 while I was working on Vue stuff before
20:29 handing off my current project. You'll see that initial function defines state when the page
20:35 loads, populate defines the layout and DOM elements. And then there's two event handlers
20:43 that update the state. And as the state updates, the DOM is updated.
20:46 Yeah, awesome. And it looks, yeah, you combined functions, Python functions as the event handler,
20:52 and you just say, go to the button and say on click equals your Python function.
20:58 And then in that function, you say state bracket current value from the dictionary.
21:04 You can increment it like plus or minus it in this case. And that reactivity propagates back
21:09 to the text box or the span in there that shows that information, right? That's kind of the
21:14 full life cycle on a pretty simple little bit of code.
21:16 That's the snippet. That's the basic video.
21:19 Let's see about the, about the old network here. What do we get if I pull this up? A couple of
21:25 things that I think are interesting. I pull up the network tools and I just pull up puepy.dev.
21:29 The whole page, I don't know how far away this is. Do you know where this is hosted?
21:32 It's on GitHub pages, so I can't tell you.
21:35 It's on the internet. Okay, awesome. All right. So it loads in, because I was thinking about,
21:39 well, it's the ping time and stuff. So it loaded in 155 milliseconds and then it processed the
21:44 DOM content in 144 milliseconds, which is, that's good. Like that's in a realm that people don't
21:51 really perceive, right? Not really. And it looks like you're doing micropython here, which is,
21:55 how big is our MicroPython? It is 1.6 megs. No, no, that's the age, sorry. Where's the content
22:03 length? There it is. 188K. That's pretty good.
22:08 There's some stuff that was downloaded that you'll also see over there. Like, you know,
22:12 the PuePy wheel.
22:13 Yeah, sure. Which, I mean, hold on to what you just said there. The PuePy wheel was downloaded.
22:20 Okay. So talk about that. Like this is not even the source, right? This is the distribution. I
22:26 mean, I'm probably in there. It has the source, but.
22:28 Yeah. I mean, a wheel file is just a zip file of the source.
22:32 Yeah. It could have binary goodies in there as well, I suppose. But this one's platform neutral,
22:37 so it's not likely. But this is basically like taking something off PyPI and pip installing it,
22:43 but for your website, for your front end, you basically pip install it for it, right?
22:47 Yeah. I would like to have it work that way, but for MicroPython, you don't get the full pip.
22:53 So.
22:53 Right, right, right. MicroPython has a funky way of working with its dependencies. I don't remember
22:57 exactly how I got it working with this little thing, but it has three or four dependencies,
23:02 my little, my 32 bit little chip thing. But I do remember that it was like,
23:07 my intuition around pip wasn't quite working. If you said, if you went to somebody,
23:11 so we have an interactive webpage and it's 189K, plus a little bit, that's fine, right? On a CDN,
23:18 no one's going to have a problem with that amount of data.
23:20 Yeah. I mean that.
23:21 Oh, and the other thing.
23:22 Absolutely competes with what a typical JavaScript framework would require.
23:26 Yeah. And the other thing worth noting here is Pupy, its wheel comes from disk cache,
23:34 as well does MicroPython WebAssembly. So once I hit this, like for example,
23:40 now looking at the processing times, it's 62 milliseconds and 50 milliseconds,
23:44 right? That's ridiculous. That's awesome. So.
23:46 Yeah.
23:47 Really, really good.
23:48 I don't know how fast your computer is, but I haven't been bothered by any of the performance
23:52 I've seen from PyScript.
23:54 Yeah, no, it's super fast. So it's down to a point where, you know, there had been,
23:58 there had been statements like, well, it'd be cool if you could use something like Pyodide,
24:02 but it's, it's just so slow. It takes five seconds for the page to come up or whatever
24:06 on the early days. And you can't really assume that that's acceptable to people.
24:12 150 milliseconds, 60 milliseconds here and there. Like that's blink of an eye type stuff. You're,
24:17 you're good to go with that, right?
24:18 Yeah. I probably wouldn't use it for like a web GL kind of stuff or.
24:23 Sure.
24:24 Anything that needs to be super performant, but most business software is just fine with these.
24:28 But, and even, you know, like that is a runtime performance versus a app initialization performance conversation, isn't it?
24:36 Yeah.
24:36 So let's talk a bit about that. What is this good for and what is it bad for?
24:40 It's most good for, especially with, with MicroPython, those kinds of use cases where
24:45 you have business logic that is presentation relevant, like, like you have a form and what
24:52 is shown on the form depends on what's already entered. You know, that's, that's the kind of
24:56 stuff you would have done with jQuery back in the day. And you could do it very easily with PuePy.
25:01 You could do kind of basic crud work. You could do data visualization. And also just anytime that
25:07 you want a full Python environment in the browser, obviously it's a good choice. It's
25:12 probably not a great choice if you don't already know and love Python, because if you're a
25:19 JavaScript developer, why would you lose all the tooling? If for that matter, if you like a lot
25:24 of tooling, you know, there's no Chrome debugger for PyScript. You just get your trace back.
25:30 You're not going to be able to run it.
25:31 Can you print? Can you print a console?
25:33 You can print and normal Python print statements go to console. That's what you get.
25:37 You're good. You know, you honestly, though, you probably could bring in some of these libraries.
25:42 Gosh, I can't remember. There's a couple that are really nice that you can bring in
25:46 and change the print statement or they'll do much richer output of like the state of an object.
25:52 They'll traverse the graph or they'll give better information about it. So you might be able to get
25:56 those print statements a little bit supercharged, but they're still print statements, right?
25:59 I mean, hopefully one day you can run like a remote debugger into PyCharm or something too.
26:06 But yeah, that would be cool. We'll get the PyCharm folks on that and just connect to the
26:10 front end. Look, they do it with JavaScript.
26:12 Yeah.
26:12 Right. So.
26:13 And also, you know, PyCharm supports remote debugging.
26:17 So let's put them together.
26:19 All right. So one of the things that does jump out at me when I see this
26:23 here is the populate method. So the way you create this interactive app that has the plus
26:29 and minus increment or decrement or things is you create a class called counter page,
26:35 direction page. When it initializes itself, it has, it sets sort of the variables to their
26:41 default values and creates them. You know, increment can change them, decrement can change
26:45 them. But then there's this populate method that says with some kind of DOM element, like
26:50 with div, with this class, with e.button as this text and its event hooks this. So you're
26:57 expressing the UI of that little section, not the whole page, but that little section
27:03 in Python code. Want to tell us about how that goes?
27:05 Yeah. So the kind of two approaches that you can have toward building a DOM, building
27:11 not even a DOM, but just any UI is a templated language, which is usually real popular on
27:17 the web. And I have experimented with embedding Jinja to templates and it works sort of
27:23 Pyodide. What I decided on is my preferred method is using context managers to specify
27:31 nesting. So in the example you're looking at, there's a div tag, and then there's two
27:38 buttons in a span and they're nested in the div tag. And the context manager tells the,
27:44 well, tells the UI what you're telling the UI to Puepy using context managers. So every
27:52 time you want to nest more elements, you use another with statement. And that way you
27:56 can use if statements for loops, just normal Python code. And the deeper you're into
28:04 your context managers, the more nested you are.
28:07 So in this case, you say with div, and then you create a button, a span and a button.
28:12 Basically anything that gets created while within that context manager just goes to the
28:16 children of the thing that was put into the context, right?
28:19 Right. Exactly. And for that matter, you could also nest more Puepy components using that.
28:25 Oh, interesting. Okay. And what is a Puepy component look like? Is it just a class or is
28:31 there like, how do we make one of the, or is it just a function that also does context
28:35 manager stuff? What's the deal?
28:37 I do have some examples of them, but yeah, a component, a page is a component. A component
28:42 is any reusable chunk of code with that state and population that you can use and reuse
28:49 throughout your application.
28:50 This portion of Talk Python to Me is brought to you by Code Comments, an original podcast
28:56 from Red Hat. You know, when you're working on a project and you leave behind a small
29:00 comment in the code, maybe you're hoping to help others learn what isn't clear at first.
29:06 Sometimes that code comment tells a story of a challenging journey to the current state
29:11 of the project. Code Comments, the podcast features technologists who've been through
29:16 tough tech transitions, and they share how their teams survived that journey. The host,
29:21 Jamie Parker is a Red Hatter and an experienced engineer. In each episode, Jamie recounts
29:26 the stories of technologists from across the industry who've been on a journey implementing
29:32 new technologies.
29:33 I recently listened to an episode about DevOps from the folks at Worldwide Technology. The
29:38 hardest challenge turned out to be getting buy-in on the new tech stack rather than using
29:43 that tech stack directly. It's a message that we can all relate to, and I'm sure you can
29:47 take some hard-won lessons back to your own team. Give Code Comments a listen. Search
29:52 for Code Comments in your podcast player or just use our link, talkpython.fm/code-comments.
29:59 The link is in your podcast player's show notes. Thank you to Code Comments and Red
30:03 Hat for supporting Talk Python to Me.
30:05 See if I can find some examples.
30:09 You also can run those examples on pyscript.com right in your browser.
30:14 Oh, that's right. Yeah. So yeah, maybe tell people just about that capability. I'll link
30:19 to the tutorials there.
30:21 Yeah, I mean, pyscript.com is a really cool project, also from Anaconda, I believe, where
30:27 it's kind of like all those million JavaScript IDEs in your browser. IDEs may be a strong
30:33 word, but you can edit the code and then run it right in your browser. And just like you
30:38 can see, there's the list of files. You can edit the files. You can fork other people's
30:42 work and edit them. It's very convenient.
30:46 Nice. Yeah. So here you have a component defined with the decorator, called it a card, and
30:51 you've got three little UI cards on there, and they have their populate thing that I
30:55 guess that you would expect.
30:56 Yeah.
30:56 Yeah. And then you can just now create the cards as if you'd created any other DOM element,
31:00 right?
31:01 Right. Exactly. And you're also seeing slots where there's a card header and then the
31:05 card body. And so if you have a component where there's multiple, in Jinja, these would
31:12 be like template inheritance. If you have a component where you want to insert code
31:18 from wherever you're using the component into where the component renders, that's
31:22 what slots do. Again, a lot like Vue or Web Component.
31:25 Sure. So it sounds to me like if I had lots of Vue experience, but at one point I created
31:30 some apps with Vue, but it's been a while. I'm sure the Vue doesn't look much like
31:33 that anymore.
31:34 Yeah. It changed a lot.
31:36 Yeah. But if you had that experience, it would carry over to PuePy pretty well, right?
31:40 Yeah. I would hope you wouldn't need that experience either, but yeah.
31:43 Sure. Yeah. You could just learn it from the PuePy perspective, but if you already
31:46 knew it, like, Hey, that's kind of nice. Right?
31:48 Yeah. If you know React or Web Components, that also would probably carry over.
31:53 Sure. Sure. Sure. Okay. So one of the things that you talked about was a single page
31:59 app, and I'm sure there's plenty of people out there who know what a single page app
32:03 is or a SPA, but there's probably a lot of people who are coming from not a web developer
32:08 areas that are like, what is that again? I want to talk about the router, but I think
32:12 we need to talk about a single page app before we can talk routers. Right? What is this?
32:15 You need a router to do it, but a single page app is instead of having that request
32:21 response cycle where the server renders HTML, and then you go to a new page and the server
32:26 renders the new HTML, and then you go to another page and the server renders that.
32:31 A single page app works where it loads the page, and then when you click on a button
32:36 or click on a link, the software in the client, in your browser, re-renders the page based
32:42 on the link you clicked without ever talking to the server. Or if it does talk to the server,
32:47 it's just kind of an API call to figure out what data it wants to render on the page.
32:53 But the page itself and the structure is not done through server calls. It's not done through
32:57 redrawing the page or navigating, even though sometimes you'll see the URL change. It might
33:04 not actually go anywhere. That might just be something so you kind of know where it
33:08 is so you can bookmark and deep link into it, but it doesn't actually make the browser go.
33:12 Right? Yeah, that's the gist. I mean, one telltale sign of kind of an older SPA is if
33:18 all the URLs, like if it's index.html or something, but then the meat of the URL is after the hash.
33:24 So it's, you know, example.com/ and then a hash, and then the hash tells you everything
33:30 about the URL. Right. That's a telltale sign that it's an SPA, an older one that used that.
33:36 Okay. Because then the client is looking at what's after the hash and deciding what it
33:40 wants to render and by client, I mean the website.
33:43 View or PuePy or whatever the front end framework is, is figuring that out.
33:48 So in order to do that, in order to make these faux URLs or whatever you call them,
33:53 actually kind of take you from place to place and navigate and redraw the page,
33:57 you need something like the URL structure that would be built in Django or Flask or other things.
34:02 And that's called a router, right? Right.
34:04 And you guys have a router, right? So that's pretty awesome.
34:07 There is a router. It's not as powerful as one in Flask or Django, but it gets the job done.
34:12 Okay. Let's see. Here we go. Router. There's a bunch of really nice tutorial walkthrough.
34:18 I went through most of these up to basically here more or less earlier today. And yeah,
34:24 tell us how about how you set up this router and how this works.
34:27 You get a link component. That's probably not real interesting, but if you scroll down,
34:32 when you define pages, there it is. App.page is a decorator. That's how you're telling PuePy that
34:39 you've made a page. And the default page is the one that renders if there is no route.
34:44 But you'll also see above it, pet page, where just like with Flask, the URL is in the decorator.
34:50 So it's saying if you go to pet and then there's a pet ID, use that class to render the page.
34:55 And I can put that whole URL without the hash in there and it'll find it. So I could just say
35:01 my server slash pet slash dog or whatever the thing's ID is, then it'll pull it'll invoke the
35:07 router instead of the browser. Well, there's two routing options. One is that hash I mentioned,
35:12 and that's easiest to set up because you don't then require any changes on the server.
35:18 If you have a server and you want, like if you have a Django project, let's say,
35:22 and you want a single page app, how that has to work is whenever the browser opens a URL,
35:29 Django, if it's a URL for the single page app, needs to return the single page app and not try
35:35 to process the URL on server side. So there's some tricks to doing that. I think there's actually a
35:40 couple of Django packages now that do that, but you're essentially just putting a wildcard up.
35:45 So maybe example.com/app, and then anything after that URL renders the exact same page as if it were
35:53 indexed on HTML. I see. Which would you recommend, the hash or the server hack?
35:57 Well, the hash doesn't require any server hack, so that's convenient.
36:01 But yeah, it probably doesn't require any server communications either, right?
36:05 No, it doesn't require you.
36:06 Not directly.
36:07 No, I mean, you can just have a static HTML website that works fine doing that.
36:12 Yeah.
36:13 You want cleaner URLs, you want to use what's called HTML5 history mode. And that's where
36:20 there's an API you can hook into on the browser and navigate around and it'll look
36:26 exactly like a normal website where you're changing the URL, but the page isn't actually
36:31 reloading. Then when you reload, you need that server hack to make sure it always serves the
36:37 same page.
36:37 Got it. So in effect, that would be what's sometimes called deep linking, right? Where
36:43 it doesn't just load up the front page of the spa and you click around and get back. But if you were
36:47 on this page with these details and that's contained in the URL, you could bookmark it and
36:52 come back and it should come back to that setup, right?
36:55 Yeah. I mean, you have to test that to make sure you did it right.
36:58 Yeah, of course.
36:59 You browse around the site and it all seems fine. And then you come back and reload later
37:04 and you get a 404 because you haven't configured your server to always go to the SBA.
37:10 Okay. Interesting.
37:11 What about working with external data and from the front end, that usually means APIs,
37:18 something like that, right? Can I use some of our standard code that we would for
37:23 HTTPX or requests or things along those lines to call out? Or how do I call out from this?
37:30 Networking is where it gets a little messy because the browser doesn't let you just have
37:35 untrammeled access to open whatever sockets you want. You have to work within either web
37:40 sockets or requests. And the best way to do that is using PyScript fetch function that
37:48 wraps the browser fetch, which is the new XML HTTP request.
37:53 Got it. So basically you kind of do an AJAX thing in the browser and then pick it back up from
37:59 there. Maybe you get some JSON back, but then you could maybe use the JSON module to process it or...
38:05 AJAX or web sockets are basically your choices.
38:08 Okay. In the PyPI library example, you have beautiful soup four for parsing data. And
38:15 that actually the example that you run, you can run it and it'll show you... Actually,
38:18 that's a pretty interesting example. Maybe it's worth giving a shout out to is, I think it's
38:23 this one perhaps, is to go and refresh your thing. It will actually go and you can give it some part
38:32 of HTML, some HTML, like, I don't know, I'll just make up some, see how forgiving this is.
38:38 So you give it any HTML, some basic page data that you have. And in here, when you run this,
38:43 it'll use beautiful soup to parse it. And then the output at the bottom is that populate thing.
38:51 So it'll basically recreate that DOM structure, take an HTML file or HTML content and convert it
38:57 to the component style of PyPI, right? Yeah. I kind of made that as a little utility
39:03 because I might go have some HTML that I really want to render that is going to be part of my
39:09 web app. And rather than going line by line and trying to figure out how to generate that
39:14 programmatically in Python, you can paste it into here and get your Python back.
39:19 Does it even do classes? Yeah.
39:21 Like if I think, so it knows all about the attributes. Yeah, it sure does. That's pretty
39:25 awesome. So maybe you could do something like write out an important chunk of HTML with all the
39:30 tooling of PyCharm or VS Code or whatever, copy paste, and then get it here, right? Like an
39:36 accelerated way to generate the first bit of structure and then just tweak it from here.
39:40 Maybe you don't like writing HTML or don't know how to, and you ask ChatGPT to write some for you and then you copy and paste it into here and see how it works.
39:49 Yeah. That's a totally reasonable thing. ChatGPT is pretty good at writing HTML. It does make up
39:55 stuff. You like, if you say use this framework or that framework, like Bootstrap or Tailwind
39:59 or something, but it'll still get you pretty close. Yeah. It's decent.
40:02 I've used it before. It was pretty excellent. Let's see what, let me rerun this whole thing
40:08 here. What other things you want to give a shout out to? I guess maybe the refs concept here,
40:15 which is worth talking about because this is an interesting challenge that people could run into.
40:20 Yeah. This is a problem that would happen in Vue as well, where as that state changes,
40:26 as your application state changes, that populate function that defines your DOM runs on every
40:32 single state change, unless you, you can override that. Maybe there's a state that isn't important
40:38 and you can turn that off, but that's the default. And so what that means is every time that you have
40:44 a state change, the DOM could be different. And if the DOM is different and it patches the DOM,
40:50 that means that the browser might have, let's say you're typing in an input element and the
40:57 input element moves, you would lose focus on that element. And that's the example that you see in
41:03 this demo. So if you give it a ref, that does two things. One, it identifies within that component,
41:11 it's kind of like an ID, but it's local to the component. It's not a document wide ID.
41:17 It identifies it so that when it comes time to patch, it will reuse that HTML tag,
41:24 that element in the DOM and only update the attributes on it and the elements around it.
41:30 So you get ultimately a smoother browser experience because it's being a little more
41:37 intelligent about how it wants to patch the DOM. Right. So in your example, there's an input,
41:41 and as you started typing into it with the naive, straightforward way, the thing reruns,
41:47 but it regenerates the DOM in a way that completely blasts away that text input.
41:52 Right. Puts it back. But as you type, now all of a sudden it goes click, click, click, because,
41:56 or beep, beep, beep, because it's no longer focused on there. Because that's not actually
42:00 the same text box. It's a new one with the same value. Right. And so in order to say,
42:04 no, this thing is permanent, leave it here. Don't recreate it for whatever reason. Maybe
42:08 you could use that for performance, right? If you had like a big grid that didn't change
42:12 or something. Yeah, it would probably help with performance. You also can use it to just reference
42:17 those components elsewhere in your code. Like if you have an event handler and you want to get at
42:24 a DOM element that's rendered, you can reference self refs, use the reference as a dictionary key,
42:29 and that gets you the component. Yeah, sure. All right. So I really recommend that people
42:33 come check out this tutorial. It's got a bunch of neat pieces and not just necessarily jumping in
42:39 here into the PyScript runner, but on the documentation, which is somewhere I found it
42:46 somewhere. There you go. There's actually a really nice walkthrough. Like you start here,
42:50 you click, take me to the next one, see that example run, right? At docs.puepy.dev, walk
42:56 through the tutorial. That's really quite nice there. Thanks. I hope it's nice. I mean,
43:00 send me any feedback because it's hard to write a tutorial for something you made yourself and
43:06 understand pretty well. Yeah, that's a good point, right? Because you know how it's supposed to look.
43:11 So yeah, it's hard to evacuate that assumed knowledge from your context. Yeah, yeah,
43:17 exactly. Okay. So this looks like a pretty well polished framework. It's still at its super,
43:25 super early stages. So I guess a couple of questions. One, contributors, PR is welcome.
43:32 What's the thoughts there? Yeah, absolutely. That's why it's on GitHub.
43:35 Yeah. And if people want to try to build with it, you know, they can give it a try and maybe
43:40 they'll discover an issue and put it on the GitHub repo or something like that. Yeah, it'd be cool.
43:43 And then sort of towards that end, what is this readiness for use? If somebody said,
43:50 I want to be all in on Python, I think PyScript awesome. What's the stability look like? Where
43:54 would you classify it? Is it an experimental stage? Is it a beta? What is it? If you're someone who
44:00 is comfortable using a relatively new project that has one contributor on GitHub, I think you know
44:06 who you are. If you took this and you try to bring it to like a review board of a Fortune 500 company,
44:12 I don't think they would go for it. But then again, a lot of things kind of get smuggled in.
44:18 They might, they can almost work it. Exactly. That's what I was going to say. That's why they
44:21 might, because while there's not a huge team behind it, they could fork it and say, look,
44:26 this is important enough for us that we'll like take it over effectively if we have to.
44:30 It's also just not that much code. I mean, I've been kind of working on it on and off in my free
44:37 time for like six months, but the volume of code, I mean, I don't know how many lines there are off
44:42 the top of my head, but there's like four main files. They're relatively straightforward. Most
44:48 of the heavy lifting is with PyScript. In terms of stability and breaking, like it promised that
44:54 I won't break anything, but I think it's pretty deliberately laid out. And like I said, one
45:00 complaint I have about the Node.js world is how aggressively everything gets broken every six
45:05 months. So I have some PTSD from that and I'm not looking to recreate it myself.
45:11 Yeah. No more left pad. That's not even the problem. The problem is just that it's the
45:15 constant change. This version changes. And it also happens in CSS frameworks. Like, oh,
45:20 we've got bootstrap six. And I know five was awesome. You wrote a bunch of stuff in it,
45:25 but we're completely redoing it because it's better now. It's like, it would be even better
45:29 if I didn't have to start over or get pinned in the past or whatever, you know? And yeah.
45:34 If you're living in that world, like it's fine because you get up every day and you eat,
45:40 breathe, sleep. Everything in your world is this Node front end framework and it's your full-time
45:46 job. You can keep up with it. But if you're like me and it's just something you did and then six
45:52 months later, you need to revisit it. It's too much. Yeah. Yeah. Well said. Okay. Last API
45:59 question. Where are you going from here? Like what do you got next in mind?
46:04 The testing is basically just Python unit tests. I'm not really, I don't have any automated testing
46:10 for how it behaves in different browsers. It's fine. It's code runs the same in all browsers.
46:15 Don't worry about it. Well, I mean, it might with PyScript, but...
46:18 I know it's getting better. It used to be really bad, but like, I'm just now dealing with the issue
46:23 like this video will play back on every single browser, except this particular one on this
46:28 particular OS. Like, great. Right. Okay. You know, it's that kind of stuff, right?
46:32 Can't solve that kind of stuff for you. The actual Python language is going to be the same. Maybe not
46:38 the JavaScript APIs you import. Yeah. Well, to a large degree, you're basically built upon the
46:44 stability or lack thereof of MicroPython, which has been pretty stable.
46:48 Yeah. MicroPython is great. Pyodide is great. Yeah. I would like to get some playwright tests
46:53 to actually do proper end-to-end testing instead of just unit tests. I think probably some direct
46:59 support for progressive web apps would be helpful for everyone. I would like to have some kind of
47:07 example on how to hook it up to like a Django or Flask backend. No, that's not usually in scope for
47:14 a front-end framework, but I kind of like the batteries included approach to development.
47:18 Sure. You know, you talked about the progressive web apps and I think they're great. I think it'd
47:23 be like, I've already said, I think it's completely possible to do with PyScript because I've done it
47:28 on iOS, but it is great though. The challenge with progressive web apps is the, how do I get it in
47:34 my doc? How do I install this thing like for real in a discoverable way? You know, I can come over on
47:40 some of these things that I can like right click on it and say, for example, if I right click on a
47:46 GitHub page, I can install GitHub, which means it will install as a progressive web app. But if I
47:51 go to PyScript and right click, it'll say create shortcut, which if I say open as a window kind of
47:56 looks like it, but it's not. And just like, that's not an end user experience, right? That's a dev
48:03 user experience, I think. That's not for you to solve. I mean, that's a problem with progressive
48:08 web apps globally. That's nothing to do with your project, but it would be nice if there was like a
48:12 really nice way to click this. Here's how it goes in your doc or your task bar. Yeah. I think the
48:17 problem that they're butting up against is that the people who make browsers are keenly aware of
48:24 how spammy websites get. So they don't want to have it be where you visit like a, you know,
48:29 a newspaper and the newspaper prompts you to install the newspaper. So having that easily
48:36 self-documenting install process is not there for the desktop. You have to actually go click
48:41 add shortcut and then it works. Right. The Safari folks, I've been, I talked Apple down a little bit
48:47 from their really horrible app store review experiences they put on people, but the Safari
48:53 browser, which I don't generally use, but they've got a really nice install this, you know, go to
48:59 file, add to doc, and then that experience, the life cycle of using that app once you've done it
49:04 is real nice. So, I mean, add to doc is I want this app as an applicant thing where my other
49:10 apps are. That's pretty good. Yeah. I've like, I've installed Google's old chat app, which I
49:16 still use as a progressive web app using Safari on my desktop. And it's great. It's, it's just
49:22 like another application that I've downloaded and installed and it's Safari, which is fine.
49:27 Yeah. As long as it stays in this little container, it doesn't affect my Vivaldi experience. I have
49:32 proton drive, Gmail, Google contacts, Google calendar. Some of the e-commerce stuff that I
49:39 have to do. I've got the analytics, my email newsletter app. I've got YouTube, YouTube music,
49:46 all those things are all installed that way these days for me. And it's really, really nice.
49:50 It beats having all those electron apps running. It does. However, I don't see any reason why this
49:54 stuff wouldn't work for electron as well. Right. You can ship your electron app with a HTML page,
50:01 and then you can just put this PyScript and PuePy art as part of your HTML. And it should,
50:06 it's on the client side. It should just run in Chrome just fine.
50:09 It should. You know, I don't know what the process for that would be. The developer in me says,
50:13 make it a PWA, but I'm, I'm sure there's some business cases for making it a dot app file.
50:19 It feels more real. Well, maybe data storage, maybe access to OS features. I know it's,
50:25 that's getting better, but it's, it's running natively on the machine. You can, you know,
50:29 do whatever you need to do. So possibly. That's true. That might get a little messy
50:34 in terms of importing those features once into JavaScript and then from JavaScript into PuePy.
50:41 Yeah. You might have to have a multi-layer interop type thing. That's a little bit funky, but.
50:46 Yeah. My suspicion is that most people making electron apps have a team that does front end
50:54 work and probably that front end work is going to be in JavaScript.
50:58 Right. Yeah, probably some framework there. All right. Awesome. So I think PuePy has
51:03 got a lot of potential. That's why I invited you on the show to talk about it. Cause it's,
51:07 it's very interesting. And honestly, it's this kind of stuff I would love to see when I visit
51:11 PyScript and not a REPL because right. That's not what most people do. I know it's PyScript a
51:16 little more data science focused, but even for them, they more have a notebook experience generally.
51:21 All right. I do have a question though. So I noticed when I was going through the documentation
51:26 here for your PuePy docs that it says powered by JetBrains right side, righter side. Tell me
51:32 about that. I have not used this, but it's like a new IDE for recruiting documentation and testing
51:37 and stuff. Like, what do you think about this? Now you've got to play with it a little.
51:41 Well, you're basically just calling out laziness on my behalf because all the real Python projects
51:47 are using something awesome like Sphinx. And I have the JetBrains all products license. So I just
51:54 saw that and tried downloading it. It works well. There's zero setup. You just open it up and start
52:00 typing in Markdown. It's clean and polished. If you have a JetBrains license, you might as well
52:06 try it out. But I expect that if people start contributing to the documentation, I'll need to
52:12 switch to something more community-oriented. Potentially. I can't remember. I feel like
52:16 right side, righter side might integrate with some of those frameworks like Sphinx, but I'm
52:21 asking about all this because I've not used it at all. So I don't really know.
52:24 It's kind of its own framework. It supports Markdown, but it has its own little kind of
52:31 HTML-ish thing for making tabs and glossaries and all that.
52:34 Yeah. Excellent. Okay. And then I guess anything else you want to give a shout out to or talk about
52:40 on the PuePy side of things when we wrap up our show?
52:44 I would kind of like to give a shout out just to the PyScript people. I've gotten stuck a few times
52:49 and headed over to their Discord server and they're always really friendly. They run little
52:55 meetups kind of on Zoom with the community and they've been great. I wouldn't have been able to
53:01 do this without their help.
53:02 Yeah. Awesome. They have been helpful for me as well. All right. And then
53:05 notable API project library?
53:09 Completely unrelated, but there is a project called PGQueuer. There you have it built up on
53:17 GitHub. And if you want something kind of like Celery, but you don't want to have to install
53:24 Celery and install a broker and figure out your Celery installation and make maybe even another
53:30 Docker container for your workers, this is great. It uses some Postgres, some Notify features that
53:38 are built right into Postgres and you get a simple task queue. I've tried it. It works great.
53:44 You can probably Celery is still, you know, quote unquote better for complex needs, but if you just
53:51 want something simple, this is great.
53:52 Yeah, it's cool. I mean, the truth is most of us have not complex needs, simple needs, and then
53:57 bringing that kind of stuff in just makes it way more complicated from a DevOps perspective, right?
54:02 Like, I'm already talking to a database. I'm already talking to Postgres. What if I could
54:05 just use it?
54:06 There's a lot to learn with Celery. Like it's a whole project unto itself.
54:10 Sure. Yeah. Over at Talk Python, I've got a MongoQer equivalent. That is, you know, because
54:17 you scale out the worker processes, right? So it's not enough to just have them running. You
54:21 want a little more durability in case for some reason, like the server restarts, but there's
54:25 still work to be done. It'll just come back and look, oh, look, there's some unprocessed work in
54:29 the database. Let's do that. It's nice. It's not quite as nice as this, I think. But I mean,
54:35 suppose if it said send an email and it like had sent the email, but it hadn't acknowledged it
54:40 sent the email yet and you restart the server at that very moment, the person's probably getting
54:44 a second email. You know what I mean? But there's a really, really small chance of these types of
54:48 things. It's much more common to like, you know, re-index these things or whatever.
54:54 There, I think actually with PGQueuer, because it's Postgres, you would get strong consistency. So
55:00 the chance of that duplicate email would be low. Well, but imagine this, like if you do a
55:05 transaction and you go to like, start the, let's say like, I'm going to move the work into running.
55:11 And then if you shut it down, that transaction is going to roll back and it'll probably go back to
55:14 ready to run. I mean, how do you deal with it without, I mean, it's almost comes back to the
55:19 poison message thing of like celery and message queues, which is really very tricky.
55:23 Like sending an email. The thing is that's, you can't put that in your transaction.
55:27 Yeah, exactly. You can't unsend. Well, a few things have tried to recall email,
55:31 but as in general, email doesn't support rollback.
55:34 Now might be a good feature for like SendGrid to consider.
55:37 Yeah, it would be very cool.
55:38 One thing you can kind of do in those situations, if you happen to have like
55:42 Redis or something available is if you, the content of the email is going to be exactly the
55:48 same. So if you just hash the email to identify it somehow, like combination of the email content
55:55 and who it's for, and then you get a hash of that, then you can have a little Redis key.
56:00 And if that Redis key is set, email has been sent and you can discard the task.
56:04 Yeah.
56:05 Yeah.
56:05 You just put that right next to where you've actually sent the email.
56:08 Yes.
56:09 The chance that it's going to crash in between those two is pretty low.
56:11 It's extremely low. Yeah, exactly. So things like this, things like that solution you talked about,
56:16 while not bank level bulletproof, most of us don't want to suffer through that level of
56:21 durability. Right. So pretty cool project.
56:23 Yeah, I like it.
56:24 Awesome. All right, Ken, final call to action. People are like, oh my gosh, front end Python.
56:30 What do they do?
56:31 Well, I don't want to oversell it as solving all your problems, but if you want to check it out,
56:35 PuePy might need spelling out. It's P-U-E-P-Y.dev.
56:42 Excellent. And love the initiative. Happy to shine a light on the project. Would like to see it grow.
56:47 Awesome. Thanks for having me on.
56:49 Yeah. Thanks for being on the show. Bye.
56:50 Bye.
56:50 Bye.
56:50 Bye.
56:51 - This has been another episode of Talk Python to Me. Thank you to our sponsors. Be sure to
56:58 check out what they're offering. It really helps support the show. Take some stress out of your
57:02 life. Get notified immediately about errors and performance issues in your web or mobile
57:07 applications with Sentry. Just visit talkpython.fm/sentry and get started for free and be
57:13 sure to use the promo code, talkpython, all one word. Code comments and original podcast from
57:19 Red Hat. This podcast covers stories from technologists who've been through tough tech
57:24 transitions and share how their teams survived the journey. Episodes are available everywhere
57:30 you listen to your podcasts and at talkpython.fm/code-comments. Want to level up your
57:36 Python? We have one of the largest catalogs of Python video courses over at Talk Python.
57:41 Our content ranges from true beginners to deeply advanced topics like memory and async. And best
57:46 of all, there's not a subscription in sight. Check it out for yourself at training.talkpython.fm.
57:51 Be sure to subscribe to the show. Open your favorite podcast app and search for Python.
57:56 We should be right at the top. You can also find the iTunes feed at /itunes, the Google Play feed
58:02 at /play, and the direct RSS feed at /rss on talkpython.fm. We're live streaming most of our
58:09 recordings these days. If you want to be part of the show and have your comments featured on the
58:13 air, be sure to subscribe to our YouTube channel at talkpython.fm/youtube. This is your host,
58:19 Michael Kennedy. Thanks so much for listening. I really appreciate it. Now get out there and
58:23 write some Python code.