-
Notifications
You must be signed in to change notification settings - Fork 0
/
tox.ini
298 lines (249 loc) · 14 KB
/
tox.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
[tox]
isolated_build = True
requires = pip >= 21.3.1
envlist = type, clean, dev
[testenv]
pasenv =
DOCS_BUILD_LOCATION
HOME
*
setenv =
PYTHONHASHSEED=2577074909
TEST_RESULTS_DIR={toxinidir}/test-results
JUNIT_TEST_RESULTS=junit-test-results.xml
PY_PACKAGE=software_patterns
DIST_DIR=dist-dir
black,lint,isort: LINT_ARGS = "tests src{/}software_patterns"
deps =
pytest
pytest-cov
commands = pytest {posargs} --cov -vv --junitxml={env:TEST_RESULTS_DIR:test-results}/{env:JUNIT_TEST_RESULTS:junit-test-results.xml}
[testenv:dev]
basepython = {env:TOXPYTHON:python}
usedevelop = true
; commands = pytest {posargs} -vv
[testenv:build-n-test]
basepython = {env:TOXPYTHON:python}
## COVERAGE
[testenv:clean]
description = Clean the working directory from any previously computed code coverage results.
Removes any data resulted from measuring code coverage. Useful before running the test suite
with code coverage enabled.
deps = coverage
skip_install = true
commands = coverage erase
[testenv:report]
description = Show the most recently computed code coverage results.
deps = coverage
skip_install = true
commands = {posargs:coverage report}
[testenv:format-report]
description = Generate xml and html formatted files out of previously computed code coverage results.
deps = coverage
skip_install = true
commands =
coverage xml
coverage html
## STATIC TYPE CHECKING
[testenv:type]
description = Python source code type hints (mypy)
deps =
mypy
pytest
usedevelop = true
changedir = {toxinidir}
commands = mypy {posargs:src tests --show-traceback \
--check-untyped-defs} # very aggresive: eg it flags 'a = Subject()' requiring 'a: Subject = Subject()'
## PYTHON PACKAGING
[testenv:check]
description = Check the code for compliance with best practises of Python packaging ecosystem (PyPI, pip, Distribute, etc).
deps =
docutils
readme-renderer
pygments
check-manifest
pyroma
skip_install = true
commands =
pyroma -d {toxinidir}
[testenv:build]
description = Create a source and wheel distribution.
Creates .tar.gz and .whl files in the 'dist-dir' folder, that can be upload to a pypi index server.
basepython = {env:TOXPYTHON:python3}
deps =
setuptools >= 40.0.0
skip_install = true
commands_pre =
# Delete the 'dist-dir' directory and its contents if found
python -c 'import os; import shutil; exec("if os.path.exists(os.path.join(\"{toxinidir}\", \"{env:DIST_DIR}\")):\n shutil.rmtree(os.path.join(\"{toxinidir}\", \"{env:DIST_DIR}\"))")'
# Create a setup.py file that simply invokes setuptools.setup without arguments (since all metadata required for building using setuptools should be present in non python files pyproject.toml and/or setup.cfg)
python -c 'import os; setup_py = os.path.join("{toxinidir}", "setup.py"); string = "from setuptools import setup\nsetup()"; exec("if not os.path.exists(setup_py):\n with open(setup_py, \"x\") as f:\n f.write(string)")'
commands =
python setup.py sdist -d dist-dir bdist_wheel -d dist-dir
commands_post =
# Delete the generated setup.py file
python -c 'import os; setup_py = os.path.join("{toxinidir}", "setup.py"); exec("if os.path.exists(setup_py):\n os.remove(setup_py)");'
[testenv:deploy]
description = Deploy the python package to be hosted in a PyPi server. Requires the SOFTWARE_PATTERNS_LIB_VERSION
environment variable to contain the string that represents the semantic version (eg 0.5.3 or 1.0.0) under which
to release the package to pypi. By default, deploys to the test-pypi server.
If you want to deploy to the "production" pypi, then you have to set the PYPI_SERVER environment
variable like `export PYPI_SERVER=pypi`. Also runs certain checks on the packaged distribution (.tar.gz and .whl)
passenv =
TWINE_*
SOFTWARE_PATTERNS_LIB_VERSION
deps =
keyring==21.3.0
twine==3.4.0
skip_install = true
commands_pre =
# check whether the distribution’s long description will render correctly on PyPI
; twine check {env:DIST_DIR}/software[\-_]patterns-{env:SOFTWARE_PATTERNS_LIB_VERSION:}*
twine check {env:DIST_DIR}/{env:PY_PACKAGE}-{env:SOFTWARE_PATTERNS_LIB_VERSION:}*
commands =
twine {posargs:upload --non-interactive} --repository {env:PYPI_SERVER:testpypi --skip-existing} {env:DIST_DIR}/{env:PY_PACKAGE}-{env:SOFTWARE_PATTERNS_LIB_VERSION:}* --verbose
## STATIC ANALYSIS OF CODE
# CODE LINTING, STATIC (STYLE) CHECKING
[testenv:lint]
description = Code Linting using Black and Isort.
To check against code style (aka lint check) run: `tox -e lint`.
To apply code style (aka lint apply) run: `APPLY_LINT= tox -e lint`.
deps =
black
isort >= 5.0.0
passenv = APPLY_LINT
skip_install = true
changedir = {toxinidir}
commands =
isort {posargs:{env:APPLY_LINT:--check}} "{env:LINT_ARGS:.}"
black {posargs:{env:APPLY_LINT:--check}} -S --config pyproject.toml "{env:LINT_ARGS:.}"
[testenv:prospector]
description = Analyse Python code and output information about errors, potential problems, convention violations and complexity.
Runs the prospector tool which brings together the functionality of other Python analysis tools such as Pyflakes and McCabe complexity.
We run tools: Pyflakes, Pyroma, McCabe and Dodgy
basepython = {env:TOXPYTHON:python}
deps = prospector[with_pyroma]
skip_install = true
commands_pre =
# We do not run pylint, since we have a dedicated pylint env for it.
# Prospector still tries to read .pylintrc, which causes a crash (because .pylintrc was generated with a pylint version higher than the one supported by prospector)
# So we temporarily "hide" .pylintrc from prospector, by simply renaming the file to ''.pylintrc-bak
python -c 'import os; file = lambda x: os.path.join("{toxinidir}", x); pylintrc = file(".pylintrc"); exec("if os.path.exists(pylintrc):\n os.rename(pylintrc, file(\".pylintrc-bak\"))");'
commands =
prospector {posargs: src}
prospector tests
; prospector {posargs: -t pyflakes -t pyroma -t mccabe -t dodgy -s medium --max-line-length 120 -T -A}
commands_post =
# We "restore" .pylintrc (to be available to the pylint env command)
# Copy .pylintrc-bak into .pylintrc and then delete .pylintrc-bak
python -c 'import os; file = lambda x: os.path.join("{toxinidir}", x); pylintrc_bak = file(".pylintrc-bak"); exec("if os.path.exists(pylintrc_bak):\n os.rename(pylintrc_bak, file(\".pylintrc\"))");'
[testenv:pylint]
description = Run the Pylint tool to analyse the Python code and output information about errors,
potential problems and convention violations
basepython = {env:TOXPYTHON:python}
deps = pylint==2.7.4
usedevelop = true
commands = python -m pylint {posargs:{toxinidir}/src/{env:PY_PACKAGE}}
## GENERATE ARCHITECTURE GRAPHS
[testenv:pydeps]
description = Visualise the dependency graphs (roughly which module imports which), by examining the
Python code. The dependency graph(s) are rendered in .svg file(s) and saved on the disk. You can
use the DEPS_GRAPHS environment variable to determine the directory location to store the visualisation(s). If
the variable is not supplied then the default folder 'dependency-graphs', inside the project's root folder, is used.
If the directory does not exist it gets created. Requires that the 'dot' executable is in your PATH. Installing the
graphviz library should make the dot executable available in PATH. Installing 'graphviz':
* For Linux users using Debian-based distributions (ie Ubuntu, Debian, Mint), please run "sudo aptitude install graphviz"
* For MacOS users Homebrew, please run "brew install graphviz"
basepython = {env:TOXPYTHON:python3.8}
passenv =
HOME
DEPS_GRAPHS
setenv =
{[testenv]setenv}
DEPS_DEFAULT_LOCATION = dependency-graphs
deps = pydeps==1.9.13
skip_install = false
usedevelop = true
commands_pre =
python -c 'import os; dir_path = os.path.join("{toxinidir}", "{env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}"); exec("if not os.path.exists(dir_path):\n os.mkdir(dir_path)");'
commands =
pydeps --version
# --max-bacon : exclude nodes that are more than n hops away
# (default=2, 0 -> infinite)
# --min-cluster-size : the minimum number of nodes a dependency must have before being clustered (default=0)
# --max-cluster-size : the maximum number of nodes a dependency can have before the cluster is collapsed to a single node (default=0)
# --keep-target-cluster : draw target module as a cluster
# Draw only the source code package inner dependencies
pydeps src/{env:PY_PACKAGE} --only {env:PY_PACKAGE} --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}_inner_deps.svg
# Draw the source code package inner and external dependencies
; pydeps src/{env:PY_PACKAGE} --cluster --pylib --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}_deps.svg
pydeps src/{env:PY_PACKAGE} --pylib --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}_deps.svg
# Visualize the package inner dependencies and abstract the external (eg with numpy, scipy, etc) ones
# Draw the source code package inner and minimum external dependencies
pydeps src/{env:PY_PACKAGE} --pylib --max-cluster-size=2 --keep-target-cluster --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}_target_cluster_deps_one_arrow.svg
# Draw the source code package inner and all external dependencies
pydeps src/{env:PY_PACKAGE} --pylib --keep-target-cluster --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}_target_cluster_deps_all_arrows.svg
# increasing max-bacon reveales the dependencies of the dependencies..
; pydeps src/{env:PY_PACKAGE} --max-bacon=8 --max-cluster-size=2 --keep-target-cluster --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}-n4.svg
# increasing max-cluster-size reveales more modules inside the external dependencies and their dependencies..
; pydeps src/{env:PY_PACKAGE} --max-bacon=8 --max-cluster-size=5 --keep-target-cluster --noshow -o {env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/{env:PY_PACKAGE}-n5.svg
python -c 'import os; print("\nGenerated dependency graph(s), as .svg files.\nThe graph(s) reside in the \"" + os.path.join("{toxinidir}", "{env:DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}") + "\" directory and you can now view them ie in your browser.\n")'
[testenv:uml]
description = Generate UML (class and package) diagrams by inspecting the code. The diagrams are stored in the
$UML_DIAGRAMS dir. Runs the pyreverse tool to parse the code and generate the files. This is a pretty legacy tool currently integrated in pylint (not available through pip).
Run `tox -e uml -- svg` to update the docs/static.
setenv =
{[testenv]setenv}
# include dirs to pythonpath to solve issue of inspect lib failing with some relative imports
PYTHONPATH={toxinidir}/src/{env:PY_PACKAGE}:{toxinidir}/src/{env:PY_PACKAGE}/utils
UML_DIAGRAMS=uml-diagrams
deps = pylint==2.7.4
usedevelop = true
commands_pre =
python -c 'from glob import glob; import os; dir = os.path.join("{toxinidir}", "{env:UML_DIAGRAMS}"); exec("if not os.path.isdir(dir):\n os.mkdir(dir)\nelse:\n _ = [os.remove(x) for x in glob(dir+\"/*\")]")'
commands =
; python -c 'import sys; print(sys.path)'
pyreverse -o {posargs:png} -A -p {env:PY_PACKAGE} src/{env:PY_PACKAGE}
# MOVE uml diagram files manually into $UML_DIAGRAMS directory (the pyreverse -p flag does not fully work when invoked with tox)
python -c 'import shutil, glob; uml_diagrams = glob.glob("classes_*.{posargs:png}", recursive=False); print(uml_diagrams); exec("for file in uml_diagrams:\n shutil.move(file, \"{env:UML_DIAGRAMS}\")")'
python -c 'import shutil, glob; uml_diagrams = glob.glob("packages_*.{posargs:png}", recursive=False); print(uml_diagrams); exec("for file in uml_diagrams:\n shutil.move(file, \"{env:UML_DIAGRAMS}\")")'
# PRINT message
python -c 'import os; my_dir = os.getcwd(); print("\nGenerated uml diagram(s), as svg/png files."); print("The diagram(s) reside in the \"" + os.path.join(my_dir, "{env:UML_DIAGRAMS}") + "\" directory.\n")'
## DOCUMENTATION OPERATIONS
[testenv:apidoc]
description = Populate rst files with directives to process docstrings. To force re-creation of
files that already exist, you can use the -f flag; eg command: tox -e apidoc -- -f. To override the
default filename 'modules', for the table of contents, you can use the --tocfile flag (takes 1 argument);
eg command: tox -e apidoc -v -- --tocfile my_contents_filename
deps = -rrequirements/docs.txt
commands = sphinx-apidoc -o docs src/{env:PY_PACKAGE} {posargs}
[testenv:docs]
description = Build the documentation. Read the source .rst and .py files and build
ready-to-render/ready-to-serve html (eg you can host it in a 'read the docs server').
Before building, any sphinx doctest found is executed.
After building, both word spelling and url links proper redirects are checked.
basepython = {env:TOXPYTHON:python3}
setenv =
{[testenv]setenv}
SPELLCHECK=1
deps = -rrequirements/docs.txt
usedevelop = true
commands =
sphinx-build {posargs:-E} -b doctest docs {env:DOCS_BUILD_LOCATION:dist/docs}
sphinx-build {posargs:-E} -b html docs {env:DOCS_BUILD_LOCATION:dist/docs}
sphinx-build -b spelling docs {env:DOCS_BUILD_LOCATION:dist/docs}
sphinx-build -b linkcheck docs {env:DOCS_BUILD_LOCATION:dist/docs}
python -c 'import os; my_dir = os.getcwd(); print("View documentation at " + os.path.join(os.getcwd(), "{env:DOCS_BUILD_LOCATION:dist/docs}", "index.html") + "; it is ready to be hosted!")'
[testenv:live-html]
description = Rebuild Sphinx documentation on changes, with live-reload in the browser.
basepython = {env:TOXPYTHON:python3.8}
setenv =
{[testenv]setenv}
SPELLCHECK=1
deps =
-rrequirements/docs.txt
sphinx-autobuild
usedevelop = true
commands =
sphinx-autobuild docs docs/_build/html {posargs}
python -c 'import os; my_dir = os.getcwd(); print("View documentation at " + os.path.join(os.getcwd(), "{env:DOCS_BUILD_LOCATION:dist/docs}", "index.html") + "; it is ready to be hosted!")'