Skip to content
Radio Logo
PodcastsNewsPython Bytes

Python Bytes

Michael Kennedy and Calvin Hendryx-Parker
Python Bytes
Latest episode

501 episodes

  • Python Bytes

    #501 A Nod to Sir-Mix-Alot

    10/20/2026 | 37 mins.
    Topics covered in this episode:

    Nod: pause your Python program and open a notebook at any line

    Polars 2.0 ships: streaming engine by default, spill-to-disk, and a row-order gotcha

    django-cachalot caches your ORM queries and invalidates them for you

    Towards async transactions in Django

    Extras

    Joke

    Watch on YouTube

    About the show

    Sponsored by us! Support our work through:

    Our courses at Talk Python

    Consulting from Six Feet Up
    Connect with the hosts

    Michael: Mastodon / BlueSky / X / LinkedIn

    Calvin: Mastodon / BlueSky / X / LinkedIn

    Show: Mastodon / BlueSky / X

    Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Tuesday at 7am PT. Older video versions available there too.

    Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to our friends of the show list, we'll never share it.

    Michael #1: Nod: pause your Python program and open a notebook at any line

    Nod (Notebooks-on-Demand) is a JupyterLab extension by Eric Rawn that drops a notebook into a running Python program. Add a notebook() call anywhere, run the program with nod, and execution pauses there with a notebook containing all variables at that point in the call stack. Edits go back to the source file with a button, with cells converted to code and markdown to comments via Jupytext.

    It answers the classic 'this would be easier in a notebook' debugging moment without copying snippets out to files.

    Like a breakpoint with a notebook inside: the left panel walks the call stack and notebook state switches with it

    Install is pip install nodpy plus nod --install-kernel, then run with nod python -m myfile

    The round trip back to source is the differentiator; markdown cells become comments, cells become newlines, and notebooks are disposable since the source file recreates them

    nodLog() stashes variable values across calls to explore later; the article also pitches notebook() for stepping through AI-generated code line by line

    Early stage: repo from December 2025 with 16 stars and essentially one contributor, so expect rough edges

    Calvin #2: Polars 2.0 ships: streaming engine by default, spill-to-disk, and a row-order gotcha

    Polars 2.0 released Oct 6, 2026 (Ritchie Vink). The post says it's "not intended to be a big feature release", but it bundles a few big changes.

    LazyFrame.collect now defaults to the streaming engine, with large memory and speed gains on most queries.

    Breaking: streaming doesn't guarantee row order for join, group_by and unpivot. Use maintain_order=True if order matters. This is why it's a major version.

    Out-of-core (spill-to-disk) is on by default. It spills at about 80% of RAM ("may need tuning") with a 64 GB default disk budget. It covers sort, window functions and many expressions. Joins and group-bys are planned, not shipped.

    The new native Map dtype (Arrow MapType) replaces the old List(Struct(key, value)) reading. It comes with map.get, map.contains_key, map.len, map.keys and map.values.

    Stricter by design: errors should surface up front and implicit handling of data mismatches is opt-in. collect_schema() catches schema mismatches without reading data.

    SQL is now a first-class interface, with join reordering, better common-subplan elimination, and dynamic predicates/bloom filters.

    Benchmarks are self-run TPC-H/TPC-DS derived numbers against DuckDB 1.5.6 and 2.0 alpha, and DataFusion 54. They are not official TPC results.

    Polars was fastest on all but one benchmark. At 192 threads its constant overhead hurts small data (SF10 TPC-DS is 1.8x slower), and a fix is hoped for in the next release.

    Roadmap, not released: out-of-core joins and group-bys, better scaling at high core counts, Polars Cloud, and early GeoPolars work.

    Upgrade guide: https://docs.pola.rs/releases/upgrade/2/

    Michael #3: django-cachalot caches your ORM queries and invalidates them for you

    django-cachalot is a Django package that caches ORM queries and invalidates them automatically when the underlying data changes. Install it, add one line to INSTALLED_APPS, and read queries run through your cache backend with no code changes. The trick is that it caches whole tables, so any write flushes that table's cached queries, making it a strong fit for read-heavy sites and a poor one for frequently updated tables. It supports Django 4.2 through 6.1 and Python 3.8 to 3.14.

    ORM caching that normally takes careful engineering drops in with pip install and one settings line, invalidation included.

    Near-100x on joins: the README reports nearly 100x speedups for initial deployments heavy on select_related and prefetch_related.

    It caches the entire table, so a hot table with frequent writes invalidates constantly; docs suggest staying under 50 modifications per minute and mixing in cache-machine for hot paths.

    Setup is two lines, plus caveats: sync clocks across servers sharing one cache, and run a manage.py command after restoring a database outside Django.

    Calvin #4: Towards async transactions in Django

    Carlton Gibson, The Stack Report, Oct 9, 2026. It's about getting async with transaction.atomic() into Django, hoped for 6.2 and not a commitment. Status check: both PRs are still open as of Oct 19-20, with no approvals and no milestone.

    The problem: asyncio tasks share one thread and so one DB connection. A slow transaction that rolls back also discards a sibling task's quick write. Today transactions go through sync_to_async, so everything runs serially on one thread.

    Design: async with transaction.atomic() opens a nested ThreadSensitiveContext, which gets its own worker thread and connection. On exit the connection is cleaned up and control returns to the request's connection. Siblings keep using the request's connection in autocommit, so their writes survive a rollback.

    Only the task that opened the block may nest further atomic() blocks. Any other task raises TransactionManagementError, and this is enforced.

    Subtasks inside a transaction are discouraged, since the connection is serial and parallel queries gain little. If you need them, use structured concurrency (TaskGroup or an awaited gather()) so they finish before the block exits. That rule is not enforced yet, and Gibson wants Django to catch late queries before 6.2.

    Caveats: each async transaction uses an extra connection for its duration, so pools may need tuning. The advice to disable CONN_MAX_AGE for async still applies.

    Origin: the Django on the Med sprint in Pescara (hosted by Paolo Melchiorre). An expert panel on Day 1 included Lily Acorn, Simon Charette, Jacob Walls, and Charlie Denton and Sam Searles-Bryant of Kraken Tech (authors of django-subatomic, which is being integrated into Django). Caleb Hattingh then investigated the design and opened both PRs.

    PRs: Django #22074 ("Fixed #33882 -- async with transaction.atomic") has review comments from four people, with the latest commit on Oct 19 adding a test for a late child-task query. asgiref #596 (ThreadSensitiveContext changes) had Gibson's review on Oct 19 and follow-up edits on Oct 20.

    Extras

    Calvin:

    Jazzband is Shutting Down (announced in March), but there are alternatives like https://django-commons.org/

    Treemd — nice TUI for viewing Markdown https://github.com/Epistates/treemd
    Michael:

    Talk Python Membership

    Talk Python Visual topic guides

    Quick Follow Up to Episode #499 where we shared PEP 824 None coalescing operator, we also have PEP 823 (None Aware access operators) the successor to PEP 505. - via Nick Muoh and Rafael

    Free Threaded Polars, but staled on PyPI?

    Joke: LGTM (Looks Good to Me) - Claude Opus 5.5 music video
  • Python Bytes

    #500 Episode 500!

    10/14/2026 | 1h 8 mins.
    Topics covered in this episode:

    A quick chat with Brian looking back

    Extras

    Joke

    Watch on YouTube

    About the show

    Brian #1: A quick chat with Brian looking back

    Nick #2: Jev and the Case for Boring ML

    Vincent Warmerdam from marimo benchmarked Jev, a new "System 1" decision model from TypeSafe AI. In his video It handles classification without the latency or token cost of generative LLMs, which raises a practical question for data teams: where does this fit alongside traditional machine learning?

    He tested Jev against classical machine learning models to see if its speed and accuracy hold up on real-world datasets.

    General LLMs work well for reasoning, but generating full token streams just to assign a category adds unnecessary latency and cloud cost.

    Jev avoids generation entirely by evaluating the input and returning only the decision, which makes it much faster and cheaper than standard chat APIs.

    It consistently outperformed eight-shot sentence transformer setups like SetFit out of the box, especially on datasets with dozens of target categories.

    Traditional models like logistic regression still matter because they run in single-digit milliseconds on basic CPUs, cost nothing per inference, and keep private data within your own network.

    You cannot fine-tune Jev directly, so standard models remain the better choice when your data contains internal company acronyms, product names, or domain slang.

    The most practical approach is using Jev to bootstrap initial labels or audit bad training data, then training a small model you can own and run locally.

    Brett #3: Announcing the 2026 Python Packaging Council Election Results!

    The inaugural Python packaging council (PPC) has been elected and started meeting!

    Introduced via PEP 772

    5 members elected

    Top 2 vote-getters get two-year terms

    Other 3 get one-year terms

    All members will get two-year terms going forward, staggering the elections

    There have been 4 meetings far as well as a meeting with the SC

    Initial meeting notes

    As the inaugural packaging council still working out basic logistics like how to take notes

    Also working out what the packaging council should do as PEP 772 explicitly says packaging.python.org falls under the PPC, but otherwise tries not to dictate what the PPC is in charge of

    Calvin #4: Parsing JSON at tens of gigabytes per second in Python

    Daniel Lemire (Oct 12) benchmarks fastsimdjson 0.6.0, a Python binding for simdjson on PyPI, repo at simdjson/fastpysimdjson. Its map_many function runs a callback per JSON line across N threads.

    Workload: Eight hours of GH Archive data, 7.6 GB and 2.2M events. The task counts event types and looks up the target repo's language for each opened PR, and it only touches a few fields per event.

    Lazy trick: With lazy=True, the whole event is parsed but Python objects are created only for the fields you access. The idea comes from Tyler Kennedy's pysimdjson.

    Single core: stdlib json gets 0.18 GB/s (about 42 s for the whole set), orjson 0.42, msgspec 1.29, fastsimdjson lazy 2.13 (3.6 s).

    64 cores: stdlib json gets 3.17 GB/s, msgspec 24.6, fastsimdjson eager 29.8, and fastsimdjson lazy 65.7. That's the full 7.6 GB in about 0.12 s, roughly 31x its own single-core speed.

    Requires free-threading: It ran on Python 3.14.6 free-threaded (3.14t) on a 64-core dual-Xeon box.

    Grain of salt:

    It's one machine and one dataset.

    It's an embarrassingly parallel job with per-thread counters.

    The lazy win only shows up when you read a few fields from big objects.

    msgspec was handed a schema declaring only the needed fields.

    The post itself doesn't say whether this generalizes.

    Michael #5: Grinberg's annual benchmark says 3.15 is flat, but the JIT finally pays off

    Miguel Grinberg ran his annual release-eve benchmark, comparing Python 3.15.0rc3 against every interpreter back to 3.10, plus PyPy, Node.js, and Rust, using his usual two CPU-bound programs: recursive Fibonacci and bubble sort. The standard 3.15 interpreter lands within noise of 3.14 on his workloads, while the experimental JIT build is roughly 20 to 28 percent faster and finally beats the standard interpreter, which has not happened before. The free-threaded build holds up well in the 4-thread tests. He is candid that the workloads are just Fibonacci and bubble sort, and the official release lands days after his measurements.

    It is an independent, workload-based counterpoint to the official 7-8 percent JIT geometric-mean claim, from a series with real trend data back to 3.10.

    He did the same exercise for 3.12, 3.13, and 3.14, so there is a multi-year trend line to draw on.

    Methodology is two hand-picked CPU-bound programs, recursive Fibonacci plus bubble sort, not a pyperformance-style suite, which cuts both ways.

    PyPy 3.12 still runs circles around every CPython in the single-threaded tests, and Rust is about 77x faster on Fibonacci.

    The JIT gain is real in these numbers, but the JIT stays experimental, so he will not use it in production yet.

    Free-threaded fibo at 4 threads ran about 4.5x faster than the standard interpreter with the GIL.

    His verdict: not worth rushing an upgrade for speed alone, though lazy imports may tempt production projects.

    Carol #6: Transparent and trusted AI Our Way - Satyrn AI

    Paul Everitt, Georgi Ker and I were discussing Python, its community and AI back in March at the JetBrains PyTV event. Python is the foundational language for data science and AI tools. We wanted something that reflects the Python community's strengths: language and learning.

    Mission: https://satyrn.ai/mission/

    Python 3.15 trained model is on Hugging Face

    After Paul's Europython keynote, he asked for folks to join the community (think of it as a collective of individuals putting their talents together

    We used some of the organizational tips from Jupyter and JupyterHub's early days on scaling community and emphasizing leveling up individuals

    Paul will be keynoting in Africa and sharing progress made by a team of dedicated volunteers

    Putting AI tools and knowledge in the hands of Pythonistas makes good sense and over time will benefit people (A theme that I have spoken about since PyCon 2023 and most recently PyCon JP 2026

    Extras

    Michael:

    Adobe Creative Suite was mostly cloned in Rust

    ArtCraft released seven free, open-source desktop apps that mirror the Adobe lineup: PhotoCraft for Photoshop, VectorCraft, FilmCraft, LightCraft, PrintCraft, EffectCraft, and DesignCraft. Everything is written from scratch in Rust with WebAssembly builds for the browser, and developer Brandon Thomas says the apps are AI-built clean-room reimplementations, a claim Ars Technica covered alongside the predictable skepticism.

    The clean-room story matters: reimplementing Adobe from public specs and behavior with AI is legally defensible, and building the apps for agents to drive, not just humans, is a genuinely different design bet.

    PhotoCraft already shows real depth: layers, masks, adjustment layers, layer styles, and real PSD support, with over 1,700 tests and dual CPU and GPU compositors tested against each other.

    The agent story: an MCP server and JSON control protocol let an agent headless-edit documents or drive the live app, useful for bulk edits and first drafts.

    Tradeoffs are real: reviewers call most of the apps super early alpha, and trade dress claims from Adobe remain a live legal risk even for clean-room code.

    Sustainability matters: the founder says token sales from their ArtCraft AI model fund the work so it does not become an orphaned small-team project.

    What happens when open-source alternatives that once took years of community work can be built by a model in weeks?

    Reminds me of the chardet story we covered awhile ago. The reason I put this topic here is I think it encapsulates a lot of what's happening in the industry for devs now. Building software has changed, creating is easy - sustaining is hard, owning an idea is more fleeting than before, Rust obviously, MCP and CLIs. It's just an interesting bridge from the first 500 episodes and the next 500 likely.

    Calvin:

    https://www.llmfit.org/) see what models can run on your hardware!

    uv 0.13.0 makes Python 3.15 the default!

    Nick:

    Black Python Devs:

    https://blackpythondevs.org/student-ambassador-program/100-campus-tour-campaign/

    Brett:

    Python 3.15.0 final is out!

    Joke:

    Exceptional by Derrick Chambers

    Interviewer: It says here on your résumé that you’re an “exceptional Python developer.” Can you prove it?

    Me: Sure. Run any of my code. It raises exceptions a lot of the time.
  • Python Bytes

    #499 So many questions??

    10/06/2026 | 32 mins.
    Topics covered in this episode:

    PEP 824 brings ?? and ??= to Python for None handling

    Python 3.15 gets a surprise RC3, and Python 3.10 reaches end of life

    asyncio.shield

    Pyxel: the retro game engine for Python

    Extras

    Joke

    Watch on YouTube

    About the show

    Sponsored by us! Support our work through:

    Our courses at Talk Python

    Consulting from Six Feet Up

    Connect with the hosts

    Michael: Mastodon / BlueSky / X / LinkedIn

    Calvin: Mastodon / BlueSky / X / LinkedIn

    Show: Mastodon / BlueSky / X

    Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Tuesday at 7am PT. Older video versions available there too.

    Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to our friends of the show list, we'll never share it.

    Michael #1: PEP 824 brings ?? and ??= to Python for None handling

    PEP 824, a new draft from Marc Mueller sponsored by Guido van Rossum, proposes None-coalescing operators for Python 3.16. The ?? operator returns its left-hand side unless that value is None, and ??= assigns a fallback only when the target is None. It revives the long-deferred PEP 505 from over a decade ago, trimmed to just these two operators, with None-aware access split off into PEP 823. The goal is replacing verbose is None checks with something closer to or, but keyed on None instead of truthiness.

    Every Python codebase has piles of if x is None fallback code, and this is the first serious move in ten years to give it real syntax.

    user.age ?? "unknown" is like or but only falls back on None, so 0, "", and [] pass through instead of getting clobbered

    user.name ??= "unknown" replaces the two-line check-then-assign pattern, with left-side subexpressions evaluated and cached exactly once

    Precedence sits between or and conditional expressions, matching JavaScript and C#, and ?? lands as a BoolOp in the AST next to and and or

    Unlike +=, ??= is a conditional assignment that skips the right side entirely, which is why it gets its own AST node rather than AugAssign

    Still draft status targeting 3.16, with a working reference implementation and an online demo to try, and it notably rejects a soft keyword like otherwise in favor of the familiar ??

    Discussion-worthy: the PEP answers the old objection that making None easier will proliferate its use, pointing out None is already everywhere and the status quo just produces uglier code

    # OG way
    user = db.get_user()
    city = None
    if user is not None:
    if user.address is not None:
    if user.address.city is not None:
    city = user.address.city

    # Michael's preferred way
    user = db.get_user()
    city = user?.address?.city

    Calvin #2: Python 3.15 gets a surprise RC3, and Python 3.10 reaches end of life

    The release team added a surprise third release candidate for Python 3.15 to fix last-minute lazy-import release blockers. They wanted time to test the fixes properly.

    That pushes the 3.15.0 final release from October 2 to October 9, 2026.

    RC3 has about 156 fixes from 82 contributors. The headline features are explicit lazy imports (PEP 810), the new frozendict (PEP 814) and sentinel (PEP 661) built-ins, and UTF-8 as the default encoding (PEP 686).

    No more ABI changes are coming, so library authors should be building 3.15 wheels now. uv 0.12.23 already added CPython 3.15.0rc3.

    On October 1, Python 3.10.22, 3.11.17, 3.12.15, 3.13.16 and 3.14.8 shipped together with nine common security fixes. They cover SSL validation, tarfile and zipfile handling, and urllib credentials.

    Python 3.10.22 is the final 3.10 release. After five years it gets no more security updates, so anyone still on 3.10 should upgrade.

    Python 3.13.16 is the last full maintenance release of 3.13, which now moves to security-only fixes. Only 3.13.16 and 3.14.8 have Windows and macOS installers, and the older releases are source-only.

    Python 3.11 gets security fixes through October 2027, and 3.12 through October 2028.

    A natural way to tie the two together: one version is nearly out the door and one is officially gone, and the same week is the time to test your code on 3.15 and move off 3.10.

    Michael #3: asyncio.shield

    Where async code can be cancelled

    In async Python, every await is a point where your coroutine can be stopped. If someone cancels the task, asyncio raises CancelledError at whichever await the coroutine is paused on, and nothing after that line runs.
    Quart does this on purpose. When the client disconnects, it cancels the request's task. From quart/asgi.py:

    elif message["type"] == "http.disconnect":
    self._disconnected = True
    request.body.disconnect()
    request_task.cancel()

    That's reasonable for a slow page nobody is waiting on anymore. It's a problem for a handler that writes to the database in two steps:

    await downloads.insert_one(event) # 1. log the download
    await totals.update_one(..., {'$inc': ...}) # 2. bump the episode's total

    A podcast app requests the MP3, gets what it needs, and hangs up. If it hangs up while step 2 is in flight, step 1 has already landed and step 2 never runs. Nothing is logged and nothing reaches Sentry, because a cancelled request isn't an error. The two collections just drift apart.
    Under WSGI this couldn't happen. A disconnect didn't stop your view; the view finished both writes and the server only failed later, when it tried to send the response.

    The demo

    I ran this on Python 3.14. The "client" hangs up 15 ms into a pair of 10 ms writes:

    async def record_download():
    await db_write('events')
    await db_write('total')
    _pending: set[asyncio.Task] = set()
    async def record_download_shielded():
    task = asyncio.create_task(record_download())
    _pending.add(task)
    task.add_done_callback(_pending.discard)
    await asyncio.shield(task)
    record_download events=1 total=0
    record_download_shielded events=1 total=1

    The unshielded version loses the increment. The shielded version finishes it, even though the request was cancelled. The full script is in the scratchpad as shield_demo.py if you want it for the show.

    What asyncio.shield does, and its traps

    shield(task) protects the inner task from a cancellation aimed at the outer one. The handler still gets CancelledError immediately, so nothing after that line runs, but the inner task keeps going until both writes finish. The traps:

    Keep a reference to the task. The event loop only holds weak references to tasks, so a task with no other reference can be garbage-collected mid-run. The asyncio docs warn about this. That's what _pending is for.

    Its errors go nowhere by default. If a shielded write fails after the handler has already been cancelled, nobody awaits the result. You only get a "Task exception was never retrieved" warning. Log errors from inside the task, or in the done callback.

    It doesn't survive a process shutdown. If the event loop is closing, as during a Granian worker recycle or a deploy, pending tasks are still cancelled. The window is tiny, but it isn't zero.

    It hides hangs. A shielded write to a stuck database lives forever. Put a timeout inside the shielded task (asyncio.timeout(...)), not outside it.

    It makes the pair finish, not atomic. A crash between the two writes still splits them. The real fix is one operation that can't half-happen. That's what the SQLite move gets: an insert and an upsert in one synchronous transaction, with no await in the middle. Shield is the right patch for the Mongo code until then.
    The general lesson: in async code, related writes made one after another are only as reliable as the client's patience. Before shipping something like that, check whether your framework cancels on disconnect. Quart does, and I believe Django 5's async views do too. I don't think Starlette cancels a plain endpoint, but I haven't checked any of these other frameworks' source, so verify them before you say it on air.

    Calvin #4: Pyxel: the retro game engine for Python

    Pyxel is a free, MIT-licensed retro game engine for Python, built and maintained by a single developer. It has been in development since 2018 and has passed 18,000 GitHub stars.

    It's modeled on classic game consoles and deliberately limits you to 16 colors and 4 sound channels, which keeps scope small and games finishable.

    Built-in editors cover pixel art, tilemaps, sound and music, so you can make the graphics, audio and game logic in one place.

    The engine is implemented in Rust and compiled to WebAssembly, but you write your games in plain Python.

    Pyxel Code Maker is a browser playground with a code editor, resource tools and a run button. It loads projects from local files, GitHub Gists or URLs, and saves back to a Gist for sharing.

    Games can also run on the web, so sharing one can be as simple as sending a link.

    It's a fun, low-barrier way into game development, good for beginners and for teaching kids.

    Extras

    Calvin:

    Python Lang Summit 2026 discusses a sys namespace

    Be Careful Updating Your Refrigerator
    Michael:

    New Siri is No Bueno

    Who out there is doing interesting work with sqlite and litestream? Trying to put an episode together on it.

    Tinymongo shoutout https://tinymongo.org

    Joke: I was there.
  • Python Bytes

    #498 A Tiny Episode

    09/29/2026 | 33 mins.
    Topics covered in this episode:

    MemTensor / MemoryOS PyPI package hijacked via a malicious build backend

    TinyMongo

    Jev: what to know

    One innocent dict read makes attribute access permanently slower

    Extras

    Joke

    Watch on YouTube

    About the show

    Sponsored by us! Support our work through:

    Our courses at Talk Python

    Consulting from Six Feet Up

    Connect with the hosts

    Michael: Mastodon / BlueSky / X / LinkedIn

    Calvin: Mastodon / BlueSky / X / LinkedIn

    Show: Mastodon / BlueSky / X

    Join us on YouTube at pythonbytes.fm/live to be part of the audience. Usually Tuesday at 7am PT. Older video versions available there too.

    Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to our friends of the show list, we'll never share it.

    Calvin #1: MemTensor / MemoryOS PyPI package hijacked via a malicious build backend

    On Sept 23 an attacker published backdoored MemoryOS 2.0.34 on PyPI and three bad versions (0.1.21, 0.1.23, 0.1.25) of MemTensor's OpenClaw plugin on npm. PyPI had no clean release that day, so 2.0.34 was the newest.

    They pushed commits to MemTensor's own GitHub Actions release pipelines. On PyPI that was a custom Poetry build backend, and on npm a tweaked validation script. Both used BASH_ENV to hand the publish token to the attacker before the real publish ran. SafeDep couldn't confirm how the attacker got push access.

    Runs on import, not install: A Go implant called sckit starts when the library loads, so --ignore-scripts won't save you.

    It harvests credentials from your home directory (npm and PyPI tokens, GitHub tokens, SSH keys, cloud CLI tokens, .env files) and sends them to skyleen[.]fr servers.

    It's a worm: It uses stolen tokens to copy itself into other repos and packages, so the victim list could grow.

    If you installed it: Downgrade to MemoryOS 2.0.33 (plugin 0.1.20) and rotate every credential reachable from $HOME. Also kill any running sckit stage0 process and check repos you can push to for a stray runtime-update.yml workflow or .sckit/ directory.

    Michael #2: TinyMongo

    Want to use a MongoDB data interface, but swap out the storage engine?

    Memory for testing/caching

    JSON/TinyDB simple JSON files

    SQLite for durable, high-perf reads with WAL

    SQLIte shared for high write apps

    DuckDB + Parquet for analytics apps

    Postgres + MariaDB for multi-machine client/server

    Great for teaching, examples, and simple deployments

    Amazing story of paired AI development

    Will completely run talkpython.fm after weeks of shared work together (in SQLite mode).

    Calvin #3: Jev: what to know

    What it is: Jev is a model from TypeSafe AI that answers with typed results (yes/no probabilities, scores, picks from your options) instead of prose. Real Python published a hands-on tutorial on 2026-09-24 and the buzz on hacker news is almost deafening.

    It's proprietary: Jev is a hosted, closed-weight model. There are no weights to download and no self-hosting. Everything called "open Jev" is an independent reimplementation, not TypeSafe's model.

    Your data leaves your machine: Every call sends your input text to a third-party API. In the tutorial that path goes through OpenRouter to TypeSafe. Think twice before sending customer messages, tickets or anything sensitive.

    Cost and stability are open questions: The tutorial calls Jev "cheap, but not free" and says it's fast and cheap "at the moment." It also says whether that stays true is "something to keep an eye on."

    Credit to Real Python: It's a good, practical intro. It shows the Noul, Score and Choice primitives, and its point that instruction wording matters more than thresholds is useful advice for any model. The tutorial itself says similar results are possible with a well-prompted LLM.

    Open options to look at instead:

    JevK5 (https://github.com/allebee/jevk5): Apache-2.0 weights and code, 4B or 9B parameters, and it accepts TypeSafe-style requests.

    SemIf, formerly OpenJev (https://github.com/TheoLeeCJ/openjev): MIT-licensed, small models, and it can run CPU-only.

    openjev-sglang (https://github.com/ekzhang/openjev-sglang): a Jev-compatible endpoint running Qwen3.6-35B-A3B, but no license is stated, so check before commercial use.

    The catch: These copy Jev's interface, not its model or training. Results will differ, and I haven't run any of them. Benchmarks are self-reported, and JevK5 is English-only.

    Michael #4: One innocent dict read makes attribute access permanently slower

    Timofei Ivankov benchmarks a CPython internals surprise: since 3.11, attribute access skips the instance dict entirely. A specialized opcode reads the attri.bute at a fixed byte offset in the object's inline values array. Read obj.__dict__ once, though, and the dict gets materialized, the object loses that specialized path for the rest of its life, and a million-iteration loop goes from 33 ms to 51 ms on CPython 3.14. vars() and copy.copy() trigger the same thing, so a debugging print or a shallow copy in code touching your hot objects quietly makes every later attribute access roughly 1.5x slower.

    The slowdown is permanent and nothing about it looks like a performance decision: ordinary code far from the hot loop can trigger it, and the function that gets slower never changes.

    Materializing dict produces a split table, and the LOAD_ATTR_WITH_HINT fallback declines split tables, so the object ends up with no specialization at all

    vars(), 'x' in o.dict, and copy.copy() all materialize it; copy.copy is the realistic trap since nobody treats a shallow copy as a performance decision

    slots instances read attributes at exactly the same speed and cannot fall into the trap since there is no dict to materialize

    On the free-threaded build both effects grow: atomic incref on reads plus an object lock on writes push the penalty from 17.6 to 25.4 ns

    Credit: this item was surfaced by the PyCoder's Weekly newsletter

    Extras

    Calvin:

    whatsnewt - a TUI text adventure through what's new in Python 3.15; playful but niche.

    Joke: Shipping a button in 2026…
  • Python Bytes

    #497 Faster than light profiling

    09/23/2026 | 26 mins.
    Topics covered in this episode:

    Tachyon: A sampling profiler ships in Python 3.15's stdlib

    Python Workers are now generally available on Cloudflare

    Flet 1.0 - build cross-platform apps in Python

    marimo-book: Build static books from marimo notebooks

    Extras

    Joke

    Watch on YouTube

    Sponsored by Logfire from Pydantic: pythonbytes.fm/logfire
    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: Tachyon: A sampling profiler ships in Python 3.15's stdlib

    Python 3.15 adds the profiling package per PEP 799: profiling.tracing (where cProfile moved) and profiling.sampling, the new sampler called Tachyon

    py-spy and Austin exist but copy raw interpreter bytes with no API, so every CPython release risks breaking them; one in the stdlib is a contract to stop breaking profilers

    Defaults: 1 kHz, main thread, wall clock, and a -live top-like view for poking at a slow server

    Output is flexible: pstats, -flamegraph, -diff-flamegraph against a baseline, -heatmap on source lines, -opcodes for specialized bytecode, -gecko for Firefox Profiler with GIL and GC markers

    Profiling modes: wall, cpu, gil (which function is starving my other threads?), and exception, plus -async-aware to see the task graph instead of just select(), -all-threads, and -subprocesses forking a profiler per child

    Near-zero overhead for production; guidance is 10-30 second windows on representative load, and free-threaded builds divide the rate by thread count

    Attach to a running PID, same minor version only; ptrace permissions are the main friction. A 3.14 backport already exists on GitHub

    Caveat: it only sees Python frames, so 90% in calculate() hides NumPy underneath. For native stacks there's Cronon from HRT, 200k samples/sec over DWARF, not yet open source

    Calvin #2: Python Workers are now generally available on Cloudflare

    Python Workers are out of beta - now GA, "first-class" language on Cloudflare's Developer Platform

    No more manual JS interop: bindings (queues, R2, D1, Durable Objects) now work natively in Python, e.g. self.env.QUEUE.send({...})

    Runs on Pyodide (WASM-compiled Python), with real TCP socket support for DB connectivity

    Frameworks supported: FastAPI, Django, Flask; AI libs like OpenAI SDK, LangChain, MCP

    Underlying platform work formalized as PEP 783 (PyEmscripten), after a year of discussion

    Bottom line: write real Python on Cloudflare's edge, no JS glue code required

    Calvin #3: Flet 1.0 - build cross-platform apps in Python

    Flet hits 1.0 - build Flutter-backed apps from pure Python, no frontend experience needed

    One codebase targets six platforms: iOS, Android, Windows, macOS, Linux, web

    150+ built-in UI controls, plus support for custom controls / wrapping Flutter packages

    Mobile now supports real Python packages: NumPy, pandas, Pillow, cryptography

    Comes with pytest-based UI testing and an MCP integration for AI coding assistants

    Milestone lands 4+ years after its first PyPI release (Sept 2022) - signals "production ready," not experimental

    Michael #4: marimo-book: Build static books from marimo notebooks

    marimo-book is a Jupyter-Book-style static site generator built specifically for marimo .py notebooks. It ships polished multi-page sites with Material for MkDocs theming, full-text search, dark mode, and code copy, plus a content-hashed incremental build cache that drops rebuilds from 100+ seconds to roughly 3 seconds on real books. Standout extras include anywidget rendering without a kernel, static reactivity for discrete sliders via pre-rendered lookup tables, an opt-in WASM/Pyodide mode per chapter, and per-chapter launch buttons.

    If you've wanted to publish a marimo notebook as a real book or course site without hosting a kernel, marimo-book gives you the static, searchable, fast-loading output you'd expect from Jupyter Book.

    Alpha (0.1.x), but in production: pin marimo-book>=0.1.5,<0.2; the book.yml schema is stable for v0.1, and dartbrains.org is a real-world user.

    Two-stage build by design: a marimo-aware preprocessor emits plain Markdown + inline HTML, then mkdocs (Material today, zensical tomorrow) renders it. Not a mkdocs plugin, so the shell stays swappable.

    Interactive widgets without a kernel: anywidget Canvas/Three.js/Plotly mounts render statically, and mo.ui.slider with explicit steps gets pre-computed as a static lookup table.

    WASM escape hatch per chapter: set mode: wasm and the chapter routes through marimo's MarimoIslandGenerator, shipping the marimo runtime + Pyodide bundle for full reactivity where you need it.

    Per-chapter launch buttons and extras: readers can jump to molab, GitHub, or a downloaded .py; optional [social], [linkcheck], and [pdf] extras cover OG cards, htmlproofer, and WeasyPrint PDF export.

    Sandboxed notebooks: the sandbox mode reads PEP 723 inline metadata and provisions per-notebook envs via uv for portable builds, at the cost of slower first runs.

    Extras

    Calvin:

    Great overview of a new feature in Python 3.15 - frozendict

    Michael:

    Microsoft Plugs Nearly 1,000 Security Holes in Windows

    I’ll be speaking at PyBay 2026

    PyCon NL on October 15 in Utrecht

    Heading to Europe in October? PyCon NL is October 15th in Utrecht. One day, three tracks, about 350 people. It's an hour by train from Schiphol. There's also a session just for community organizers from groups like PyLadies, PyData, and Django. And the location fits. The Netherlands is where Python itself was born.

    Joke: You have homework (no really ;) )

    Watch Interview with Big Data engineer in 2026 by Kai Lentit
More News podcasts
About Python Bytes
Python Bytes is a weekly podcast hosted by Michael Kennedy and Calvin Hendryx-Parker. The show is a short discussion on the headlines and noteworthy news in the Python, developer, and data science space.
Podcast website

Listen to Python Bytes, Pod Save America and many other podcasts from around the world with the radio.net app

Get the free radio.net app

  • Stations and podcasts to bookmark
  • Stream via Wi-Fi or Bluetooth
  • Supports Carplay & Android Auto
  • Many other app features