Brought to you by Talk Python Courses and Six Feet Up consulting

#499: So many questions??

Published Tue, Oct 6, 2026, recorded Tue, Oct 6, 2026
0:00
00:32:54
Watch this episode on YouTube
Play on YouTube
Watch the live stream replay

About the show

Sponsored by us! Support our work through:

Connect with the hosts

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:

  1. 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.
  2. 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.
  3. 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.
  4. It hides hangs. A shielded write to a stuck database lives forever. Put a timeout inside the shielded task (asyncio.timeout(...)), not outside it.
  5. 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:

Joke: I was there.

Episode Transcript

Collapse transcript

00:00 Hello, and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.

00:05 This is episode 499, recorded Monday,

00:10 October 5th, 2026.

00:12 I'm Calvin Hendryx-Parker.

00:13 And I'm Michael Kennedy.

00:14 Glad to have you, Michael.

00:16 Please support this show and all the sponsors.

00:20 Make sure you support our work.

00:22 Michael and I are doing lots of interesting things out in the community.

00:25 So support the courses at talkpython.fm.

00:28 So head over there.

00:29 There's some really interesting new stuff, some Rust stuff,

00:32 some web stuff.

00:33 There's all kinds of data stuff.

00:34 So check out Michael's courses online at talkpython.fm and check out the consulting from Six Feet Up.

00:42 So I am co-founder and CTO of Six Feet Up.

00:45 We are a Python AI shop who loves solving hard problems.

00:48 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.

00:52 So let's move right along with connecting with us.

00:54 you can find Michael and myself on Mastodon, Bluesky X,

00:59 and LinkedIn.

01:00 And the show is on Mastodon, Bluesky, and X.

01:02 So check us out over there at Python Bytes.

01:05 Join us on YouTube for pythonbytes.fm slash live to be part of the audience. You can actually participate live, ask questions. We may

01:12 put them on the air and answer them in real time.

01:16 Usually it's Tuesdays at 7 a.m.

01:17 Pacific.

01:18 Older versions are available there too.

01:20 And finally, if you want an artisanal handcrafted

01:23 digest of every week's episode show notes and email form put your email in the friends of the

01:28 show and we will give you a beautiful email summary actually includes lots of little extras

01:33 I kind of like that summary very meta but I like the meta-ness of it and we'll never share your

01:37 email address so it's safe with Michael and I all right Michael uh I've got questions so many

01:43 questions question so many question marks so many so many question marks hey before we jump into

01:47 the questions I just want to say I just came from a place with large buildings outside my hotel window

01:51 and you have large buildings outside your hotel window.

01:54 I do.

01:54 I'm in New York City today.

01:56 That's awesome.

01:56 Where were you, Michael?

01:57 I was in San Francisco.

01:58 I want to give a downtown San Francisco.

02:00 I'm going to give a shout out to PiBay.

02:02 That conference just happened two days ago and was tons of fun.

02:06 And all the sessions were recorded.

02:08 So they're going to be up.

02:08 And I think it'll be really fun for everyone.

02:10 We'll give the videos a shout out when they're up.

02:13 So that was really nice.

02:14 Nice.

02:14 PiBay's on my bucket list of conferences to attend.

02:17 I've never been.

02:18 Well, it was fun, I can tell you.

02:19 Nice.

02:20 But you have questions.

02:21 you say questions there are question marks there questions there are questions now this topic is

02:26 really interesting to me so there was a PEP 505 is this yeah 505 now often you'll hear this referred

02:33 to as the idea is i'm dealing with variables that have no values and so you'll get like attribute

02:39 errors because none type doesn't support whatever you're trying to do you know what i mean and so

02:43 you got to check right is this thing not none then i can do thing with it right often these are referred

02:48 to as null coalescing operators because like most programming languages call nothing for pointers

02:55 null but by then we call it none so we have none coalescing operators so this was a proposal from

03:00 10 years ago and it's revived as an idea for 3.16 by mark muller with sponsor none other than guido

03:09 van rossom and the idea is let's go back to 505 from 10 years ago and just do like a really simple

03:15 bit.

03:15 Now I don't just have questions.

03:17 I got, I got ideas.

03:20 I have opinions.

03:21 So, but let's, let's go with what it is first before I,

03:24 I, um, there was a lot of ideas in 505, 10 years ago

03:27 for this one.

03:28 It's very short and simple.

03:30 There's two things, question mark, question mark is the

03:32 operator.

03:33 Hence the comment, the opening transition and question mark, question mark equal.

