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/activateOn Windows Powershell / cmd:
> py -m venv venv
> venv\Scripts\activateOnce 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 wheelThis project uses pip-tools to lock project dependencies and create reproducible virtual environments.
(venv) $ python -m pip install pip-toolsTo cleanly install your dependencies into your virtual environment:
(venv) $ python -m piptools sync requirements/requirements.txt requirements/dev-requirements.txtNote:
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.txtAfter 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) $ pytestCode coverage is provided by the pytest-cov plugin.
(venv) $ pytest --cov=pathpy --cov-report=html --cov-report=termPEP8 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/dictcomprehensions.pep8-naming: Ensure functions, classes, and variables are named with correct casing.
(venv) $ flake8Code 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 htmlOpen 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
pythonin 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 packagefactis in the project root, it shadows thefactpackage installed in the tox environment. - Calling
pytestdirectly anywhere that it can find the tests will also add the project root tosys.pathif thetestsfolder is a Python package (that is, it contains a__init__.pyfile). pytest adds all folders containing packages tosys.pathbecause 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