diff options
Diffstat (limited to 'tasks.py')
-rw-r--r-- | tasks.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..3a7e1e3 --- /dev/null +++ b/tasks.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +"""Common development tasks for setup.py to use.""" + +import re +import subprocess +import sys + +from setuptools import Command + + +class BaseCommand(Command, object): + """The base command for project tasks.""" + + user_options = [] + + default_cmd_options = ("verbose", "quiet", "dry_run") + + def __init__(self, *args, **kwargs): + super(BaseCommand, self).__init__(*args, **kwargs) + self.verbose = False + + def initialize_options(self): + """Override the distutils abstract method.""" + pass + + def finalize_options(self): + """Override the distutils abstract method.""" + # Distutils uses incrementing integers for verbosity. + self.verbose = bool(self.verbose) + + def call_and_exit(self, cmd, shell=True): + """Run the *cmd* and exit with the proper exit code.""" + sys.exit(subprocess.call(cmd, shell=shell)) + + def call_in_sequence(self, cmds, shell=True): + """Run multiple commmands in a row, exiting if one fails.""" + for cmd in cmds: + if subprocess.call(cmd, shell=shell) == 1: + sys.exit(1) + + def apply_options(self, cmd, options=()): + """Apply command-line options.""" + for option in self.default_cmd_options + options: + cmd = self.apply_option(cmd, option, active=getattr(self, option, False)) + return cmd + + def apply_option(self, cmd, option, active=True): + """Apply a command-line option.""" + return re.sub( + r"{{{}\:(?P<option>[^}}]*)}}".format(option), + r"\g<option>" if active else "", + cmd, + ) + + +class lint(BaseCommand): + """A PEP 8 lint command that optionally fixes violations.""" + + description = "check code against PEP 8 (and fix violations)" + + user_options = [ + ("branch=", "b", "branch or revision to compare against (e.g. master)"), + ("fix", "f", "fix the violations in place"), + ] + + def initialize_options(self): + """Set the default options.""" + self.branch = "master" + self.fix = False + super(lint, self).initialize_options() + + def run(self): + """Run the linter.""" + cmd = "black ." + cmd = cmd.format(branch=self.branch) + self.call_and_exit(self.apply_options(cmd, ("fix",))) + + +class test(BaseCommand): + """Run the test suites for this project.""" + + description = "run the test suite" + + user_options = [ + ("all", "a", "test against all supported versions of Python"), + ("coverage", "c", "measure test coverage"), + ] + + unit_test_cmd = ( + "pytest{quiet: -q}{verbose: -v}{dry_run: --setup-only}" + "{coverage: --cov-report= --cov=cli_helpers}" + ) + test_all_cmd = "tox{verbose: -v}{dry_run: --notest}" + coverage_cmd = "coverage report" + + def initialize_options(self): + """Set the default options.""" + self.all = False + self.coverage = False + super(test, self).initialize_options() + + def run(self): + """Run the test suites.""" + if self.all: + cmd = self.apply_options(self.test_all_cmd) + self.call_and_exit(cmd) + else: + cmds = (self.apply_options(self.unit_test_cmd, ("coverage",)),) + if self.coverage: + cmds += (self.apply_options(self.coverage_cmd),) + self.call_in_sequence(cmds) + + +class docs(BaseCommand): + """Use Sphinx Makefile to generate documentation.""" + + description = "generate the Sphinx HTML documentation" + + clean_docs_cmd = "make -C docs clean" + html_docs_cmd = "make -C docs html" + view_docs_cmd = "open docs/build/html/index.html" + + def run(self): + """Generate and view the documentation.""" + cmds = (self.clean_docs_cmd, self.html_docs_cmd, self.view_docs_cmd) + self.call_in_sequence(cmds) |