03:38 So you got to scroll, scroll, scroll, scroll, scroll.

03:40 Here it is.

03:41 It comes down to something than like this line age.

03:45 If you're going to get a user, maybe you got the user from a database.

03:48 This example is bad.

03:50 Example in the, in the thing is not good because that's what is the type safety

03:54 say about this?

03:55 Can it be none?

03:56 I have a user colon user, like lowercase user,

03:59 uppercase user.

04:00 Python's type system says if something could ever, ever possibly be none,

04:04 it must be marked as optional or, you know,

04:07 type pipe, none, if you prefer the union variant of that.

04:10 I don't like it, but you know what?

04:11 I also have opinions there.

04:12 So basically the way this thing is typed, it's literally not necessarily to check

04:16 necessarily to use a null check, because if the type system is cohesive and you're

04:21 running things like T Y or whatever, and they pass, then you would be good.

04:24 But the example is what it is.

04:26 And so, so we take a user, but the user might be null or none,

04:29 even though it says it can't be none.

04:31 it says, well, we're going to need to check.

04:34 You might need to write if I'm up here, if you know,

04:37 the user is itself not none, then,

04:41 oh, wait, sorry.

04:41 This is actually, so this is different.

04:43 So no, this is still fine.

04:44 It says if user.age, trying to get the age from the user.

04:47 So instead of saying if user is not none, if user.age is not none,

04:52 well, just user.age is not none.

04:53 Done that so many times in my life.

04:55 Other, yes, I know.

04:57 Other, otherwise, if I got a user and it has no age set,

05:01 then instead of saying I have an if statement where I set the value,

05:05 I can say question mark, question mark,

05:07 unknown age.

05:09 Okay.

05:09 I'm not, I'm not against this.

05:10 my opinions are not saying this is bad.

05:12 It doesn't seem to buy me very much, right?

05:15 I mean, you could say user.age if user.age is,

05:21 you know, else unknown or whatever.

05:23 Like it's, you can still kind of one line it

05:26 in not much more effort.

05:27 You don't, as a ternary sort of expression or something.

05:31 Yeah, I was thinking like ternary would be appropriate.

05:33 Yeah, that's how you would have done it before

05:35 if you wanted one line.

05:36 But, you know, it's fine.

05:37 I think it's, I think it's okay.

05:39 Now, if we go back to 505 from 10 years ago, there's other things as well,

05:44 like question mark dot.

05:45 And now this one I think is actually, if they're going to pick one thing in the

05:49 language and use, and like, so we're going to add a little bit of null or none

05:53 help here.

05:54 This one is the one that makes such a difference.

05:56 So in the show notes, I put a little example, um,

05:59 down here where you'd have to do it the old way or you have to do it the new way.

06:03 And this little example here lost my comments, but the comments are in the

06:07 show notes.

06:07 So I go to the database I get a user, I may or may not be logged in.

06:11 So this could be, could be a user object or it could be none right.

06:14 And I have a city, I want to set the city to a value.

06:17 But if I don't set it to a value, I want the city to be none.

06:19 So I have to say, if user is not none,

06:21 then I can run the test if user.address is not none,

06:25 then I can run the test.

06:27 If user.address.city is not none, then say it equals user.address.city and I

06:31 mean like this, this is a lot.

06:33 Yeah.

06:34 What was in the original one and what I wish was here,

06:37 if they could add one more thing, just one little bit would be this one line here.

06:42 City equals user question mark dot address question mark dot city.

06:46 I can see why this is controversial.

06:48 Is it, you have opinions now?

06:51 So the way this works, the way this works in other languages is when you,

06:55 instead of saying dot for attribute access or function calls or whatever,

06:59 you say question mark dot.

07:00 And if the thing that you're trying to do attribute access on itself is none,

07:06 so like user question mark dot.

07:08 So if user is none, then you just short circuit and return none.

07:11 If user is not none, but user address is none,

07:13 you short circuit that and you return none.

07:16 Otherwise, you just give the value of city, none or not.

07:18 A little opaque for me.

07:19 A little.

07:20 Okay.

07:21 Yeah.

07:21 I mean, I agree that the verboseness of the example given there

07:25 is a lot of what feels like boilerplate to get the same thing done.

07:29 So I can understand why they didn't go all the way for this version of this index.

07:33 Yes.

07:34 So to be...

07:35 I mean, if you thought the walrus was contentious.

07:37 I know, it's true.

07:37 The walrus has left scars.

