Project Structure
A clean project structure helps people understand where things belong.
When a project is small, it may be tempting to put everything in one file. That can work for experiments, but it usually becomes difficult to maintain as the project grows.
This guide uses a simple structure that can grow gradually.
The current structure
The repository currently uses this structure:
modern-python-project-guide/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── learning_feedback.yml
│ │ └── problem_report.yml
│ ├── workflows/
│ │ ├── ci.yml
│ │ └── pages.yml
│ └── pull_request_template.md
├── docs/
│ ├── 00_why_this_guide.md
│ ├── 01_project_structure.md
│ ├── index.md
│ └── ...
├── src/
│ └── text_toolkit/
│ ├── __init__.py
│ └── text_stats.py
├── tests/
│ └── test_text_stats.py
├── .editorconfig
├── .gitignore
├── .python-version
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── mkdocs.yml
├── pyproject.toml
└── uv.lock
The repository was built step by step, with each part introduced when it became useful.
Why use separate directories?
Different files have different responsibilities.
A clear structure makes those responsibilities visible.
docs/
The docs/ directory contains guide chapters and explanations.
It is used for human-readable documentation, not Python source code.
Examples:
docs/00_why_this_guide.md
docs/01_project_structure.md
docs/02_uv.md
docs/index.md
The index.md file is the landing page for the generated documentation site.
src/
The src/ directory contains the actual Python package code.
This guide uses the src/ layout:
src/text_toolkit/
The src/ layout helps separate project source code from configuration files, tests, documentation, and other repository files.
It also makes imports more realistic, because the package has to be discovered properly instead of being accidentally imported from the current working directory.
tests/
The tests/ directory contains automated tests.
Tests should be separate from the implementation code.
Example:
tests/test_text_stats.py
Keeping tests in a dedicated directory makes them easier to find and run.
.github/
The .github/ directory contains GitHub-specific files.
This may include:
- pull request templates,
- GitHub Actions workflows,
- issue templates.
Example:
.github/pull_request_template.md
.github/ISSUE_TEMPLATE/learning_feedback.yml
.github/ISSUE_TEMPLATE/problem_report.yml
.github/workflows/ci.yml
.github/workflows/pages.yml
The CI workflow validates pull requests and main. The Pages workflow publishes
the documentation after relevant changes reach main. The issue forms help
learners provide structured feedback without needing to design an issue report
from scratch.
mkdocs.yml
The mkdocs.yml file defines the documentation site, including its navigation,
theme, and validation settings.
MkDocs reads the Markdown sources from docs/ and writes generated HTML to the
ignored site/ directory.
pyproject.toml
The pyproject.toml file is the central configuration file for a modern Python project.
In this guide, it contains:
- project metadata,
- Python version requirements,
- build system configuration,
- dependency configuration,
- pytest configuration,
- mypy configuration,
- coverage configuration,
rumdlconfiguration,- Ruff configuration.
Keeping these settings together makes the project easier to inspect and maintain.
uv.lock
The uv.lock file records exact dependency versions.
It helps make installations reproducible across machines and continuous integration environments.
It is generated by uv and committed to the repository.
Why not start with everything?
A common beginner mistake is copying a large project template without understanding it.
This guide avoids that.
Each file and directory should appear for a reason.
The goal is not to create the biggest possible project structure.
The goal is to create a structure that is simple, useful, and understandable.
Rule of thumb
A good project structure should help answer these questions:
- Where does the application code live?
- Where do the tests live?
- Where is the documentation?
- Where is the project configuration?
- How can another person run and check the project?
If the structure answers these questions clearly, it is doing its job.