Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
344: Writing a pyproject.toml
For a long time, the Python ecosystem had a bit of a "too many cooks" problem when it came to packaging. If you've been around the block, you remember the chaos: a requirements.txt for your dependencies, a setup.py for your installation logic, a setup.cfg for some of the static metadata, and maybe a MANIFEST.in just to make sure your README actually got included in the build. It was a fragmented mess that required you to execute a Python script just to find out what a package's name was.
The sprawl of setup.py and requirements.txt
Let's say you're building a small utility called pdf-summarizer. In the old, naive way, you'd probably create a requirements.txt file listing pypdf and openai. Then, you'd write a setup.py that looks something like this:
from setuptools import setup
setup(
name="pdf-summarizer",
version="0.1.0",
install_requires=[
"pypdf>=3.0.0",
"openai>=1.0.0",
],
# ... more boilerplate
)
The problem here is that setup.py is an executable script. To know the dependencies of your project, a tool has to actually run that code. This is a security nightmare and a performance drag. Plus, having your dependencies split between a text file for your environment and a Python script for your distribution is just asking for a version mismatch. I've lost more hours than I care to admit debugging why a package worked in my local venv but crashed on a colleague's machine because requirements.txt and setup.py had drifted apart.
Consolidating the truth into pyproject.toml
The modern approach—standardized via PEP 518 and 621—is to use pyproject.toml. Instead of executing a script, we use a declarative configuration file. It's essentially the "single source of truth" for your project. For our pdf-summarizer, the configuration now lives in a clean, readable TOML format:
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "pdf-summarizer"
version = "0.1.0"
description = "A simple tool to summarize PDFs using AI"
dependencies = [
"pypdf >= 3.0.0",
"openai >= 1.0.0",
]
[project.optional-dependencies]
dev = ["pytest", "black", "ruff"]
Notice how we've eliminated the need for requirements.txt entirely for the base installation. The [project] table is standardized; whether you use Setuptools, Flit, or Hatch, they all look for these same keys. I love this because it decouples the project metadata from the tool used to build it. If I decide I hate Setuptools and want to switch to Poetry or PDM, I don't have to rewrite a complex Python script; I just change the [build-system] section.
When the build system actually matters
You might wonder if this is just "moving text from one file to another." In a way, it is, but the trade-off is in tool interoperability. Modern Python tools—like Ruff for linting or Black for formatting—now use pyproject.toml to store their own settings. Instead of having a .ruff.toml, a .black.toml, and a pytest.ini cluttering your root directory, you can just add a [tool.ruff] section to your existing TOML file.
It cleans up your workspace and makes the project much more approachable for a new contributor. They don't have to hunt through five different hidden dot-files to figure out how the project is configured; they just open one file and see the dependencies, the version, and the tool settings in one glance. It's a shift from "imperative" packaging (do this, then that) to "declarative" packaging (this is what the project is).
📋 Practical Task
Configure the "Weather-Alert-Notifier" Project
You have been handed a project called weather-alert-notifier. Currently, it has a messy requirements.txt containing requests and python-dotenv. The developer also wants to include pytest and mypy as optional development dependencies.
Your task is to create a pyproject.toml file that replaces the need for requirements.txt. Ensure you include:
- A
[build-system]section usingsetuptools. - A
[project]section with the name, a version of1.2.0, and the core dependencies. - A
[project.optional-dependencies]section calleddevfor the testing and typing tools.
There are no comments for now.