07:40 But here's the thing.

07:41 So how much does this, I don't know, how much does this new addition here help,

07:46 right?

07:46 This user.age?

07:48 ?unknown.

07:49 You know, how do you solve problems?

07:50 It doesn't really solve problems like that one.

07:54 It just compresses ternary expressions, right?

07:57 it doesn't actually alleviate the none checking.

08:00 Like if you wanted to check is user none or age none.

08:03 Yeah, but maybe I don't I don't see.

08:05 Yeah, I don't see any way to this feels cleaner for the ternary version of that.

08:10 Yeah, yeah, let's see. We got some again, this is this is personal opinions. I think both of us are

08:15 absolutely I'm okay without it. But if you're gonna add no operator,

08:20 like no operations to the language, The biggest one is the if this is not, if this is like just the sawtooth of four things,

08:27 ifs.

08:28 Kiva out there says, when I went from C# to Python, I really,

08:31 really missed the null coalescing operators more than anything else,

08:35 even the type system.

08:36 Yeah.

08:37 Yeah, yeah, yeah.

08:38 But like you just mentioned with the sawtoothing,

08:41 the flat is better than nested Python, you

08:44 know, to tenant.

08:45 Really, I believe in that one.

08:47 And that breaks it when you go that deep like that.

08:50 Yeah.

08:50 Yeah. So you would, I mean, what would I do? All right.

08:52 We're in the danger of going too deep.

08:53 So what I would do is I would use for this, this,

08:56 like the way it has to work now, not Michael's beaver dream of null checking.

09:00 You've got to use what are called guarding clauses, right? You say,

09:02 if user is none, return, return something like none or whatever.

09:07 And then if user.address is none, return something else.

09:11 And then finally you can get the city and you know, you can flatten it with the right patterns.

09:15 That's the Vincent of Python pattern I would have used.

09:18 Yeah.

09:18 All right. That's enough for this.

09:19 People, this is a proposal, a draft for 3.6.

09:24 We have had opinions and we've shared them and now you can have yours.

09:27 Over to you, Calvin.

09:29 Yep.

09:29 Well, speaking of language features and new versions that are out.

09:33 So we've been talking about Python 3.15 for at least the last month of episodes,

09:39 hoping it would have been out October 1st, but that got moved.

09:42 So we actually have got Python 315 RC3 that came out this week. So if you are

09:48 keeping track, you should probably notice that there's not been a formal release, but it will

09:53 be coming.

09:54 I believe they're saying final is scheduled here for the ninth.

09:58 So before the next episode, we will have Python 315 that is out.

10:03 The showstopper roadblock that was going on in there

10:08 was basically some support or fix for what was lazy import release blockers.

10:14 So the kind of one of the really nice new features of Python 3.15 that you probably should check out.

10:18 And if you wanted to go use what's newt to do a dungeon crawler and explore those features.

10:23 But the lazy imports had a last minute bug.

10:28 So they want to make sure they get the fixes tested properly.

10:32 So if you aren't familiar again, lazy imports means that you can say lazy import from

10:37 blah, blah, blah, blah, blah.

10:38 And when you go to use it is actually when it'll import

10:41 at that point in time.

10:42 So you could actually have imports at the top that actually never get imported based on conditions,

10:47 which might actually be preferable given your stance

10:50 on memory usage or loading things for security reasons

10:53 or lots of other things that could be basically

10:55 be wrapped into that.

10:56 I'm very excited about the lazy imports.

10:58 Yeah, I am too.

11:00 So I think the lazy imports and then the frozendicts that we get now as well.

11:05 I think that's the other major one that was going in there.

11:07 But there's no major ABI changes for this RC.

11:11 It's just making sure dotting the I's and crossing the T's and making sure that the version 3.15 is very, very solid.

11:19 So that's part of the news I wanted to cover on this one.

11:21 The other piece that I wanted to cover was that on October 1st, they also released the last version of 3.10.

11:29 So if you see right here, Python 3.10,

11:32 .22, 11, da, da, da, da, da,

11:34 all the minor releases there for 10 through 14 are now available.

11:38 The most important piece I think of this release

11:41 that I wanted to bring it up during this segment

11:44 was there'll be no more releases of Python 3.10.

11:48 This is the EOL final end of line.

11:50 There'll be no more security releases for 3.10.

11:53 So if you've got code in production that is running 3.10,

11:56 you've been warned, you've been told probably many, many, many, many times,

11:59 along the way that this is coming, but it's become, we're here.

