Python

What's New in Python 3.14: t-strings, Deferred Annotations, Official Free-Threading
5 min read

What's New in Python 3.14: t-strings, Deferred Annotations, Official Free-Threading

The practical changes in Python 3.14, released October 2025: t-strings that look like f-strings but produce template objects, deferred annotation evaluation becoming the default, what the free-threaded (no-GIL) build losing its experimental label means, multiple interpreters and Zstandard compression landing in the standard library, parenthesis-free except syntax, and the remote debugging interface — everything worth knowing before upgrading.

Deploying Python Web Apps to Production: gunicorn, uvicorn, systemd, Docker
5 min read

Deploying Python Web Apps to Production: gunicorn, uvicorn, systemd, Docker

From why the development server must never serve production traffic to the standard deployment stack: the WSGI and ASGI split, combining gunicorn with uvicorn workers, how to choose a worker count, managing the process with a systemd service, what the nginx reverse proxy is actually for, the basic shape of a Docker deployment, logs to stdout, health checks, and graceful shutdown — as a checklist.

Async Task Processing in Python with Celery: Queues, Workers, and an Ops Checklist
5 min read

Async Task Processing in Python with Celery: Queues, Workers, and an Ops Checklist

How to move work that never belonged inside a web request into Celery: the task-queue architecture of broker, worker, and result backend, defining tasks and calling delay, configuring retries with exponential backoff, the idempotency principle that follows from at-least-once delivery, operational settings like acks_late and time limits, monitoring with Flower, and when FastAPI BackgroundTasks or RQ is all you actually need.

SQLAlchemy 2.0 #7 Alembic and Production Setup: Migrations, Async, Team Rules
5 min read

SQLAlchemy 2.0 #7 Alembic and Production Setup: Migrations, Async, Team Rules

The series finale on operational topics: why create_all cannot handle schema changes and Alembic takes over, what autogenerate detects and what it misses, the review rules for migration files, going async with create_async_engine and AsyncSession and the lazy-loading restriction that comes with it, laying out models, sessions, and settings in a project, and the team rules worth enforcing.

SQLAlchemy 2.0 #6 Advanced Queries: Joins, Aggregation, Subqueries, Bulk Operations
5 min read

SQLAlchemy 2.0 #6 Advanced Queries: Joins, Aggregation, Subqueries, Bulk Operations

Building real-world queries on select() alone: the difference between scalars and execute return shapes, combining conditions with or_, joins and explicit ON clauses, reading group_by aggregates through labels, subqueries and EXISTS, LIMIT-OFFSET pagination and its limits versus keyset pagination, and bulk INSERT and UPDATE that bypass the ORM unit of work.

SQLAlchemy 2.0 #5 Relationships: One-to-Many, Many-to-Many, and the N+1 Problem
5 min read

SQLAlchemy 2.0 #5 Relationships: One-to-Many, Many-to-Many, and the N+1 Problem

The ORM at its best and its most dangerous — relationship(): how foreign keys and relationship() divide the work, declaring bidirectional one-to-many with back_populates, many-to-many through a secondary table, cascade and delete-orphan for parent-child lifecycles, spotting the N+1 problem that lazy loading creates by reading the echo log, and choosing between selectinload and joinedload to fix it.

SQLAlchemy 2.0 #4 The Session: Change Tracking, flush vs commit, and the Four Object States
5 min read

SQLAlchemy 2.0 #4 The Session: Change Tracking, flush vs commit, and the Four Object States

The heart of the ORM, the Session: how it batches changes as a unit of work and emits them as SQL, the difference between flush and commit, the four object states — transient, pending, persistent, detached — the identity map that returns the same object for the same row, why attribute access after commit triggers a new query, and the one-session-per-request scoping rule for web applications.

SQLAlchemy 2.0 #3 Defining ORM Models: DeclarativeBase, Mapped, mapped_column
4 min read

SQLAlchemy 2.0 #3 Defining ORM Models: DeclarativeBase, Mapped, mapped_column

The 2.0-style way of declaring tables as Python classes: the DeclarativeBase inheritance structure, how Mapped type hints and mapped_column divide the work, the rules mapping Python types to database types, how Optional drives nullable, declaring defaults, unique constraints, and indexes, and the naming convention that gives constraints predictable names from day one.

SQLAlchemy 2.0 #2 Engines and Transactions: Connection Pools and the Two Commit Patterns
5 min read

SQLAlchemy 2.0 #2 Engines and Transactions: Connection Pools and the Two Commit Patterns

The foundation of SQLAlchemy: engines and transactions. Why connection pools exist and how they behave, what pool_size and max_overflow actually limit, the commit-as-you-go and begin-once patterns split between connect() and begin(), why transactions never auto-commit, defining tables with MetaData and Table, and running CRUD with Core expressions.

SQLAlchemy 2.0 #1 The Big Picture: Core, ORM, and the 2.0 Style
5 min read

SQLAlchemy 2.0 #1 The Big Picture: Core, ORM, and the 2.0 Style

First post in a series covering SQLAlchemy, the de facto standard database library for Python, from the ground up: the two-layer structure of Core and ORM, why 1.x-era code and 2.0-style code look different, the unified select()-centric query style and type hint support, installation and the first connection, and running raw SQL with text().

Python Packaging #7 Team Conventions and Tool Choice: uv, poetry, pip
5 min read

Python Packaging #7 Team Conventions and Tool Choice: uv, poetry, pip

The series finale: tool choice and team conventions. uv, poetry, and pip+venv on one table with criteria that decide between them, the real cost of migration, caching and frozen verification in CI, the standard pattern for uv in Docker images, and a team convention checklist that survives new teammates — closing with a look back at the whole series.

Python Packaging #6 Publishing: Building Wheels and Uploading to PyPI
5 min read

Python Packaging #6 Publishing: Building Wheels and Uploading to PyPI

Switching from the receiving side to the making side: the workflow that turns your code into an installable package. The src layout and the role of build backends, the difference between sdist and wheel, building with uv build and rehearsing on TestPyPI before the real upload, tokenless deployment with GitHub Actions Trusted Publishing as the modern standard, and internal-only distribution alternatives.