-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtox.ini
More file actions
executable file
·554 lines (487 loc) · 21.8 KB
/
tox.ini
File metadata and controls
executable file
·554 lines (487 loc) · 21.8 KB
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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
[tox]
envlist =
{py312, py311, py310, py39, py38, py37}-{dev, sdist, wheel}-{linux, macos, windows}
coverage
isolated_build = true
skip_missing_interpreters = true
# Hide warnings to reduce clutter due to interpreter version mismatch on local dev machine
ignore_basepython_conflict = true
[gh-actions]
python =
3.7: {py37}{, -path, -sdist, -wheel, -dev}
3.8: {py38}{, -path, -sdist, -wheel, -dev}
3.9: {py39}{, -path, -sdist, -wheel, -dev}
3.10: {py310}{, -path, -sdist, -wheel, -dev}
3.11: {py311}{, -path, -sdist, -wheel, -dev}
3.12: {py312}{, -path, -sdist, -wheel, -dev}
[gh-actions:env]
PLATFORM =
ubuntu-latest: linux
macos-latest: macos
windows-latest: windows
[testenv]
description = An environment designed to facilitate testing (running the test suite)
passenv =
*
LC_ALL
PIP_*
PYTEST_*
# See https://github.com/codecov/codecov-python/blob/5b9d539a6a09bc84501b381b563956295478651a/README.md#using-tox
codecov: TOXENV
codecov: CI
codecov: TRAVIS TRAVIS_*
setenv =
# It will overide variables in passenv in case of collision
PYTHONPATH = {toxinidir}{/}tests
PYTHONBUFFERED = yes
TEST_RESULTS_DIR = {toxinidir}{/}test-results
PY_PACKAGE = cookiecutter_python
DIST_DIR = dist
COVERAGE_FILE = {toxworkdir}{/}.coverage.{envname}
TEST_STATUS_DIR = {envtmpdir}
PYPY3323BUG = 1
# For Windows: account for inability to do post Gen delete of log file in
# Gen Proj Dir, due to Permission Error, when running on windows:
# other process is using the file, so removing is denied, at Generator runtime
# log deletion post hook fails on windows, due to permission error! (other process is using the file, so removing is denied)
# windows spawn multiple processes, so log deletion is not possible, even when running 1 Single Unit Test
BUG_LOG_DEL_WIN = permission_error
# Fallback File name for storing output of for all poetry export operations
DEFAULT_REQS_FILE = reqs.txt
extras =
test
commands =
# --cov-config pyproject.toml
pytest -ra --cov --cov-report=term-missing \
--cov-report=html:{envdir}/htmlcov --cov-context=test \
--cov-report=xml:{toxworkdir}/coverage.{envname}.xml \
{posargs:-n auto {toxinidir}{/}tests}
### Quick Testing locally ###
[testenv:dev]
description = Install in 'edit' mode & Test
basepython = {env:TOXPYTHON:python3}
# deps = tox == 3.27.1 # required when enabling --run-integration pytest flag
usedevelop = true
commands = pytest -ra {posargs:-n auto} {toxinidir}{/}tests
[testenv:dev-cov]
description = Using `python3` in PATH: Install in 'edit' mode, Test & measure Coverage
basepython = {env:TOXPYTHON:python3}
deps = tox == 3.27.1 # required when enabling --run-integration pytest flag
usedevelop = true
commands =
pytest -ra --cov --cov-report=term-missing \
--cov-report=html:{envdir}/htmlcov --cov-context=test \
--cov-report=xml:{toxworkdir}/coverage.{envname}.xml \
{posargs:-n auto} {toxinidir}{/}tests
# PATH
[testenv:{py312, py311, py310, py39, py38, py37, py36, pypy3}-path{, -linux, -macos, -windows}]
description = Add Source Code to Path & Test
setenv =
{[testenv]setenv}
PYTHONPATH = {toxinidir}{/}src{:}{toxinidir}{/}tests
deps = poetry
skip_install = true
commands =
poetry install --no-root -E test
{[testenv]commands}
# SDIST
[testenv:{py312-, py311-, py310-, py39-, py38-, py37-, py36-, pypy3-,}sdist{, -linux, -macos}]
description = Install as Source Distribution & Test
basepython = {env:TOXPYTHON:python3}
[testenv:{py37-, py36-}sdist-windows]
description = Install as Source Distribution & Test
basepython = {env:TOXPYTHON:python3}
# SDIST Windows special cases
[testenv:{py312-, py311-, py310-, py39-, py38-, pypy3-,}sdist-windows]
description = Install as Source Distribution & Test
basepython = {env:TOXPYTHON:python3}
setenv =
{[testenv]setenv}
PY_SDIST = 1
# Support/Common Env for Pip Wheel
[wheel_env]
setenv =
{[testenv]setenv}
_WHEEL_DIR = {env:BUILD_DEST:{toxworkdir}{/}{env:DIST_DIR}}
commands_pre =
pip install --exists-action w --force-reinstall "{env:_WHEEL_DIR}{/}{env:_WHEEL}[test]"
# Build WHEEL via PIP
[testenv:{py312-, py311-, py310-, py39-, py38-, py37-, py36-, pypy3-,}wheel{, -linux, -macos, -windows}]
description = Build Wheel, via pip
basepython = {env:TOXPYTHON:python3}
setenv = {[wheel_env]setenv}
skip_install = true
changedir = {toxinidir}
commands = pip wheel --wheel-dir {env:_WHEEL_DIR} {toxinidir}
# Install WHEEL and TEST
[testenv:{py312-, py311-, py310-, py39-, py38-, py37-, py36-, pypy3-,}wheel-test{, -linux, -macos}]
description = Install Wheel, and Test
basepython = {env:TOXPYTHON:python3}
setenv =
{[wheel_env]setenv}
_WHEEL = {env:WHEEL:{env:PY_PACKAGE}-{env:PKG_VERSION:wheel_not_set_but_version_not_set}-py3-none-any.whl}
skip_install = true
changedir = {toxinidir}
commands_pre = {[wheel_env]commands_pre}
# Install WHEEL and TEST - Special case on Windows
[testenv:{py312-, py311-, py310-, py39-, py38-, }wheel-test-windows]
description = Install Wheel, and Test
basepython = {env:TOXPYTHON:python3}
setenv =
{[wheel_env]setenv}
_WHEEL = {env:WHEEL:{env:PY_PACKAGE}-{env:PKG_VERSION:wheel_not_set_but_version_not_set}-py3-none-any.whl}
PY_WHEEL = 1
skip_install = true
changedir = {toxinidir}
commands_pre = {[wheel_env]commands_pre}
## DEV on CI ##
[testenv:{py312, py311, py310, py39, py38, py37, py36, pypy3}-dev{, -linux, -macos, -windows}]
description = Install in 'edit' mode & Test
usedevelop = true
[testenv:coverage]
description = combine coverage from test environments
passenv =
DIFF_AGAINST
TOX_COVERAGE_FILE
setenv =
COVERAGE_FILE = {env:TOX_COVERAGE_FILE:{toxworkdir}/.coverage}
skip_install = true
deps =
coverage[toml]>=5.1
diff_cover>=6
parallel_show_output = true
commands_pre = python -c 'import os; print("-----\n" + os.environ.get("COVERAGE_FILE"))'
commands =
coverage combine --keep
coverage report --skip-covered --show-missing -i
coverage xml -o {toxworkdir}/coverage.xml -i
coverage html -d {toxworkdir}/htmlcov -i
depends = {py311, py310, py39, py38, py37, py36}{, -path, -sdist, -wheel, -dev}
[testenv:dev-env]
description = generate a DEV environment
usedevelop = true
extras =
{[testenv]extras}
docs
typing
commands =
python -m pip list --format=columns
python -c 'import sys; print(sys.executable)'
python -m pip freeze > {envdir}{/}requirements-dev.txt
[testenv:pin-deps]
# Pin Deps : tox -e pin-deps
# With Test Extras: tox -e pin-deps -- -E test
# With Target File: REQS_FILE=reqs-test.txt tox -e pin-deps -- -E test
description = Pin dependencies from poetry lock. Use the REQS_FILE var to override default
basepython = {env:TOXPYTHON:python3}
passenv = REQS_FILE
skip_install = true
deps =
poetry
poetry-plugin-export
commands =
python -m poetry export -f requirements.txt -o {env:REQS_FILE:{env:DEFAULT_REQS_FILE}} {posargs}
python -c 'print( "\n Generated requirements file: " + "{env:REQS_FILE:{env:DEFAULT_REQS_FILE}}" );'
## STATIC TYPE CHECKING
[testenv:type]
description = Type checking with mypy
basepython = {env:TOXPYTHON:python3}
setenv =
{[testenv]setenv}
MYPYPATH = {toxinidir}{/}src{/}stubs
deps = -r {env:REQS_FILE:{env:DEFAULT_REQS_FILE:reqs-typing.txt}}
skip_install = true
changedir = {toxinidir}
commands_pre =
# mypy does not like, by default, multiple conftest.py (ses pytest) files
# trick mypy into believing that tests is a package, beucase it wants to be
# able to distinguish our 2 conftest.py files
# create empty __init__.py in tests, temporarily
python -c 'open("tests/__init__.py", "a").close();'
# pre-emptively check if reqs-typing.txt exists, if not print error msg and exit with 1
; python -c 'import os; f = "reqs-typing.txt"; exec("if not os.path.exists(f):\n print(\"\\n[ERROR] File \" + f + \"does not exist. Please generate it, with tox -e pin-deps, before running this env.\\n\")\n exit(1)");'
commands =
mypy --show-error-codes \
--exclude tests/data \
{posargs:src{/}{env:PY_PACKAGE}{/}hooks \
src{/}{env:PY_PACKAGE}{/}backend tests src{/}{env:PY_PACKAGE}{/}handle \
src{/}{env:PY_PACKAGE}{/}utils.py src{/}{env:PY_PACKAGE}{/}exceptions.py \
src{/}{env:PY_PACKAGE}{/}cli.py src{/}{env:PY_PACKAGE}{/}cli_handlers.py \
src{/}{env:PY_PACKAGE}{/}__main__.py src{/}{env:PY_PACKAGE}{/}__init__.py}
commands_post =
# delete temporarily created empty __init__.py in tests
python -c 'import os; os.remove("tests/__init__.py");'
## BUILD DOCUMENTATION PAGES ##
[docsenv]
setenv =
{[testenv]setenv}
SPELLCHECK=1
deps =
myst-parser>=2.0.0,<=2.1.0
markdown-it-py>=3.0.0,<3.1.0
# tox -e pin-docs,docs
# tox -e pin-docs -- docslive && tox -r -e docs-live
[testenv:pin-docs]
description = 'Pin Docs Python Dependencies in requirements.txt type of format.'
basepython = {env:TOXPYTHON:python3}
deps =
poetry
poetry-plugin-export
skip_install = true
commands = poetry export -o req-docs.txt -E {posargs:docs}
# tox -e pin-docs
# TOC_API="modules_api" tox -e apidoc -v -- -f --tocfile "$TOC_API"
# will generate 'docs/contents/modules_api.rst' file
[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
basepython = {env:TOXPYTHON:python3}
deps =
{[docsenv]deps}
; -r {env:REQS_FILE:{env:DEFAULT_REQS_FILE:reqs-docs.txt}}
usedevelop = true
extras = docs
commands = sphinx-apidoc -o docs/contents/33_refs/api/modules 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 = {[docsenv]setenv}
; deps = -r {env:REQS_FILE:{env:DEFAULT_REQS_FILE:reqs-docs.txt}}
deps = {[docsenv]deps}
usedevelop = true
extras = docs
changedir = {toxinidir}
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 'print("View documentation at {env:DOCS_BUILD_LOCATION:dist/docs}/index.html; it is ready to be hosted!")'
## SERVE LIVE DOCUMENTATION ##
# export REQS_FILE=reqs-docslive.txt && tox -e pin-deps -- -E docslive && tox -r -e live-html
[testenv:docs-live]
description = Rebuild Sphinx documentation on changes, with live-reload in the browser.
basepython = {env:TOXPYTHON:python3}
setenv = {[docsenv]setenv}
; deps = -r {env:REQS_FILE:{env:DEFAULT_REQS_FILE:reqs-docslive.txt}}
deps = {[docsenv]deps}
usedevelop = true
extras = docslive
changedir = {toxinidir}
commands = sphinx-autobuild docs docs{/}_build{/}html {posargs}
## PYTHON PACKAGING
[testenv:build]
description = "Builds our wheel, from sdist (after build it from source), and runs Tests. Note: builds only our wheel."
basepython = {env:TOXPYTHON:python3}
setenv =
{[testenv]setenv}
_BUILD_DEST = {env:BUILD_DEST:{toxworkdir}{/}{env:DIST_DIR}}
deps =
build
poetry-core
skip_install = true
changedir = {toxinidir}
; create _BUILD_DEST if not exists
commands_pre = python -c 'import os; d = os.environ["_BUILD_DEST"]; from pathlib import Path; exec("if not Path(d).exists():\n Path(d).mkdir(parents=True)");'
commands =
python -m build {toxinidir} --outdir {env:_BUILD_DEST}
[testenv:check]
description = Check the code for compliance with best practises of Python packaging ecosystem (PyPI, pip, Distribute, etc).
deps =
poetry-core
pyroma
twine
skip_install = true
commands =
pyroma --directory {toxinidir}
pyroma --file {env:DIST_DIR}/{env:PY_PACKAGE}-{env:PKG_VERSION}.tar.gz
python -m twine check {env:DIST_DIR}/{env:PY_PACKAGE}-{env:PKG_VERSION}*
# TODO Improvement run 'pyroma --pypi' from some script/CI server after uploading to test-pypi
depends = build
## DEPLOYMENT
[testenv:deploy]
# Deploy to test.pypi.org : TWINE_USERNAME=user TWINE_PASSWROD=pass PACKAGE_DIST_VERSION=1.0.0 tox -e deploy
# Deploy to pypi.org : TWINE_USERNAME=user TWINE_PASSWROD=pass PACKAGE_DIST_VERSION=1.0.0 PYPI_SERVER=pypi tox -e deploy
description = Deploy the python package to be hosted in a pypi server. Requires to authenticate with the pypi
server, so please set the TWINE_PASSWORD and TWINE_PASSWORD environment variables.
Also, requires the PACKAGE_DIST_VERSION variable to explicitly indicate which distribution
(semantic version: ie 0.5.3, 1.0.0) we intent to deploy/upload. That way we avoid unintentionally deploying
a wrong version and we make sure that the correct version is released to pypi. By default, deploys to a
pypi 'test server', currently at test.pypi.org. If you want to deploy to the "production" pypi (at pypi.org),
then you have to set the PYPI_SERVER environment variable to 'pypi', like `export PYPI_SERVER=pypi`.
Before deploying, certain sanity checks are ran on the distribution artefacts (ie .tar.gz, .whl) to be uploaded.
basepython = {env:TOXPYTHON:python3}
passenv =
PACKAGE_DIST_VERSION
TWINE_USERNAME
TWINE_PASSWORD
deps =
; keyring==21.3.0
; twine==3.4.0
twine >6.0, <7.0
skip_install = true
commands_pre =
python -c 'import os; n = "TWINE_USERNAME"; v = os.environ.get(n); exec("if not v:\n print(\"Please set the \" + str(n) + \" variable.\")\n exit(1)");'
python -c 'import os; n = "TWINE_PASSWORD"; v = os.environ.get(n); exec("if not v:\n print(\"Please set the \" + str(n) + \" variable.\")\n exit(1)");'
python -c 'import os; n = "PACKAGE_DIST_VERSION"; v = os.environ.get(n); exec("if not v:\n print(\"Please set the \" + str(n) + \" variable.\")\n exit(1)");'
python -c 'import os; n = "PYPI_SERVER"; exec("if n in os.environ:\n v = os.environ[n]\n if v != \"pypi\":\n print(\"Environment variable PYPI_SERVER detected, but was not set to pypi. Please set to pypi or run tox -e deploy from an environment where the PYPI_SERVER variable is NOT present at all.\")\n exit(1)");'
python -m twine check {env:DIST_DIR}/{env:PY_PACKAGE}-{env:PACKAGE_DIST_VERSION:MISSMATCHED_PACKAGE_DIST_VERSION_ERROR}*
commands =
twine {posargs:upload --non-interactive} --repository {env:PYPI_SERVER:testpypi --skip-existing} {env:DIST_DIR}{/}{env:PY_PACKAGE}-{env:PACKAGE_DIST_VERSION:MISSMATCHED_PACKAGE_DIST_VERSION_ERROR}* --verbose
## 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}
# CODE LINTING, STATIC (STYLE) CHECKING
[sca]
setenv =
{[testenv]setenv}
TESTS_DIR_NAME = 'tests'
TEST_DATA_DIR_NAME = 'data'
TEST_SNAPSHOTS_DIR_NAME = 'snapshots'
# Exclude Test Snapshots from Isort and Black, since they contain Python Code
ISORT_EXCLUDE = '{env:TESTS_DIR_NAME}{/}{env:TEST_DATA_DIR_NAME}{/}{env:TEST_SNAPSHOTS_DIR_NAME}'
BLACK_EXCLUDE = '{env:TESTS_DIR_NAME}/{env:TEST_DATA_DIR_NAME}/{env:TEST_SNAPSHOTS_DIR_NAME}'
# Note: we use forward slashes (/), because Black resolves paths under the hood
LINT_ARGS = "tests src{/}cookiecutter_python{/}backend src{/}cookiecutter_python{/}handle scripts"
[testenv:lint]
description = test if code conforms with our styles
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
setenv = {[sca]setenv}
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:.}"
# black --check --skip-string-normalization --exclude tests/data/snapshots --config pyproject.toml tests src/cookiecutter_python/backend src/cookiecutter_python/handle
[testenv:black]
# To see DIFF: `tox -e black -- --diff`
# To APPLY! : `APPLY_BLACK= tox -e black`
description = black ops
deps = black
setenv = {[sca]setenv}
skip_install = true
changedir = {toxinidir}
commands = black {posargs:{env:APPLY_BLACK:--check}} \
--skip-string-normalization \
--exclude {env:BLACK_EXCLUDE} \
--config pyproject.toml "{env:LINT_ARGS:.}"
# isort --skip tests/data/snapshots --check tests src/cookiecutter_python/backend src/cookiecutter_python/handle
[testenv:isort]
# To see DIFF: tox -e isort -- --diff
# To APPLY! : `APPLY_ISORT= tox -e isort`
description = isort
deps = isort >= 5.0.0
setenv = {[sca]setenv}
skip_install = true
changedir = {toxinidir}
commands = isort \
--skip {env:ISORT_EXCLUDE} \
{posargs:{env:APPLY_ISORT:--check}} \
"{env:LINT_ARGS:.}"
## RUFF ##
# To see DIFF : tox -e ruff -- --diff
# To APPLY! : `tox -e ruff -- --fix`
# To APPLY More! : `tox -e ruff -- --fix --unsafe-fixes`
[testenv:ruff]
description = Run the ruff static analysis tool
basepython = {env:TOXPYTHON:python3}
setenv = {[sca]setenv}
deps = ruff
skip_install = true
# make sure to avoid checking the Template pyproject.toml, due to parse error
commands = ruff check "{env:LINT_ARGS:.}" {posargs}
[testenv:bandit]
description = static code security check, configured in pyproject.toml
deps =
bandit[toml]
bandit-sarif-formatter==1.1.1
skip_install = true
commands = bandit -r -c pyproject.toml {posargs} src tests
[testenv:pylint]
description = Run the Pylint tool to analyse the Python code and output
information about errors, potential problems and convention violations
deps =
pylint ; python_version == '3.11'
pylint == 2.7.4 ; python_version < '3.11'
usedevelop = true
changedir = {toxinidir}
commands =
- python -m pylint src{/}{env:PY_PACKAGE}
- python -m pylint tests
[testenv:prospector]
description = Run multiple static code analysis tools defined in .prospector.yml
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
deps = prospector[with_pyroma] == 1.3.1
skip_install = true
changedir = {toxinidir}
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
python -c 'import os; f = ".pylintrc"; exec("if os.path.exists(f):\n os.rename(f, \".pylintrc-bak\")")'
commands =
prospector src
prospector tests
commands_post =
# We "restore" .pylintrc (to be available to the pylint env command)
python -c 'import os; f = ".pylintrc-bak"; exec("if os.path.exists(f):\n os.rename(f, \".pylintrc\")")'
## GENERATE ARCHITECTURE GRAPHS
[testenv:pydeps]
description =
Visualise Python dependency graphs (roughly which module imports which) and store in .svg file(s).
Eg: `tox -e pydeps`, `PYDEPS_DIR=my-destination-dir tox -e pydeps`.
PYDEPS_DIR controls the relative location (to your current working dir) of the target dir to store
the generated files. The default target dir is 'pydeps'. Dir is created if it doesn't exist.
Requires the 'dot' executable to be in your PATH. Installing the graphviz library should make
the dot executable available in your PATH. Installing 'graphviz':
* For Linux, please run "sudo apt install graphviz"
* For MacOS, please run "brew install graphviz"
basepython = {env:TOXPYTHON:python3.10}
passenv =
HOME
PWD
PYDEPS_DIR
deps = pydeps==1.11.0
usedevelop = true
commands_pre =
python -c 'from pathlib import Path; import os; p = Path(os.environ["PWD"]) / os.getenv("PYDEPS_DIR", "pydeps"); p.mkdir(parents=True, exist_ok=True);'
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:PWD}{/}{env:PYDEPS_DIR:pydeps}{/}deps_inner.svg
; # Draw the source code package inner and external dependencies
pydeps src{/}{env:PY_PACKAGE} --cluster --noshow -o {env:PWD}{/}{env:PYDEPS_DIR:pydeps}{/}deps_all.svg
; # Visualize the package inner dependencies and abstract the external (eg with numpy, pandas, etc) ones
; # Draw the source code package inner and minimum external dependencies
pydeps src{/}{env:PY_PACKAGE} --max-cluster-size=2 --keep-target-cluster --noshow -o {env:PWD}{/}{env:PYDEPS_DIR:pydeps}{/}deps_ktc-mcs_2.svg
; # Draw the source code package inner and all external dependencies
pydeps src{/}{env:PY_PACKAGE} --keep-target-cluster --noshow -o {env:PWD}{/}{env:PYDEPS_DIR:pydeps}{/}deps_ktc.svg
python -c 'from pathlib import Path; p = Path("{env:PWD}{/}{env:PYDEPS_DIR:pydeps}"); print(f"\nGenerated .svg files in \"\{str(p.absolute())\}\".");'