Saltar al contenido
PodcastsNoticiasPython Bytes

Python Bytes

Michael Kennedy and Calvin Hendryx-Parker
Python Bytes
Último episodio

501 episodios

  • Python Bytes

    #500 Episode 500!

    14/10/2026 | 1 h 8 min
    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??

    06/10/2026 | 32 min
    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

    29/09/2026 | 33 min
    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

    23/09/2026 | 26 min
    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
  • Python Bytes

    #496 A lake house in Seattle

    15/09/2026 | 32 min
    Topics covered in this episode:

    Pandas Should Go Extinct

    Pydantic-pint puts real-world units in your Pydantic models

    How Libraries Run Rust Inside Python (With PyO3)

    AWS acquires DuckLabs

    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 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: Pandas Should Go Extinct

    Pandas' slowness pushes teams toward "Big Data" tools (Spark, Databricks) they don't actually need — most workloads never hit true Big Data scale

    Amazon Redshift telemetry: ~95% of tables are under 100GB, ~87% of queries touch 80GB or less — that's "Medium Data," not Big Data

    Polars and DuckDB fill that gap: single-machine, fast, no cluster required

    1 Billion Row Challenge benchmark: Pandas took 4m28s vs. Polars 5.04s and DuckDB 5.19s — DuckDB also used 19x less memory

    On a real-world NYC taxi dataset (3GB parquet), pure DuckDB ran 2x faster than pure Pandas while using a fraction of the RAM

    Bonus: Apache Arrow lets you pass data between Pandas/Polars/DuckDB with zero copying, so trying them out doesn't mean a full rewrite

    Michael #2: Pydantic-pint puts real-world units in your Pydantic models

    Pydantic-pint bridges Pydantic and Pint so models can validate physical quantities like 4m or 12 meters instead of bare floats. Fields annotated with PydanticPintQuantity parse user input, convert between compatible units, and serialize quantities back out as strings. That closes a real gap for anything consuming API payloads, config files, or sensor data with measurements, letting you enforce units at the validation boundary instead of hoping every caller remembered them.

    via PyCoder's Weekly newsletter

    Unit mix-ups have literally crashed spacecraft; now your Pydantic models can refuse them at the door.

    Annotate a field as Annotated[Quantity, PydanticPintQuantity('km')] and inputs like 12 meters arrive auto-converted to kilometers

    Validation covers string, numeric, and quantity inputs, and model_dump_json serializes quantities as readable unit strings

    Installable from PyPI as pydantic-pint, MIT licensed, with docs at pydantic-pint.readthedocs.io

    Early-stage solo project at version 0.4, so API stability and maintenance are open questions worth discussing

    Calvin #3: How Libraries Run Rust Inside Python (With PyO3)

    Pydantic v2's validation core (pydantic-core) is Rust under the hood, built with PyO3 — this post shows how that bridge actually works via a small hand-built JSON parser

    Four steps to get Rust into Python: write a normal Rust module, annotate with PyO3 macros (#[pyfunction], #[pymodule]), compile/install with maturin, then just import it

    The parser builds a Rust tree first — Python never touches it until the boundary crossing

    Key insight: converting the Rust result into Python objects (.into_pyobject) is often the expensive part, not the parsing — 100,000 JSON values means ~100,000 Python objects built after parsing's already done

    Errors cross the boundary too: Rust's typed errors convert into real Python exceptions (ValueError, FileNotFoundError) via From/?, so callers get clean Python semantics

    Takeaway for anyone porting Rust in: if you're returning a scalar, don't sweat it; if you're returning a big structure, profile the boundary — that's the real cost, not the algorithm

    Michael #4: AWS acquires DuckLabs

    Thank you Dylan McConnell.

    What does this mean for the DuckDB ecosystem?

    DuckDB is the open-source in-process analytical SQL engine. MIT licensed. The IP is not owned by any company - it's held by the nonprofit DuckDB Foundation, which was created when the team spun out of CWI Amsterdam. Peter Boncz, the CWI representative on the Foundation board, describes it as the entity that holds all IP of open-source DuckDB.

    DuckLabs (ducklabs.com) is the company, formerly branded DuckDB Labs. Founded a little over five years ago by Hannes Mühleisen and Mark Raasveldt to give the DuckDB team a stable long-term home, bootstrapped deliberately instead of taking VC, grown to 30+ people in Amsterdam, funded by support and feature-prioritization contracts. It employs the core devs. It does not own DuckDB.

    DuckLake is one of three projects DuckLabs builds, what they call the Duck Stack: DuckDB, DuckLake, and Quack. DuckLake is the lakehouse format that puts catalog metadata in a SQL database instead of in files on object storage. Quack is newer - an RPC-style protocol that turns DuckDB into a client-server system where both ends are DuckDB instances, slated to stabilize in DuckDB v2.0 in September 2026.

    MotherDuck is a separate Seattle company, Jordan Tigani's, selling serverless hosted DuckDB. It was started in partnership with DuckDB Labs and has worked closely with Hannes and Mark for four years. It contracted DuckLabs for engineering work and contributes heavily upstream - three of its engineers are among the top 10 outside contributors to DuckDB. It also sells its own DuckLake offering. Customer and collaborator, never owner.

    What the AWS post changes. Amazon bought the company, not the project. DuckLabs joined AWS effective September 1, with the process concluding August 31, 2026. Hannes and Mark keep leading the team and the project's technical direction, the team stays in Amsterdam, and DuckDB stays MIT under the Foundation. AWS gets the people and a direct line to the roadmap. The license protects your code, not your priorities.

    Three second-order effects worth tracking:

    The Foundation board is the real question. It has three directors: Mühleisen, Raasveldt, and Boncz. Two now work for AWS. Commentary on the deal has focused on exactly this - the license protects the code, not the roadmap. The announced counterweight is governance: a technical advisory board on the Foundation, and opening the extension stack so extensions signed by other developers can run in DuckDB.

    MotherDuck immediately moved into the business DuckLabs vacated. It now sells DuckDB enterprise support, which it had avoided because it didn't want to compete with DuckLabs' business model, and says it has explicit blessing from Hannes and Mark now that they're joining Amazon. It also bought Tower.dev the day before the AWS announcement.

    Everyone expects an AWS DuckDB service. Tigani says Amazon will likely release one eventually, and welcomes the competition, citing Redshift's failure to slow Snowflake on AWS. The groundwork is already visible: Amazon Quick uses DuckDB to query S3 Tables and has processed over 2.5B queries with it since launching in October 2025.

    The DuckLake angle is the one to watch. AWS is heavily committed to Iceberg through S3 Tables, and it just acquired the team behind a competing lakehouse format. The stated plan is to use DuckDB, DuckLake, and Quack together to power a new generation of data services, but which format wins internal priority is unannounced.

    Extras

    Calvin:

    astral-sh/uv 0.12.12: code-signed release binaries 🥳

    Michael:

    My MacBook power supply rebooted to install updates (?!?)

    The Story of VS Code | Official Documentary

    Amazon/AWS acquires DuckLabs (see recent episode on DuckLake)

    Joke: We’re agentic now
Más podcasts de Noticias
Acerca de 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.
Sitio web del podcast

Escucha Python Bytes, Es la Mañana de Federico y muchos más podcasts de todo el mundo con la aplicación de radio.es

Descarga la app gratuita: radio.es

  • Añadir radios y podcasts a favoritos
  • Transmisión por Wi-Fi y Bluetooth
  • Carplay & Android Auto compatible
  • Muchas otras funciones de la app