Python Logging Done Right

I have never once, in production, wished I had more print() statements to grep through. What I have wished for, repeatedly, at 2am, is a log line that included a request ID, a timestamp in a sane timezone, and a severity level I could filter on. The standard library’s logging module gives you all of that for free. Most people just don’t use it that way, they call logging.info("here") a few times, never touch the configuration, and end up with something barely better than print. This article is about the difference between using logging and using it well. ...

August 25, 2026 · 10 min

Building a CLI Tool in Python: Publishing to PyPI

In part 1 we built taskcli’s command structure with Typer. In part 2 we added persistent storage and a pyproject.toml that makes pip install -e . work locally. The last step is making taskcli installable by anyone, anywhere, with a plain pip install taskcli. That means publishing to PyPI, the Python Package Index. What “publishing” actually means PyPI hosts two kinds of build artifacts for every release: A wheel (.whl), a prebuilt, ready-to-install package. pip prefers this when one is available for the user’s platform. A source distribution or sdist (.tar.gz), the raw source plus enough metadata to build a wheel from scratch. pip falls back to this if no matching wheel exists. For a pure-Python tool like taskcli (no compiled extensions), a single wheel works on every platform. Publishing is: build both artifacts, then upload them. ...

August 19, 2026 · 7 min

Building a CLI Tool in Python: Config Files & Packaging

In part 1 we built taskcli, a command-line task tracker, using Typer for argument parsing and subcommands. It works, but every task vanishes the moment the process exits, and there’s no way to install taskcli as a real command on your system. This part fixes both: we’ll persist tasks to a proper data file and package the project with pyproject.toml. Where should data live? The instinct is to write a tasks.json file next to the script. That breaks the moment someone runs taskcli from a different directory, since relative paths resolve against the current working directory, not the tool’s location. ...

August 5, 2026 · 6 min

Building a CLI Tool in Python: Structure & Typer

Every Python developer eventually writes a script that starts as a single if __name__ == "__main__": block and grows into something that needs subcommands, flags, help text, and configuration. The difference between a script and a real CLI tool is structure: how you parse arguments, how you organize commands, and how you keep the whole thing testable as it grows. This is part one of a three-part series where we build a real CLI tool from scratch. By the end of this series you’ll have a tool that’s structured cleanly, reads configuration files, and is published to PyPI so anyone can pip install it. This part covers project structure and argument parsing with Typer. ...

August 4, 2026 · 7 min