Python Bytes: #501 A Nod to Sir-Mix-Alot

Wait 5 sec.

Topics covered in this episode:Nod: pause your Python program and open a notebook at any linePolars 2.0 ships: streaming engine by default, spill-to-disk, and a row-order gotchadjango-cachalot caches your ORM queries and invalidates them for youTowards async transactions in DjangoExtrasJokeWatch on YouTubeAbout the showSponsored by us! Support our work through:Our courses at Talk PythonConsulting from Six Feet UpConnect with the hostsMichael: Mastodon / BlueSky / X / LinkedInCalvin: Mastodon / BlueSky / X / LinkedInShow: Mastodon / BlueSky / XJoin 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 lineNod (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 itInstall is pip install nodpy plus nod --install-kernel, then run with nod python -m myfileThe round trip back to source is the differentiator; markdown cells become comments, cells become newlines, and notebooks are disposable since the source file recreates themnodLog() stashes variable values across calls to explore later; the article also pitches notebook() for stepping through AI-generated code line by lineEarly stage: repo from December 2025 with 16 stars and essentially one contributor, so expect rough edgesCalvin #2: Polars 2.0 ships: streaming engine by default, spill-to-disk, and a row-order gotchaPolars 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 youdjango-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 DjangoCarlton 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.ExtrasCalvin: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/treemdMichael:Talk Python MembershipTalk Python Visual topic guidesQuick 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 RafaelFree Threaded Polars, but staled on PyPI?Joke: LGTM (Looks Good to Me) - Claude Opus 5.5 music video