Python Bytes - #499 So many questions??
Episode Date: October 6, 2026Topics covered in this episode: PEP 824 brings ?? and ??= to Python for None handling Python 3.15 gets a surprise RC3, and Python 3.10 reaches end of life asyncio.shield Pyxel: the retro game engin...e for Python Extras Joke Watch on YouTube About the show Sponsored by us! Support our work through: Our courses at Talk Python Consulting from Six Feet Up Connect with the hosts Michael: Mastodon / BlueSky / X / LinkedIn Calvin: Mastodon / BlueSky / X / LinkedIn Show: Mastodon / BlueSky / X Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Tuesday at 7am PT. Older video versions available there too. Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to our friends of the show list, we'll never share it. Michael #1: PEP 824 brings ?? and ??= to Python for None handling PEP 824, a new draft from Marc Mueller sponsored by Guido van Rossum, proposes None-coalescing operators for Python 3.16. The ?? operator returns its left-hand side unless that value is None, and ??= assigns a fallback only when the target is None. It revives the long-deferred PEP 505 from over a decade ago, trimmed to just these two operators, with None-aware access split off into PEP 823. The goal is replacing verbose is None checks with something closer to or, but keyed on None instead of truthiness. Every Python codebase has piles of if x is None fallback code, and this is the first serious move in ten years to give it real syntax. user.age ?? "unknown" is like or but only falls back on None, so 0, "", and [] pass through instead of getting clobbered user.name ??= "unknown" replaces the two-line check-then-assign pattern, with left-side subexpressions evaluated and cached exactly once Precedence sits between or and conditional expressions, matching JavaScript and C#, and ?? lands as a BoolOp in the AST next to and and or Unlike +=, ??= is a conditional assignment that skips the right side entirely, which is why it gets its own AST node rather than AugAssign Still draft status targeting 3.16, with a working reference implementation and an online demo to try, and it notably rejects a soft keyword like otherwise in favor of the familiar ?? Discussion-worthy: the PEP answers the old objection that making None easier will proliferate its use, pointing out None is already everywhere and the status quo just produces uglier code # OG way user = db.get_user() city = None if user is not None: if user.address is not None: if user.address.city is not None: city = user.address.city # Michael's preferred way user = db.get_user() city = user?.address?.city Calvin #2: Python 3.15 gets a surprise RC3, and Python 3.10 reaches end of life The release team added a surprise third release candidate for Python 3.15 to fix last-minute lazy-import release blockers. They wanted time to test the fixes properly. That pushes the 3.15.0 final release from October 2 to October 9, 2026. RC3 has about 156 fixes from 82 contributors. The headline features are explicit lazy imports (PEP 810), the new frozendict (PEP 814) and sentinel (PEP 661) built-ins, and UTF-8 as the default encoding (PEP 686). No more ABI changes are coming, so library authors should be building 3.15 wheels now. uv 0.12.23 already added CPython 3.15.0rc3. On October 1, Python 3.10.22, 3.11.17, 3.12.15, 3.13.16 and 3.14.8 shipped together with nine common security fixes. They cover SSL validation, tarfile and zipfile handling, and urllib credentials. Python 3.10.22 is the final 3.10 release. After five years it gets no more security updates, so anyone still on 3.10 should upgrade. Python 3.13.16 is the last full maintenance release of 3.13, which now moves to security-only fixes. Only 3.13.16 and 3.14.8 have Windows and macOS installers, and the older releases are source-only. Python 3.11 gets security fixes through October 2027, and 3.12 through October 2028. A natural way to tie the two together: one version is nearly out the door and one is officially gone, and the same week is the time to test your code on 3.15 and move off 3.10. Michael #3: asyncio.shield Where async code can be cancelled In async Python, every await is a point where your coroutine can be stopped. If someone cancels the task, asyncio raises CancelledError at whichever await the coroutine is paused on, and nothing after that line runs. Quart does this on purpose. When the client disconnects, it cancels the request's task. From quart/asgi.py: elif message["type"] == "http.disconnect": self._disconnected = True request.body.disconnect() request_task.cancel() That's reasonable for a slow page nobody is waiting on anymore. It's a problem for a handler that writes to the database in two steps: await downloads.insert_one(event) # 1. log the download await totals.update_one(..., {'$inc': ...}) # 2. bump the episode's total A podcast app requests the MP3, gets what it needs, and hangs up. If it hangs up while step 2 is in flight, step 1 has already landed and step 2 never runs. Nothing is logged and nothing reaches Sentry, because a cancelled request isn't an error. The two collections just drift apart. Under WSGI this couldn't happen. A disconnect didn't stop your view; the view finished both writes and the server only failed later, when it tried to send the response. The demo I ran this on Python 3.14. The "client" hangs up 15 ms into a pair of 10 ms writes: async def record_download(): await db_write('events') await db_write('total') _pending: set[asyncio.Task] = set() async def record_download_shielded(): task = asyncio.create_task(record_download()) _pending.add(task) task.add_done_callback(_pending.discard) await asyncio.shield(task) record_download events=1 total=0 record_download_shielded events=1 total=1 The unshielded version loses the increment. The shielded version finishes it, even though the request was cancelled. The full script is in the scratchpad as shield_demo.py if you want it for the show. What asyncio.shield does, and its traps shield(task) protects the inner task from a cancellation aimed at the outer one. The handler still gets CancelledError immediately, so nothing after that line runs, but the inner task keeps going until both writes finish. The traps: Keep a reference to the task. The event loop only holds weak references to tasks, so a task with no other reference can be garbage-collected mid-run. The asyncio docs warn about this. That's what _pending is for. Its errors go nowhere by default. If a shielded write fails after the handler has already been cancelled, nobody awaits the result. You only get a "Task exception was never retrieved" warning. Log errors from inside the task, or in the done callback. It doesn't survive a process shutdown. If the event loop is closing, as during a Granian worker recycle or a deploy, pending tasks are still cancelled. The window is tiny, but it isn't zero. It hides hangs. A shielded write to a stuck database lives forever. Put a timeout inside the shielded task (asyncio.timeout(...)), not outside it. It makes the pair finish, not atomic. A crash between the two writes still splits them. The real fix is one operation that can't half-happen. That's what the SQLite move gets: an insert and an upsert in one synchronous transaction, with no await in the middle. Shield is the right patch for the Mongo code until then. The general lesson: in async code, related writes made one after another are only as reliable as the client's patience. Before shipping something like that, check whether your framework cancels on disconnect. Quart does, and I believe Django 5's async views do too. I don't think Starlette cancels a plain endpoint, but I haven't checked any of these other frameworks' source, so verify them before you say it on air. Calvin #4: Pyxel: the retro game engine for Python Pyxel is a free, MIT-licensed retro game engine for Python, built and maintained by a single developer. It has been in development since 2018 and has passed 18,000 GitHub stars. It's modeled on classic game consoles and deliberately limits you to 16 colors and 4 sound channels, which keeps scope small and games finishable. Built-in editors cover pixel art, tilemaps, sound and music, so you can make the graphics, audio and game logic in one place. The engine is implemented in Rust and compiled to WebAssembly, but you write your games in plain Python. Pyxel Code Maker is a browser playground with a code editor, resource tools and a run button. It loads projects from local files, GitHub Gists or URLs, and saves back to a Gist for sharing. Games can also run on the web, so sharing one can be as simple as sending a link. It's a fun, low-barrier way into game development, good for beginners and for teaching kids. Extras Calvin: Python Lang Summit 2026 discusses a sys namespace Be Careful Updating Your Refrigerator Michael: New Siri is No Bueno Who out there is doing interesting work with sqlite and litestream? Trying to put an episode together on it. Tinymongo shoutout https://tinymongo.org Joke: I was there.
Transcript
Discussion (0)
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
This is episode 499 recorded Monday, October 5th, 26. I'm Calvin Hendricks Parker.
And I'm Michael Kennedy. Glad to have you, Michael. Please support this show and all the sponsors.
Make sure you support our work. Michael and I are doing lots of interesting things out in the community.
So support the courses at talk python.fm. So head over there. There's some
really interesting new stuff, some rest stuff, some web stuff. There's all kinds of data stuff.
So check out Michael's courses online at talk python.fm. And check out the consulting from
six feet up. So I am co-founder and CTO of six feet up. We are a Python AI shop who loves
solving hard problems. So if you've got a hard problem and you'd love to talk about it, I'd love
to talk to you about it. So let's move right along with connecting with us. You can find Michael
and myself on Macedon, Blue Sky, X, and LinkedIn.
and the show is on Macedon, Blue Sky, and X.
So check us out over there at Pythonbytes.
Join us on YouTube for Pythonbites.fm.fm.
slash live to be part of the audience.
You can actually participate live, ask questions.
We may put them on the air and answer them in real time.
Usually it's Tuesdays at 7 a.m. Pacific.
Older versions are available there too.
And finally, if you want an artisanal handcrafted digest
of every week's episode, show notes, and email form,
put your email in the friends of the show,
and we will give you a beautiful email summary.
Actually includes also little extras.
I kind of like that summary.
Very meta, but I like the metanness of it.
And we'll never share your email address.
So it's safe with Michael and I.
All right, Michael.
I've got questions.
So many questions.
So many question marks.
So many question marks.
Hey, before we jump into the questions,
I just want to say I just came from a place
with large buildings outside my hotel window
and you have large buildings outside your hotel window.
I do.
I'm in New York City today.
That's awesome.
I was in San Francisco.
I want to give a downtown San Francisco.
I'm going to give a shout out to Pibe.
That conference just happened two days ago and was tons of fun and all the sessions were
recorded.
So they're going to be up.
And I think it'll be really fun for everyone.
We'll give the videos a shout out when they're up.
So that was really nice.
Nice.
Pi Bay is on my bucket list of conferences to attend.
I've never been.
Well, it was fun, I can tell you.
Nice.
But you have questions.
Do you say?
I do have questions.
There are questions.
There are questions.
Now, this topic is really interesting to me.
So there was a PEP 505.
Yeah, 505.
Now, often you'll hear this referred to as,
the idea is I'm dealing with variables that have no values.
And so you'll get like attribute errors
because none type doesn't support whatever you're trying to do.
You know what I mean?
And so you got to check, right?
Is this thing not none, then I can do thing with it.
Often these are referred to as null coalescing operators
because like most programming languages call nothing
for pointers null.
But by then we call it none.
And so we have none-collessing operators.
So this was a proposal from 10 years ago, and it's revived as an idea for 316 by Mark Mueller
with sponsor, none other than Guido von Rossum.
And the idea is, let's go back to 505 from 10 years ago and just do like a really simple bit.
Now, I don't just have questions.
I got.
I got ideas.
I have opinions.
So, but let's go with what it is first before I.
There was a lot of ideas in 5.
five, 10 years ago. For this one, it's very short and simple. There's two things. Question
mark, question mark, question mark, is the operator, hence the opening transition. And question
mark, question mark, equal. So you got a scroll, scroll, scroll, scroll, scroll, here it is. It comes
down to something like this line. Age, if you get a user, maybe it got the user from a database.
This example is bad. The example in the thing is not good because what does the type safety
say about this? Can it be none?
I have a user colon user, like lowercase user, uppercase user.
Python's type system says, if something could ever, ever possibly mean none,
it must be marked as optional.
Or, you know, type, pipe, none, if you prefer, the union variant of that.
I don't like it, but you know what, I also have opinions there.
So basically the way this thing is typed, it's literally not necessarily to check,
necessarily to use a null check because if the type system is cohesive
when you're running things like TiWI or whatever and they pass, then it would be good.
But the example is what it is.
And so we take a user, but the user might be null or none, even though it says it can't be none.
It says, well, we're going to need to check.
You might need to write if, I'm up here, if, you know, the user is itself not none, then, oh, wait, sorry, this is actually, so this is different.
So no, this is still fine.
It says if user.
Dot age, trying to get the age from the user.
So instead of saying if user is not none, if user.
Dot age is not none, well, just user.
Dot age is not none.
Done that so many times in my life.
Oh, there.
Yes, I know.
Otherwise, if I got a user and it has no age set, then instead of saying I have an if statement where I set the value, I can say question mark, question mark unknown age.
Okay.
I'm not against this.
My opinions are not saying this is bad.
It doesn't seem to buy me very much, right?
I mean, you could say user.
dot age if user.age is not you know else unknown or whatever I like it's you can still kind of
one-line it in a not much more effort you don't have as a turnary sort of expression or something
yeah I was thinking attorney or it'd be appropriate yeah that's how you would have done it
before if you want one line but you know it's fine I think it's I think it's okay now if we go
back to 505 from 10 years ago there's other things as well like question mark dot and now this one
I think is actually, if they're going to pick one thing in the language and use, and like,
say we're going to add a little bit of null or none help here, this one is the one that makes
such a difference.
So in the show notes, I put a little example down here where you'd have to do it the old way
or you have to do it the new way.
And this little example here lost my comments, but the comments are in the show notes.
So I go to the database, I get a user.
I may or may not be logged in.
So this could be a user object or it could be none, right?
And I have a city.
I want to set the city to a value, but if I don't set it to a value, I want the city to be none.
So I have to say if user is not none, then I can run the test.
If user.org.
Address is not none.
Then I can run the test if user.
dot address.
Dot city is not none.
Then city equals user.
Dot address.
Dot city.
Like this, this is a lot.
Yeah.
What was in the original one and what I wish was here, if they could add one more thing,
just one little bit, would be this one line here.
city equals user question mark dot address question mark dot city I could see why this is controversial
it's is it you have opinions now so the way the way this works the way this works in other languages
is when you instead of saying dot for attribute access or function calls or whatever you say question
mark dot and if the thing that you're trying to do attributes attribute access on itself is none
so like user question mark dot so if user is none then you just short circuit and return none if user is not
but user addresses none, you short circuit that and you return none.
Otherwise, you just give the value of city, none or not.
A little opaque for me.
A little, a little.
Okay.
Yeah.
I mean, I agree that the verboseness of the example given there is a lot of what feels like
boilerplate to get the same thing done.
Uh-huh.
So I can understand why they didn't go all the way for this version of this index.
Yes.
So to be...
I mean, if you thought the Walrus was contentious.
I know, it's true.
The Walrus has left scars.
But here's the thing.
So how much does that...
this, I don't know, how much does this, this new edition here help, right? This user.
Dot age question mark, question mark unknown. You know, how do you solve problems like,
you don't, it doesn't really solve problems like, like that one. It just compresses
turnerary expressions, right? It doesn't actually alleviate the, the none checking. Like, if you
wanted to check is user none or age none. Yeah, but maybe it's, I don't, I don't see, yeah,
I don't see any way to. This feels cleaner for the turnary version of that. Yeah. Yeah, let's see.
We got some...
Again, this is personal opinions.
I think both of us are passing back and forth here, unfortunately.
And I'm okay without it, but if you're going to add null operator, like no operations to the language,
the biggest one is the if this is not, if this, like just the sawtooth of four things.
Ifs.
Yeah.
Kiva out there says, when I went from C Sharp to Python, I really, really missed the nullus.
No colosting operators more than anything else, even the type system.
Yeah.
Yeah, yeah, yeah.
But like you just mentioned with the sawtoothing thing.
the flat is better than nested Python, you know, to tenant.
Really, I believe in that one.
And that, that breaks it when you go that deep like that.
Yeah.
Yeah.
So, I mean, what would I do?
All right, what can, we're in the danger going too deep.
So what I would do is I would use for this, this, like the way it has to work now,
not Michael's fever dream of null checking.
You've got to use what are called guarding clauses, right?
You say, if user is none, return something like none or whatever.
And then if user dot address is none, return something else.
And then finally you can get the city.
And you know, you can flatten it with the right patterns.
That's the Zen of Python pattern I would have used.
Yeah.
All right.
That's enough for this.
People, this is a proposal, a draft for 3.6.
We have had opinions and we've shared them.
And now you can have yours.
Over to you, Calvin.
Yep.
Well, speaking of language features and new versions that are out.
So we've been talking about Python 315 for at least the last month of episodes,
hoping it would have been out October 1st, but that got moved.
So we actually have got Python 315 RC3 that came out this week.
So if you are keeping track, you should probably notice that there's not been a formal release,
but it will be coming.
I believe they're saying final is scheduled here for the ninth.
So before the next episode, we will have Python 315 that is out.
The showstopper roadblock that was going on in there was basically,
some support or fix for what was lazy import release blockers so the kind of one of the really nice
new features of python 315 that you probably should check out and if you wanted to go use what's
new to do a dungeon crawler and explore those features but the the lazy imports had a last minute
bug so they want to make sure they get the testes the fixes tested properly so if you aren't familiar
again lazy imports means that you can say lazy import from blah blah blah blah blah blah and
when you go to use it is actually when it'll import at that point in time.
So you could actually have imports at the top that actually never get imported based on conditions,
which might actually be preferable given your stance on memory usage or loading things for security reasons
or lots of other things that could basically be wrapped into that.
I'm very excited about the lazy imports.
Yeah, I am too.
So I mean, the lazy imports and then the frozen dicks that we get now as well.
I think that's the other major one that was going on there.
But there's no major ABI changes for this RC.
It's just making sure dot in the eyes and crossing the T's
and making sure that the version 3.15 is very, very solid.
So that's part of the news I wanted to cover on this one.
The other piece that I wanted to cover was that on October 1st,
they also released the last version of 3.10.
So if you see right here, Python 310.22, 11, da, da, da, da, da,
all of mine releases there for 10 through 14,
are now available.
The most important piece I think of this release
that's why I wanted to bring it up
during this segment was there'll be no more releases
of Python 3.10.
This is the EOL final end of line.
There'll be no more security releases for 310.
So if you've got code in production
that is running 310, you've been warned,
you've been told probably many, many, many times
along the way that this is coming,
but it's become, we're here.
So for example, there was nine common security fixes,
in this October first release, there was things like SSL validation, that tar file and zip file
handling, URL lib credentials. Those all sound pretty important. And those are the kind of things
you're going to want to have fixes for inside your code, especially given the state of...
Credentials.
Don't we just trust people? Come on.
AI and all the things that are kind of coming after it. So it's been five years. It's time-free
upgrade. That's going to be no more 3-10.
That's wild because I'll tell you that 3-10 sounds pretty modern to me.
Same for me. I mean, I think we are of an age and have been in the Python community long enough
that five years passes before your eyes before you know it. But 315 is about to become very much
a reality. 314 is very stable. 311 has all the things you probably want and probably is
most likely a drop-in. These releases of Python, I don't believe there's been too many
backward-compatible breaking changes in there. So there's not really much of a reason not to
If you've got great test suites and you can go and do a Knox style test against all of them,
find out which one doesn't break for you quickly through your CI pipeline and get your code
updated for the latest versions of Python.
Now, that said, Python 311 will get security fixes through October of 2027.
So you got another year on 11 and another year after that for 12.
But why not just go to the 315?
It'll be outdated this week.
If you're already doing the work, if you're already doing the work, you might as well get yourself another five-year lease on.
on this work theater.
Run, as you said, run Knox, run all of them.
Run all of them.
And see if they all passed or if layers issues and either fixed or just go back to the, you know,
313 or whatever that works.
Yeah.
I just, again, I hate, I put this one here because I really do not want to see anyone be a headline
on hacker news or any other major news outlet.
I've got an extra that's kind of related to this, that you shouldn't, don't be a victim.
Keep up to date.
Python is very, the Python community is very good about compatibility up to
having updating notes.
We learned a lot of lessons in the two to three history of Python.
So go out there and get yourself upgraded.
One of those lessons was waiting for a very long time for the world to sort itself out.
It doesn't necessarily treat you that well.
Yeah, that's true.
Maybe stay on top of things as they're changing rather than like waiting eight years ago.
Oh gosh, we got to upgrade.
Like you should have a shield.
Let me just put up like a shield sort of thing.
Is there a shield people?
could use? There is a shield people can use and I've got details for you. So I've been experimenting
with ideas. Some crazy ideas and I'm not ready to share with you. I might share with you privately,
of course, Calvin, but I'm not ready to share with you, dear listeners, as a broad world until I have
more info on it. But it's pretty wild. So I've been doing a lot of testing on like different database
type systems and so on a couple of the websites. And I have this place where I write basically
an analytics entry.
Someone's downloaded this or they watched a video or something like that.
And then I increment it somewhere else because, you know,
50 million records, you don't want that to be your operational.
Like, who has done this thing?
You might want it like a little more concise or how many people downloaded that thing or whatever.
So it writes it once to this kind of summary table that the websites use and then it writes
this analytics one.
Well, it turned out that out of many, many millions, there was 1,200 missing entries.
Where did they go? It says right here and then it says right there. Well, these came into existence once I switched to an async web framework.
Court, but it could be fast API. It could be Lightstar. It is not anything necessarily specific with court, not necessarily.
So what happens is with court, if somebody makes a request and the request is in flight and they decide they're not doing that anymore or they're going to cancel that or they're going to go somewhere else, court itself does a request.
dot cancel. So it says, oh, did somebody disconnect? Like, here's the LF.
Literally says disconnected, request body disconnect. And the last thing is request task.
cancel in the court asg.i.5 file. Well, what happens is if you're writing one event and you're
awaiting it and you're writing another event and you're awaiting it, if this first one has not
has finished, but it hasn't quite gotten done, it hasn't finished awaiting, well, this thing just
raises a task canceled exception and that one doesn't run.
Or maybe this one's starting, the second one is starting to do a database negotiation like,
hey, give me something on the connection pool and I'm going to start talking.
I'm out.
And so these don't have to happen atomically, right?
So there's different things you can do to do that.
Obviously, you could use a transaction, but then you would lose the first one, which maybe
you, like a request did come in.
Maybe you want to save them both, right?
So what are you going to do?
You can bust out the asyncio.
shield.
And this, I've done a lot of asyncio stuff.
And this is surprising to me.
So what you can actually do is with this ASync I.O. shield, it basically says this subroutine,
I do not want it, even if the outer task gets canceled, I want this to either not run or completely run.
Right.
So I can do like record Delmode.
I can say await.
Instead of wait just the task, I wait, ASync IO shielding the task.
And you get consistent.
Yeah.
Yeah.
You get more intentional control over this specific use case, because that can happen in you,
like you said, you're left scratching your head.
Why?
It doesn't make any sense.
Like, it's either running or it's not running.
Well, apparently the web framework unwinds it part way through, which is reasonable so that
it can go handle requests that are not disconnected.
I mean, it's more than reasonable.
It cleans up after itself because it allows you then to perform other cleanup operations
that may have happened along the way, too.
Yeah, exactly.
So, this is not a third party thing.
This is just built into the async Io module.
But to me, this was a mystery until I learned about it.
Yeah, I've never explored this before. This is really cool. Yeah, yeah. And the other thing that's really
noteworthy here is you need to make sure that you have something holding onto the task. Right. So here you can see the
task is created and then it adds it to the pending tasks. Because I remember where I said, where I wrote about this.
Let's see fire and forget. Not ever, never. So both I wrote about this and Will McGugan wrote about this.
But it turns out that if you start a task and you don't hold on to a reference to it,
the async IO event loop uses weak references.
So it's very likely that once you create a task and start it,
if you don't hang on to it,
there might be a garbage collection or some sort of reference kind of thing
that just drops it halfway through.
So kind of got to keep this in mind plus that.
So it's a little not super obvious.
So that's what this pending task thing is about.
Anyway, it doesn't solve all your.
problems like you've got to keep a reference to the task errors go nowhere by default because now
you've you basically said the outer thing that called it i don't want it to see that anymore don't
worry about it doesn't survive shut down if something hangs well you told it it can't cancel so
it's not going to cancel if i keep going and um it'll make them both finish but it's not necessarily
atomic right if there's an exception that's different than just avoiding cancellation so anyway
if i feel like you've solved one one one interesting edge case you've only saw one interesting age case
but have potentially introduced like six more.
Welcome to the current program.
Yeah, traps and be careful.
I'm tired of it.
I don't want to do anymore.
Let's just go play games.
Do you want to play games?
Yeah, let's play some games.
Okay, let's play some games.
So this is not a new framework necessarily, but it's been getting a lot of exposure recently on the
interwebs.
And so it's called Pixel.
It is a retro game engine for Python.
It's a free MIT licensed game engine that you use Python to build games in.
What kind of attracted to me is I am obviously a fan of the retro-looking game aesthetic.
So it's kind of like how Twitter used to deliberately limit you to 140 characters.
This deliberately limits you to 16 colors and four sound channels.
So you are basically operating in the world of classic game consoles like the NES and so on.
So it keeps the scope small.
And one of their goals was to make the games finishable as a programmer,
Not as the player, but as the person building the game.
So you don't get into me the traps of all the features and all 3D and all the other kind of things.
It's been in development since 2018.
It's got 18,000 GitHub stars on there.
It has built-in editors for the pixel art, which is also something I is near and dear to my heart,
which is like the art and the aesthetic behind the game.
So you can build art and the tile maps.
It's got editors for the sound and the music.
So you can make graphics, audio, and the game logic in one place.
So again, not to get distracted by going to five other tools to get something done.
It's a great way to do all that stuff in one tight place for that.
What's awesome is that's actually the engine behind the scenes is implemented in Rust.
And so we've been hearing a lot about Rust lately.
It gets compiled into WebAssembly, which you can launch the games locally on your computer.
It compiles down into a locally executal Rust binary.
but you can also play the games on your web browser.
So it uses WebAssembly to deploy these
or make them deployable into your web browser.
So the code maker has a browser playground
with the code editor and all the tools built into it.
You can load programs from local files,
GitHub Gist or URLs.
Actually, I'll show you a quick demo of this right here.
So in the showcase, if you actually,
you can just run UVX pixel copy examples
and they will pull these examples
to your local computer where you can run them,
or you can just go into the docs over here
and they've got the pixel showcase
where these are the exact same examples
from that copy examples I was running locally on my machine.
These will run here.
I'm going to run one.
I'll run the platformer.
It's kind of fun.
This is WebAssembly, this Python code compiled to run in my browser.
And so you can see here.
It's got sound a whole bit.
You can obviously hear the sound,
I think because I didn't share it over there.
That's so cool.
Boom, and there you die.
So a ton's fun.
You know what we got to do?
Did you ever play the game Lemmings?
Yes.
Oh my God, that's one of the best games of this genre, in my opinion.
And it has to come back.
Yeah, let's see if I can find my mouse again.
Wasn't the original Prince of Persia a little like this as well?
Very original.
Yeah.
These are good.
Yeah.
They've got some nice, interesting examples.
And then there's a whole, like, gallery of examples on the site for Pixel as well.
If you come down here and you can see these, a bunch of examples that run.
They're cross-platform, obviously.
They run Windows, Mac, Linux, Web.
They don't care.
They run everywhere.
It's great for, like, if you want to teach people how to code and program,
some of the most popular sessions we've ever done in our IndyPy user group
have always been like the arcade library or the Pi gaming libraries where people,
because people can relate to and know that if they can build games like this,
they can learn on a program and do really, really cool stuff.
So it's a fun, low barrier way into game development, good for beginners,
good for teaching kids again because it all runs in one spot.
You're not having them install a bazillion different things.
Actually, I think if we go, yeah, here we go.
I've got the examples over here.
You just run like that's the same platformer and it launched a rich looking
app right on my desktop.
Yeah, that's awesome.
Let's see if I can get right up.
Oh, there we go. I'll get a little further.
Oh.
You know what reminds me of? I was going to say Flappy Bird, but that's not what it is.
It reminds me of joust, but you can even come in here and run like the
the hello world, oops, not one.
Pi, let's say there's like the O1, obviously.
And then this one's just like the hello world of pixel,
hello pixel.
And this is a click tag.
Yeah, yeah, yeah.
And so if we just bat the O one, hello,
you can see here 20 lines of Python code
that run on the Rust engine using Pixel.
Yeah.
So super fun, very easy way to get started
and go run some cool Python code.
I love it.
Yeah, very fun.
It was very fun.
I don't know if you've got any extras, Michael, you wanted to cover real quick.
I got a couple, actually.
Let's jump in here.
So where do we want to go?
These are both pretty small.
So first of all, we're back from Stefan on Tiny Mongo.
This Mongo one's got a lot of legs.
It's got legs.
Well, because I, you know, we worked for weeks on getting this thing,
almost performance compatible and API compatible with MongoDB as just a SQLite rapper.
It was incredible.
So we talked about it on the podcast last week.
And he's like, I loved it so much.
I gave you guys a little bit of shout out.
So here, check this two things.
One, a little shout out to watch you and me debate it from or to discuss it last time.
But also, this, this, click here to like give you a stuff.
Help me use Tiny Mongo.
Here's the thing.
Da-da-da-da-da-da.
Right?
You just copy this.
Give it to your AI coding agent.
This gets started by copying a prompt.
Give it to your AI coding agent and let them get you going using Tiny Mongo.
It's pretty sweet.
I just want to give that a quick job.
I like the way to bootstrap people into success.
Like, yes, I do.
Because otherwise you're kind of stuck with a blank sheet of paper syndrome, like where you're just like, oh, it's a big blank sheet.
I don't know what to do.
Here you go.
Exactly.
You get to go.
Yeah, you get to go.
Then the other one is I'm, I've become kind of fascinated with Lightstream.
Are you familiar with Lightstream?
Lightstream.
I don't, I don't have ever used Lightstream, no.
So it's super interesting.
There's this video that I'm going to link to called Lightstream plus SQLite, scale two million users without Postgres or Cloud Builds.
And this video, this guy puts this together.
Let me see if I can get it to skip ahead.
But those really cool animated sort of architectural tech talks,
usually like 10 minutes.
This guy's called Cloud Codes.
Now, it's AI text to speech generated.
I don't know that it's AI generate,
but it is, I think a person is behind it,
but I think it's spoken by an AI.
So like, it says Littstream,
even though it's not pronounced that way.
I don't believe.
That said, I'm recommended anyway,
because it's so good.
This is such an interesting topic.
So Lightstream is a thing that you can put next to any app that runs on SQLite.
If you turn on the right-ahead log wall mode, which is the durability mode of SQLite anyway,
if you turn that on and you run Lightstream next to it, it will take the right-ahead log
and it will stream it to somewhere like S3 or anywhere else.
And the way it works is it will eventually compact those.
So instead of just having a bunch of write logs, it'll say, okay, it's been,
I don't know, an hour.
So I'm going to take all of those and like merge them into a SQLite file and then some more and some more.
So you get within a few seconds of my SQL Lite file is now backed up somewhere else.
And if whatever reason it fails, you know, I could just restore it in reverse, which is pretty interesting.
That's really cool.
Yeah.
So they talk about some other projects like Expensified.
It's something like four million rights a second on SQL Lite or something.
Like an incredible thing they set up.
So why do I bring this up?
What does this have to do with an extra?
Why is it not a topic?
I'm trying to do an episode with somebody from Lightstream.
I reached out to the creator, Ben, who has just completely goes to me.
I send like three or four different channels of messages, not interested.
This is a plea for help, Michael.
So it is a plea to like, hey, if someone out there is doing cool stuff with Lightstream and SQL
Lite and embedded data and wants to come on Talk Python and talk about it, shoot me a message,
and maybe we'll make that happen.
My traditional channels have run dry.
All right, you heard the man.
It's a plea.
If you'd like to do that, come on down.
I got a couple quick extras.
One of them I didn't make a segment as part of my Python language bits, which was there's a new namespace potentially coming to Python called SIS.
So if you have ever made a file in your directory that conflicted with the name of a standard library module, you may have experienced this bug.
So you can see here that if you cat the game.
that pi it imports random and then it uses random dot randint to pick an integer between one and ten here
and if you run the game you'll see module random has no attribute random how is that possible it's because
you've got a module in your cis path someplace that is uh shadowing it so instead so i'm correction
i wasn't talking about a cis name space this is now the standard namespace which could be
uh for example import std dot json and now you are
certainly very explicitly using the JSON library that comes with Python explicitly.
So this was discussed, seemed to be met with lots of enthusiasm and people who are very excited.
I'll go just scrolling down here to the very end, that it was many attendees loved the idea.
No one attending hated the idea.
So I'll call that a, that was a resounding success for this one.
We'll see the, there'll be a pep probably coming soon to get this included.
So I don't expect this soon, but I think this is on the horizon.
Lots of other languages have this.
I think they mentioned in here.
So we've got Rust, Java, Go, Node, all have something similar to make this explicit and safe.
So Python was the holdout on this, which is kind of funny, given our love of explicitness
that we would not have this level of care there.
There's to be one and preferably only one way to do a thing unless there's six ways to do a thing.
Correct.
The last extra, be careful out there, folks.
If you have a refrigerator that is smart and you need to upgrade it or update the firmware,
some Samsung owners have reported that the firmware update bricked not only their Samsung smart part of the fridge, but the refrigerator itself.
They had spoiled food after firmware updates bricked their Samsung smart refrigerators.
This appeared to only have happened in Korea.
So this seems to be kind of limited to an early release.
Samsung did respond to Arstechnica on this article saying that they will,
they had a response in their user complaints for them.
This is just a translation,
but they're doing their best to ensure that customers do not suffer any losses
during the specific holiday period in Korea.
So be careful out there, folks.
Your refrigerator could get bricked.
And I'm just shocked that this did not have a failsafe to go back to being just a standard
refrigerator after the smartness wore off.
It seems like a natural state to fail into.
You know, kind of like an escalator.
When an escalator is broken, it's just stairs.
You know, it still works.
Instead of being the ride where you free fall for three stories.
Right.
That's crazy.
Yeah, so be careful.
Yeah, yeah.
All right, Michael.
Do you have a joke for us this week?
I do have a joke.
I do.
All right, let's...
I'm always down for jokes.
So this one comes to us for us for.
from Will Vincent. He doesn't, he didn't send it in. I just found him saying something funny and it's
the joke now. So the title of the joke makes me think of an LCD sound system song. Okay. You should be
thinking perhaps Lord of the Rings, something like that. Okay, that's a different direction.
Okay, so well here we go. So Will Vincent says, today I was talking with a colleague about how
difficult Python installation and packaging was before UV. And there's whatever the elf from
Lord of the Rings is like, forgot the name, character name, but I was there, Gandalf.
I was there 3,000 years ago.
We didn't even have PIP.
We called it the cheese shop eventually.
It was brutal.
I was there, Gandalf.
How appropriate that they would pick 3,000 years,
given that Python always,
or Guido always referred to Python 3 as Python 3K in the early days?
A lot of intersections going on here for that joke.
Yeah, pretty funny, right?
But I was there back in the day.
It is related to the song a little bit.
Okay.
I don't know the song.
I'm going to have to be educated later.
I'll put a show note to it maybe.
Sweet.
Nice.
Well, thanks, Michael, for joining me for this week's episode.
And hopefully we'll connect again next week.
I would like to actually add something for people listening really quick.
Because next week, what episode is it?
500.
It's special.
We're going to do a little bit something special for next week.
We're going to have Brian Ockin is going to be back on the show as a guest.
First time ever, actually.
And we're going to have some other folks also join in on the show.
and kind of just do a little bit of an extended version, a little bit special with some other folks.
So try to come and be a part of it if you really care and want to.
It's not going to be at a normal time.
But if you look on YouTube or the upcoming version live stream, it is at the time.
So I believe that's noon Pacific on Tuesday the 13th.
Yeah, join live.
You won't want to miss the special guests.
Exactly.
Exactly.
All right.
Well, we will be there.
As always.
Sounds good.
See you then.
