Project Structure
Organizing your Python projects with a clear structure and modern tools makes your code easier to maintain, test, and share. Here's how I scaffold a project with a standardized layout, using pyproject.toml for configuration and uv for environment and dependency management.
Standard Project Structure
This layout separates source code, tests, documentation, and metadata:
myproject/
├── README.md
├── pyproject.toml
├── src/
│ └── myproject/
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ └── test_main.py
└── docs/
Key Points:
src/myproject/: All your Python source lives here.tests/: Your test code.docs/: Documentation.pyproject.toml: Project and dependency configuration.README.md: Project description.
Why pyproject.toml and uv?
pyproject.toml is the new standard for Python project configuration. It unifies settings for packaging, dependencies, formatting, and more. See the official documentation at Python packaging docs.
As covered in the Dev Environment chapter, uv is a fast Python package manager and virtual environment tool, compatible with PEP 508 dependency specification and pyproject.toml. It's a drop-in replacement for pip and virtualenv and simplifies managing a Python project.
Example pyproject.toml
[project]
name = "myproject"
version = "0.1.0"
description = "A sample Python project"
readme = "README.md"
requires-python = ">=3.10"
[project.dependencies]
rich = "^13.0.0"
[tool.pytest.ini_options]
pythonpath = ["src"]
addopts = "-ra"
Add any extra dependencies you need under [project.dependencies].
Using uv for a local environment
In your project directory, create a per project virtual environment:
uv venv
source .venv/bin/activate
Install dependencies from pyproject.toml:
uv sync
To add a new dependency, uv add will add to pyproject.toml and sync:
uv add requests
Use uv remove to remove a dependency:
uv remove requests
Run Your Code
For any new terminal session, be sure to activate your virtual environment (see Tips below):
source .venv/bin/activate
To run your code:
python src/myproject/main.py
Test Your Code
To run tests, first add pytest as a dev dependency:
uv add --dev pytest
This will add a section to pyproject.toml:
[dependency-groups]
dev = [
"pytest>=8.1",
]
To install dev dependencies use:
uv sync --dev
Run your tests using pytest that is now in your virtual environment:
pytest
Tips
- Use
uveverywhere you used to usepiporvirtualenv— it's much faster and uses yourpyproject.tomldirectly. - Keep dependencies declared in
pyproject.tomlfor reproducibility. - Check in your
pyproject.toml; never commit your.venv.
I use Starship.rs to customize my shell to display the current virtual environment in the command prompt, this lets me know if I've activated the correct virtual environment. See the Python section of the Starship.rs documentation for details.