MODERN PYTHON MICROSERVICE
Template for creating src-layout PEP628 compliant hexagonal python microservice.
Repo containing a template for creating a modern Python microservice. The template is designed to contain the important parts of a Hexagonal python microservice, with a minimal dockerfile and a CI workflow that builds and tests the service. It uses modern python standards, such as pyproject.toml and src-layout, and is designed to be easily extended. The contents of this README are an example of what you might expect to find in a well-documented service.
Depending on the source and sink you choose to read and write data from, environment variables will need to be set. The program will inform you of missing env vars, but you can also check the config for the given module.
Whether running via Docker or the Python package, available commands can be found with the command help
or the
--help
flag. For example:
$ package-name --help
# or
$ docker run ghcr.io/user/package-name:latest --help
The following terms are used throughout the codebase and documentation. They are defined here to avoid ambiguity.
- Ubiquitous Language - The language describing terms relevant to the bounded context of the service. These are high-level business descriptions of the function of the application, not code-specific terms.
Produced using exa:
$ exa --tree --git-ignore -F -I "*init*|test*.*"
./
├── Containerfile # Dockerfile for building the image
├── pyproject.toml # The build configuration for the service
├── README.md
└── src/
├── package_name/ # The python package
│ ├── cmd/
│ │ └── main.py # The entrypoint for the service
│ └── internal/ # Packages internal to the service. Akin to 'lib' folder
│ ├── config/
│ │ └── config.py # Configuration for the service
│ ├── models.py
│ ├── outputs/ # Holds subpackages for each data sink
│ └── service/ # Contains the business logic and use-cases of the application
package-name
is structured following principles from the hexagonal architecture pattern. In brief, this means a clear
separation between the application's business logic - it's Core - and the Actors that are external to it. In
this package, the core of the service is in internal/service/
and the actors are in internal/inputs/
and
internal/outputs/
. The service logic has no knowledge of the external actors, instead defining interfaces that the
actors must implement. These are found in internal/models.py
. The actors are then responsible for implementing these
interfaces, and are dependency-injected in at runtime. This allows the service to be easily tested and extended. See
further reading for more information.
Clone the repository and create and activate a new python virtualenv for it. cd
to the repository root.
Install the Python dependencies as shown in the section below.
Install the required python dependencies (including dev dependencies) and make it editable with
$ pip install -e .[dev]
This looks for requirements specified in the pyproject.toml
file.
Where is the requirements.txt file?
There is no requirements.txt
file. Instead, the project uses setuptool's pyproject.toml integration to specify
dependencies. This is a new feature of setuptools and pip, and is the
recommended way to specify dependencies.
See the setuptools guide and
the PEP621 specification
for more information, as well as Further Reading.
Ensure you have installed the Python requirements.
Run the unit tests with
$ python -m unittest discover -s src/package_name -p "test_*.py"
and the integration tests with
$ python -m unittest discover -s test_integration -p "test_*.py"
See further reading for more information on the src
directory structure.
This project uses Ruff for linting and autoformatting. It can be run whilst developing via
$ ruff check --watch --fix src
On packaging a python project using setuptools and pyproject.toml:
- The official PyPA packaging guide.
- A step-by-step practical guide on the godatadriven blog.
- The pyproject.toml metadata specification.
On hexagonal architecture:
- A concrete example using Python.
- An overview of the fundamentals incorporating Typescript
- Another example using Go.
On the directory structure:
- The official PyPA discussion on src and flat layouts.