Workflow
The bohicalog module has codified its workflow using tox.
Quick Start
To get started, you need to install tox:
$ pip install tox
Then, you can run the tests using tox:
$ tox
For example, by default it will:
$ tox
lint: commands[0]> black .
All done! ✨ 🍰 ✨
28 files left unchanged.
lint: commands[1]> isort .
Skipped 4 files
lint: commands[2]> nbqa isort .
No notebooks found in given path(s)
lint: OK ✔ in 0.76 seconds
manifest: commands[0]> check-manifest
...
lint: OK (0.76=setup[0.02]+cmd[0.18,0.10,0.45] seconds)
manifest: FAIL code 1 (8.50=setup[0.01]+cmd[8.49] seconds)
pyroma: OK (0.50=setup[0.01]+cmd[0.48] seconds)
flake8: FAIL code 1 (1.48=setup[0.01]+cmd[1.47] seconds)
mypy: OK (0.13=setup[0.01]+cmd[0.12] seconds)
doc8: FAIL code 1 (0.22=setup[0.01]+cmd[0.21] seconds)
docstr-coverage: OK (0.16=setup[0.01]+cmd[0.15] seconds)
docs-test: FAIL code 2 (4.97=setup[2.85]+cmd[0.01,0.01,2.10] seconds)
py: OK (2.93=setup[2.43]+cmd[0.31,0.06,0.13] seconds)
evaluation failed :( (19.78 seconds)
The above is defined by the tox section of the tox.ini file.
Tox Commands
The tox.ini file also defines a number of environments, which can be ran individually:
doctests: runs document tests, xdoctest
coverge-clean: cleans up the coverage files, coverage erase
lint: runs linting, black, isort, nbqa isort
doclint: runs linting on the documentation. This will fail on custom directives, rstfmt
manifest: checks the manifest, check-manifest
flake8: runs flake8 linting
pyroma: runs pyroma to check the package friendliness of the project, pyroma
mypy: runs mypy type checking, mypy
doc8: runs doc8 to check the documentation, doc8
docstr-coverage: runs docstr-coverage to check the documentation coverage, docstr-coverage
docs: builds the documentation, sphinx
docs-test: Test building the documentation in an isolated environment, sphinx
coverage-report: generates a coverage report, coverage report
bumpversion: bumps the version, bumpversion
build: builds the package, python setup.py sdist bdist_wheel
release: releases the package, twine
testrelease: releases the package to test.pypi.org, twine
finish: finishes the release, bumpversion
To run a specific environment, you can use the -e flag:
$ tox -e lint
Release Workflow
The release workflow is defined below:
tox -e lint
tox -e manifest
tox -e pyroma
tox -e flake8
tox -e mypy
tox -e doc8
tox -e docstr-coverage
tox -e docs-test
tox -e py
tox
tox -e bumpversion – {major, minor} <– Only if required, finish automatically bumps the minor version after each release
tox -e finish
Ensure you have the following environment variables set:
TWINE_USERNAME
TWINE_PASSWORD
TELEGRAM_BOT_TOKEN
TELEGRAM_BOT_CHAT_ID
Execute steps 1-10 to ensure that the code is ready for release. If any of the steps fail, fix the issues and repeat the steps.
If the release is a major or minor release, execute step 11 to bump the version. If the release is a patch release, skip step 11.
Execute step 12 to finish the release. This will automatically bump the version to the next minor version. This is to ensure that the version is always ahead of the latest release.
Tox File
The full tox.ini is listed below:
1# Tox (http://tox.testrun.org/) is a tool for running tests
2# in multiple virtualenvs. This configuration file will run the
3# test suite on all supported python versions. To use it, "pip install tox"
4# and then run "tox" from this directory.
5
6[tox]
7# To use a PEP 517 build-backend you are required to configure tox to use an isolated_build:
8# https://tox.readthedocs.io/en/latest/example/package.html
9isolated_build = True
10
11# These environments are run in order if you just use `tox`:
12envlist =
13 # always keep coverage-clean first
14 # coverage-clean
15 # code linters/stylers
16 lint
17 manifest
18 pyroma
19 flake8
20 mypy
21 # documentation linters/checkers
22 doc8
23 docstr-coverage
24 docs-test
25 # the actual tests
26 py
27 # always keep coverage-report last
28 # coverage-report
29
30[testenv]
31# Runs on the "tests" directory by default, or passes the positional
32# arguments from `tox -e py <posargs_1> ... <posargs_n>
33commands =
34 coverage run -p -m pytest --durations=20 {posargs:tests}
35 coverage combine
36 coverage xml
37extras =
38 # See the [options.extras_require] entry in setup.cfg for "tests"
39 tests
40
41[testenv:doctests]
42commands =
43 xdoctest -m src
44deps =
45 xdoctest
46 pygments
47
48[testenv:coverage-clean]
49deps = coverage
50skip_install = true
51commands = coverage erase
52
53[testenv:lint]
54deps =
55 black[jupyter]
56 isort
57 nbqa
58skip_install = true
59commands =
60 black .
61 isort .
62 nbqa isort .
63description = Run linters.
64
65[testenv:doclint]
66deps =
67 rstfmt
68skip_install = true
69commands =
70 rstfmt docs/source/
71description = Run documentation linters.
72
73[testenv:manifest]
74deps = check-manifest
75skip_install = true
76commands = check-manifest
77description = Check that the MANIFEST.in is written properly and give feedback on how to fix it.
78
79[testenv:flake8]
80skip_install = true
81deps =
82 darglint
83 flake8
84 flake8-black
85 flake8-bandit
86 flake8-bugbear
87 flake8-colors
88 flake8-docstrings
89 flake8-isort
90 flake8-print
91 pep8-naming
92 pydocstyle
93commands =
94 flake8 src/ tests/
95description = Run the flake8 tool with several plugins (bandit, docstrings, import order, pep8 naming). See https://cthoyt.com/2020/04/25/how-to-code-with-me-flake8.html for more information.
96
97[testenv:pyroma]
98deps =
99 pygments
100 pyroma
101skip_install = true
102commands = pyroma --min=10 .
103description = Run the pyroma tool to check the package friendliness of the project.
104
105[testenv:mypy]
106deps = mypy
107skip_install = true
108commands = mypy --install-types --non-interactive --ignore-missing-imports src/
109description = Run the mypy tool to check static typing on the project.
110
111[testenv:doc8]
112skip_install = true
113deps =
114 sphinx
115 doc8
116commands =
117 doc8 docs/source/
118description = Run the doc8 tool to check the style of the RST files in the project docs.
119
120[testenv:docstr-coverage]
121skip_install = true
122deps =
123 docstr-coverage
124commands =
125 docstr-coverage src/ tests/ --skip-private --skip-magic
126description = Run the docstr-coverage tool to check documentation coverage
127
128[testenv:docs]
129description = Build the documentation locally.
130extras =
131 # See the [options.extras_require] entry in setup.cfg for "docs"
132 docs
133 # You might need to add additional extras if your documentation covers it
134commands =
135 pip install -e .
136 python -m sphinx -W -b html -d docs/build/doctrees docs/source docs/build/html -a -E
137
138[testenv:docs-test]
139description = Test building the documentation in an isolated environment.
140passenv =
141 TELEGRAM_BOT_TOKEN
142 TELEGRAM_BOT_CHAT_ID
143changedir = docs
144extras =
145 {[testenv:docs]extras}
146commands =
147 mkdir -p {envtmpdir}
148 cp -r source {envtmpdir}/source
149 cp -r ../.github {envtmpdir}/../.github
150 cp -r ../tox.ini {envtmpdir}/../tox.ini
151 python -m sphinx -W -b html -d {envtmpdir}/build/doctrees {envtmpdir}/source {envtmpdir}/build/html
152 python -m sphinx -W -b coverage -d {envtmpdir}/build/doctrees {envtmpdir}/source {envtmpdir}/build/coverage
153 cat {envtmpdir}/build/coverage/c.txt
154 cat {envtmpdir}/build/coverage/python.txt
155allowlist_externals =
156 cp
157 cat
158 mkdir
159
160[testenv:coverage-report]
161deps = coverage
162skip_install = true
163commands =
164 coverage combine
165 coverage report
166
167####################
168# Deployment tools #
169####################
170
171[testenv:bumpversion]
172commands = bumpversion {posargs}
173skip_install = true
174passenv = HOME
175deps =
176 bumpversion
177
178[testenv:build]
179skip_install = true
180deps =
181 wheel
182 build
183commands =
184 python -m build --sdist --wheel --no-isolation
185
186[testenv:release]
187description = Release the code to PyPI so users can pip install it
188passenv =
189 TWINE_USERNAME
190 TWINE_PASSWORD
191skip_install = true
192deps =
193 {[testenv:build]deps}
194 twine >= 1.5.0
195commands =
196 {[testenv:build]commands}
197 twine upload --skip-existing dist/*
198
199[testenv:testrelease]
200description = Release the code to the test PyPI site
201skip_install = true
202deps =
203 {[testenv:build]deps}
204 twine >= 1.5.0
205commands =
206 {[testenv:build]commands}
207 twine upload --skip-existing --repository-url https://test.pypi.org/legacy/ dist/*
208
209[testenv:finish]
210skip_install = true
211passenv =
212 HOME
213 TWINE_USERNAME
214 TWINE_PASSWORD
215deps =
216 {[testenv:release]deps}
217 bump2version
218commands =
219 bump2version release --tag
220 {[testenv:release]commands}
221 git push --tags
222 bump2version patch
223 git push
224allowlist_externals =
225 git