12:03 So for example, there was

12:06 nine common security fixes in this October 1st release.

12:08 There was things like SSL validation, that tar file and zip file handling,

12:12 URL lib credentials.

12:14 Those all sound pretty important.

12:16 And those are the kinds of things you're going to want to have fixes for inside your code,

12:20 especially given the state of credentials.

12:22 AI and all the things that are kind of coming out

12:27 after it.

12:28 So it's been five years. It's time-free to upgrade.

12:31 There's going to be no more 3.10.

12:32 That's wild because I'll tell you that 3.10 sounds pretty modern to me.

12:36 Same for me.

12:37 I mean, I think we are of an age and have been in the Python community long enough

12:41 that five years passes before your eyes, before you know it.

12:44 But 3.15 is about to become very much a reality. 3.14 is very stable.

12:48 3.11 has all the things you probably want and probably is most

12:51 likely a drop in.

12:53 These releases of Python, I don't believe there's been too many backward

12:58 compatible breaking changes in there. So there's not really much of a reason not to.

13:02 If you've got great test suites and you can go and do a Nox style test against all of them, find out which

13:08 one doesn't break for you quickly through your CI pipeline and get your code updated for the latest

13:12 versions of Python.

13:13 Now that said, Python 3.11 will get security fixes through October of 2027.

13:18 So you got another year on 11 and another year after that for 12.

13:21 But why not just go to the 315?

13:23 It'll be out later this week.

13:25 If you're already doing the work, you might as well get yourself another five

13:30 year lease on this work.

13:33 Run Knox, run all of them. Run all of them. See if they all pass or if there's

13:38 issues and either fix or just go back to the, you know,

13:41 313 or whatever that works.

13:42 Yeah.

13:42 I just, again, I hate, I put this one here because I really do not want to see anyone be a headline

13:47 on Hacker News or any other major news outlet, I've got an extra that's kind of related to this,

13:54 that you shouldn't, don't be a victim.

13:57 Keep up to date.

13:57 Python is very, the Python community is very good

14:00 about compatibility, updating,

14:02 having updating notes.

14:03 We learned a lot of lessons in the two to three history of Python.

14:08 So go out there and get yourself upgraded.

14:12 But Michael, that's what I got for.

14:13 One of those lessons was waiting for a very long time

14:16 for the world to sort itself out.

14:18 It doesn't necessarily treat you that well.

14:20 Yeah, that's true.

14:21 Maybe stay on top of things as they're changing rather than like waiting eight years to go,

14:25 oh gosh, we got to upgrade.

14:27 Like you should have a shield.

14:28 Let me just put up like a shield sort of thing.

14:30 Is there a shield people could use?

14:32 There is a shield people can use and I've got details for you.

14:36 So I've been experimenting with ideas, some crazy ideas and I'm not ready to share with you.

14:42 Well, I might share with you privately, of course, Calvin,

14:45 But I'm not ready to share with you, dear listeners as a broad world until I have more info on it.

14:49 But it's pretty wild.

14:51 So I've been doing a lot of testing on like different database type systems and so on a couple of the websites.

14:57 And I have this place where I write basically an analytics entry.

15:03 You know, someone's downloaded this or they watched a video or something like that.

15:07 And then I increment it somewhere else because, you know, 50 million records,

15:11 you don't want that to be operational.

15:12 Like who has done this thing?

15:14 You might want it like a little more concise or how many people downloaded

15:17 that thing or whatever.

15:18 So it writes it once to this kind of summary table that the websites use.

15:22 And then it writes this, this analytics one.

15:24 Well, it turned out that out of many,

15:27 many millions, there was 1,200 missing

15:31 entries, where, where did they go?

15:32 It says right here.

15:33 And then it says right there.

15:35 Well, these came into existence once I switched to an async web framework

15:40 court, but it could be FastAPI.

15:41 It could be Litestar.

15:42 It's not anything necessarily specific with court, not necessarily.

15:46 So what happens is with court, if somebody makes a request and the request is in flight

15:52 and they decide they're not doing that anymore, or they're going to cancel that, or they're

15:56 going to go somewhere else, court itself does a request.cancel.

15:59 So it says, oh, did somebody disconnect?

16:02 Like here's the LF literally says disconnected, request body disconnect.

16:06 And the last thing is request task.cancel in the court ASCII.py file.

16:12 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,

16:20 has finished, but it hasn't quite gotten done, it hasn't finished awaiting.

