Opinionated best practices when developing with Python.
Stop naming your python modules "utils"
- pydantic
- fastapi-
black
closes the topic of formatting and style of the code. Saves time during the PRs by avoiding repetitive discussions.mypy
makes the type annotations valuable and up to date. It helps to find the bugs, especially those related toNone
values.- pre-commit saves time by checking basic things (mypy, stylechecks) before pushing to CI and running expensive tests.
tox
, it simplifies CI configuration (scripts) and saves tons of time by ensuring that environment corresponds to what you have the requirements. Considertox-battery
to ensure thatrequirements
files for pip are checked and virtual environments are recreated.
The configuration
[mypy]
warn_unused_ignores = True
follow_imports = skip
show_error_context = True
warn_incomplete_stub = True
ignore_missing_imports = True
check_untyped_defs = True
cache_dir = /dev/null
# Cannot enable this one as we still allow defining functions without any types.
# disallow_untyped_defs = True
warn_redundant_casts = True
warn_unused_configs = True
strict_optional = True
For small projects we can always access evars (environment variables) with os.getenv
directly and that is ok.
I assume that for the small projects code base is in 1-2 modules and I can scan it every time I need to answer some question.
Services. In the era of services and micro-services the code base is slightly bigger than 2 modules and it would be nice to see how application is configured.
For that purpose I always use config.yml
file that is self-documented with the extensive comments, examples and structure.
The app is configured only by the configuration file, no other sources of configuration. It's how it appears to the code.
But we want to follow the 12 factors and configure our app with the environment variables.
Configuration can use substitution variables to access environment variables.
Example of the configuration.
web:
port: ${WEB_PORT:9090}
feature:
publish_events:
enabled: ${PUBLISH_EVENTS_ENABLED:False}
# TICKET-111: hot fix ...
hotfix_1:
enable: ${HOTFIX_111_ENABLED:False}
expire: 2020-09-08
From the configuration we can see all the evars that can be set and their usage context.
Test double from Martin Fowler
Keep doubles.py
and pytest_fixtures.py
in the package of a relevant domain. Usually I put it in the testing
package.
Example
Packageapp.currency
has
model.py
client.py
controller.py
testing
doubles.py
pytest_fixtures.py
Looks like this package is responsible for serviing currency-related logic in the app. We created testing
package that will contain
fakes for the client, different currency objects ready to be used in testing. pytest_fixtures
can be added as a plugin in pytest to access the fixture of a client, for instance.
Important that we can answer the questions like "Is there a test double I can reuse?"
- doctest