Python
- Version
- The version of Python used SHOULD be 3.11 or above
- The version of Python used MUST be 3.8 or above
- Python projects SHOULD use one of the TNA base Docker images
- Style/linting
- Python code MUST be styled with Black, Flake8 and isort
- The maximum cyclomatic complexity of the code MUST be no larger than 20
- The maximum cyclomatic complexity of the code SHOULD be no larger than 12
- Line lengths SHOULD NOT exceed 80 characters
- Absolute imports SHOULD be used
- Relative imports COULD be used for importing files within the same directory
- Dependencies
- Python dependencies SHOULD be managed using Poetry
- Frameworks, tools and libraries
- Python applications MUST use one of the approved frameworks
- Packages
- Python packages SHOULD be made using pip
- Python packages SHOULD be deployed to PyPI
- Python packages COULD be hosted in AWS CodeArtifact
- Security
- A CSP SHOULD be set up
Frameworks
Use either Flask, Django or FastAPI for your Python applications.
Framework | Best choice for making |
---|---|
Flask | Applications with a UI |
Django | Applications that need to work with data and databases |
FastAPI | RESTful JSON APIs |
Application templates have been made for new projects to enable you to get started much quicker.
Tools and libraries
Some suggested tools and libraries for Python applications are:
Tool/library | Use case |
---|---|
Wagtail | Services that require a CMS |
WTForms | Validating form inputs from Flask applications |
flask-talisman | Adding a CSP and other security measures to Flask applications |
django-csp | Adding a CSP and other security measures to Django applications |
WhiteNoise | Serving static files in production from django.contrib.staticfiles |
Formatters and linters
Black
Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting.
To ensure compatibility with Flake8 (sometimes the two disagree) the following config can be used in a pyproject.toml
file:
[tool.black]
line-length = 80
include = '\.pyi?$'
Flake8
Flake8 is a Python linting tool that checks your Python codebase for errors, styling issues and complexity and follows the PEP 8 style guide for Python code.
The following configuration can be set in a .flake8
file to ensure all projects remain consistent and compliant with Black:
[flake8]
ignore = E203, E266, E501, W503, F403, F401
exclude = venv*,__pycache__,node_modules,migrations
max-line-length = 80
max-complexity = 12
select = B,C,E,F,W,T4,B9
max-complexity
will put a limit on the cyclomatic complexity of the code.
Note: you can also ignore rules on particular lines of code or files by adding a # noqa comment - see flake8's noqa syntax.
If using the tna-python-dev
Docker image, this Flake8 configuration is included.
isort
The order of the imports can be standardised with isort.
Add the following configuration to your pyproject.toml
file:
[tool.isort]
profile = "black"
Dev Docker image
The Dev Docker image comes preinstalled with Black, Flake8 and isort. It also includes all the relevant configurations.
You can use it to lint your code by mounting the container image with your project code in your docker-compose.yml
:
services:
dev:
image: ghcr.io/nationalarchives/tna-python-dev:latest
volumes:
- ./:/app
Now you can lint your code by running:
docker compose exec dev format
Alternatively, you can simply run format
inside the container.
Poetry
Poetry is a tool for dependency management and packaging in Python.
PEP 20 – The Zen of Python
If in doubt, consult The Zen of Python:
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!