tox-dev.ini
[tox]
skip_missing_interpreters = true
requires =
tox >= 3.20.0
[testenv]
basepython = {spell,clean,report,codecov,graphs,quickstart,apidoc,deploy,check,uml}: {env:TOXPYTHON:python3}
passenv =
*
# See https://github.com/codecov/codecov-python/blob/5b9d539a6a09bc84501b381b563956295478651a/README.md#using-tox
codecov: TOXENV
codecov: CI
codecov: TRAVIS TRAVIS_*
setenv =
PYTHONPATH={toxinidir}/tests
PYTHOUNBUFFERED=yes
PIP_DISABLE_PIP_VERSION_CHECK=1
VIRTUALENV_NO_DOWNLOAD=0
DOCS_BUILD_LOCATION=dist/docs
deps =
setuptools >= 40.0.0
-rrequirements/docs.txt
skip_install = true
## 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 -c tox-dev.ini -e apidocs -- -f. To override the
default filename 'modules', of the table of contents, you can use the --tocfile flag (takes 1 argument); eg command:
tox -c tox-dev.ini -e apidoc -v -- --tocfile my_contents_filename
commands = sphinx-apidoc -o docs src/so_magic {posargs}
[testenv:spell]
description = Check the documentation spelling. Checks spelling both for the .rst files in 'docs' directory and for the
code docstrings. Writes the errors in separate .spelling files, in the {env:DOCS_BUILD_LOCATION:dist/docs}
directory. Requires as external dependency the "pyenchant C library", which you should install manually (eg
command on Linux: sudo apt install python-pyenchant).
setenv =
{[testenv]setenv}
SPELLCHECK=1
deps =
{[testenv]deps}
pyenchant
commands = sphinx-build -E -b spelling docs {env:DOCS_BUILD_LOCATION:dist/docs}
## 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
commands =
check-manifest
pyroma -d {toxinidir}
[testenv:build]
description = Create/build the python package/distribution.
Creates .tar.gz and .whl files in the dist folder, that can be upload to a pypi index server.
basepython = {env:TOXPYTHON:python3}
deps =
setuptools >= 40.0.0
commands_pre =
python -c 'import os; import shutil; exec("if os.path.exists(os.path.join(\"{toxinidir}\", \"dist\")):\n shutil.rmtree(os.path.join(\"{toxinidir}\", \"dist\"))")'
commands =
python setup.py sdist bdist_wheel
; commands_post =
; twine check dist/so-magic-*.tar.gz
; twine check dist/so_magic-*.whl
############## DEPLOY ##############
# usage 1
# deploy to testpypi while ignoring collisions (case where the version already exists on remote)
# python -m tox -c tox-dev.ini -e deploy
# usage 2
# deploy to pypi
# PYPI_SERVER=pypi python -m tox -c tox-dev.ini -e deploy
[testenv:deploy]
description = Deploy the python package to be hosted in a pypi server. Requires the SO_MAGIC_RELEASE_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 so_magic package to pypi. By default, deploys to the official 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)
deps =
keyring==21.3.0
twine==3.4.0
commands_pre =
python -m twine check dist/so[\-_]magic-{env:SO_MAGIC_RELEASE_VERSION:PLEASE_INDICATE_THE_SEM_VER_FOR_RELEASE}*
commands =
python -m twine {posargs:upload --non-interactive} --repository {env:PYPI_SERVER:testpypi --skip-existing} dist/so[\-_]magic-{env:SO_MAGIC_RELEASE_VERSION:PLEASE_INDICATE_THE_SEM_VER_FOR_RELEASE}* --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
commands = coverage erase
[testenv:report]
description = Show the most recently computed codecoverage results.
deps = coverage
commands = {posargs:coverage report}
[testenv:format-report]
description = Generate xml and html formatted files out of previously computed code coverage results.
deps = coverage
commands =
coverage xml
coverage html
## CODECOV
[testenv:codecov]
description = Send code coverage data to codecov.io
passenv = TOXENV CI TRAVIS TRAVIS_* CODECOV_*
deps = codecov
commands = codecov
## STATIC ANALYSIS OF CODE
[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:python3.6}
deps = prospector[with_pyroma]
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 (bevause .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; exec("if os.path.exists(os.path.join(\"{toxinidir}\", \".pylintrc\")):\n os.rename(os.path.join(\"{toxinidir}\", \".pylintrc\"), os.path.join(\"{toxinidir}\", \".pylintrc-bak\"))")'
commands =
prospector
; 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)
python -c 'import os; exec("if os.path.exists(os.path.join(\"{toxinidir}\", \".pylintrc-bak\")):\n os.rename(os.path.join(\"{toxinidir}\", \".pylintrc-bak\"), os.path.join(\"{toxinidir}\", \".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:python3.8}
deps =
attrs
pandas
numpy
scikit-learn
pylint==2.7.4
skip_install = false
use_develop = true
commands = python -m pylint {posargs:{toxinidir}/src/so_magic}
## GENERATE ARCHITECTURE GRAPHS
[testenv:graphs]
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 SO_MAGIC_DEPS_GRAPHS environment variable to determine the directory location to store the visualisation(s). If
the variable is not supplied then the default folder 'so-magic-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 apt install graphviz"
* For MacOS users Homebrew, please run "brew install graphviz"
basepython = {env:TOXPYTHON:python3.8}
passenv =
HOME
SO_MAGIC_DEPS_GRAPHS
setenv =
{[testenv]setenv}
DEPS_DEFAULT_LOCATION = so-magic-dependency-graphs
deps =
attrs
pandas
numpy
scikit-learn
pydeps==1.9.13
skip_install = false
use_develop = true
commands_pre =
- python -c 'import os; my_dir = os.getcwd(); os.mkdir(os.path.join(my_dir, "{env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}"))'
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/so_magic --only so_magic --noshow -o {env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/so_magic_inner_deps.svg
# Draw the source code package inner and external dependencies
pydeps src/so_magic --cluster --noshow -o {env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/so_magic_deps.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/so_magic --max-cluster-size=2 --keep-target-cluster --noshow -o {env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/so_magic_target_cluster_deps_one_arrow.svg
# Draw the source code package inner and all external dependencies
pydeps src/so_magic --keep-target-cluster --noshow -o {env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/so_magic_target_cluster_deps_all_arrows.svg
# increasing max-bacon reveales the dependencies of the dependencies..
; pydeps src/so_magic --max-bacon=8 --max-cluster-size=2 --keep-target-cluster --noshow -o {env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/so_magic-n4.svg
# increasing max-cluster-size reveales more modules inside the external dependencies and their dependencies..
; pydeps src/so_magic --max-bacon=8 --max-cluster-size=5 --keep-target-cluster --noshow -o {env:SO_MAGIC_DEPS_GRAPHS:{env:DEPS_DEFAULT_LOCATION}}/so_magic-n5.svg
python -c 'import os; my_dir = os.getcwd(); print("\nGenerated dependency graph(s), as .svg files."); print("The graph(s) reside in the \"" + os.path.join(my_dir, "{env:SO_MAGIC_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
$SO_MAGIC_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).
setenv =
{[testenv]setenv}
# include dirs to pythonpath to solve issue of inspect lib failing with for some relative imports
PYTHONPATH={toxinidir}/src/so_magic:{toxinidir}/src/so_magic/data
SO_MAGIC_UML_DIAGRAMS=uml-diagrams
deps =
attrs
pandas
numpy
scikit-learn
pylint==2.7.4
skip_install = false
use_develop = true
commands_pre =
- python -c 'import os; my_dir = os.getcwd(); os.mkdir(os.path.join(my_dir, "{env:SO_MAGIC_UML_DIAGRAMS}"))'
commands =
python -c 'import sys; print(sys.path)'
# so_magic.utils
pyreverse -o {posargs:png} -A -p utils src/so_magic/utils
# so_magic.som
pyreverse -o {posargs:png} -A -p som src/so_magic/som
# so_magic.data.datapoints
pyreverse -o {posargs:png} -A -p data.datapoints src/so_magic/data/datapoints
# so_magic.data.features
pyreverse -o {posargs:png} -A -p data.features src/so_magic/data/features
# so_magic.data.backend
pyreverse -o {posargs:png} -A -p data.backend src/so_magic/data/backend
pyreverse -o {posargs:png} -k -A -p data.backend-only-class-names src/so_magic/data/backend
# so_magic.data.variables
pyreverse -o {posargs:png} -A -p data.variables src/so_magic/data/variables
# so_magic.data
pyreverse -o {posargs:png} -A -p data src/so_magic/data
pyreverse -o {posargs:png} -k -A -p data-only-class-names src/so_magic/data
# so_magic
pyreverse -o {posargs:png} -A -p so_magic src/so_magic
pyreverse -o {posargs:png} -k -A -p so_magic-only-class-names src/so_magic
# so_magic.so_master
pyreverse -o {posargs:png} -A -p so_magic.so_master src/so_magic/so_master.py
pyreverse -o {posargs:png} -A -p data.data_manager src/so_magic/data/data_manager.py
pyreverse -o {posargs:png} -A -p data.magic_datapoints_factory src/so_magic/data/magic_datapoints_factory.py
# MOVE uml diagram files manually into $SO_MAGIC_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:SO_MAGIC_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:SO_MAGIC_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:SO_MAGIC_UML_DIAGRAMS}") + "\" directory.\n")'