Python Best practice
I will present here the best practice when you are coding with Python. I will not speak about syntaxing but more the tools and code structure to follow.
Code Structure
Keep your code, tests, and configs separated:
my-project/
├── src/ # all your main code here
│ ├── __init__.py
│ ├── main.py
│ ├── utils.py
│ └── dataset/
│ ├── __init__.py
│ └── dataset_creation.py
├── tests/ # all tests in a parallel folder
│ ├── test_main.py
│ └── test_utils.py
├── requirements.txt # list of dependencies
├── README.md # project description and usage
├── .gitignore # files to ignore in git
Each file or folder should have one clear purpose:
- init.py → turns a folder into a Python package This file tells Python: “Hey, this folder can be imported as a module.”
Without it, you couldn’t do this:
from src.utils import my_function
- main.py → entry point of the app
- utils.py → helper functions, a place for small, reusable functions like logging, connecting to APIs, etc.
- dataset/ → logic related to dataset creation
- tests/ → unit tests to check your code works
- requirements.txt, list of dependencies
- .gitignore
Virtual Environments
Each project may need different versions of libraries. A virtual environment keeps them separate, so no version conflicts.
How to create one venv and activate
python3 -m venv .venv
source .venv/bin/activate # on macOS / Linux
Then install dependencies inside it:
pip install -r requirements.txt
Deactivate it when done:
deactivate
Best practice:
- Always have one virtual environment per project
- Add .venv/ to your .gitignore
- Never commit dependencies, only requirements.txt or pyproject.toml
Dependency management and versioning
Use pinned versions Specify exact versions so builds are reproducible
boto3==1.35.3
pandas==2.2.2
Then, when you want to update safely:
pip list --outdated
pip install -U boto3
pip freeze > requirements.txt
Application versioning and pyproject.toml
pyproject.toml is a configuration file for Python projects. Think of it as a central hub where you can define:
- Your project metadata (name, version, description, authors…)
- Dependencies your project needs
- Configuration for tools like linters, formatters, testing, type checking, etc.
It’s like a settings panel for your Python project.
Use Semantic Versioning (SemVer) insde this file and update after each big change: MAJOR.MINOR.PATCH → 1.2.3
Example:
1.0.0 → First stable release 1.1.0 → New features (no breaking change) 1.1.1 → Bug fix
vim pyproject.toml
[project]
name = "ai-writer"
version = "0.1.0"
description = "Python project to read ebooks, create datasets, and upload to MinIO"
authors = ["Julien <you@example.com>"]
dependencies = [
"boto3==1.40.61",
"botocore==1.40.61",
"EbookLib==0.20",
"jmespath==1.0.1",
"lxml==6.0.2",
"pi==0.1.2",
"PyPDF2==3.0.1",
"python-dateutil==2.9.0.post0",
"s3transfer==0.14.0",
"six==1.17.0",
"urllib3==2.5.0"
]
[tool.black]
line-length = 88
target-version = ['py310']
[tool.ruff]
line-length = 88
select = ["E", "F", "I"]
exclude = ["tests", ".venv"]
[tool.bandit]
targets = ["src"]
exclude = [".venv", "tests"]
severity-level = "medium"
confidence-level = "medium"
[tool.pip-audit]
requirement-files = ["requirements.txt"]
[tool.isort]
profile = "black"
Here
Linting — catch errors and bad patterns
Linters check for code smells, unused imports, bad syntax, etc.
Popular tools
- Flake8 → lightweight and standard
- Ruff → very fast modern linter (recommended)
- Pylint → very strict, useful for large projects
Example (Ruff)
pip install ruff
ruff check src/
Best practice: run ruff in CI before merging to main.
Security and vulnerabilities
Use pip-audit to find vulnerabilities in dependencies.
Installation:
pip install pip-audit
(venv) jusi@Juliens-MacBook-Air src % pip-audit
Found 1 known vulnerability in 1 package
Name Version ID Fix Versions
---- ------- ------------------- ------------
pip 25.2 GHSA-4xh5-x5gv-qwph 25.3
Automate all with pre-commit hooks
Pre-commit runs checks before commits, perfect for linting and formatting.
Installation:
pip install pre-commit
Create .pre-commit-config.yaml:
repos:
# Formatter
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
# Linter
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.1
hooks:
- id: ruff
# Dependency vulnerability
- repo: https://github.com/pypa/pip-audit
rev: v2.7.3
hooks:
- id: pip-audit