16:24 Well, this thing just raises a task canceled exception and that one doesn't run.

16:30 Or maybe this one's starting, the second one is starting to do a database negotiation.

16:34 Like, hey, give me something on the connection pool and I'm going to start talking.

16:36 I'm out.

16:37 And so these don't have to happen atomically.

16:41 Right.

16:41 So there's different things you can do to do that.

16:43 Obviously you could use a transaction, but then you would lose the first one,

16:47 which maybe like a request did come in.

16:49 Maybe you want to save them both, right?

16:50 So what are you going to do?

16:51 You can bust out the asyncio dot shield and this, I've done a lot of asyncio stuff.

16:55 And this is surprising to me.

16:57 So what you can actually do is with this asyncio shield,

17:02 it basically says this sub, this async subroutine.

17:06 I do not want it.

17:08 Even if the outer task gets canceled, I want this to either not run or completely run,

17:13 right?

17:13 So I can do like record download.

17:15 I can say await.

17:16 Instead of wait, just the task, I await asyncio shielding the task and you get consistent.

17:22 Yeah, you get more intentional control over the specific use case because that can happen

17:26 in your, like you said, your left scratch in your head.

17:29 Why?

17:29 It doesn't make any sense.

17:30 Like it's either running or it's not running.

17:32 Well, apparently the web framework unwinds it partway through,

17:35 which is reasonable so that they can go handle requests that are not disconnected.

17:38 I mean, it's more than reasonable.

17:39 It cleans up after itself 'cause it allows you then to perform

17:42 other cleanup operations that may have happened

17:43 along the way too.

17:44 Yeah, exactly.

17:45 So this is not a third party thing.

17:48 This is just built into the asyncio module.

17:50 But to me, this was a mystery until I learned about it.

17:53 Yeah, I've never explored this before.

17:55 This is really cool.

17:55 Yeah, yeah.

17:56 And the other thing that's really noteworthy here is you need to make sure that you have something

18:01 holding onto the task, right?

18:04 So here you can see the task is created And then it adds it to the pending tasks.

18:09 Because I remember where I wrote about this.

18:13 Let's see.

18:15 Fire and forget.

18:16 Not ever, never.

18:16 So both I wrote about this and Will McGugan wrote about this.

18:20 But it turns out that if you start a task and you don't hold on to a reference to it,

18:27 the asyncio event loop uses weak references.

18:30 So it's very likely that once you create a task and start it,

18:34 If you don't hang on to it, there might be a garbage collection or some sort of

18:37 reference kind of thing that just drops it halfway through.

18:40 So kind of got to keep this in mind plus that.

18:44 So it's a little, not super obvious.

18:46 Like, so that's what this pending task thing is about.

18:48 Anyway, it doesn't solve all your problems.

18:50 Like you've got to keep a reference to the task.

18:52 Errors go nowhere by default, because now you've, you basically said the

18:56 outer thing that called it, I don't want it to see that anymore.

18:58 Don't worry about it.

18:58 Doesn't survive shut down.

19:00 If something hangs while you told it, it can't cancel.

19:02 so it's not going to cancel if you keep going and um it'll make him both finish but it's not

19:07 necessarily atomic right if there's an exception that's different than just avoiding cancellation

19:12 so anyway i feel like you solved one one interesting edge case you've only solved one

19:17 interesting edge case but potentially introduced like six more in the traps and current traps and

19:23 be careful i'm tired of it i don't want to do any more let's just go play games you want to play

19:27 games yeah okay let's play some games this is a so this is not a new framework necessarily but

19:33 it's been getting a lot of uh exposure recently on the interwebs and so it's called pixel it is a

19:39 retro game engine for python it's a free mit licensed game engine that you use python to build

19:46 games in uh what kind of attracted to me is i am obviously a fan of the retro looking game aesthetic

19:54 So it's kind of like how Twitter used to deliberately limit you to 140 characters.

20:00 This deliberately limits you to 16 colors and four sound channels.

20:03 So you are basically operating in the world of classic game consoles like the NES and so on.

20:10 So it keeps the scope small.

20:12 And one of their goals was to make the games finishable as a programmer,

20:17 not as the player, but as the person building the game.

20:20 So you're not getting, you don't get into me the traps of all the features and all the 3D and all the other kind of things.

20:26 It's been in development since 2018.

20:28 It's got 18,000 GitHub stars on there.

20:31 It has built-in editors for the pixel art, which is also something I,

20:36 is near and dear to my heart, which is like the art and the aesthetic behind the game.

