1.10.0Note: You only have to do this once.
This project is meant to work with version 3.9.10 of Python. Before we even start,
we have to make sure that the right version is set. We highly suggest you to use
a version manager such as pyenv. For instructions on how to
install pyenv, check
pyenv's official documentation.
Note: Don't forget to run
source ~/.bashrcafter installingpyenv.
Once pyenv is installed, do the following (considering you're in the
project's root directory):
$ pyenv install 3.9.10
$ pyenv local 3.9.10
$ pyenv rehash
There should be now a file called .python-version with the content '3.9.10'.
It is always good to check if the Python version has switched correctly:
$ python --version
You should see an output like this:
Python 3.9.10
From now on, every Python-related command you use in this project (outside a virtual
environment, see below) should be provided by pyenv.
For instance, the output for the which pip3 command should be similar to this:
/home/john_doe/.pyenv/shims/pip3
When running a script in the project, call Python explicitly as in python main.py.
Do not make the script executable and then call it directly. The reason for
this is that calling it explicitly will use the Python version as defined by pyenv as expected.
If you run the script as an executable, it will check for system's Python
(possibly with the wrong version).
Troubleshooting: If you are having problems with pyenv, make sure you have the following line towards the end of your
.bashrcorbash_profilefile:eval "$(pyenv init -)"
In order to keep Python's version and related libraries under control, we use
virtual environments as provided by poetry.
It is a pretty common pattern in development with Python.
Poetry will automatically create a virtual environment in the .venv folder,
if it doesn't already exist, when running commands such as poetry install or
poetry shell.
To install poetry, run make install-requisites-locally.
To activate the virtual environment, run:
$ poetry shell
It should now include a (.venv) string at the beginning of your prompt. It
makes clear that you are running a virtual environment and so all your Python
commands will be provided by .venv.
From now on, every Python-related command you use in this project should be
provided by .venv. For instance, the output for the which pip3 command should be similar to this:
/home/john_doe/myproject/.venv/bin/pip3
When running a script in the project, call Python explicitly as in python main.py.
Do not make the script executable and then call it directly. The reason for
this is that calling it explicitly will use the Python version as defined by venv as expected.
If you run the script as an executable, it will check for system's Python
(possibly with the wrong version).
To deactivate the session, simply run:
$ exit
Note: DO NOT run deactivate (as you would with venv), otherwise you will have
to kill poetry shell.
To install the packages needed for development, run:
$ make install-deps-locally
We are currently using the following third-party packages:
psycopg2 version 2.7.3.1 or later (official site)sphinx version 1.6.3 or later (official site)sqlalchemy version 1.2.0b2 or later (official site)To check if the installation ran successfuly, try to import them (in the project's root directoy):
$ python -c "import psycopg2"
$ python -c "import sqlalchemy"
It should run successfuly (showing no output).
Note: Sphinx is actually used to generate documentation. It makes little sense to import it.
We use the standard unittest package to run tests. All tests go in the
tests/ directory with the filename pattern *_test.py. The main script for
tests is tests.py in the project's root directory and its configuration
file is config/tests.json.
Note: After making any modifications in the package, please, run the corresponding (all would be still better) tests.
For further information about unittest, check
unittest's official documentation.
If you want to test, say aggregator_test.py, you have two approaches:
tests.py script as follows:$ python tests.py aggregator_test.py
unittest on the test file in the
tests/ directory.$ python -m unittest tests/aggregator_test.py
You can also run multiple test modules, known as test suite, through
the tests.py script. Test suites are intended to group together tests
that are related to each other, for instance, by functionality.
In order to create a new test suite, add the test
suite name and a list of existing modules (from tests/) in the test_suites
field of config/tests.json.
For example, to run the test suite aggregator, do:
$ python tests.py aggregator
To run the suite integration of integration tests, do:
$ python tests.py integration
To run all tests, you also have two approaches:
tests/ is by calling the
tests.py script with no arguments:$ python tests.py
Note that this does not run the integration tests. To run them, you have to run
the integration suite specifically.
We are currently using Sphinx to document our project.
Documentation is in the docs/ directory, but it is generated mostly from the
docstrings in the Python code. The docstring format in use is the numpydoc.
The documentation is in reStructuredText format.
Please, keep the docstrings always up-to-date.
To generate the HTML files of documentation, run (in the docs/ directory):
$ make html
The generated code will be in the docs/_build/html/ directory.
One simple way to navigate through these files is creating an ephemeral server with
the SimpleHTTPServer Python built-in module. From the docs/_build/html/ directory, run:
$ python -m http.server
It will create a server on localhost:8000. You can check it out in your browser.
We also provide a bunch of Dockerfiles to build images of the applications. They are built upon the python image.
Refer to the Makefile section below to further details on the recommended way to run Docker.
An important subject is how to tag Docker images. Here we use the following patterns:
Local development images receive tag:
<app>-<full_version>-<revision>Stable releases receive tags:
<app>-<number_version><app>-<major_version><app>-<revision><app>-latestUnstable releases receive tags:
<app>-<full_version><app>-<revision>For instance, if the webhook app is at version 0.0.2-pre-alpha and current commit hash is 36fba5, local tags we be built as:
webhook-0.0.2-pre-alpha-36fba5The stable release will have tags:
webhook-0.0.2webhook-0webhook-36fba5webhook-latestAnd the unstable release will have tags:
webhook-0.0.2-pre-alphawebhook-36fba5There is also a staging tag that is intended for pre-release images.
The version is obtained from the
.versionfile.
You can also develop using a single Docker image. The actual code run is replaced by the code residing in the current directory of the project.
To build the development image manually, run:
$ docker build -f Dockerfile.development -t mconf/mconf-aggr:dev .
It is also nice to tag it as latest:
$ docker tag mconf/mconf-aggr:dev mconf/mconf-aggr:dev-latest
The easiest way however is to use the Makefile provided.
To build the development image using Docker, run:
$ make docker-build-dev
To run this image passing some other options to docker run use theEXTRA_OPTS
(for instance, for publishing ports), run:
$ make docker-run-dev EXTRA_OPTS="-p 8000:8000"
In order to shorten build time, we recommend using images based on a "dockerized" base image.
We use dockerize to generate configuration files from template files and environment variables in Docker containers. To do this, we need to install dockerize in the Docker image, a process that is time-consuming.
To make build time faster, you can build new base images with dockerize already included.
In the dockerize/ directory, there are two Dockerfiles:
Dockerfile.alpine.dockerize: builds alpine:latest-dockerize that is alpine:latest with Dockerize installed.Dockerfile.python3.dockerize: builds python:3.6-alpine-dockerize that is python:3.6-alpine with Dockerize installed.To make things easier, we provide a Makefile with the command docker-build. To build these
two dockerized images, you only need to run (from dockerize/):
$ make docker-build
You actually have to this to use the Makefile commands below since it is configured to build the final images from the dockerized base images.
To debug with vscode you must set launch.json which is the config file for debugging in vscode.
To debug aggregator, for example:
"version": "0.2.0",
"configurations": [
{
"name": "Python: Tests",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/tests.py",
"console": "integratedTerminal"
},
{
"name": "Python: Anexar",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
]
}
]
When it's done, make sure the image is built and run the container with makefile. After the container is up, the debugger will wait the attach to start running the service. Just click on "Start debugging" and a debug console should appears on your panel.
We use flake8 for linting, and black and isort for formatation.
To lint and format you can run make lint and make format.
Here is an example of .vscode/settings.json to use with Visual Studio.
{
"python.formatting.provider": "black",
"python.linting.enabled": true,
"python.linting.flake8Enabled": true,
"python.sortImports.args": ["--profile=black",],
"python.sortImports.path": "${workspaceFolder}/.venv/bin/isort",
"[python]": {
"editor.codeActionsOnSave": { "source.organizeImports": true },
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"editor.rulers": [ 88 ],
},
}
Some tasks can be done using the make utility. The most important ones are
shown below:
$ make run$ make docker-build$ make docker-build-dev$ make up$ make up-dev$ make docker-tag$ make docker-tag-unstable$ make docker-tag-latest$ make docker-push$ make docker-push-unstable$ make docker-push-latest$ make test$ make html$ make lint$ make format$ make cleanThe Makefile also provides sensitive defaults:
AGGR_PATH=<current_directory>
DOCKER_USERNAME=mconf
REPOSITORY=mconf-aggr
Content type
Image
Digest
sha256:57b4428e3…
Size
93.2 MB
Last updated
3 months ago
docker pull mconf/mconf-aggr