इस एपिसोड के बारे में
- 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 engine for Python
- Extras
- Joke
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 cancelledIn 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 demoI 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 trapsshield(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
sysnamespace - 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.
नोद्स दिखाएं 🔗
अनुलिपि 🔗
00:00:00.100 --> 00:00:00.400
Hello,
00:00:00.690 --> 00:00:05.380
and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
00:00:05.820 --> 00:00:08.580
This is episode 499,
00:00:08.940 --> 00:00:10.220
recorded Monday,
00:00:10.540 --> 00:00:11.160
October 5th,
00:00:11.440 --> 00:00:11.780
2026.
00:00:12.280 --> 00:00:13.240
I'm Calvin Hendryx-Parker.
00:00:13.490 --> 00:00:14.420
And I'm Michael Kennedy.
00:00:14.860 --> 00:00:15.660
Glad to have you, Michael.
00:00:16.740 --> 00:00:19.640
Please support this show and all the sponsors.
00:00:20.140 --> 00:00:21.760
Make sure you support our work.
00:00:22.080 --> 00:00:24.580
Michael and I are doing lots of interesting things out in the community.
00:00:25.140 --> 00:00:28.220
So support the courses at talkpython.fm.
00:00:28.350 --> 00:00:29.220
So head over there.
00:00:29.520 --> 00:00:30.880
There's some really interesting new stuff,
00:00:31.140 --> 00:00:31.880
some Rust stuff,
00:00:32.099 --> 00:00:33.240
some web stuff.
00:00:33.660 --> 00:00:34.780
There's all kinds of data stuff.
00:00:34.980 --> 00:00:42.220
So check out Michael's courses online at talkpython.fm and check out the consulting from Six Feet Up.
00:00:42.360 --> 00:00:45.860
So I am co-founder and CTO of Six Feet Up.
00:00:45.920 --> 00:00:48.560
We are a Python AI shop who loves solving hard problems.
00:00:48.980 --> 00:00:52.480
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:00:52.720 --> 00:00:54.760
So let's move right along with connecting with us.
00:00:54.900 --> 00:00:57.560
you can find Michael and myself on Mastodon,
00:00:58.020 --> 00:00:58.900
Bluesky X,
00:00:59.200 --> 00:00:59.740
and LinkedIn.
00:01:00.400 --> 00:01:01.840
And the show is on Mastodon,
00:01:01.840 --> 00:01:02.500
Bluesky, and X.
00:01:02.740 --> 00:01:05.420
So check us out over there at Python Bytes.
00:01:05.740 --> 00:01:08.580
Join us on YouTube for pythonbytes.fm
00:01:08.770 --> 00:01:12.600
slash live to be part of the audience. You can actually participate live, ask questions. We may
00:01:12.780 --> 00:01:15.520
put them on the air and answer them in real time.
00:01:16.040 --> 00:01:17.340
Usually it's Tuesdays at 7 a.m.
00:01:17.540 --> 00:01:17.660
Pacific.
00:01:18.520 --> 00:01:19.840
Older versions are available there too.
00:01:20.150 --> 00:01:20.500
And finally,
00:01:20.700 --> 00:01:23.080
if you want an artisanal handcrafted
00:01:23.220 --> 00:01:28.400
digest of every week's episode show notes and email form put your email in the friends of the
00:01:28.520 --> 00:01:33.160
show and we will give you a beautiful email summary actually includes lots of little extras
00:01:33.190 --> 00:01:37.300
I kind of like that summary very meta but I like the meta-ness of it and we'll never share your
00:01:37.370 --> 00:01:42.980
email address so it's safe with Michael and I all right Michael uh I've got questions so many
00:01:43.280 --> 00:01:47.280
questions question so many question marks so many so many question marks hey before we jump into
00:01:47.280 --> 00:01:51.480
the questions I just want to say I just came from a place with large buildings outside my hotel window
00:01:51.500 --> 00:01:54.040
and you have large buildings outside your hotel window.
00:01:54.280 --> 00:01:54.540
I do.
00:01:54.720 --> 00:01:55.540
I'm in New York City today.
00:01:56.040 --> 00:01:56.260
That's awesome.
00:01:56.260 --> 00:01:56.520
Where were you,
00:01:56.740 --> 00:01:56.820
Michael?
00:01:57.300 --> 00:01:58.460
I was in San Francisco.
00:01:58.600 --> 00:02:00.700
I want to give a downtown San Francisco.
00:02:00.840 --> 00:02:02.240
I'm going to give a shout out to PiBay.
00:02:02.560 --> 00:02:04.580
That conference just happened two days ago
00:02:04.940 --> 00:02:05.960
and was tons of fun.
00:02:06.180 --> 00:02:07.900
And all the sessions were recorded.
00:02:08.020 --> 00:02:08.759
So they're going to be up.
00:02:08.840 --> 00:02:10.179
And I think it'll be really fun for everyone.
00:02:10.500 --> 00:02:12.840
We'll give the videos a shout out when they're up.
00:02:13.020 --> 00:02:13.860
So that was really nice.
00:02:14.180 --> 00:02:14.460
Nice.
00:02:14.940 --> 00:02:17.340
PiBay's on my bucket list of conferences to attend.
00:02:17.480 --> 00:02:17.940
I've never been.
00:02:18.180 --> 00:02:18.360
Well,
00:02:18.580 --> 00:02:19.560
it was fun, I can tell you.
00:02:19.720 --> 00:02:19.900
Nice.
00:02:20.100 --> 00:02:20.780
But you have questions.
00:02:21.100 --> 00:02:26.620
you say questions there are question marks there questions there are questions now this topic is
00:02:26.740 --> 00:02:33.820
really interesting to me so there was a PEP 505 is this yeah 505 now often you'll hear this referred
00:02:33.820 --> 00:02:38.940
to as the idea is i'm dealing with variables that have no values and so you'll get like attribute
00:02:39.320 --> 00:02:43.840
errors because none type doesn't support whatever you're trying to do you know what i mean and so
00:02:43.840 --> 00:02:48.239
you got to check right is this thing not none then i can do thing with it right often these are referred
00:02:48.260 --> 00:02:55.040
to as null coalescing operators because like most programming languages call nothing for pointers
00:02:55.320 --> 00:03:00.760
null but by then we call it none so we have none coalescing operators so this was a proposal from
00:03:00.790 --> 00:03:08.940
10 years ago and it's revived as an idea for 3.16 by mark muller with sponsor none other than guido
00:03:09.060 --> 00:03:15.119
van rossom and the idea is let's go back to 505 from 10 years ago and just do like a really simple
00:03:15.140 --> 00:03:15.320
bit.
00:03:15.760 --> 00:03:17.160
Now I don't just have questions.
00:03:17.920 --> 00:03:18.640
I got,
00:03:18.960 --> 00:03:19.960
I got ideas.
00:03:20.160 --> 00:03:20.700
I have opinions.
00:03:21.400 --> 00:03:21.560
So,
00:03:22.180 --> 00:03:22.560
but let's,
00:03:22.920 --> 00:03:24.460
let's go with what it is first before I,
00:03:24.780 --> 00:03:24.940
I,
00:03:25.180 --> 00:03:25.280
um,
00:03:25.580 --> 00:03:27.580
there was a lot of ideas in 505, 10 years ago
00:03:27.920 --> 00:03:28.360
for this one.
00:03:28.620 --> 00:03:29.980
It's very short and simple.
00:03:30.180 --> 00:03:30.800
There's two things,
00:03:31.060 --> 00:03:32.540
question mark, question mark is the
00:03:32.640 --> 00:03:32.960
operator.
00:03:33.400 --> 00:03:34.460
Hence the comment,
00:03:35.200 --> 00:03:38.220
the opening transition and question mark, question mark equal.
00:03:38.720 --> 00:03:40.120
So you got to scroll, scroll, scroll, scroll, scroll.
00:03:40.960 --> 00:03:41.360
Here it is.
00:03:41.590 --> 00:03:42.839
It comes down to something
00:03:42.860 --> 00:03:44.680
than like this line age.
00:03:45.040 --> 00:03:46.140
If you're going to get a user,
00:03:46.680 --> 00:03:48.000
maybe you got the user from a database.
00:03:48.740 --> 00:03:49.980
This example is bad.
00:03:50.280 --> 00:03:51.040
Example in the,
00:03:51.340 --> 00:03:54.340
in the thing is not good because that's what is the type safety
00:03:54.480 --> 00:03:55.020
say about this?
00:03:55.960 --> 00:03:56.580
Can it be none?
00:03:56.900 --> 00:03:58.100
I have a user colon user,
00:03:58.460 --> 00:03:59.240
like lowercase user,
00:03:59.500 --> 00:03:59.980
uppercase user.
00:04:00.400 --> 00:04:02.580
Python's type system says if something could ever,
00:04:03.000 --> 00:04:04.140
ever possibly be none,
00:04:04.280 --> 00:04:06.280
it must be marked as optional or,
00:04:06.580 --> 00:04:06.800
you know,
00:04:07.060 --> 00:04:07.660
type pipe,
00:04:07.880 --> 00:04:08.500
none, if you prefer
00:04:08.800 --> 00:04:10.200
the union variant of that.
00:04:10.280 --> 00:04:11.400
I don't like it, but you know what?
00:04:11.500 --> 00:04:12.380
I also have opinions there.
00:04:12.620 --> 00:04:16.340
So basically the way this thing is typed, it's literally not necessarily to check
00:04:16.660 --> 00:04:17.940
necessarily to use a null check,
00:04:18.220 --> 00:04:21.380
because if the type system is cohesive and you're
00:04:21.380 --> 00:04:22.780
running things like T Y or whatever,
00:04:23.240 --> 00:04:24.500
and they pass, then you would be good.
00:04:24.660 --> 00:04:26.180
But the example is what it is.
00:04:26.540 --> 00:04:27.420
And so, so we take a user,
00:04:27.600 --> 00:04:29.100
but the user might be null or none,
00:04:29.390 --> 00:04:29.780
even though it
00:04:30.100 --> 00:04:30.800
says it can't be none.
00:04:31.090 --> 00:04:31.180
Um,
00:04:31.960 --> 00:04:32.460
it says,
00:04:32.720 --> 00:04:33.760
well, we're going to need to check.
00:04:34.090 --> 00:04:36.440
You might need to write if I'm up here,
00:04:36.640 --> 00:04:37.300
if you know,
00:04:37.660 --> 00:04:39.920
the user is itself not none,
00:04:40.340 --> 00:04:40.700
then,
00:04:41.150 --> 00:04:41.620
oh, wait, sorry.
00:04:41.780 --> 00:04:42.340
This is actually,
00:04:42.500 --> 00:04:43.180
so this is different.
00:04:43.340 --> 00:04:44.180
So no, this is still fine.
00:04:44.240 --> 00:04:45.640
It says if user.age,
00:04:45.800 --> 00:04:47.360
trying to get the age from the user.
00:04:47.610 --> 00:04:51.920
So instead of saying if user is not none, if user.age is not none,
00:04:52.220 --> 00:04:53.500
well, just user.age is not none.
00:04:53.740 --> 00:04:55.220
Done that so many times in my life.
00:04:55.270 --> 00:04:55.380
Other,
00:04:55.600 --> 00:04:56.180
yes, I know.
00:04:57.050 --> 00:04:57.140
Other,
00:04:57.320 --> 00:04:57.760
otherwise,
00:04:58.320 --> 00:05:01.020
if I got a user and it has no age set,
00:05:01.580 --> 00:05:04.720
then instead of saying I have an if statement where I set the value,
00:05:05.070 --> 00:05:06.580
I can say question mark,
00:05:07.010 --> 00:05:07.380
question mark,
00:05:07.940 --> 00:05:08.720
unknown age.
00:05:09.100 --> 00:05:09.200
Okay.
00:05:09.480 --> 00:05:10.780
I'm not, I'm not against this.
00:05:10.900 --> 00:05:12.600
my opinions are not saying this is bad.
00:05:12.900 --> 00:05:14.920
It doesn't seem to buy me very much,
00:05:15.320 --> 00:05:15.440
right?
00:05:15.840 --> 00:05:18.640
I mean, you could say user.age
00:05:19.040 --> 00:05:20.960
if user.age is,
00:05:21.200 --> 00:05:21.680
you know,
00:05:22.120 --> 00:05:23.680
else unknown or whatever.
00:05:23.940 --> 00:05:24.320
Like it's,
00:05:24.600 --> 00:05:25.940
you can still kind of one line it
00:05:26.140 --> 00:05:27.400
in not much more effort.
00:05:27.900 --> 00:05:30.980
You don't, as a ternary sort of expression or something.
00:05:31.120 --> 00:05:32.660
Yeah, I was thinking like ternary
00:05:32.760 --> 00:05:33.400
would be appropriate.
00:05:33.880 --> 00:05:34.040
Yeah,
00:05:34.260 --> 00:05:35.280
that's how you would have done it before
00:05:35.460 --> 00:05:36.260
if you wanted one line.
00:05:36.700 --> 00:05:36.780
But,
00:05:36.960 --> 00:05:37.440
you know, it's fine.
00:05:37.480 --> 00:05:38.760
I think it's, I think it's okay.
00:05:39.320 --> 00:05:41.720
Now, if we go back to 505 from 10 years ago,
00:05:41.920 --> 00:05:43.680
there's other things as well,
00:05:44.240 --> 00:05:45.480
like question mark dot.
00:05:45.670 --> 00:05:49.260
And now this one I think is actually, if they're going to pick one thing in the
00:05:49.460 --> 00:05:50.500
language and use, and like,
00:05:50.780 --> 00:05:53.000
so we're going to add a little bit of null or none
00:05:53.190 --> 00:05:53.600
help here.
00:05:54.020 --> 00:05:56.140
This one is the one that makes such a difference.
00:05:56.630 --> 00:05:58.400
So in the show notes, I put a little example,
00:05:58.890 --> 00:05:58.980
um,
00:05:59.500 --> 00:06:01.340
down here where you'd have
00:06:01.350 --> 00:06:03.520
to do it the old way or you have to do it the new way.
00:06:03.980 --> 00:06:07.140
And this little example here lost my comments, but the comments are in the
00:06:07.260 --> 00:06:07.440
show notes.
00:06:07.740 --> 00:06:09.380
So I go to the database I get a user,
00:06:09.760 --> 00:06:11.320
I may or may not be logged in.
00:06:11.440 --> 00:06:11.940
So this could be,
00:06:12.340 --> 00:06:14.400
could be a user object or it could be none right.
00:06:14.780 --> 00:06:15.480
And I have a city,
00:06:15.900 --> 00:06:17.260
I want to set the city to a value.
00:06:17.380 --> 00:06:19.340
But if I don't set it to a value, I want the city to be none.
00:06:19.460 --> 00:06:19.920
So I have to say,
00:06:20.080 --> 00:06:21.120
if user is not none,
00:06:21.580 --> 00:06:23.920
then I can run the test if user.address
00:06:24.260 --> 00:06:24.940
is not none,
00:06:25.400 --> 00:06:26.580
then I can run the test.
00:06:27.060 --> 00:06:31.500
If user.address.city is not none, then say it equals user.address.city and I
00:06:31.580 --> 00:06:32.580
mean like this,
00:06:33.020 --> 00:06:33.680
this is a lot.
00:06:33.940 --> 00:06:34.100
Yeah.
00:06:34.540 --> 00:06:37.320
What was in the original one and what I wish was here,
00:06:37.720 --> 00:06:39.160
if they could add one more thing,
00:06:39.270 --> 00:06:42.260
just one little bit would be this one line here.
00:06:42.730 --> 00:06:46.660
City equals user question mark dot address question mark dot city.
00:06:46.870 --> 00:06:48.180
I can see why this is controversial.
00:06:48.700 --> 00:06:51.060
Is it, you have opinions now?
00:06:51.420 --> 00:06:55.440
So the way this works, the way this works in other languages is when you,
00:06:55.660 --> 00:06:56.000
instead of saying
00:06:56.340 --> 00:06:58.820
dot for attribute access or function calls or whatever,
00:06:59.230 --> 00:07:00.440
you say question mark dot.
00:07:00.660 --> 00:07:06.260
And if the thing that you're trying to do attribute access on itself is none,
00:07:06.440 --> 00:07:07.920
so like user question mark dot.
00:07:08.030 --> 00:07:09.040
So if user is none,
00:07:09.250 --> 00:07:11.060
then you just short circuit and return none.
00:07:11.340 --> 00:07:12.400
If user is not none,
00:07:12.560 --> 00:07:13.680
but user address is none,
00:07:13.890 --> 00:07:15.820
you short circuit that and you return none.
00:07:16.080 --> 00:07:17.420
Otherwise, you just give the value of city,
00:07:17.710 --> 00:07:18.120
none or not.
00:07:18.340 --> 00:07:19.380
A little opaque for me.
00:07:19.680 --> 00:07:20.400
A little.
00:07:20.660 --> 00:07:20.820
Okay.
00:07:21.240 --> 00:07:21.320
Yeah.
00:07:21.580 --> 00:07:25.560
I mean, I agree that the verboseness of the example given there
00:07:25.960 --> 00:07:28.880
is a lot of what feels like boilerplate to get the same thing done.
00:07:29.900 --> 00:07:33.100
So I can understand why they didn't go all the way for this version of this index.
00:07:33.740 --> 00:07:34.100
Yes.
00:07:34.310 --> 00:07:35.200
So to be...
00:07:35.200 --> 00:07:37.120
I mean, if you thought the walrus was contentious.
00:07:37.210 --> 00:07:37.760
I know, it's true.
00:07:37.850 --> 00:07:39.760
The walrus has left scars.
00:07:40.100 --> 00:07:40.800
But here's the thing.
00:07:41.080 --> 00:07:45.740
So how much does this, I don't know, how much does this new addition here help,
00:07:46.100 --> 00:07:46.200
right?
00:07:46.280 --> 00:07:47.580
This user.age?
00:07:48.960 --> 00:07:49.320
?unknown.
00:07:49.680 --> 00:07:50.700
You know, how do you solve problems?
00:07:50.920 --> 00:07:53.860
It doesn't really solve problems like that one.
00:07:54.120 --> 00:07:56.180
It just compresses ternary expressions,
00:07:56.850 --> 00:07:56.960
right?
00:07:57.060 --> 00:07:59.940
it doesn't actually alleviate the none checking.
00:08:00.520 --> 00:08:03.080
Like if you wanted to check is user none or age none.
00:08:03.480 --> 00:08:03.640
Yeah,
00:08:03.860 --> 00:08:05.380
but maybe I don't I don't see.
00:08:05.880 --> 00:08:07.180
Yeah, I don't see any way to
00:08:07.400 --> 00:08:10.140
this feels cleaner for the ternary version of that.
00:08:10.420 --> 00:08:10.560
Yeah,
00:08:10.760 --> 00:08:15.040
yeah, let's see. We got some again, this is this is personal opinions. I think both of us are
00:08:15.280 --> 00:08:19.500
absolutely I'm okay without it. But if you're gonna add no operator,
00:08:20.040 --> 00:08:21.680
like no operations to the language,
00:08:22.160 --> 00:08:27.520
The biggest one is the if this is not, if this is like just the sawtooth of four things,
00:08:27.780 --> 00:08:28.120
ifs.
00:08:28.720 --> 00:08:31.580
Kiva out there says, when I went from C# to Python, I really,
00:08:31.760 --> 00:08:32.860
really missed the null
00:08:33.099 --> 00:08:34.800
coalescing operators more than anything else,
00:08:35.060 --> 00:08:36.280
even the type system.
00:08:36.620 --> 00:08:36.840
Yeah.
00:08:37.099 --> 00:08:37.640
Yeah, yeah, yeah.
00:08:38.599 --> 00:08:41.020
But like you just mentioned with the sawtoothing,
00:08:41.300 --> 00:08:43.659
the flat is better than nested Python,
00:08:44.020 --> 00:08:44.380
you
00:08:44.400 --> 00:08:44.480
know,
00:08:44.800 --> 00:08:45.140
to tenant.
00:08:45.920 --> 00:08:47.160
Really, I believe in that one.
00:08:47.160 --> 00:08:49.760
And that breaks it when you go that deep like that.
00:08:50.020 --> 00:08:50.180
Yeah.
00:08:50.360 --> 00:08:51.420
Yeah. So you would, I mean,
00:08:51.600 --> 00:08:52.300
what would I do? All right.
00:08:52.500 --> 00:08:53.820
We're in the danger of going too deep.
00:08:53.960 --> 00:08:55.840
So what I would do is I would use for this,
00:08:56.100 --> 00:08:56.180
this,
00:08:56.500 --> 00:08:57.580
like the way it has to work now,
00:08:57.660 --> 00:08:59.700
not Michael's beaver dream of null checking.
00:09:00.120 --> 00:09:02.020
You've got to use what are called guarding clauses,
00:09:02.220 --> 00:09:02.460
right? You say,
00:09:02.640 --> 00:09:03.760
if user is none,
00:09:04.440 --> 00:09:04.560
return,
00:09:05.000 --> 00:09:07.260
return something like none or whatever.
00:09:07.740 --> 00:09:08.180
And then if
00:09:08.360 --> 00:09:09.700
user.address is none,
00:09:10.060 --> 00:09:10.980
return something else.
00:09:11.340 --> 00:09:13.120
And then finally you can get the city and you know,
00:09:13.200 --> 00:09:15.080
you can flatten it with the right patterns.
00:09:15.520 --> 00:09:17.259
That's the Vincent of Python pattern I would
00:09:17.280 --> 00:09:17.640
have used.
00:09:18.000 --> 00:09:18.060
Yeah.
00:09:18.440 --> 00:09:19.300
All right. That's enough for this.
00:09:19.520 --> 00:09:19.640
People,
00:09:20.440 --> 00:09:21.520
this is a proposal,
00:09:21.880 --> 00:09:23.520
a draft for 3.6.
00:09:24.080 --> 00:09:26.940
We have had opinions and we've shared them and now you can have yours.
00:09:27.660 --> 00:09:28.440
Over to you, Calvin.
00:09:29.500 --> 00:09:29.620
Yep.
00:09:29.860 --> 00:09:30.000
Well,
00:09:30.500 --> 00:09:33.360
speaking of language features and new versions that are out.
00:09:33.780 --> 00:09:35.080
So we've been talking
00:09:35.180 --> 00:09:38.880
about Python 3.15 for at least the last month of episodes,
00:09:39.340 --> 00:09:41.380
hoping it would have been out October 1st,
00:09:41.460 --> 00:09:42.440
but that got moved.
00:09:42.600 --> 00:09:48.380
So we actually have got Python 315 RC3 that came out this week. So if you are
00:09:48.560 --> 00:09:48.980
keeping track,
00:09:49.500 --> 00:09:53.960
you should probably notice that there's not been a formal release, but it will
00:09:53.960 --> 00:09:54.280
be coming.
00:09:54.860 --> 00:09:58.300
I believe they're saying final is scheduled here for the ninth.
00:09:58.700 --> 00:09:59.540
So before the next
00:09:59.740 --> 00:10:03.500
episode, we will have Python 315 that is out.
00:10:03.900 --> 00:10:07.879
The showstopper roadblock that was going on in there
00:10:08.360 --> 00:10:13.840
was basically some support or fix for what was lazy import release blockers.
00:10:14.040 --> 00:10:15.340
So the kind of one
00:10:15.340 --> 00:10:18.240
of the really nice new features of Python 3.15 that you probably should check out.
00:10:18.390 --> 00:10:18.720
And if you
00:10:18.770 --> 00:10:22.760
wanted to go use what's newt to do a dungeon crawler and explore those features.
00:10:23.820 --> 00:10:24.040
But the
00:10:24.920 --> 00:10:27.840
lazy imports had a last minute bug.
00:10:28.080 --> 00:10:32.380
So they want to make sure they get the fixes tested properly.
00:10:32.980 --> 00:10:33.840
So if you aren't familiar again,
00:10:34.020 --> 00:10:37.560
lazy imports means that you can say lazy import from
00:10:37.700 --> 00:10:38.440
blah, blah, blah, blah, blah.
00:10:38.820 --> 00:10:41.660
And when you go to use it is actually when it'll import
00:10:41.780 --> 00:10:42.640
at that point in time.
00:10:42.720 --> 00:10:44.560
So you could actually have imports at the top
00:10:44.720 --> 00:10:46.580
that actually never get imported based on conditions,
00:10:47.100 --> 00:10:50.080
which might actually be preferable given your stance
00:10:50.260 --> 00:10:53.020
on memory usage or loading things for security reasons
00:10:53.320 --> 00:10:55.120
or lots of other things that could be basically
00:10:55.600 --> 00:10:56.320
be wrapped into that.
00:10:56.620 --> 00:10:58.660
I'm very excited about the lazy imports.
00:10:58.720 --> 00:10:58.900
Yeah,
00:10:59.340 --> 00:10:59.800
I am too.
00:11:00.040 --> 00:11:04.960
So I think the lazy imports and then the frozendicts that we get now as well.
00:11:05.000 --> 00:11:07.280
I think that's the other major one that was going in there.
00:11:07.600 --> 00:11:10.400
But there's no major ABI changes for this RC.
00:11:11.140 --> 00:11:18.620
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.
00:11:19.040 --> 00:11:21.160
So that's part of the news I wanted to cover on this one.
00:11:21.800 --> 00:11:29.400
The other piece that I wanted to cover was that on October 1st, they also released the last version of 3.10.
00:11:29.800 --> 00:11:30.600
So if you see right here,
00:11:30.860 --> 00:11:31.480
Python 3.10,
00:11:32.060 --> 00:11:32.440
.22,
00:11:32.800 --> 00:11:33.100
11,
00:11:33.340 --> 00:11:33.900
da, da, da, da, da,
00:11:34.180 --> 00:11:36.920
all the minor releases there for 10 through 14
00:11:37.300 --> 00:11:37.960
are now available.
00:11:38.400 --> 00:11:40.780
The most important piece I think of this release
00:11:41.060 --> 00:11:43.640
that I wanted to bring it up during this segment
00:11:44.000 --> 00:11:47.840
was there'll be no more releases of Python 3.10.
00:11:48.080 --> 00:11:50.280
This is the EOL final end of line.
00:11:50.920 --> 00:11:53.400
There'll be no more security releases for 3.10.
00:11:53.540 --> 00:11:55.740
So if you've got code in production that is running 3.10,
00:11:56.080 --> 00:11:56.820
you've been warned,
00:11:57.240 --> 00:11:59.240
you've been told probably many, many, many, many times,
00:11:59.640 --> 00:12:01.460
along the way that this is coming,
00:12:01.980 --> 00:12:03.580
but it's become, we're here.
00:12:03.740 --> 00:12:04.840
So for example,
00:12:05.060 --> 00:12:05.480
there was
00:12:06.000 --> 00:12:08.360
nine common security fixes in this October 1st release.
00:12:08.540 --> 00:12:09.960
There was things like SSL validation,
00:12:10.780 --> 00:12:12.140
that tar file and zip file handling,
00:12:12.920 --> 00:12:14.240
URL lib credentials.
00:12:14.720 --> 00:12:16.140
Those all sound pretty important.
00:12:16.600 --> 00:12:19.900
And those are the kinds of things you're going to want to have fixes for inside your code,
00:12:20.260 --> 00:12:21.640
especially given the state of credentials.
00:12:22.440 --> 00:12:27.380
AI and all the things that are kind of coming out
00:12:27.400 --> 00:12:28.000
after it.
00:12:28.300 --> 00:12:30.380
So it's been five years. It's time-free to upgrade.
00:12:31.000 --> 00:12:31.980
There's going to be no more 3.10.
00:12:32.300 --> 00:12:36.340
That's wild because I'll tell you that 3.10 sounds pretty modern to me.
00:12:36.680 --> 00:12:37.480
Same for me.
00:12:37.700 --> 00:12:41.020
I mean, I think we are of an age and have been in the Python community long enough
00:12:41.360 --> 00:12:43.940
that five years passes before your eyes, before you know it.
00:12:44.480 --> 00:12:46.540
But 3.15 is about to become very much
00:12:46.540 --> 00:12:48.240
a reality. 3.14 is very stable.
00:12:48.780 --> 00:12:51.919
3.11 has all the things you probably want and probably is most
00:12:51.940 --> 00:12:52.940
likely a drop in.
00:12:53.580 --> 00:12:55.560
These releases of Python,
00:12:55.920 --> 00:12:58.380
I don't believe there's been too many backward
00:12:58.560 --> 00:13:01.940
compatible breaking changes in there. So there's not really much of a reason not to.
00:13:02.250 --> 00:13:02.700
If you've got
00:13:02.770 --> 00:13:08.000
great test suites and you can go and do a Nox style test against all of them, find out which
00:13:08.000 --> 00:13:12.540
one doesn't break for you quickly through your CI pipeline and get your code updated for the latest
00:13:12.680 --> 00:13:13.180
versions of Python.
00:13:13.920 --> 00:13:14.580
Now that said,
00:13:14.750 --> 00:13:17.820
Python 3.11 will get security fixes through October of 2027.
00:13:18.030 --> 00:13:18.379
So you
00:13:18.300 --> 00:13:21.080
got another year on 11 and another year after that for 12.
00:13:21.660 --> 00:13:23.600
But why not just go to the 315?
00:13:23.880 --> 00:13:24.000
It'll be
00:13:24.010 --> 00:13:24.680
out later this week.
00:13:25.320 --> 00:13:26.820
If you're already doing the work,
00:13:27.120 --> 00:13:29.900
you might as well get yourself another five
00:13:30.060 --> 00:13:33.280
year lease on this work.
00:13:33.600 --> 00:13:34.080
Run Knox,
00:13:34.320 --> 00:13:38.020
run all of them. Run all of them. See if they all pass or if there's
00:13:38.220 --> 00:13:40.820
issues and either fix or just go back to the, you know,
00:13:41.000 --> 00:13:41.980
313 or whatever that works.
00:13:42.130 --> 00:13:42.240
Yeah.
00:13:42.650 --> 00:13:43.000
I just,
00:13:43.310 --> 00:13:47.739
again, I hate, I put this one here because I really do not want to see anyone be a headline
00:13:47.760 --> 00:13:51.000
on Hacker News or any other major news outlet,
00:13:51.740 --> 00:13:54.360
I've got an extra that's kind of related to this,
00:13:54.820 --> 00:13:56.180
that you shouldn't, don't be a victim.
00:13:57.040 --> 00:13:57.520
Keep up to date.
00:13:57.860 --> 00:14:00.440
Python is very, the Python community is very good
00:14:00.640 --> 00:14:01.400
about compatibility,
00:14:01.880 --> 00:14:02.140
updating,
00:14:02.440 --> 00:14:03.620
having updating notes.
00:14:03.840 --> 00:14:08.740
We learned a lot of lessons in the two to three history of Python.
00:14:08.930 --> 00:14:11.620
So go out there and get yourself upgraded.
00:14:12.040 --> 00:14:12.340
But Michael,
00:14:12.520 --> 00:14:13.360
that's what I got for.
00:14:13.510 --> 00:14:16.639
One of those lessons was waiting for a very long time
00:14:16.660 --> 00:14:18.000
for the world to sort itself out.
00:14:18.090 --> 00:14:19.740
It doesn't necessarily treat you that well.
00:14:20.120 --> 00:14:20.420
Yeah,
00:14:20.940 --> 00:14:21.220
that's true.
00:14:21.460 --> 00:14:23.660
Maybe stay on top of things as they're changing
00:14:23.930 --> 00:14:25.240
rather than like waiting eight years to go,
00:14:25.430 --> 00:14:26.240
oh gosh, we got to upgrade.
00:14:27.400 --> 00:14:28.600
Like you should have a shield.
00:14:28.860 --> 00:14:30.620
Let me just put up like a shield sort of thing.
00:14:30.710 --> 00:14:32.360
Is there a shield people could use?
00:14:32.640 --> 00:14:34.500
There is a shield people can use
00:14:34.610 --> 00:14:35.920
and I've got details for you.
00:14:36.100 --> 00:14:39.200
So I've been experimenting with ideas,
00:14:39.780 --> 00:14:42.300
some crazy ideas and I'm not ready to share with you.
00:14:42.720 --> 00:14:45.180
Well, I might share with you privately, of course, Calvin,
00:14:45.280 --> 00:14:49.480
But I'm not ready to share with you, dear listeners as a broad world until I have more info on it.
00:14:49.630 --> 00:14:51.060
But it's pretty wild.
00:14:51.110 --> 00:14:57.280
So I've been doing a lot of testing on like different database type systems and so on a couple of the websites.
00:14:57.900 --> 00:15:03.500
And I have this place where I write basically an analytics entry.
00:15:03.820 --> 00:15:06.880
You know, someone's downloaded this or they watched a video or something like that.
00:15:07.010 --> 00:15:09.240
And then I increment it somewhere else because,
00:15:09.820 --> 00:15:10.960
you know, 50 million records,
00:15:11.270 --> 00:15:12.440
you don't want that to be operational.
00:15:12.770 --> 00:15:14.100
Like who has done this thing?
00:15:14.200 --> 00:15:17.780
You might want it like a little more concise or how many people downloaded
00:15:17.830 --> 00:15:18.460
that thing or whatever.
00:15:18.920 --> 00:15:22.640
So it writes it once to this kind of summary table that the websites use.
00:15:22.760 --> 00:15:24.680
And then it writes this, this analytics one.
00:15:24.800 --> 00:15:24.920
Well,
00:15:25.080 --> 00:15:26.920
it turned out that out of many,
00:15:27.080 --> 00:15:27.520
many millions,
00:15:28.000 --> 00:15:30.680
there was 1,200 missing
00:15:31.000 --> 00:15:32.580
entries, where, where did they go?
00:15:32.640 --> 00:15:33.600
It says right here.
00:15:33.680 --> 00:15:34.780
And then it says right there.
00:15:35.120 --> 00:15:35.200
Well,
00:15:35.380 --> 00:15:39.920
these came into existence once I switched to an async web framework
00:15:40.180 --> 00:15:40.520
court,
00:15:40.760 --> 00:15:41.720
but it could be FastAPI.
00:15:41.870 --> 00:15:42.520
It could be Litestar.
00:15:42.620 --> 00:15:46.020
It's not anything necessarily specific with court, not necessarily.
00:15:46.480 --> 00:15:52.580
So what happens is with court, if somebody makes a request and the request is in flight
00:15:52.670 --> 00:15:56.420
and they decide they're not doing that anymore, or they're going to cancel that, or they're
00:15:56.420 --> 00:15:57.020
going to go somewhere else,
00:15:57.420 --> 00:15:59.540
court itself does a request.cancel.
00:15:59.840 --> 00:16:01.800
So it says, oh, did somebody disconnect?
00:16:02.130 --> 00:16:05.400
Like here's the LF literally says disconnected,
00:16:05.860 --> 00:16:06.760
request body disconnect.
00:16:06.850 --> 00:16:11.780
And the last thing is request task.cancel in the court ASCII.py file.
00:16:12.100 --> 00:16:20.560
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,
00:16:20.740 --> 00:16:23.160
has finished, but it hasn't quite gotten done,
00:16:23.380 --> 00:16:24.560
it hasn't finished awaiting.
00:16:24.960 --> 00:16:25.120
Well,
00:16:25.280 --> 00:16:29.640
this thing just raises a task canceled exception and that one doesn't run.
00:16:30.240 --> 00:16:31.300
Or maybe this one's starting,
00:16:31.480 --> 00:16:33.740
the second one is starting to do a database negotiation.
00:16:34.160 --> 00:16:34.520
Like, hey,
00:16:34.720 --> 00:16:36.800
give me something on the connection pool and I'm going to start talking.
00:16:36.980 --> 00:16:37.640
I'm out.
00:16:37.960 --> 00:16:40.880
And so these don't have to happen atomically.
00:16:41.220 --> 00:16:41.360
Right.
00:16:41.740 --> 00:16:43.660
So there's different things you can do to do that.
00:16:43.840 --> 00:16:45.480
Obviously you could use a transaction,
00:16:45.730 --> 00:16:47.000
but then you would lose the first one,
00:16:47.400 --> 00:16:49.260
which maybe like a request did come in.
00:16:49.360 --> 00:16:50.460
Maybe you want to save them both, right?
00:16:50.760 --> 00:16:51.400
So what are you going to do?
00:16:51.430 --> 00:16:53.880
You can bust out the asyncio dot shield and this,
00:16:54.040 --> 00:16:55.220
I've done a lot of asyncio stuff.
00:16:55.310 --> 00:16:56.980
And this is surprising to me.
00:16:57.380 --> 00:17:01.780
So what you can actually do is with this asyncio shield,
00:17:02.220 --> 00:17:04.819
it basically says this sub,
00:17:04.959 --> 00:17:06.339
this async subroutine.
00:17:06.890 --> 00:17:07.939
I do not want it.
00:17:08.220 --> 00:17:12.920
Even if the outer task gets canceled, I want this to either not run or completely run,
00:17:13.120 --> 00:17:13.240
right?
00:17:13.400 --> 00:17:15.459
So I can do like record download.
00:17:15.579 --> 00:17:16.560
I can say await.
00:17:16.860 --> 00:17:17.400
Instead of wait,
00:17:17.560 --> 00:17:18.180
just the task,
00:17:18.360 --> 00:17:22.240
I await asyncio shielding the task and you get consistent.
00:17:22.420 --> 00:17:22.540
Yeah,
00:17:22.839 --> 00:17:26.839
you get more intentional control over the specific use case because that can happen
00:17:26.920 --> 00:17:27.160
in your,
00:17:27.380 --> 00:17:28.920
like you said, your left scratch in your head.
00:17:29.240 --> 00:17:29.460
Why?
00:17:29.680 --> 00:17:30.440
It doesn't make any sense.
00:17:30.660 --> 00:17:32.360
Like it's either running or it's not running.
00:17:32.380 --> 00:17:32.500
Well,
00:17:32.720 --> 00:17:35.060
apparently the web framework unwinds it partway through,
00:17:35.500 --> 00:17:36.600
which is reasonable so that
00:17:36.620 --> 00:17:38.640
they can go handle requests that are not disconnected.
00:17:38.700 --> 00:17:39.580
I mean, it's more than reasonable.
00:17:39.640 --> 00:17:40.600
It cleans up after itself
00:17:40.740 --> 00:17:42.100
'cause it allows you then to perform
00:17:42.200 --> 00:17:43.820
other cleanup operations that may have happened
00:17:43.880 --> 00:17:44.420
along the way too.
00:17:44.820 --> 00:17:45.020
Yeah,
00:17:45.280 --> 00:17:45.400
exactly.
00:17:45.780 --> 00:17:47.940
So this is not a third party thing.
00:17:48.100 --> 00:17:50.340
This is just built into the asyncio module.
00:17:50.780 --> 00:17:53.140
But to me, this was a mystery until I learned about it.
00:17:53.220 --> 00:17:54.740
Yeah, I've never explored this before.
00:17:55.060 --> 00:17:55.540
This is really cool.
00:17:55.800 --> 00:17:56.320
Yeah, yeah.
00:17:56.640 --> 00:17:58.780
And the other thing that's really noteworthy here
00:17:58.980 --> 00:18:01.580
is you need to make sure that you have something
00:18:01.980 --> 00:18:03.800
holding onto the task,
00:18:04.200 --> 00:18:04.260
right?
00:18:04.260 --> 00:18:06.580
So here you can see the task is created
00:18:06.600 --> 00:18:08.480
And then it adds it to the pending tasks.
00:18:09.660 --> 00:18:13.540
Because I remember where I wrote about this.
00:18:13.940 --> 00:18:14.660
Let's see.
00:18:15.140 --> 00:18:15.620
Fire and forget.
00:18:16.120 --> 00:18:16.580
Not ever, never.
00:18:16.940 --> 00:18:19.700
So both I wrote about this and Will McGugan wrote about this.
00:18:20.100 --> 00:18:25.740
But it turns out that if you start a task and you don't hold on to a reference to it,
00:18:27.480 --> 00:18:30.260
the asyncio event loop uses weak references.
00:18:30.660 --> 00:18:33.960
So it's very likely that once you create a task and start it,
00:18:34.160 --> 00:18:35.040
If you don't hang on to it,
00:18:35.220 --> 00:18:37.600
there might be a garbage collection or some sort of
00:18:37.820 --> 00:18:40.040
reference kind of thing that just drops it halfway through.
00:18:40.240 --> 00:18:44.020
So kind of got to keep this in mind plus that.
00:18:44.160 --> 00:18:44.620
So it's a little,
00:18:44.820 --> 00:18:45.920
not super obvious.
00:18:46.120 --> 00:18:48.060
Like, so that's what this pending task thing is about.
00:18:48.160 --> 00:18:48.340
Anyway,
00:18:48.760 --> 00:18:50.060
it doesn't solve all your problems.
00:18:50.380 --> 00:18:52.180
Like you've got to keep a reference to the task.
00:18:52.640 --> 00:18:53.780
Errors go nowhere by default,
00:18:54.020 --> 00:18:55.980
because now you've, you basically said the
00:18:56.100 --> 00:18:57.940
outer thing that called it, I don't want it to see that anymore.
00:18:58.120 --> 00:18:58.660
Don't worry about it.
00:18:58.900 --> 00:18:59.960
Doesn't survive shut down.
00:19:00.300 --> 00:19:02.440
If something hangs while you told it, it can't cancel.
00:19:02.640 --> 00:19:07.260
so it's not going to cancel if you keep going and um it'll make him both finish but it's not
00:19:07.460 --> 00:19:11.840
necessarily atomic right if there's an exception that's different than just avoiding cancellation
00:19:12.160 --> 00:19:17.280
so anyway i feel like you solved one one interesting edge case you've only solved one
00:19:17.420 --> 00:19:23.320
interesting edge case but potentially introduced like six more in the traps and current traps and
00:19:23.320 --> 00:19:27.760
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
00:19:27.720 --> 00:19:33.560
games yeah okay let's play some games this is a so this is not a new framework necessarily but
00:19:33.560 --> 00:19:38.800
it's been getting a lot of uh exposure recently on the interwebs and so it's called pixel it is a
00:19:39.220 --> 00:19:46.320
retro game engine for python it's a free mit licensed game engine that you use python to build
00:19:46.840 --> 00:19:54.480
games in uh what kind of attracted to me is i am obviously a fan of the retro looking game aesthetic
00:19:54.480 --> 00:19:59.860
So it's kind of like how Twitter used to deliberately limit you to 140 characters.
00:20:00.080 --> 00:20:03.500
This deliberately limits you to 16 colors and four sound channels.
00:20:03.740 --> 00:20:10.420
So you are basically operating in the world of classic game consoles like the NES and so on.
00:20:10.900 --> 00:20:12.200
So it keeps the scope small.
00:20:12.620 --> 00:20:17.020
And one of their goals was to make the games finishable as a programmer,
00:20:17.220 --> 00:20:18.260
not as the player,
00:20:18.620 --> 00:20:20.700
but as the person building the game.
00:20:20.820 --> 00:20:25.440
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.
00:20:26.540 --> 00:20:27.740
It's been in development since 2018.
00:20:28.080 --> 00:20:31.220
It's got 18,000 GitHub stars on there.
00:20:31.660 --> 00:20:34.040
It has built-in editors for the pixel art,
00:20:34.220 --> 00:20:35.500
which is also something I,
00:20:36.000 --> 00:20:37.280
is near and dear to my heart,
00:20:37.320 --> 00:20:40.360
which is like the art and the aesthetic behind the game.
00:20:40.600 --> 00:20:42.580
So you can build art and the tile maps.
00:20:42.960 --> 00:20:45.760
It's got editors for the sound and the music.
00:20:46.020 --> 00:20:47.100
So you can make graphics,
00:20:47.560 --> 00:20:47.640
audio,
00:20:47.880 --> 00:20:49.900
and the game logic in one place.
00:20:50.040 --> 00:20:50.680
So again,
00:20:50.940 --> 00:20:54.100
not to get distracted by going to five other tools to get something done.
00:20:54.540 --> 00:20:58.660
That's a great way to do all that stuff in one tight place for that.
00:20:59.020 --> 00:21:03.460
What's awesome is that actually the engine behind the scenes is implemented in Rust.
00:21:03.590 --> 00:21:05.100
And so we've been hearing a lot about Rust lately.
00:21:05.500 --> 00:21:07.220
It gets compiled into WebAssembly,
00:21:07.620 --> 00:21:10.320
which you can launch the games locally on your computer,
00:21:10.580 --> 00:21:14.460
compiles down into a locally executable Rust binary.
00:21:15.020 --> 00:21:17.520
But you can also play the games on your web browser.
00:21:17.900 --> 00:21:23.200
So it uses WebAssembly to deploy these or make them deployable into your web browser.
00:21:23.580 --> 00:21:29.500
So the CodeMaker has a browser playground with the code editor and all the tools built into it.
00:21:29.780 --> 00:21:32.000
You can load programs from local files,
00:21:32.700 --> 00:21:33.900
GitHub Gists or URLs.
00:21:34.380 --> 00:21:36.800
Actually, I'll show you a quick demo of this right here.
00:21:36.880 --> 00:21:37.520
So in the showcase,
00:21:38.160 --> 00:21:42.080
you can just run uvx pixel copy examples,
00:21:42.540 --> 00:21:45.540
and it will pull these examples to your local computer where you can run them.
00:21:45.860 --> 00:21:47.900
or you can just go into the docs over here
00:21:48.000 --> 00:21:48.980
and they've got the pixel showcase
00:21:49.640 --> 00:21:52.140
where these are the exact same examples
00:21:52.280 --> 00:21:54.160
from that copy examples I was running locally on my machine.
00:21:54.860 --> 00:21:55.540
These will run here.
00:21:55.720 --> 00:21:56.420
I'm going to run one.
00:21:56.740 --> 00:21:57.700
I'll run the platformer.
00:21:57.700 --> 00:21:58.160
It's kind of fun.
00:21:58.480 --> 00:21:59.580
This is WebAssembly.
00:22:00.180 --> 00:22:02.960
This Python code compiled to run in my browser.
00:22:03.340 --> 00:22:04.160
And so you can see here,
00:22:04.580 --> 00:22:05.720
it's got sound a whole bit.
00:22:05.800 --> 00:22:07.140
You can't obviously hear the sound,
00:22:07.280 --> 00:22:08.500
I think because I didn't share it over there.
00:22:09.040 --> 00:22:09.800
That's so cool.
00:22:10.140 --> 00:22:10.240
Boom,
00:22:10.540 --> 00:22:11.000
there you die.
00:22:12.200 --> 00:22:12.780
So it's fun.
00:22:13.100 --> 00:22:13.860
You know what we got to do?
00:22:14.240 --> 00:22:15.540
Did you ever play the game Lemming?
00:22:15.960 --> 00:22:16.120
Yes.
00:22:16.680 --> 00:22:17.200
Oh my God.
00:22:17.420 --> 00:22:19.500
That's one of the best games of the genre in my opinion.
00:22:20.100 --> 00:22:21.200
And it has to come back.
00:22:21.520 --> 00:22:21.660
Yeah.
00:22:22.040 --> 00:22:23.480
Let's see if I can find my mouse again.
00:22:24.080 --> 00:22:27.120
Wasn't the original Prince of Persia a little like this as well?
00:22:27.520 --> 00:22:28.100
Very original.
00:22:28.480 --> 00:22:28.680
Yeah.
00:22:28.840 --> 00:22:29.260
These are good.
00:22:29.700 --> 00:22:29.820
Yeah.
00:22:30.700 --> 00:22:31.720
They got some nice,
00:22:32.660 --> 00:22:33.220
interesting examples.
00:22:33.800 --> 00:22:39.900
And then there's a whole like gallery of examples on the site for pixel as well.
00:22:40.420 --> 00:22:43.880
If you come down here and you can see these a bunch of examples that run.
00:22:44.340 --> 00:22:45.160
They're cross-platform,
00:22:45.380 --> 00:22:45.520
obviously.
00:22:45.710 --> 00:22:46.620
They run Windows,
00:22:46.820 --> 00:22:47.240
Mac, Linux,
00:22:47.390 --> 00:22:47.500
Web.
00:22:47.590 --> 00:22:48.100
They don't care.
00:22:48.360 --> 00:22:48.860
They run everywhere.
00:22:49.560 --> 00:22:50.020
It's great for,
00:22:50.230 --> 00:22:52.720
like, if you want to teach people how to code and program,
00:22:52.960 --> 00:22:53.520
some of the
00:22:53.620 --> 00:22:58.100
most popular sessions we've ever done in our IndyPy user group have always been like the
00:22:58.920 --> 00:23:02.920
arcade library or the PyGaming libraries,
00:23:03.140 --> 00:23:05.680
because people can relate to and know that
00:23:05.770 --> 00:23:09.560
if they can build games like this, they can learn how to program and do really, really
00:23:09.590 --> 00:23:09.960
cool stuff.
00:23:10.660 --> 00:23:13.120
It's a fun low barrier way into game development.
00:23:13.300 --> 00:23:13.740
Good for beginners,
00:23:13.960 --> 00:23:16.700
good for teaching kids again, because it all runs in one spot.
00:23:17.100 --> 00:23:19.760
You're not having them install a bazillion different things.
00:23:20.320 --> 00:23:21.360
Actually, I think if we go.
00:23:21.820 --> 00:23:22.260
Yeah, here we go.
00:23:22.600 --> 00:23:23.680
I've got the examples over here.
00:23:23.960 --> 00:23:25.320
You just run like that.
00:23:25.520 --> 00:23:27.020
That's the same platformer.
00:23:27.320 --> 00:23:31.880
And it launched a rich looking app right on my desktop.
00:23:32.220 --> 00:23:32.500
Yeah,
00:23:32.780 --> 00:23:33.060
that's awesome.
00:23:33.340 --> 00:23:33.900
Let's see if I can get right.
00:23:33.980 --> 00:23:34.240
I can't.
00:23:34.780 --> 00:23:35.440
Oh, there we go.
00:23:35.600 --> 00:23:36.080
I'll get a little further.
00:23:36.460 --> 00:23:37.660
Oh, you know what reminds me of?
00:23:37.800 --> 00:23:39.560
I was going to say Flappy Bird, but that's not what it is.
00:23:39.680 --> 00:23:40.800
It reminds me of Joust,
00:23:41.220 --> 00:23:41.780
but bird form.
00:23:42.000 --> 00:23:44.660
But you can even come in here and run like the hello world.
00:23:45.180 --> 00:23:45.400
Oops,
00:23:45.700 --> 00:23:46.200
not 1.py.
00:23:46.680 --> 00:23:48.160
Let's say there's like the 01,
00:23:49.140 --> 00:23:49.240
obviously.
00:23:49.660 --> 00:23:52.260
And then this one's just like the hello world of pixel.
00:23:52.540 --> 00:23:52.620
Hello,
00:23:52.840 --> 00:23:52.940
pixel.
00:23:53.680 --> 00:23:54.760
And there's a link tag.
00:23:55.340 --> 00:23:55.720
Yeah, yeah, yeah.
00:23:56.060 --> 00:23:58.680
And so if we just bat the 01 hello,
00:23:59.140 --> 00:24:01.620
you can see here 20 lines of Python code
00:24:02.020 --> 00:24:04.020
that run on the Rust engine using pixel.
00:24:04.360 --> 00:24:04.520
Yeah.
00:24:04.880 --> 00:24:05.620
So super fun,
00:24:05.980 --> 00:24:07.460
very easy way to get started
00:24:07.480 --> 00:24:09.920
and go run some cool Python code.
00:24:10.120 --> 00:24:10.520
I love it.
00:24:10.700 --> 00:24:10.900
Yeah.
00:24:11.460 --> 00:24:11.980
Very fun.
00:24:12.140 --> 00:24:12.700
It was very fun.
00:24:13.360 --> 00:24:15.080
I don't know if you've got any extras, Michael,
00:24:15.220 --> 00:24:16.340
you wanted to cover real quick?
00:24:16.540 --> 00:24:17.440
I got a couple,
00:24:17.860 --> 00:24:17.980
actually.
00:24:18.260 --> 00:24:19.380
Let's jump in here.
00:24:19.580 --> 00:24:20.700
So where do we want to go?
00:24:20.900 --> 00:24:21.620
These are both pretty small.
00:24:22.160 --> 00:24:23.140
So first of all,
00:24:23.600 --> 00:24:25.400
we're back from Stefan on Tiny Mongo.
00:24:25.560 --> 00:24:27.180
This Mongo one's got a lot of legs.
00:24:27.560 --> 00:24:28.160
It's got legs.
00:24:28.540 --> 00:24:28.640
Well,
00:24:28.860 --> 00:24:31.540
because we worked for weeks
00:24:31.780 --> 00:24:34.440
on getting this thing almost performance compatible
00:24:35.020 --> 00:24:37.440
and API compatible with MongoDB
00:24:37.440 --> 00:24:43.740
a sequel light rapper it was incredible so we talked about it on the podcast last week and he's
00:24:43.780 --> 00:24:48.020
like i loved it so much i gave you guys a little bit of shout out so here check this two things one
00:24:48.280 --> 00:24:53.820
nice little shout out to watch you and me debate it from or to discuss it last time but also this
00:24:53.980 --> 00:24:58.440
this click here to like give you something help me use tiny mongo here's the thing that it had it on
00:24:58.760 --> 00:25:04.879
right you just copy this give it to your ai coding agent this gets started by copying a prompt
00:25:04.940 --> 00:25:09.100
give it to your AI coding agent and let them get you going using tiny mongos.
00:25:09.250 --> 00:25:09.520
Pretty sweet.
00:25:09.840 --> 00:25:12.960
I like the way to bootstrap people into success.
00:25:13.800 --> 00:25:13.900
Yes,
00:25:14.070 --> 00:25:14.400
I do too.
00:25:14.690 --> 00:25:17.020
Because otherwise you're kind of stuck with the blank sheet of paper syndrome,
00:25:17.540 --> 00:25:19.140
like where you're just like, oh, it's a big blank sheet.
00:25:19.140 --> 00:25:19.680
I don't know what to do.
00:25:20.100 --> 00:25:20.380
Here you go.
00:25:20.700 --> 00:25:21.000
Get started.
00:25:21.300 --> 00:25:21.520
Exactly.
00:25:21.970 --> 00:25:22.460
You get to go.
00:25:22.800 --> 00:25:22.880
Yeah,
00:25:23.230 --> 00:25:23.700
you get to go.
00:25:24.080 --> 00:25:27.460
Then the other one is I've become kind of fascinated with Lightstream.
00:25:27.960 --> 00:25:29.060
Are you familiar with Lightstream?
00:25:29.580 --> 00:25:29.940
Lightstream.
00:25:30.150 --> 00:25:31.880
I don't know if I've ever used Lightstream.
00:25:31.970 --> 00:25:32.080
No.
00:25:32.380 --> 00:25:33.400
So it's super interesting.
00:25:33.720 --> 00:25:37.040
There's this video that I'm going to link to called Lightstream plus SQLite.
00:25:37.220 --> 00:25:39.980
Scale to a million users without Postgres or CloudBills.
00:25:40.320 --> 00:25:41.400
And this video,
00:25:41.700 --> 00:25:42.620
this guy puts this together.
00:25:43.740 --> 00:25:46.160
Let me see if I can get it to skip ahead.
00:25:46.560 --> 00:25:51.640
But there's really cool animated sort of architectural tech talks,
00:25:51.690 --> 00:25:52.420
usually like 10 minutes.
00:25:52.800 --> 00:25:53.860
This guy's called Claude Codes.
00:25:55.100 --> 00:25:58.080
Now, it's AI text-to-speech generated.
00:25:58.400 --> 00:26:00.080
I don't know that it's AI generated,
00:26:00.240 --> 00:26:00.680
but it is.
00:26:00.960 --> 00:26:02.440
I think a person's behind it,
00:26:02.540 --> 00:26:04.100
but I think it's spoken by an AI.
00:26:04.230 --> 00:26:05.520
So it says Litstream,
00:26:05.710 --> 00:26:07.520
even though it's not pronounced that way,
00:26:08.430 --> 00:26:08.840
I don't believe.
00:26:09.420 --> 00:26:10.700
That said, I'm recommending it anyway
00:26:10.770 --> 00:26:12.500
because it's so good.
00:26:12.740 --> 00:26:13.800
This is such an interesting topic.
00:26:14.160 --> 00:26:16.580
So Lightstream is a thing
00:26:16.950 --> 00:26:18.400
that you can put next to any app
00:26:18.430 --> 00:26:19.500
that runs on SQLite.
00:26:19.760 --> 00:26:22.360
If you turn on the write-ahead log wall mode,
00:26:22.440 --> 00:26:25.300
which is the durability mode of SQLite anyway,
00:26:25.740 --> 00:26:26.540
if you turn that on
00:26:26.870 --> 00:26:28.100
and you run Lightstream next to it,
00:26:28.110 --> 00:26:29.580
it will take the write-ahead log
00:26:29.720 --> 00:26:31.420
and it will stream it to somewhere
00:26:31.420 --> 00:26:34.660
like S3 or anywhere else.
00:26:35.090 --> 00:26:39.120
And the way it works is it will eventually compact those.
00:26:39.230 --> 00:26:40.980
So instead of just having a bunch of write logs,
00:26:41.280 --> 00:26:41.660
it'll say, okay,
00:26:41.920 --> 00:26:42.340
it's been,
00:26:42.650 --> 00:26:43.720
I don't know, an hour.
00:26:43.850 --> 00:26:44.740
So I'm going to take all of those
00:26:44.960 --> 00:26:46.860
and like merge them into a SQLite file
00:26:47.210 --> 00:26:48.200
and then some more and some more.
00:26:48.460 --> 00:26:51.960
So you get within a few seconds of my SQLite file
00:26:52.120 --> 00:26:53.560
is now backed up somewhere else.
00:26:53.990 --> 00:26:55.400
And if for whatever reason it fails,
00:26:55.900 --> 00:26:57.600
you know, I could just restore it in reverse,
00:26:58.060 --> 00:26:58.940
which is pretty interesting.
00:26:59.480 --> 00:27:00.040
That's really cool.
00:27:00.480 --> 00:27:00.620
Yeah.
00:27:00.810 --> 00:27:03.180
So they talk about some other projects like,
00:27:03.840 --> 00:27:07.400
Expensify does something like 4 million rights a second on SQL light or
00:27:07.480 --> 00:27:09.340
something like an incredible thing they set up.
00:27:09.510 --> 00:27:10.300
So why do I bring this up?
00:27:10.380 --> 00:27:11.440
What does this have to do with an extra?
00:27:11.660 --> 00:27:12.320
Why is it not a topic?
00:27:12.820 --> 00:27:16.100
I'm trying to do an episode with somebody from light stream.
00:27:16.390 --> 00:27:17.300
I reached out to the creator,
00:27:17.540 --> 00:27:17.640
Ben,
00:27:17.960 --> 00:27:18.440
who has,
00:27:19.010 --> 00:27:19.100
um,
00:27:19.980 --> 00:27:21.100
just completely ghosted me.
00:27:21.100 --> 00:27:22.960
I sent him like three or four different channels of messages,
00:27:23.280 --> 00:27:23.720
not interested.
00:27:24.120 --> 00:27:25.240
This is a plea for help.
00:27:25.980 --> 00:27:28.540
So my, it is a plea to like, Hey,
00:27:28.660 --> 00:27:33.940
If someone out there is doing cool stuff with Lightstream and SQLite embedded data and wants
00:27:33.940 --> 00:27:35.500
to come on Talk Python and talk about it,
00:27:35.840 --> 00:27:38.100
shoot me a message and maybe we'll make that happen.
00:27:38.370 --> 00:27:40.580
My traditional channels have run dry.
00:27:41.080 --> 00:27:41.460
All right.
00:27:41.550 --> 00:27:42.700
You heard the man.
00:27:43.660 --> 00:27:44.260
It's a plea.
00:27:44.620 --> 00:27:45.760
If you'd like to do that,
00:27:46.080 --> 00:27:46.520
come on down.
00:27:46.980 --> 00:27:48.400
I got a couple quick extras.
00:27:48.750 --> 00:27:51.480
One of them I didn't make a segment as part of my Python language bits,
00:27:51.630 --> 00:27:52.520
which was there's
00:27:52.520 --> 00:27:55.620
a new namespace potentially coming to Python called Sys.
00:27:56.060 --> 00:28:03.800
So if you have ever made a file in your directory that conflicted with the name of a standard library module,
00:28:04.040 --> 00:28:05.480
you may have experienced this bug.
00:28:05.690 --> 00:28:08.500
So you can see here that if you cat the game.py,
00:28:08.660 --> 00:28:09.840
it imports random.
00:28:10.290 --> 00:28:14.860
And then it uses random.randint to pick an integer between 1 and 10 here.
00:28:15.160 --> 00:28:15.960
And if you run the game,
00:28:16.360 --> 00:28:18.860
you'll see module random has no attribute randint.
00:28:18.960 --> 00:28:19.640
How is that possible?
00:28:20.100 --> 00:28:26.120
It's because you've got a module in your syspath someplace that is shadowing it.
00:28:26.420 --> 00:28:27.040
So instead,
00:28:27.400 --> 00:28:28.020
correction,
00:28:28.210 --> 00:28:30.120
I wasn't talking about a sys namespace.
00:28:30.130 --> 00:28:32.460
This is now the standard namespace,
00:28:32.830 --> 00:28:33.440
which could be,
00:28:34.090 --> 00:28:34.580
for example,
00:28:34.760 --> 00:28:36.740
import std.json.
00:28:37.010 --> 00:28:43.820
And now you are certainly very explicitly using the JSON library that comes with Python explicitly.
00:28:44.150 --> 00:28:45.220
So this was discussed,
00:28:45.980 --> 00:28:49.360
seemed to be met with lots of enthusiasm and people who are very excited.
00:28:49.520 --> 00:28:51.200
I'll go just scrolling down here to the very end,
00:28:52.160 --> 00:28:56.240
that it was many attendees loved the idea.
00:28:56.620 --> 00:28:58.460
No one attending hated the idea.
00:28:58.570 --> 00:29:01.560
So I'll call that a, that was a resounding success for this one.
00:29:02.020 --> 00:29:02.480
We'll see the,
00:29:02.900 --> 00:29:05.900
there'll be a PEP probably coming soon to get this included.
00:29:06.360 --> 00:29:07.520
So I don't expect this soon,
00:29:07.880 --> 00:29:08.920
but I think this is on the horizon.
00:29:09.560 --> 00:29:11.460
Lots of other languages have this.
00:29:11.470 --> 00:29:12.380
I think they mentioned in here.
00:29:12.620 --> 00:29:13.180
So we've got Rust,
00:29:13.520 --> 00:29:13.720
Java,
00:29:13.960 --> 00:29:14.100
Go,
00:29:14.540 --> 00:29:14.600
Node,
00:29:14.820 --> 00:29:18.900
all have something similar to make this explicit and safe.
00:29:19.400 --> 00:29:21.960
So Python was the holdout on this,
00:29:22.500 --> 00:29:24.620
which is kind of funny given our love of explicitness
00:29:25.140 --> 00:29:27.960
that we would not have this level of care there.
00:29:28.440 --> 00:29:32.320
There should be one and preferably only one way to do a thing unless there's six ways to
00:29:32.320 --> 00:29:32.700
do a thing.
00:29:32.880 --> 00:29:33.020
Correct.
00:29:33.960 --> 00:29:35.080
The last extra,
00:29:36.080 --> 00:29:37.380
be careful out there,
00:29:37.540 --> 00:29:37.700
folks.
00:29:38.080 --> 00:29:42.300
If you have a refrigerator that is smart and you need to upgrade it or update the firmware,
00:29:42.880 --> 00:29:48.519
some Samsung owners have reported that the firmware update bricked not only their Samsung
00:29:48.520 --> 00:29:51.440
smart part of the fridge, but the refrigerator itself.
00:29:52.170 --> 00:29:54.440
They had spoiled food after firmware
00:29:54.700 --> 00:29:59.560
updates bricked their Samsung smart refrigerators. This appeared to only have happened in Korea.
00:30:00.350 --> 00:30:03.740
So this seems to be kind of limited to an early release.
00:30:04.300 --> 00:30:06.900
Samsung did respond to Ars Technica on
00:30:06.910 --> 00:30:11.940
this article saying that they had a response in their user complaints forum.
00:30:12.240 --> 00:30:12.960
This is just a
00:30:13.080 --> 00:30:13.260
translation,
00:30:13.810 --> 00:30:16.940
but they're doing their best to ensure that customers do not suffer any losses
00:30:17.300 --> 00:30:19.360
during this specific holiday period in Korea.
00:30:19.620 --> 00:30:20.900
So be careful out there, folks.
00:30:21.120 --> 00:30:23.100
Your refrigerator could get bricked.
00:30:23.500 --> 00:30:26.460
And I'm just shocked that this did not have a fail safe
00:30:26.560 --> 00:30:28.780
to go back to being just a standard refrigerator
00:30:29.200 --> 00:30:30.580
after the smartness wore off.
00:30:30.840 --> 00:30:33.960
It seems like a natural state to fail into.
00:30:34.380 --> 00:30:35.320
You know, kind of like an escalator.
00:30:35.640 --> 00:30:36.520
When an escalator is broken,
00:30:36.720 --> 00:30:37.580
it's just stairs.
00:30:38.020 --> 00:30:38.940
You know, it still works.
00:30:39.500 --> 00:30:43.180
Instead of being the ride where you free fall for three stories.
00:30:43.640 --> 00:30:43.940
Right.
00:30:44.360 --> 00:30:44.840
That's crazy.
00:30:45.940 --> 00:30:46.060
Yeah,
00:30:46.320 --> 00:30:46.720
so be careful.
00:30:47.540 --> 00:30:52.180
yeah yeah all right michael if you have do you have a joke for us this week i do have a joke
00:30:52.560 --> 00:31:00.540
all right let's i'm always down for jokes so this one comes to us from uh will vincent he doesn't
00:31:00.540 --> 00:31:04.620
he didn't send it in i just found him saying something funny and it's the joke so the title
00:31:04.720 --> 00:31:10.780
of the joke makes me think of an lcd sound system song okay you should be thinking perhaps lord of
00:31:10.780 --> 00:31:15.020
the rings lord of the rings something like that okay that's a different direction okay so well
00:31:15.040 --> 00:31:19.340
here we go so will vincent says today i was talking with a colleague about how difficult
00:31:19.610 --> 00:31:24.620
python installation and packaging was before uv and there's whatever the elf from lord of the
00:31:24.720 --> 00:31:30.220
rings like forgot the name character name but i was there gandalf i was there 3 000 years ago
00:31:30.570 --> 00:31:36.940
we didn't even have pip we called it the cheese shop eventually it was brutal i was there gandalf
00:31:37.200 --> 00:31:42.820
how appropriate that they would pick 3 000 years given that python always guido always referred to
00:31:42.840 --> 00:31:45.300
Python 3 as Python 3K in the early days.
00:31:46.920 --> 00:31:50.360
A lot of intersections going on here for that joke.
00:31:50.780 --> 00:31:50.860
Yeah,
00:31:51.070 --> 00:31:51.400
pretty funny,
00:31:51.580 --> 00:31:51.660
right?
00:31:52.040 --> 00:31:53.580
But I was there back in the day.
00:31:53.870 --> 00:31:55.260
It is related to the song a little bit.
00:31:55.500 --> 00:31:55.740
Okay.
00:31:55.870 --> 00:31:56.500
I don't know the song.
00:31:56.980 --> 00:31:58.000
I'm going to have to be educated later.
00:31:59.240 --> 00:32:00.600
I'll put a show note to it, maybe.
00:32:00.940 --> 00:32:01.080
Sweet.
00:32:01.480 --> 00:32:01.620
Nice.
00:32:02.030 --> 00:32:02.120
Well,
00:32:02.540 --> 00:32:05.320
thanks, Michael, for joining me for this week's episode.
00:32:05.690 --> 00:32:07.880
And hopefully we'll connect again next week.
00:32:08.180 --> 00:32:10.740
I would like to actually add something for people listening really quick.
00:32:10.980 --> 00:32:11.480
Because next week,
00:32:11.640 --> 00:32:12.740
what episode is it?
00:32:13.880 --> 00:32:18.260
500 it's special we're going to do a little bit something special for next week we're going to have
00:32:18.780 --> 00:32:25.860
brian auken is going to be back on the show as a guest first time ever actually and we're going to
00:32:25.900 --> 00:32:30.440
have some other folks also join in on the show and kind of just do a little bit of an extended
00:32:30.680 --> 00:32:34.840
version a little bit special with some other folks so try to come and be a part of it if you
00:32:34.940 --> 00:32:39.760
really care and want to yeah it's not going to be at a normal time but if you look on youtube for
00:32:39.780 --> 00:32:41.380
the upcoming version live stream.
00:32:41.540 --> 00:32:42.500
It is at the time.
00:32:42.700 --> 00:32:45.340
So I believe that's noon Pacific on Tuesday,
00:32:45.480 --> 00:32:46.060
the 13th.
00:32:46.260 --> 00:32:46.320
Yeah.
00:32:46.600 --> 00:32:48.300
Join live. You won't miss the special guests.
00:32:48.900 --> 00:32:49.220
Exactly.
00:32:49.680 --> 00:32:49.740
Exactly.
00:32:50.200 --> 00:32:50.600
All right. Well,
00:32:50.720 --> 00:32:51.900
we will be there as always.
00:32:52.360 --> 00:32:52.660
Sounds good.
00:32:53.000 --> 00:32:53.340
See you then.