20:40 So you can build art and the tile maps.

20:42 It's got editors for the sound and the music.

20:46 So you can make graphics, audio,

20:47 and the game logic in one place.

20:50 So again, not to get distracted by going to five other tools to get something done.

20:54 That's a great way to do all that stuff in one tight place for that.

20:59 What's awesome is that actually the engine behind the scenes is implemented in Rust.

21:03 And so we've been hearing a lot about Rust lately.

21:05 It gets compiled into WebAssembly, which you can launch the games locally on your computer,

21:10 compiles down into a locally executable Rust binary.

21:15 But you can also play the games on your web browser.

21:17 So it uses WebAssembly to deploy these or make them deployable into your web browser.

21:23 So the CodeMaker has a browser playground with the code editor and all the tools built into it.

21:29 You can load programs from local files, GitHub Gists or URLs.

21:34 Actually, I'll show you a quick demo of this right here.

21:36 So in the showcase, you can just run uvx pixel copy examples,

21:42 and it will pull these examples to your local computer where you can run them.

21:45 or you can just go into the docs over here and they've got the pixel showcase

21:49 where these are the exact same examples from that copy examples I was running locally on my machine.

21:54 These will run here.

21:55 I'm going to run one.

21:56 I'll run the platformer.

21:57 It's kind of fun.

21:58 This is WebAssembly.

22:00 This Python code compiled to run in my browser.

22:03 And so you can see here, it's got sound a whole bit.

22:05 You can't obviously hear the sound, I think because I didn't share it over there.

22:09 That's so cool.

22:10 Boom, there you die.

22:12 So it's fun.

22:13 You know what we got to do?

22:14 Did you ever play the game Lemming?

22:15 Yes.

22:16 Oh my God.

22:17 That's one of the best games of the genre in my opinion.

22:20 And it has to come back.

22:21 Yeah.

22:22 Let's see if I can find my mouse again.

22:24 Wasn't the original Prince of Persia a little like this as well?

22:27 Very original.

22:28 Yeah.

22:28 These are good.

22:29 Yeah.

22:30 They got some nice, interesting examples.

22:33 And then there's a whole like gallery of examples on the site for pixel as well.

22:40 If you come down here and you can see these a bunch of examples that run.

22:44 They're cross-platform, obviously.

22:45 They run Windows, Mac, Linux,

22:47 Web.

22:47 They don't care.

22:48 They run everywhere.

22:49 It's great for, like, if you want to teach people how to code and program,

22:52 some of the most popular sessions we've ever done in our IndyPy user group have always been like the

22:58 arcade library or the PyGaming libraries, because people can relate to and know that

23:05 if they can build games like this, they can learn how to program and do really, really

23:09 cool stuff.

23:10 It's a fun low barrier way into game development.

23:13 Good for beginners, good for teaching kids again, because it all runs in one spot.

23:17 You're not having them install a bazillion different things.

23:20 Actually, I think if we go.

23:21 Yeah, here we go.

23:22 I've got the examples over here.

23:23 You just run like that.

23:25 That's the same platformer.

23:27 And it launched a rich looking app right on my desktop.

23:32 Yeah, that's awesome.

23:33 Let's see if I can get right.

23:33 I can't.

23:34 Oh, there we go.

23:35 I'll get a little further.

23:36 Oh, you know what reminds me of?

23:37 I was going to say Flappy Bird, but that's not what it is.

23:39 It reminds me of Joust, but bird form.

23:42 But you can even come in here and run like the hello world.

23:45 Oops, not 1.py.

23:46 Let's say there's like the 01, obviously.

23:49 And then this one's just like the hello world of pixel.

23:52 Hello, pixel.

23:53 And there's a link tag.

23:55 Yeah, yeah, yeah.

23:56 And so if we just bat the 01 hello, you can see here 20 lines of Python code

24:02 that run on the Rust engine using pixel.

24:04 Yeah.

24:04 So super fun, very easy way to get started

24:07 and go run some cool Python code.

24:10 I love it.

24:10 Yeah.

24:11 Very fun.

24:12 It was very fun.

24:13 I don't know if you've got any extras, Michael,

24:15 you wanted to cover real quick?

24:16 I got a couple, actually.

24:18 Let's jump in here.

24:19 So where do we want to go?

24:20 These are both pretty small.

24:22 So first of all, we're back from Stefan on Tiny Mongo.

24:25 This Mongo one's got a lot of legs.

24:27 It's got legs.

