My integration scheme usually works somewhat like this, though it changes in complexity per project:
README.rst that suggests a Developing section, specifying that virtualenv and pip are required and instructs the developer to use prepare an existing virtualenv environment for testing using,
python setup.py develop, achieved by a custom SetupDevelop command class in setup.py, that derives the run() method to assert that os.getenv('VIRTUAL_ENV') is defined (to remind you not to pollute your environment accidentally), run the baseclass setuptools.command.develop.develop.run(), which installs the egg link to allow rapidly editing without re-installing, and then call self.spawn(('pip', 'install', '--upgrade', '--requirement', 'requirements-dev.txt')).
setup.py file contains:
from setuptools.command.develop import develop class SetupDevelop(develop): """ 'setup.py develop' is augmented to install development tools. """ # pylint: disable=R0904 # Too many public methods (43/20) def run(self): """ Execute command pip for development requirements. """ # pylint: disable=E1101 # Instance of 'SetupDevelop' has no 'spawn' member (col 8) assert os.getenv('VIRTUAL_ENV'), 'You should be in a virtualenv' develop.run(self) self.spawn(('pip', 'install', '--upgrade', '--requirement', 'requirements-dev.txt')) setup( name=PACKAGE_NAME, version=VERSION, (...) cmdclass={ 'develop': SetupDevelop, }, )
requirements-dev.txt file contains:
# This file contains dependencies required for running tests, and any other # miscellaneous developer tools tox IPython
tox.ini file contains:
[tox] envlist = prospector, py27, py34, [testenv] # for any python, run simple pytest with coverage deps = -r{toxinidir}/requirements-testing.txt commands = {envbindir}/py.test --strict --cov {envsitepackagesdir}/PACKAGENAME \ PACKAGE/TESTS {posargs} [testenv:prospector] # run static analysis using prospector deps = -r{toxinidir}/requirements-analysis.txt commands = prospector \ --die-on-tool-error \ --test-warnings \ --doc-warnings \ {toxinidir}
requirements-testing.txt file containing:
# This file contains python dependencies required by tox when running tests webtest==2.0.6 pytest==2.6.4 pytest-cov==1.6
requirements-analysis.txt file containing:
prospector[with_dodgy,with_frosted,with_mccabe,with_pep257,with_pep8,with_pyroma,with_vulture]
and a sample .prospector.yaml file containing:
inherits: - strictness_veryhigh ignore: - (^|/)\..+ - ^docs/ - ^build/ test-warnings: true output-format: grouped dodgy: # Looks at Python code to search for things which look "dodgy" # such as passwords or git conflict artifacts run: true frosted: # static analysis run: true mccabe: # complexity checking. run: true pep257: # docstring checking run: true pep8: # style checking run: true options: max-line-length: 100 pyflakes: # preferring 'frosted' instead (a fork of) run: false pylint: # static analysis and then some run: true options: max-line-length: 100 # allow 'log' as global constant const-rgx: "(([A-Z_][A-Z0-9_]*)|(__.*__)|log)$" const-hint: "(([A-Z_][A-Z0-9_]*)|(__.*__)|log)$" # pytest module has dynamically assigned functions, # raising errors such as: E1101: Module 'pytest' has # no 'mark' member ignored-classes: pytest disable: # Too many lines in module - C0302 # Used * or ** magic - W0142 # Used builtin function 'filter'. # (For maintainability, one should prefer list comprehension.) - W0141 pyroma: # checks setup.py run: true vulture: # this tool does a good job of finding unused code. run: true
The workflow then simply becomes:
- create or active a virtualenv (mkvirtualenv, workon, etc.)
- run ./setup.py develop
- run tox, or optionally just tox -eprospector for static analysis