Michael Kennedy's Thoughts on Technology

https://mkennedy.codes/posts

7 posts

Tech

Subscribe via RSS

  1. What the pls?

    tl;dr; The pls package on PyPI is an abandoned Python version (last released as v6.0.0 in 2023). The actively-developed pls was rewritten in Rust and now lives at pls-rs/pls. If you installed it with uv tool install pls or pipx install pls, you have the wrong one. Uninstall it and install the Rust build instead (e.g. brew install pls-rs/pls/pls). You may have heard me sing the praises of pls. I really love the icons and colors to disambiguate files and provide more information about them, the…

    0
  2. Cutting Python Web App Memory Over 31%

    tl;dr; I cut 3.2 GB of memory usage from our Python web apps using five techniques: async workers, import isolation, the Raw+DC database pattern, local imports for heavy libraries, and disk-based caching. Here are the exact before-and-after numbers for each optimization. Over the past few weeks, I’ve been ruthlessly focused on reducing memory usage on my web apps, APIs, and daemons. I’ve been following the one big server pattern for deploying all the Talk Python web apps, APIs, background se...

    0
  3. Raw+DC Database Pattern: A Retrospective

    TL;DR; After migrating three production Python web apps from MongoEngine to the Raw+DC database pattern, I measured nearly 2x the requests per second, 18% less memory, and gained native async support. Raw+DC delivered real-world performance gains, not just synthetic benchmarks. About a month ago, I wrote about a new design pattern I’m seeing gain traction in the software space: Raw+DC: The ORM pattern of 2026. This article generated a lot of interest and a lot of debate. The short version: i...

    0
  4. Fire and Forget at Textual

    If you read my Fire and Forget (or Never) about Python and asynchronous programming, you could think it’s a super odd edge case. But a reader/listener, Richard, pointed me at Will McGugan’s article The Heisenbug lurking in your async code. This is basically the same article, but in Will-style. Will does say “This behavior is well documented, as you can see from this excerpt.” True, but the documentation got this emphasis and warning in Python 3.12 whereas the feature create_task was added in ...

    0
  5. Replacing Flask with Robyn wasn't worth it

    TL;DR; I converted Python Bytes from Quart/Flask to the Rust-backed Robyn framework and benchmarked it with Locust. There was no meaningful speed or memory improvement - and Robyn actually used more memory. Framework maturity, ecosystem depth, and app server flexibility still matter more than raw benchmark numbers. Last week I played with the idea of replacing Quart (async Flask ) with Robyn for our bigger web apps. Robyn is built almost entirely in Rust, and in the benchmarks, it looks dram...

    0
  6. Use Chameleon templates in the Robyn web framework

    TL;DR; Chameleon-robyn is a new Python package I created that brings Chameleon template support to the Robyn web framework. If you prefer Chameleon’s structured, HTML-first approach over Jinja and want to try Robyn’s Rust-powered performance, this package bridges the two. People who have known me for a while know that I’m very much not a fan of the Jinja templating language. Neither am I a fan of the Django templating language, since it’s very similar. I dislike the fact that you’re mostly p...

    0
  7. Fire and forget (or never) with Python’s asyncio

    TL;DR; Python’s asyncio.create_task() can silently garbage collect your fire-and-forget tasks starting in Python 3.12 - they may never run. The fix: store task references in a set and register a done_callback to clean them up. Do you use Python’s async/await in programming? Often you have some async task that needs to run, but you don’t care to monitor it, know when it’s done, or even if it errors. Let’s imagine you have an async function that logs to a remote service. You want its executio...

    0