24:28 Well, because we worked for weeks on getting this thing almost performance compatible

24:35 and API compatible with MongoDB a sequel light rapper it was incredible so we talked about it on the podcast last week and he's

24:43 like i loved it so much i gave you guys a little bit of shout out so here check this two things one

24:48 nice little shout out to watch you and me debate it from or to discuss it last time but also this

24:53 this click here to like give you something help me use tiny mongo here's the thing that it had it on

24:58 right you just copy this give it to your ai coding agent this gets started by copying a prompt

25:04 give it to your AI coding agent and let them get you going using tiny mongos.

25:09 Pretty sweet.

25:09 I like the way to bootstrap people into success.

25:13 Yes, I do too.

25:14 Because otherwise you're kind of stuck with the blank sheet of paper syndrome,

25:17 like where you're just like, oh, it's a big blank sheet.

25:19 I don't know what to do.

25:20 Here you go.

25:20 Get started.

25:21 Exactly.

25:21 You get to go.

25:22 Yeah, you get to go.

25:24 Then the other one is I've become kind of fascinated with Lightstream.

25:27 Are you familiar with Lightstream?

25:29 Lightstream.

25:30 I don't know if I've ever used Lightstream.

25:31 No.

25:32 So it's super interesting.

25:33 There's this video that I'm going to link to called Lightstream plus SQLite.

25:37 Scale to a million users without Postgres or CloudBills.

25:40 And this video, this guy puts this together.

25:43 Let me see if I can get it to skip ahead.

25:46 But there's really cool animated sort of architectural tech talks,

25:51 usually like 10 minutes.

25:52 This guy's called Claude Codes.

25:55 Now, it's AI text-to-speech generated.

25:58 I don't know that it's AI generated, but it is.

26:00 I think a person's behind it, but I think it's spoken by an AI.

26:04 So it says Litstream, even though it's not pronounced that way,

26:08 I don't believe.

26:09 That said, I'm recommending it anyway because it's so good.

26:12 This is such an interesting topic.

26:14 So Lightstream is a thing that you can put next to any app

26:18 that runs on SQLite.

26:19 If you turn on the write-ahead log wall mode, which is the durability mode of SQLite anyway,

26:25 if you turn that on and you run Lightstream next to it,

26:28 it will take the write-ahead log and it will stream it to somewhere

26:31 like S3 or anywhere else.

26:35 And the way it works is it will eventually compact those.

26:39 So instead of just having a bunch of write logs, it'll say, okay,

26:41 it's been, I don't know, an hour.

26:43 So I'm going to take all of those and like merge them into a SQLite file

26:47 and then some more and some more.

26:48 So you get within a few seconds of my SQLite file is now backed up somewhere else.

26:53 And if for whatever reason it fails, you know, I could just restore it in reverse,

26:58 which is pretty interesting.

26:59 That's really cool.

27:00 Yeah.

27:00 So they talk about some other projects like, Expensify does something like 4 million rights a second on SQL light or

27:07 something like an incredible thing they set up.

27:09 So why do I bring this up?

27:10 What does this have to do with an extra?

27:11 Why is it not a topic?

27:12 I'm trying to do an episode with somebody from light stream.

27:16 I reached out to the creator, Ben,

27:17 who has, um, just completely ghosted me.

27:21 I sent him like three or four different channels of messages,

27:23 not interested.

27:24 This is a plea for help.

27:25 So my, it is a plea to like, Hey, If someone out there is doing cool stuff with Lightstream and SQLite embedded data and wants

27:33 to come on Talk Python and talk about it, shoot me a message and maybe we'll make that happen.

27:38 My traditional channels have run dry.

27:41 All right.

27:41 You heard the man.

27:43 It's a plea.

27:44 If you'd like to do that, come on down.

27:46 I got a couple quick extras.

27:48 One of them I didn't make a segment as part of my Python language bits,

27:51 which was there's a new namespace potentially coming to Python called Sys.

27:56 So if you have ever made a file in your directory that conflicted with the name of a standard library module,

28:04 you may have experienced this bug.

28:05 So you can see here that if you cat the game.py,

28:08 it imports random.

28:10 And then it uses random.randint to pick an integer between 1 and 10 here.

28:15 And if you run the game, you'll see module random has no attribute randint.

28:18 How is that possible?

28:20 It's because you've got a module in your syspath someplace that is shadowing it.

28:26 So instead, correction,

28:28 I wasn't talking about a sys namespace.

28:30 This is now the standard namespace, which could be,

