{"version":"https://jsonfeed.org/version/1.1","title":"Bernát Gábor — Python packaging, tox, virtualenv \u0026 open source","home_page_url":"https://bernat.tech/","feed_url":"https://bernat.tech/index.json","description":"Engineering notes from Bernát Gábor — PyPA maintainer of tox, virtualenv, pipx, filelock, and platformdirs. Python packaging, type hints, and supply chain security.","authors":[{"name":"Bernát Gábor"}],"language":"en-US","items":[{"id":"https://bernat.tech/posts/blazing-fast-html-parser/","url":"https://bernat.tech/posts/blazing-fast-html-parser/","title":"How turbohtml makes Python HTML work 3-22x faster","summary":"Python\u0026rsquo;s html.escape can scan one string five times. Moving those loops into C removes the interpreter from the hot path, which explains part of a 22x result on prose. Most prose contains nothing to escape. turbohtml gets the rest of the speedup by proving that sixteen bytes need no work, then moving past them in one step.\nI began with a small accelerator for html.escape and html.unescape . The Python implementation of escape runs up to five str.replace passes. unescape runs a regular expression and calls back into Python for each match in the 2,231-entry HTML5 entity table. html.parser.HTMLParser calls unescape for each text run it encounters, so both functions sit on hot paths. Interpreter dispatch explains the standard-library gap; its authors made reasonable choices under different maintenance constraints.\n","date_published":"2026-06-18T09:00:00Z","date_modified":"2026-08-08T21:31:13-07:00","tags":["python","c","performance","simd","html","parser","tokenizer","unicode","turbohtml","idna","pgo","lto","benchmarking"]},{"id":"https://bernat.tech/posts/blanket-deterministic-threading/","url":"https://bernat.tech/posts/blanket-deterministic-threading/","title":"Deterministic Multithreaded Testing in Python with blanket","summary":" TLDR:\nThe problem : testing multithreaded code is hard because the OS scheduler decides which thread runs when, making race conditions all but impossible to reproduce in a test suite. The solution : blanket wraps real threading primitives (Lock, Condition, Event, Barrier, Semaphore) and lets your test act as the scheduler, controlling which thread proceeds at each step. Why now : free-threaded Python (no GIL ) shipped as an experimental build in 3.13, is officially supported in 3.14 , and keeps maturing in 3.15 . The GIL was hiding thread-safety bugs you did not know you had; without it, they surface. How it works : every method call on a blanket primitive becomes a transaction that parks at a scheduler block. Your test unblocks transactions in whatever order you want, making execution 100% deterministic. What makes it different : unlike stateless model checkers (Loom , Shuttle , CHESS ) that discover bugs by exploring interleavings, blanket lets you declare specific scenarios by hand, useful for regression tests of known bugs and for full coverage of rare code paths. Most multithreaded Python codebases keep at least one test marked @pytest.mark.flaky(reruns=5): the one that fails once in a thousand because of a race condition you cannot reproduce on demand. The bug is a specific sequence of thread interactions. You do not get to pick the sequence; the OS scheduler does. You ship the retry and hope.\n","date_published":"2026-05-28T17:57:48Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","testing","concurrency","threading","free-threading","blanket","pycon","race-condition","gil"]},{"id":"https://bernat.tech/posts/pycon-us-2026-packaging-summit-recap/","url":"https://bernat.tech/posts/pycon-us-2026-packaging-summit-recap/","title":"PyCon US 2026 Packaging Summit Recap","summary":"The PyCon US 2026 Packaging Summit ran Friday May 15, 2026, from 1:45 PM to 5:45 PM in Room 201A of the Long Beach Convention Center. Three talks, nine lightning talks, six roundtable discussions. Organized by Pradyun Gedam , C.A.M. Gerlach , and Jannis Leidel . This recap is for anyone who could not be in the room.\nTLDR:\nEmma Smith\u0026rsquo;s revised PEP 777 (Wheel 2.0) is a minimal change with sub-PEPs layered on top; the first sub-PEP proposes Zstandard compression for ~25% smaller wheels. Mike Fiedler brought three PyPI abuse vectors (persistent state, open-ended releases, PyPI as a CDN), framed by 3× growth against 1× resources (~24,000 new packages per month, up from ~8,000) and a single full-time PyPI safety and security engineer. Mahe Iram Khan argued conda and pip are two parallel ecosystems, not two competing tools. Lightning talks: PEP 772 Packaging Council approved (Barry Warsaw), mobile wheel pipeline live (Malcolm Smith), Coherent + Compile-to-Flit (Jason Coombs), wheel variants for AI accelerators and shared malware scanning (Joongi Kim), conda-pypi (Daniel Holth), Nebi (Dharhas Pothina). Roundtables: PEP 803 abi3t , Wheel 2.0 hardening, cross-platform builds, CVE propagation, and nab (Damian Shaw\u0026rsquo;s pure-Python resolver aimed at pip swap-in). Involved in Python packaging? Consider running for the Packaging Council this fall or becoming a voting PSF member to nominate and vote. For background, I list the packaging-topic PEPs resolved in the year leading up to the summit (January 2025 through May 2026), newest first.\n","date_published":"2026-05-15T23:00:00Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","pycon","pycon-us","packaging-summit","packaging","pypi","wheel","pep-777","pep-694","pep-772","pep-817","pep-825","pep-803","conda","trusted-publishing","supply-chain","mobile","beeware","wheel-variants"]},{"id":"https://bernat.tech/posts/pycon-us-2026-typing-summit-recap/","url":"https://bernat.tech/posts/pycon-us-2026-typing-summit-recap/","title":"PyCon US 2026 Typing Summit Recap","summary":"The PyCon US 2026 Typing Summit ran Thursday May 14, 2026, from 1 PM to 5 PM in Room 201A of the Long Beach Convention Center, the day before the main conference started. Eight talks plus a Typing Council Q\u0026amp;A, single track. This recap is for anyone who could not be in the room.\nTLDR:\nGuido van Rossum argued that PEP 484 \u0026rsquo;s no-new-syntax rule is already broken in practice and that the field should weigh user pain over power features, citing the 2025 Python Typing Survey . Jelle Zijlstra proposed adding intersection and restricted-negation types to the typing spec, with an inhabitation check as the load-bearing new rule. Michael Sullivan presented PEP 827 (Vercel) for type manipulation, modelled on TypeScript\u0026rsquo;s conditional and mapped types. Douglas Creager showed how ty represents generic-call constraints internally with ternary decision diagrams, and a third solver strategy that fixes a 9-line partial(choose, None) example every production checker today gets wrong. Conner Nilsen presented a Pyrefly experiment with AI coding agents: type checking moves success on well-typed Meta code from 79.6% to 83.9% with 21% fewer steps; no measurable help on lightly-typed SWE-bench Verified. Avik Chaudhuri demoed tensor-shape types in Pyrefly, blocked in practice by PEP 695 \u0026rsquo;s eager evaluation of type parameters. Jia Chen presented a Lean 4 formalization (Featherweight Python) with mechanized soundness and decidability proofs; AI assistants turned what used to take years into weeks. The Typing Council panel (Carl Meyer, Jelle Zijlstra, Rebecca Chen on stage) opened the floor to attendee questions on governance, error-code consistency, metaprogramming, and the spec direction. Experiments with AI agents and Pyrefly type errors — Conner Nilsen Link to heading Conner (Meta, Pyrefly team) presented two questions: (1) does giving an AI coding agent a type checker help it finish tasks, and (2) does it prevent the agent from re-introducing old bugs while fixing new ones? His team ran two benchmarks with and without type-checker feedback and tracked three metrics: success rate, number of steps to completion, and wall-clock duration.\n","date_published":"2026-05-14T23:30:00Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","pycon","pycon-us","typing-summit","typing","type-hints","pyrefly","ty","astral","openai","meta","vercel","pep-827","intersection-types","constraint-sets","lean","tensor-types","pytorch","typing-council","guido"]},{"id":"https://bernat.tech/posts/pytexas-2026-recap/","url":"https://bernat.tech/posts/pytexas-2026-recap/","title":"PyTexas 2026 Recap","summary":"PyTexas is the annual Python conference held in Austin, Texas. The 2026 edition ran April 17–19 at the Austin Central Library in downtown Austin.\nTLDR:\nPyTexas 2026 ran April 17–19 in Austin. Friday was tutorials, Saturday and Sunday were talks with two keynotes and two lightning-talk blocks. A few themes kept coming back across unrelated talks:\nDesign deliberately. A thread across both keynotes. Hynek Schlawack: the domain model is \u0026ldquo;the precious\u0026rdquo; - design it first, translate at the edges. Dawn Wages: ownership over your stack as one of her three pillars for model and career specialization. Agents should write code, not decide what to write. Peter Sobot\u0026rsquo;s Seven Stages of AI Grief ended on that line. Al Sweigart argued \u0026ldquo;agentic engineering\u0026rdquo; is vibe coding with better marketing, and that almost-right is worse than wrong. Maria Silvia Mielniczuk\u0026rsquo;s MCP talk built the same idea into an architecture: models suggest, only the server executes. Adam Gordon Bell\u0026rsquo;s running coach split deterministic work (plain Python) from interpretation (LLM). The Sunday opener framed it: when AI ships a bad PR, fix the process, not the model. Code quality is an input to AI productivity. Miguel Vargas\u0026rsquo;s framing: AI agents produce cleaner, safer code in codebases that are already clean, safe, and typed, so Ruff, ty, and uv matter more now. The supply chain is still the attack surface. Christopher Ariza on why pip install still runs arbitrary code, with .pth files, sitecustomize.py, and setup.py as the specific places to pay attention. CPython itself is getting faster. Jacob Coffee on PEP 810 lazy imports for startup wins; Charlie Lin on the free-threaded build and what it takes to make an extension module safe under it. This post details the takeaways from each talk I attended, in schedule order.\n","date_published":"2026-04-19T22:00:00Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","pytexas","conference","austin","ai","llm","mcp","keynote","hynek","packaging","supply-chain","pep-810","free-threading","ruff","uv","ty","type-checking","observability","cli"]},{"id":"https://bernat.tech/posts/securing-python-supply-chain/","url":"https://bernat.tech/posts/securing-python-supply-chain/","title":"Defense in Depth: A Practical Guide to Python Supply Chain Security","summary":" TLDR:\nLayer your defenses and do not trust any single control. Use Ruff with security rules to catch bugs in your code before they ship. Pin all your dependencies with cryptographic hashes using uv lock or uv pip compile --generate-hashes so nobody can swap out packages on you. Run pip-audit in CI to catch known CVEs before they hit production. Generate SBOMs with CycloneDX so when the next Ultralytics-style compromise drops, you can answer \u0026ldquo;are we affected?\u0026rdquo; in minutes instead of days.\n","date_published":"2026-03-10T00:00:00Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","security","dependencies","supply-chain","sbom","pypi","pip"]},{"id":"https://bernat.tech/posts/version-numbers/","url":"https://bernat.tech/posts/version-numbers/","title":"Version numbers: how to use them?","summary":"The DRY principle (an acronym for don\u0026rsquo;t repeat yourself) encourages software engineers to abstract code into a separate component and reuse it rather than write it over and over again. If this happens across the system, the best practice is to put it inside a package that lives on its own (a library) and then pull it in from the applications when required.\nAs most of us can\u0026rsquo;t think of every feature that the library might offer or what bugs it might contain, these packages tend to evolve. Therefore, we need some mechanism to encode these evolutions of the library, and most commonly, this is a version number.\n","date_published":"2020-05-16T14:15:00Z","date_modified":"2026-07-10T18:47:45-07:00","tags":["python","version","semver","calver","0ver"]},{"id":"https://bernat.tech/posts/growing-pain/","url":"https://bernat.tech/posts/growing-pain/","title":"Python packaging - Growing Pains","summary":"In my previous two posts, I\u0026rsquo;ve gone over [what package types python has](https://bernat.tech/posts/pep-517-and-python-packaging/), and [how the package building works](https://bernat.tech/posts/pep-517-518/), especially with the introduction of the PEP-517/518. Although the changes were meant to make things more robust, we did run into a few issues while implementing and releasing them. The following are a few of those, serving as lessons learned for all of us and presenting some interesting problems to solve in the future.\n","date_published":"2019-02-07T13:41:03Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","packaging","pip","setuptools","pep517","pep518"]},{"id":"https://bernat.tech/posts/pep-517-518/","url":"https://bernat.tech/posts/pep-517-518/","title":"Python packaging - Past, Present, Future","summary":"Have you ever wondered what happens when you run pip install? This post gives a detailed overview of the steps involved in the past, and how it all changes with the adoption of PEP-517 and PEP-518.\n[In my previous post](https://bernat.tech/posts/pep-517-and-python-packaging/) I\u0026rsquo;ve described how it\u0026rsquo;s possible to install three types of content: source tree, source distribution, and wheels. Only the last two types are uploaded to PyPI, the central Python repository. However, one could get its hands on a source tree (by feeding, for example, a git protocol for pip). The advantage of wheels over the others is that it does not require any build operation to happen on the user machine; it\u0026rsquo;s a download and extract.\n","date_published":"2019-02-07T13:40:59Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","pip","install","packaging","setuptools","pep517","pep518"]},{"id":"https://bernat.tech/posts/pep-517-and-python-packaging/","url":"https://bernat.tech/posts/pep-517-and-python-packaging/","title":"The state of Python Packaging","summary":"pip 19.0 has been released on 22nd January 2019. On the feature list, most notably, it now supports PEP-517, which by default is turned on when that the project has a pyproject.toml at the root folder. The PEP in question has been created in 2015 and accepted in 2017. Even though it took a while until pip implemented it, the release and the issues that followed confirmed that many people are not familiar with it. Read on if you want a picture of how the Python packaging ecosystem evolved today and where we hope to see it down the line. The introduction of this python enhancement proposal may cause some discomfort, but we will benefit from it in the long term.\n","date_published":"2019-02-07T13:40:54Z","date_modified":"2026-07-10T15:27:11-07:00","tags":["python","packaging","pip","setuptools","pep517","pep518","wheel","sdist"]},{"id":"https://bernat.tech/posts/the-state-of-type-hints-in-python/","url":"https://bernat.tech/posts/the-state-of-type-hints-in-python/","title":"The state of type hints in Python","summary":"One of the main selling points for Python is that it is dynamically-typed. There is no plan to change this. Nevertheless, in September 2014 Guido van Rossum (Python BDFL ) created a python enhancement proposal (PEP-484 ) to add type hints to Python. It has been released for general usage a year later, in September 2015, as part of Python 3.5.0. Twenty-five years into its existence now there was a standard way to add type information to Python code. In this blog post, I\u0026rsquo;ll explore how the system matured, how you can use it, and what\u0026rsquo;s next for type hints.\n","date_published":"2018-05-30T09:51:55Z","date_modified":"2026-07-16T12:37:22-07:00","tags":["mypy","python","types","type-hint"]}]}