diff --git a/.gitignore b/.gitignore index 3815d553..70d616a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +tox.ini + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/.travis.yml b/.travis.yml index eefc834b..fa99e4d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,6 +65,6 @@ install: - pip freeze - printenv script: - - $TRAVISCMD tox -vv -e $TOXENV -- $TOTEST + - $TRAVISCMD tox -c tox-pyenv.ini -e $TOXENV -- $TOTEST after_success: - codecov diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b7127071..b9657c6c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -90,7 +90,15 @@ to see the available make targets. If you cannot use ``make``, but want to use $ tox -av -to see a list of tox environments and a description. +to see a list of tox environments and a description. For the initial +configuration of tox environments, you may have to run + +.. code-block:: console + + $ tox -e bootstrap + +in order to set up the ``tox.ini`` configuration file. + If you are a member of the `qucontrol organization`_, there is no need to fork ``krotov`` - you can directly pull and push to ``git@github.com:qucontrol/krotov.git``. @@ -128,7 +136,8 @@ that you may run into occasional binary incompatibilities between conda packages If you want to use `conda`, you must use the ``tox-conda.ini`` configuration file. That is, run all ``make`` comands as e.g. ``make TOXINI=tox-conda.ini test`` and ``tox`` commands as e.g. - ``tox -c tox-conda.ini -e py35-test,py36-test,py37-test`` + ``tox -c tox-conda.ini -e py35-test,py36-test,py37-test``. Alternatively, + make ``tox-conda.ini`` the default by copying it to ``tox.ini``. .. _pyenv: https://github.com/pyenv/pyenv .. _pyenv-win: https://github.com/pyenv-win/pyenv-win @@ -258,7 +267,7 @@ Testing The Krotov package includes a full test-suite using pytest_. We strive for a `test coverage`_ above 90%. -From a checkout of the ``krotov`` repository, assuming conda_ is installed, you can use +From a checkout of the ``krotov`` repository, you can use .. code-block:: console @@ -315,8 +324,9 @@ requirements. These hooks are managed through the `pre-commit framework`_. .. warning:: After cloning the ``krotov`` repository, you should run - ``make bootstrap``, or ``tox -e run-cmd -- pre-commit install`` - from within the project root folder. + ``make bootstrap``, ``tox -e bootstrap``, or ``python scripts/bootstrap.py`` + from within the project root folder. These set up ``tox``, and the + pre-commit hooks .. _pre-commit framework: https://pre-commit.com @@ -373,8 +383,7 @@ Also see :ref:`math-in-example-notebooks`. You may use the BibTeX_ plugin for citations. -At any point, from a checkout of the ``krotov`` repository (and -assuming you have conda_ installed), you may run +At any point, from a checkout of the ``krotov`` repository, you may run .. code-block:: console diff --git a/Makefile b/Makefile index 53f21662..5b10f65c 100644 --- a/Makefile +++ b/Makefile @@ -22,53 +22,33 @@ e.g. with `make TOXINI=tox-conda.ini test` You may also run `tox` directly. See endef export PRINT_HELP_PYSCRIPT -define BOOTSTRAP_PYSCRIPT -import sys -import os -from textwrap import dedent -try: - import tox - TOXINI = os.environ.get('TOXINI', 'tox.ini') - if not os.path.isfile(".git/hooks/pre-commit"): - print("bootstrapping pre-commit hook") - cmdline = ['-c', TOXINI, '-e', 'run-cmd', '--', 'pre-commit', 'install'] - print("tox " + " ".join(cmdline)) - tox.cmdline(cmdline) -except ImportError: - print(dedent(""" - tox is not available. See https://tox.readthedocs.io for installation - instructions. - """)) - sys.exit(1) -endef -export BOOTSTRAP_PYSCRIPT help: ## show this help @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) bootstrap: ## verify that tox is available and pre-commit hooks are active - @TOXINI="$(TOXINI)" python -c "$$BOOTSTRAP_PYSCRIPT" + python scripts/bootstrap.py -clean: ## remove all build, test, coverage, and Python artifacts, as well as environments +clean: bootstrap ## remove all build, test, coverage, and Python artifacts, as well as environments $(TOX) -e clean -clean-build: ## remove build artifacts +clean-build: bootstrap ## remove build artifacts $(TOX) -e clean-build -clean-tests: ## remove test and coverage artifacts +clean-tests: bootstrap ## remove test and coverage artifacts $(TOX) -e clean-tests -clean-venvs: ## remove tox virtual environments +clean-venvs: bootstrap ## remove tox virtual environments $(TOX) -e clean-venv -clean-docs: ## remove documentation artifacts +clean-docs: bootstrap ## remove documentation artifacts $(TOX) -e clean-docs -flake8-check: ## check style with flake8 +flake8-check: bootstrap ## check style with flake8 $(TOX) -e run-flake8 -pylint-check: ## check style with pylint +pylint-check: bootstrap ## check style with pylint $(TOX) -e run-pylint test: bootstrap ## run tests for current stable Python release diff --git a/scripts/bootstrap.py b/scripts/bootstrap.py new file mode 100755 index 00000000..02e4d30f --- /dev/null +++ b/scripts/bootstrap.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +"""Bootstrap script for setting up tox and pre-commit hooks + +This scripts is called either by any invocation of the Makefile, or by the tox +configuration in setup.cvg, if there is no tox.ini. + +It sets up the main tox.ini file and the pre-commit hooks. +""" +import os +import pathlib +import shutil +import sys + + +_TOX_ERR_MSG = r''' +tox is not available. See https://tox.readthedocs.io for installation +instructions. +''' + + +def main(argv=None): + """Main function""" + if argv is None: + argv = sys.argv + root = pathlib.Path(__file__).parent.parent + + # 1. Bootstrap the tox.ini file + if not (root / 'tox.ini').is_file(): + tox_ini = os.environ.get('TOXINI', 'tox-pyenv.ini') + if not (root / tox_ini).is_file(): + tox_ini = 'tox-pyenv.ini' + tox_src = root / tox_ini + tox_dst = root / "tox.ini" + print("Copying %s to %s" % (tox_src, tox_dst)) + shutil.copyfile(tox_src, tox_dst) + + # 2. Ensure tox is installed + try: + import tox + except ImportError: + print(_TOX_ERR_MSG) + sys.exit(1) + + # 3. Ensure pre-commit hooks are installed + if not (root / ".git" / "hooks" / "pre-commit").is_file(): + # we're using the tox.ini environments that we got from step 1 + print("bootstrapping pre-commit hook") + cmdline = ['-e', 'run-cmd', '--', 'pre-commit', 'install'] + print("tox " + " ".join(cmdline)) + tox.cmdline(cmdline) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/setup.cfg b/setup.cfg index 7a05001b..fbdb1502 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,3 +29,16 @@ use_parentheses = True multi_line_output = 3 include_trailing_comma = True skip = src/krotov/__init__.py + +[tox:tox] +minversion = 3.7 +envlist = bootstrap + +[testenv:bootstrap] +description = "Configure tox" +whitelist_externals = + python +skip_install = True +deps = tox +commands = + python scripts/bootstrap.py diff --git a/tox-conda.ini b/tox-conda.ini index 1a4eb240..a632d47a 100644 --- a/tox-conda.ini +++ b/tox-conda.ini @@ -10,7 +10,7 @@ envdir = {toxworkdir}/.tox [testenv] basepython = # current "stable" python - py37,run,docs,coverage: python3.7 + py37,run,docs,coverage,clean,bootstrap: python3.7 # older pythons py36: python3.6 py35: python3.5 @@ -58,6 +58,17 @@ commands = sphinx-build . _build {posargs:--color} +[testenv:bootstrap] +description = "Configure tox" +envdir = {toxworkdir}/bootstrap +deps = tox +conda_deps = +skip_install = True +commands_pre = +commands = + python scripts/bootstrap.py + + [testenv:clean] description = "Clean up" envdir = {toxworkdir}/clean_ diff --git a/tox.ini b/tox-pyenv.ini similarity index 95% rename from tox.ini rename to tox-pyenv.ini index be080da8..40078584 100644 --- a/tox.ini +++ b/tox-pyenv.ini @@ -9,7 +9,7 @@ envdir = {toxworkdir}/.tox [testenv] basepython = # current "stable" python - py37,run,docs,coverage,clean: python3.7 + py37,run,docs,coverage,clean,bootstrap: python3.7 # older pythons py36: python3.6 py35: python3.5 @@ -63,6 +63,16 @@ commands = sphinx-build . _build {posargs:--color} +[testenv:bootstrap] +description = "Configure tox" +envdir = {toxworkdir}/bootstrap +deps = tox +skip_install = True +commands_pre = +commands = + python scripts/bootstrap.py + + [testenv:clean] description = "Clean up" envdir = {toxworkdir}/clean_