28:34 for example, import std.json.

28:37 And now you are certainly very explicitly using the JSON library that comes with Python explicitly.

28:44 So this was discussed, seemed to be met with lots of enthusiasm and people who are very excited.

28:49 I'll go just scrolling down here to the very end,

28:52 that it was many attendees loved the idea.

28:56 No one attending hated the idea.

28:58 So I'll call that a, that was a resounding success for this one.

29:02 We'll see the, there'll be a PEP probably coming soon to get this included.

29:06 So I don't expect this soon, but I think this is on the horizon.

29:09 Lots of other languages have this.

29:11 I think they mentioned in here.

29:12 So we've got Rust, Java,

29:13 Go, Node, all have something similar to make this explicit and safe.

29:19 So Python was the holdout on this, which is kind of funny given our love of explicitness

29:25 that we would not have this level of care there.

29:28 There should be one and preferably only one way to do a thing unless there's six ways to

29:32 do a thing.

29:32 Correct.

29:33 The last extra, be careful out there,

29:37 folks.

29:38 If you have a refrigerator that is smart and you need to upgrade it or update the firmware,

29:42 some Samsung owners have reported that the firmware update bricked not only their Samsung

29:48 smart part of the fridge, but the refrigerator itself.

29:52 They had spoiled food after firmware updates bricked their Samsung smart refrigerators. This appeared to only have happened in Korea.

30:00 So this seems to be kind of limited to an early release.

30:04 Samsung did respond to Ars Technica on this article saying that they had a response in their user complaints forum.

30:12 This is just a translation,

30:13 but they're doing their best to ensure that customers do not suffer any losses

30:17 during this specific holiday period in Korea.

30:19 So be careful out there, folks.

30:21 Your refrigerator could get bricked.

30:23 And I'm just shocked that this did not have a fail safe

30:26 to go back to being just a standard refrigerator

30:29 after the smartness wore off.

30:30 It seems like a natural state to fail into.

30:34 You know, kind of like an escalator.

30:35 When an escalator is broken, it's just stairs.

30:38 You know, it still works.

30:39 Instead of being the ride where you free fall for three stories.

30:43 Right.

30:44 That's crazy.

30:45 Yeah, so be careful.

30:47 yeah yeah all right michael if you have do you have a joke for us this week i do have a joke

30:52 all right let's i'm always down for jokes so this one comes to us from uh will vincent he doesn't

31:00 he didn't send it in i just found him saying something funny and it's the joke so the title

31:04 of the joke makes me think of an lcd sound system song okay you should be thinking perhaps lord of

31:10 the rings lord of the rings something like that okay that's a different direction okay so well

31:15 here we go so will vincent says today i was talking with a colleague about how difficult

31:19 python installation and packaging was before uv and there's whatever the elf from lord of the

31:24 rings like forgot the name character name but i was there gandalf i was there 3 000 years ago

31:30 we didn't even have pip we called it the cheese shop eventually it was brutal i was there gandalf

31:37 how appropriate that they would pick 3 000 years given that python always guido always referred to

31:42 Python 3 as Python 3K in the early days.

31:46 A lot of intersections going on here for that joke.

31:50 Yeah, pretty funny, right?

31:52 But I was there back in the day.

31:53 It is related to the song a little bit.

31:55 Okay.

31:55 I don't know the song.

31:56 I'm going to have to be educated later.

31:59 I'll put a show note to it, maybe.

32:00 Sweet.

32:01 Nice.

32:02 Well, thanks, Michael, for joining me for this week's episode.

32:05 And hopefully we'll connect again next week.

32:08 I would like to actually add something for people listening really quick.

32:10 Because next week, what episode is it?

32:13 500 it's special we're going to do a little bit something special for next week we're going to have

32:18 brian auken is going to be back on the show as a guest first time ever actually and we're going to

32:25 have some other folks also join in on the show and kind of just do a little bit of an extended

32:30 version a little bit special with some other folks so try to come and be a part of it if you

32:34 really care and want to yeah it's not going to be at a normal time but if you look on youtube for

32:39 the upcoming version live stream.

32:41 It is at the time.

32:42 So I believe that's noon Pacific on Tuesday, the 13th.

32:46 Yeah.

32:46 Join live. You won't miss the special guests.

32:48 Exactly.

32:49 Exactly.

32:50 All right. Well, we will be there as always.

32:52 Sounds good.

32:53 See you then.


Want to go deeper? Check our courses




Subscribe to Python Bytes