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