Python 3.9+.
It is best practice during development to create an isolated Python virtual
environment using the venv
standard library module. This will keep dependant Python packages from
interfering with other Python projects on your system.
On Linux and Unix (Mac):
# On Python 3.9+, add --upgrade-deps
$ python3 -m venv venv
$ source venv/bin/activate
On Windows Powershell / cmd
:
> py -m venv venv
> venv\Scripts\activate
Once activated, it is good practice to update core packaging tools (pip
,
setuptools
, and wheel
) to the latest versions.
(venv) $ python -m pip install --upgrade pip setuptools wheel
This project uses pip-tools to lock project dependencies and create reproducible virtual environments.
(venv) $ python -m pip install pip-tools
To cleanly install your dependencies into your virtual environment:
(venv) $ python -m piptools sync requirements/requirements.txt requirements/dev-requirements.txt
Note:
To update dependencies and add new requirements, modify the requirements.in
and dev-requirements.in
files in the folder requirements
:
(venv) $ python -m piptools compile --upgrade requirements/requirements.txt
(venv) $ python -m piptools compile --upgrade requirements/dev-requirements.txt
After successful installation and update of the virtual environment, pathpy
can
be installed in the developer mode.
(venv) $ python -m pip install -e .
Unit testing is performed with pytest. pytest has become the defacto Python unit testing framework. Some key advantages over the built in unittest module are:
- Significantly less boilerplate needed for tests.
- PEP8 compliant names (e.g.
pytest.raises()
instead ofself.assertRaises()
). - Vibrant ecosystem of plugins.
pytest will automatically discover and run tests by recursively searching for folders and .py
files prefixed with test
for any functions prefixed by test
.
The tests
folder is created as a Python package (i.e. there is an __init__.py
file within it)
because this helps pytest
uniquely namespace the test files. Without this, two test files cannot
be named the same, even if they are in different sub-directories.
(venv) $ pytest
Code coverage is provided by the pytest-cov plugin.
(venv) $ pytest --cov=pathpy --cov-report=html --cov-report=term
PEP8 is the universally accepted style guide for
Python code. PEP8 code compliance is verified using Flake8. Flake8 is
configured in the [flake8]
section of tox.ini
. Extra Flake8 plugins are also included:
flake8-bugbear
: Find likely bugs and design problems in your program.flake8-broken-line
: Forbid using backslashes (\
) for line breaks.flake8-comprehensions
: Helps write betterlist
/set
/dict
comprehensions.pep8-naming
: Ensure functions, classes, and variables are named with correct casing.
(venv) $ flake8
Code is automatically formatted using black. Imports are automatically sorted and grouped using isort.
These tools are configured by:
pyproject.toml
To check what has to be formatted, run:
(venv) $ isort --check .
(venv) $ black --check .
To automatically format code, run:
(venv) $ isort .
(venv) $ black .
Sphinx is a powerful static site generator that combines easy-to-write Markdown, with a number of Markdown extensions that increase the power of Markdown. This makes it a great fit for user guides and other technical documentation.
To build the user guide, change to the docs
folder and run.
(venv) $ cd docs/
(venv) $ make clean
(venv) $ make html
Open docs/_build/html/index.html
using a web browser.
Each time the master
Git branch is updated, the
.github/workflows/gh-pages.yml
GitHub Action will automatically build the user
guide and publish it to GitHub Pages. This hosted
user guide can be viewed at https://pathpy.github.io/pathpy4/
This project uses sphinx.ext.autodoc plugin for sphinx , which renders numpydoc into an sphinx project. numpydoc docstrings provide a good mix of easy-to-read docstrings in code as well as nicely-rendered output.
"""Computes the factorial through a recursive algorithm.
Parameters
----------
n: int
A positive input value.
Returns
-------
int
Returns the computed factorial.
Raises
------
InvalidFactorialError
If `n` is less than 0.
Examples
--------
>>> pathpy.factorial(1)
1
"""
Traditionally, Python projects place the source for their packages in the root of the project structure, like:
pathpy4
├── pathpy
│ ├── __init__.py
│ ├── cli.py
│ └── lib.py
├── tests
│ ├── __init__.py
│ └── test_pathpy.py
├── tox.ini
└── setup.py
However, this structure is
known
to have bad interactions with pytest
and tox
, two standard tools maintaining
Python projects. The fundamental issue is that tox creates an isolated virtual
environment for testing. By installing the distribution into the virtual
environment, tox
ensures that the tests pass even after the distribution has
been packaged and installed, thereby catching any errors in packaging and
installation scripts, which are common. Having the Python packages in the
project root subverts this isolation for two reasons:
- Calling
python
in the project root (for example,python -m pytest tests/
) causes Python to add the current working directory ( the project root) tosys.path
, which Python uses to find modules. Because the source packagefact
is in the project root, it shadows thefact
package installed in the tox environment. - Calling
pytest
directly anywhere that it can find the tests will also add the project root tosys.path
if thetests
folder is a Python package (that is, it contains a__init__.py
file). pytest adds all folders containing packages tosys.path
because it imports the tests like regular Python modules.
In order to properly test the project, the source packages must not be on the
Python path. To prevent this, a dedicated src
directory is the recommended
solution
by pytest
when using tox and the solution this blueprint promotes because it
is the least brittle even though it deviates from the traditional Python project
structure. It results is a directory structure like:
pathpy4
├── src
│ └── pathpy
│ ├── __init__.py
│ ├── cli.py
│ └── lib.py
├── tests
│ ├── __init__.py
│ └── test_pathpy.py
├── tox.ini
└── setup.py