diff --git a/noxfile.py b/noxfile.py index 2a72dfe..683ab79 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,8 +1,9 @@ """Configure nox for the isolated test and lint environments.""" +import contextlib import os import tempfile -from typing import Any +from typing import Any, Generator import nox from nox.sessions import Session @@ -34,7 +35,7 @@ nox.options.sessions = ( @nox.session(name='format', python=MAIN_PYTHON) -def format_(session: Session): +def format_(session: Session) -> None: """Format source files with autoflake, black, and isort.""" _begin(session) _install_packages(session, 'autoflake', 'black', 'isort') @@ -54,24 +55,52 @@ def format_(session: Session): ) session.run('black', '--version') session.run('black', *locations) - session.run('isort', '--version') - session.run('isort', *locations) + with _isort_fix(session): # TODO (isort): Remove after upgrading + session.run('isort', '--version') + session.run('isort', *locations) @nox.session(python=MAIN_PYTHON) -def lint(session: Session): - """Lint source files.""" +def lint(session: Session) -> None: + """Lint source files with flake8, mypy, and pylint.""" _begin(session) + _install_packages( + session, + 'flake8', + 'flake8-annotations', + 'flake8-black', + 'flake8-expression-complexity', + 'mypy', + 'pylint', + 'wemake-python-styleguide', + ) + # Interpret extra arguments as locations of source files. + locations = session.posargs or SRC_LOCATIONS + session.run('flake8', '--version') + session.run('flake8', '--ignore=I0', *locations) # TODO (isort): Remove flag + with _isort_fix(session): # TODO (isort): Remove after upgrading + session.run('isort', '--version') + session.run('isort', '--check-only', *locations) + session.run('mypy', '--version') + session.run('mypy', *locations) + # Ignore errors where pylint cannot import a third-party package due its + # being run in an isolated environment. One way to fix this is to install + # all develop dependencies in this nox session, which we do not do. The + # whole point of static linting tools is to not rely on any package be + # importable at runtime. Instead, these imports are validated implicitly + # when the test suite is run. + session.run('pylint', '--version') + session.run('pylint', '--disable=import-error', *locations) @nox.session(python=[MAIN_PYTHON, NEXT_PYTHON]) -def test(session: Session): +def test(session: Session) -> None: """Test the code base.""" _begin(session) @nox.session(name='pre-commit', python=MAIN_PYTHON, venv_backend='none') -def pre_commit(session: Session): +def pre_commit(session: Session) -> None: """Source files must be well-formed before they enter git.""" _begin(session) session.notify('format') @@ -79,7 +108,7 @@ def pre_commit(session: Session): @nox.session(name='pre-merge', python=MAIN_PYTHON, venv_backend='none') -def pre_merge(session: Session): +def pre_merge(session: Session) -> None: """The test suite must pass before merges are made.""" _begin(session) session.notify('test') @@ -88,17 +117,17 @@ def pre_merge(session: Session): def _begin(session: Session) -> None: """Show generic info about a session.""" if session.posargs: - print('extra arguments:', *session.posargs) + print('extra arguments:', *session.posargs) # noqa:WPS421 session.run('python', '--version') # Fake GNU's pwd. session.log('pwd') - print(os.getcwd()) + print(os.getcwd()) # noqa:WPS421 def _install_packages( - session: Session, *packages_or_pip_args: str, **kwargs: Any + session: Session, *packages_or_pip_args: str, **kwargs: Any, ) -> None: """Install packages respecting the poetry.lock file. @@ -110,7 +139,7 @@ def _install_packages( session: the Session object *packages_or_pip_args: the packages to be installed or pip options **kwargs: passed on to nox.sessions.Session.install() - """ + """ # noqa:RST210,RST213 if session.virtualenv.reuse_existing: session.log( 'No dependencies are installed as an existing environment is re-used', @@ -131,3 +160,15 @@ def _install_packages( session.install( f'--constraint={requirements_txt.name}', *packages_or_pip_args, **kwargs, ) + + +# TODO (isort): Remove this fix after +# upgrading to isort ^5.2.2 in pyproject.toml. +@contextlib.contextmanager +def _isort_fix(session: Session) -> Generator: + """Temporarily upgrade to isort 5.2.2.""" + session.install('isort==5.2.2') + try: + yield + finally: + session.install('isort==4.3.21') diff --git a/poetry.lock b/poetry.lock index ffceece..2c6ed11 100644 --- a/poetry.lock +++ b/poetry.lock @@ -17,6 +17,38 @@ version = "1.12.0" [package.extras] test = ["coverage", "flake8", "pexpect", "wheel"] +[[package]] +category = "dev" +description = "Read/rewrite/write Python ASTs" +name = "astor" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "0.8.1" + +[[package]] +category = "dev" +description = "Pretty print the output of python stdlib `ast.parse`." +name = "astpretty" +optional = false +python-versions = ">=3.6.1" +version = "2.0.0" + +[package.extras] +typed = ["typed-ast"] + +[[package]] +category = "dev" +description = "An abstract syntax tree for Python with inference support." +name = "astroid" +optional = false +python-versions = ">=3.5" +version = "2.4.2" + +[package.dependencies] +lazy-object-proxy = ">=1.4.0,<1.5.0" +six = ">=1.12,<2.0" +wrapt = ">=1.11,<2.0" + [[package]] category = "dev" description = "Classes Without Boilerplate" @@ -42,6 +74,21 @@ version = "1.3.1" [package.dependencies] pyflakes = ">=1.1.0" +[[package]] +category = "dev" +description = "Security oriented static analyser for python code." +name = "bandit" +optional = false +python-versions = "*" +version = "1.6.2" + +[package.dependencies] +GitPython = ">=1.0.1" +PyYAML = ">=3.13" +colorama = ">=0.3.9" +six = ">=1.10.0" +stevedore = ">=1.20.0" + [[package]] category = "dev" description = "The uncompromising code formatter." @@ -73,7 +120,7 @@ version = "7.1.2" [[package]] category = "dev" description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" +marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -90,6 +137,14 @@ version = "4.2.1" [package.dependencies] colorama = "*" +[[package]] +category = "dev" +description = "A utility for ensuring Google-style docstrings stay up to date with the source code." +name = "darglint" +optional = false +python-versions = ">=3.5,<4.0" +version = "1.5.2" + [[package]] category = "dev" description = "Distribution utilities" @@ -98,6 +153,22 @@ optional = false python-versions = "*" version = "0.3.1" +[[package]] +category = "dev" +description = "Docutils -- Python Documentation Utilities" +name = "docutils" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.16" + +[[package]] +category = "dev" +description = "Removes commented-out code." +name = "eradicate" +optional = false +python-versions = "*" +version = "1.0" + [[package]] category = "dev" description = "A platform independent file lock." @@ -106,18 +177,290 @@ optional = false python-versions = "*" version = "3.0.12" +[[package]] +category = "dev" +description = "the modular source code checker: pep8 pyflakes and co" +name = "flake8" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +version = "3.8.3" + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.6.0a1,<2.7.0" +pyflakes = ">=2.2.0,<2.3.0" + +[[package]] +category = "dev" +description = "Flake8 Type Annotation Checks" +name = "flake8-annotations" +optional = false +python-versions = ">=3.6.1,<4.0.0" +version = "2.3.0" + +[package.dependencies] +flake8 = ">=3.7,<3.9" + +[[package]] +category = "dev" +description = "Automated security testing with bandit and flake8." +name = "flake8-bandit" +optional = false +python-versions = "*" +version = "2.1.2" + +[package.dependencies] +bandit = "*" +flake8 = "*" +flake8-polyfill = "*" +pycodestyle = "*" + +[[package]] +category = "dev" +description = "flake8 plugin to call black as a code style validator" +name = "flake8-black" +optional = false +python-versions = "*" +version = "0.2.1" + +[package.dependencies] +black = "*" +flake8 = ">=3.0.0" + +[[package]] +category = "dev" +description = "Flake8 plugin to forbid backslashes for line breaks" +name = "flake8-broken-line" +optional = false +python-versions = ">=3.6,<4.0" +version = "0.2.1" + +[package.dependencies] +flake8 = ">=3.5,<4.0" + +[[package]] +category = "dev" +description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." +name = "flake8-bugbear" +optional = false +python-versions = ">=3.5" +version = "19.8.0" + +[package.dependencies] +attrs = "*" +flake8 = ">=3.0.0" + +[[package]] +category = "dev" +description = "Flake8 lint for trailing commas." +name = "flake8-commas" +optional = false +python-versions = "*" +version = "2.0.0" + +[package.dependencies] +flake8 = ">=2,<4.0.0" + +[[package]] +category = "dev" +description = "A flake8 plugin to help you write better list/set/dict comprehensions." +name = "flake8-comprehensions" +optional = false +python-versions = ">=3.5" +version = "3.2.3" + +[package.dependencies] +flake8 = ">=3.0,<3.2.0 || >3.2.0,<4" + +[[package]] +category = "dev" +description = "ipdb/pdb statement checker plugin for flake8" +name = "flake8-debugger" +optional = false +python-versions = "*" +version = "3.2.1" + +[package.dependencies] +flake8 = ">=1.5" +pycodestyle = "*" + +[[package]] +category = "dev" +description = "Extension for flake8 which uses pydocstyle to check docstrings" +name = "flake8-docstrings" +optional = false +python-versions = "*" +version = "1.5.0" + +[package.dependencies] +flake8 = ">=3" +pydocstyle = ">=2.1" + +[[package]] +category = "dev" +description = "Flake8 plugin to find commented out code" +name = "flake8-eradicate" +optional = false +python-versions = ">=3.6,<4.0" +version = "0.3.0" + +[package.dependencies] +attrs = "*" +eradicate = ">=1.0,<2.0" +flake8 = ">=3.5,<4.0" + +[[package]] +category = "dev" +description = "A flake8 extension that checks expressions complexity" +name = "flake8-expression-complexity" +optional = false +python-versions = ">=3.6" +version = "0.0.8" + +[package.dependencies] +astpretty = "*" +flake8 = "*" +setuptools = "*" + +[[package]] +category = "dev" +description = "flake8 plugin that integrates isort ." +name = "flake8-isort" +optional = false +python-versions = "*" +version = "3.0.1" + +[package.dependencies] +flake8 = ">=3.2.1,<4" +testfixtures = ">=6.8.0,<7" + +[package.dependencies.isort] +extras = ["pyproject"] +version = ">=4.3.5,<5" + +[package.extras] +test = ["pytest (>=4.0.2,<6)"] + +[[package]] +category = "dev" +description = "Polyfill package for Flake8 plugins" +name = "flake8-polyfill" +optional = false +python-versions = "*" +version = "1.0.2" + +[package.dependencies] +flake8 = "*" + +[[package]] +category = "dev" +description = "Flake8 lint for quotes." +name = "flake8-quotes" +optional = false +python-versions = "*" +version = "2.1.2" + +[package.dependencies] +flake8 = "*" + +[[package]] +category = "dev" +description = "Python docstring reStructuredText (RST) validator" +name = "flake8-rst-docstrings" +optional = false +python-versions = "*" +version = "0.0.12" + +[package.dependencies] +flake8 = ">=3.0.0" +restructuredtext_lint = "*" + +[[package]] +category = "dev" +description = "string format checker, plugin for flake8" +name = "flake8-string-format" +optional = false +python-versions = "*" +version = "0.2.3" + +[package.dependencies] +flake8 = "*" + +[[package]] +category = "dev" +description = "Git Object Database" +name = "gitdb" +optional = false +python-versions = ">=3.4" +version = "4.0.5" + +[package.dependencies] +smmap = ">=3.0.1,<4" + +[[package]] +category = "dev" +description = "Python Git Library" +name = "gitpython" +optional = false +python-versions = ">=3.4" +version = "3.1.7" + +[package.dependencies] +gitdb = ">=4.0.1,<5" + [[package]] category = "dev" description = "A Python utility / library to sort Python imports." name = "isort" optional = false -python-versions = ">=3.6,<4.0" -version = "5.2.2" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "4.3.21" [package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib", "tomlkit (>=0.5.3)"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] +pipfile = ["pipreqs", "requirementslib"] +pyproject = ["toml"] +requirements = ["pipreqs", "pip-api"] +xdg_home = ["appdirs (>=1.4.0)"] + +[[package]] +category = "dev" +description = "A fast and thorough lazy object proxy." +name = "lazy-object-proxy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.3" + +[[package]] +category = "dev" +description = "McCabe checker, plugin for flake8" +name = "mccabe" +optional = false +python-versions = "*" +version = "0.6.1" + +[[package]] +category = "dev" +description = "Optional static typing for Python" +name = "mypy" +optional = false +python-versions = ">=3.5" +version = "0.782" + +[package.dependencies] +mypy-extensions = ">=0.4.3,<0.5.0" +typed-ast = ">=1.4.0,<1.5.0" +typing-extensions = ">=3.7.4" + +[package.extras] +dmypy = ["psutil (>=4.0)"] + +[[package]] +category = "dev" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +name = "mypy-extensions" +optional = false +python-versions = "*" +version = "0.4.3" [[package]] category = "dev" @@ -144,6 +487,25 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "0.8.0" +[[package]] +category = "dev" +description = "Python Build Reasonableness" +name = "pbr" +optional = false +python-versions = "*" +version = "5.4.5" + +[[package]] +category = "dev" +description = "Check PEP-8 naming conventions, plugin for flake8" +name = "pep8-naming" +optional = false +python-versions = "*" +version = "0.9.1" + +[package.dependencies] +flake8-polyfill = ">=1.0.2,<2" + [[package]] category = "dev" description = "library with cross-python path, ini-parsing, io, code, log facilities" @@ -152,6 +514,25 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.9.0" +[[package]] +category = "dev" +description = "Python style guide checker" +name = "pycodestyle" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.6.0" + +[[package]] +category = "dev" +description = "Python docstring style checker" +name = "pydocstyle" +optional = false +python-versions = ">=3.5" +version = "5.0.2" + +[package.dependencies] +snowballstemmer = "*" + [[package]] category = "dev" description = "passive checker of Python programs" @@ -160,6 +541,37 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.2.0" +[[package]] +category = "dev" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = ">=3.5" +version = "2.6.1" + +[[package]] +category = "dev" +description = "python code static checker" +name = "pylint" +optional = false +python-versions = ">=3.5.*" +version = "2.5.3" + +[package.dependencies] +astroid = ">=2.4.0,<=2.5" +colorama = "*" +isort = ">=4.2.5,<5" +mccabe = ">=0.6,<0.7" +toml = ">=0.7.1" + +[[package]] +category = "dev" +description = "YAML parser and emitter for Python" +name = "pyyaml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.3.1" + [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -168,6 +580,17 @@ optional = false python-versions = "*" version = "2020.7.14" +[[package]] +category = "dev" +description = "reStructuredText linter" +name = "restructuredtext-lint" +optional = false +python-versions = "*" +version = "1.3.1" + +[package.dependencies] +docutils = ">=0.11,<1.0" + [[package]] category = "dev" description = "Python 2 and 3 compatibility utilities" @@ -176,6 +599,46 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" version = "1.15.0" +[[package]] +category = "dev" +description = "A pure Python implementation of a sliding window memory map manager" +name = "smmap" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.0.4" + +[[package]] +category = "dev" +description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." +name = "snowballstemmer" +optional = false +python-versions = "*" +version = "2.0.0" + +[[package]] +category = "dev" +description = "Manage dynamic plugins for Python applications" +name = "stevedore" +optional = false +python-versions = ">=3.6" +version = "3.2.0" + +[package.dependencies] +pbr = ">=2.0.0,<2.1.0 || >2.1.0" + +[[package]] +category = "dev" +description = "A collection of helpers and mock objects for unit tests and doc tests." +name = "testfixtures" +optional = false +python-versions = "*" +version = "6.14.1" + +[package.extras] +build = ["setuptools-git", "wheel", "twine"] +docs = ["sphinx", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"] +test = ["pytest (>=3.6)", "pytest-cov", "pytest-django", "zope.component", "sybil", "twisted", "mock", "django (<2)", "django"] + [[package]] category = "dev" description = "Python Library for Tom's Obvious, Minimal Language" @@ -192,6 +655,14 @@ optional = false python-versions = "*" version = "1.4.1" +[[package]] +category = "dev" +description = "Backported and Experimental Type Hints for Python 3.5+" +name = "typing-extensions" +optional = false +python-versions = "*" +version = "3.7.4.2" + [[package]] category = "dev" description = "Virtual Python Environment builder" @@ -210,8 +681,45 @@ six = ">=1.9.0,<2" docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] testing = ["coverage (>=5)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "pytest-xdist (>=1.31.0)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] +[[package]] +category = "dev" +description = "The strictest and most opinionated python linter ever" +name = "wemake-python-styleguide" +optional = false +python-versions = ">=3.6,<4.0" +version = "0.14.1" + +[package.dependencies] +astor = ">=0.8,<0.9" +attrs = "*" +darglint = ">=1.2,<2.0" +flake8 = ">=3.7,<4.0" +flake8-bandit = ">=2.1,<3.0" +flake8-broken-line = ">=0.2,<0.3" +flake8-bugbear = ">=19.3,<20.0" +flake8-commas = ">=2.0,<3.0" +flake8-comprehensions = ">=3.1.0,<4.0.0" +flake8-debugger = ">=3.1,<4.0" +flake8-docstrings = ">=1.3.1,<2.0.0" +flake8-eradicate = ">=0.3,<0.4" +flake8-isort = ">=3.0.1,<4" +flake8-quotes = ">=2.0.1,<3.0.0" +flake8-rst-docstrings = ">=0.0.12,<0.0.13" +flake8-string-format = ">=0.2,<0.3" +pep8-naming = ">=0.9.1,<0.10.0" +pygments = ">=2.4,<3.0" +typing_extensions = ">=3.6,<4.0" + +[[package]] +category = "dev" +description = "Module for decorators, wrappers and monkey patching." +name = "wrapt" +optional = false +python-versions = "*" +version = "1.12.1" + [metadata] -content-hash = "9894f7290cbab39b1fa0f3d0ba9cd2aebe16228169867415a69e039ee2b12425" +content-hash = "e69534c9133ef3fb975f33937c97711f69281a8ffb931097a7b9e4ae1132fa09" lock-version = "1.0" python-versions = "^3.8" @@ -224,6 +732,18 @@ argcomplete = [ {file = "argcomplete-1.12.0-py2.py3-none-any.whl", hash = "sha256:91dc7f9c7f6281d5a0dce5e73d2e33283aaef083495c13974a7dd197a1cdc949"}, {file = "argcomplete-1.12.0.tar.gz", hash = "sha256:2fbe5ed09fd2c1d727d4199feca96569a5b50d44c71b16da9c742201f7cc295c"}, ] +astor = [ + {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, + {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, +] +astpretty = [ + {file = "astpretty-2.0.0-py2.py3-none-any.whl", hash = "sha256:7f27633ed885033da8b58666e7079ffff7e8e01869ec1aa66484cb5185ea3aa4"}, + {file = "astpretty-2.0.0.tar.gz", hash = "sha256:e4724bfd753636ba4a84384702e9796e5356969f40af2596d846ce64addde086"}, +] +astroid = [ + {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, + {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, +] attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, @@ -231,6 +751,10 @@ attrs = [ autoflake = [ {file = "autoflake-1.3.1.tar.gz", hash = "sha256:680cb9dade101ed647488238ccb8b8bfb4369b53d58ba2c8cdf7d5d54e01f95b"}, ] +bandit = [ + {file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"}, + {file = "bandit-1.6.2.tar.gz", hash = "sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"}, +] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, @@ -247,17 +771,145 @@ colorlog = [ {file = "colorlog-4.2.1-py2.py3-none-any.whl", hash = "sha256:43597fd822ce705190fc997519342fdaaf44b9b47f896ece7aa153ed4b909c74"}, {file = "colorlog-4.2.1.tar.gz", hash = "sha256:75e55822c3a3387d721579241e776de2cf089c9ef9528b1f09e8b04d403ad118"}, ] +darglint = [ + {file = "darglint-1.5.2-py3-none-any.whl", hash = "sha256:049a98cf3aec8cf6ea344a863c68112d80b7f8de214459b5fa6853371f89c3e7"}, + {file = "darglint-1.5.2.tar.gz", hash = "sha256:6b9461f96694c2cf1d8edb1597a783fe6840953b0eb18cc6cc1e72a26f196d79"}, +] distlib = [ {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, ] +docutils = [ + {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, + {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, +] +eradicate = [ + {file = "eradicate-1.0.tar.gz", hash = "sha256:4ffda82aae6fd49dfffa777a857cb758d77502a1f2e0f54c9ac5155a39d2d01a"}, +] filelock = [ {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, ] +flake8 = [ + {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"}, + {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"}, +] +flake8-annotations = [ + {file = "flake8-annotations-2.3.0.tar.gz", hash = "sha256:8d18db74a750dd97f40b483cc3ef80d07d03f687525bad8fd83365dcd3bfd414"}, + {file = "flake8_annotations-2.3.0-py3-none-any.whl", hash = "sha256:7816a5d8f65ffdf37b8e21e5b17e0fd1e492aa92638573276de066e889a22b26"}, +] +flake8-bandit = [ + {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"}, +] +flake8-black = [ + {file = "flake8-black-0.2.1.tar.gz", hash = "sha256:f26651bc10db786c03f4093414f7c9ea982ed8a244cec323c984feeffdf4c118"}, +] +flake8-broken-line = [ + {file = "flake8-broken-line-0.2.1.tar.gz", hash = "sha256:414477070231a5aa05468d48db2742a594b53fbc1ecba28044646706a11fb861"}, + {file = "flake8_broken_line-0.2.1-py3-none-any.whl", hash = "sha256:75858359e3ccd4f1d92a9e7582aa5c9e4485cbc920dd05954703900cf907667e"}, +] +flake8-bugbear = [ + {file = "flake8-bugbear-19.8.0.tar.gz", hash = "sha256:d8c466ea79d5020cb20bf9f11cf349026e09517a42264f313d3f6fddb83e0571"}, + {file = "flake8_bugbear-19.8.0-py35.py36.py37-none-any.whl", hash = "sha256:ded4d282778969b5ab5530ceba7aa1a9f1b86fa7618fc96a19a1d512331640f8"}, +] +flake8-commas = [ + {file = "flake8-commas-2.0.0.tar.gz", hash = "sha256:d3005899466f51380387df7151fb59afec666a0f4f4a2c6a8995b975de0f44b7"}, + {file = "flake8_commas-2.0.0-py2.py3-none-any.whl", hash = "sha256:ee2141a3495ef9789a3894ed8802d03eff1eaaf98ce6d8653a7c573ef101935e"}, +] +flake8-comprehensions = [ + {file = "flake8-comprehensions-3.2.3.tar.gz", hash = "sha256:d5751acc0f7364794c71d06f113f4686d6e2e26146a50fa93130b9f200fe160d"}, + {file = "flake8_comprehensions-3.2.3-py3-none-any.whl", hash = "sha256:44eaae9894aa15f86e0c86df1e218e7917494fab6f96d28f96a029c460f17d92"}, +] +flake8-debugger = [ + {file = "flake8-debugger-3.2.1.tar.gz", hash = "sha256:712d7c1ff69ddf3f0130e94cc88c2519e720760bce45e8c330bfdcb61ab4090d"}, +] +flake8-docstrings = [ + {file = "flake8-docstrings-1.5.0.tar.gz", hash = "sha256:3d5a31c7ec6b7367ea6506a87ec293b94a0a46c0bce2bb4975b7f1d09b6f3717"}, + {file = "flake8_docstrings-1.5.0-py2.py3-none-any.whl", hash = "sha256:a256ba91bc52307bef1de59e2a009c3cf61c3d0952dbe035d6ff7208940c2edc"}, +] +flake8-eradicate = [ + {file = "flake8-eradicate-0.3.0.tar.gz", hash = "sha256:d0b3d283d85079917acbfe39b9d637385cd82cba3ae3d76c1278c07ddcf0d9b9"}, + {file = "flake8_eradicate-0.3.0-py3-none-any.whl", hash = "sha256:e8b32b32300bfb407fe7ef74667c8d2d3a6a81bdf6f09c14a7bcc82b7b870f8b"}, +] +flake8-expression-complexity = [ + {file = "flake8_expression_complexity-0.0.8.tar.gz", hash = "sha256:c23f8ae677eb13b073be9bafa2cf443a87d3e2594817ba82c1f3e184e2de4afa"}, +] +flake8-isort = [ + {file = "flake8-isort-3.0.1.tar.gz", hash = "sha256:5d976da513cc390232ad5a9bb54aee8a092466a15f442d91dfc525834bee727a"}, + {file = "flake8_isort-3.0.1-py2.py3-none-any.whl", hash = "sha256:df1dd6dd73f6a8b128c9c783356627231783cccc82c13c6dc343d1a5a491699b"}, +] +flake8-polyfill = [ + {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, + {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, +] +flake8-quotes = [ + {file = "flake8-quotes-2.1.2.tar.gz", hash = "sha256:c844c9592940c8926c60f00bc620808912ff2acd34923ab5338f3a5ca618a331"}, +] +flake8-rst-docstrings = [ + {file = "flake8-rst-docstrings-0.0.12.tar.gz", hash = "sha256:01d38327801781b26c3dfeb71ae37e5a02c5ca1b774a686f63feab8824ca6f9c"}, +] +flake8-string-format = [ + {file = "flake8-string-format-0.2.3.tar.gz", hash = "sha256:774d56103d9242ed968897455ef49b7d6de272000cfa83de5814273a868832f1"}, + {file = "flake8_string_format-0.2.3-py2.py3-none-any.whl", hash = "sha256:68ea72a1a5b75e7018cae44d14f32473c798cf73d75cbaed86c6a9a907b770b2"}, +] +gitdb = [ + {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, + {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, +] +gitpython = [ + {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, + {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, +] isort = [ - {file = "isort-5.2.2-py3-none-any.whl", hash = "sha256:aea484023188ef1c38256dd24afa96e914adafe3a911a1786800a74e433006d1"}, - {file = "isort-5.2.2.tar.gz", hash = "sha256:96b27045e3187b9bdde001143b79f9b10a462f372bff7062302818013b6c86f3"}, + {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, + {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"}, +] +lazy-object-proxy = [ + {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, + {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"}, + {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"}, + {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"}, + {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"}, + {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"}, + {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"}, + {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"}, + {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"}, + {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"}, + {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"}, + {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"}, + {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"}, + {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"}, + {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"}, + {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"}, + {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"}, + {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"}, + {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"}, + {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"}, + {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +mypy = [ + {file = "mypy-0.782-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:2c6cde8aa3426c1682d35190b59b71f661237d74b053822ea3d748e2c9578a7c"}, + {file = "mypy-0.782-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9c7a9a7ceb2871ba4bac1cf7217a7dd9ccd44c27c2950edbc6dc08530f32ad4e"}, + {file = "mypy-0.782-cp35-cp35m-win_amd64.whl", hash = "sha256:c05b9e4fb1d8a41d41dec8786c94f3b95d3c5f528298d769eb8e73d293abc48d"}, + {file = "mypy-0.782-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:6731603dfe0ce4352c555c6284c6db0dc935b685e9ce2e4cf220abe1e14386fd"}, + {file = "mypy-0.782-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f05644db6779387ccdb468cc47a44b4356fc2ffa9287135d05b70a98dc83b89a"}, + {file = "mypy-0.782-cp36-cp36m-win_amd64.whl", hash = "sha256:b7fbfabdbcc78c4f6fc4712544b9b0d6bf171069c6e0e3cb82440dd10ced3406"}, + {file = "mypy-0.782-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:3fdda71c067d3ddfb21da4b80e2686b71e9e5c72cca65fa216d207a358827f86"}, + {file = "mypy-0.782-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7df6eddb6054d21ca4d3c6249cae5578cb4602951fd2b6ee2f5510ffb098707"}, + {file = "mypy-0.782-cp37-cp37m-win_amd64.whl", hash = "sha256:a4a2cbcfc4cbf45cd126f531dedda8485671545b43107ded25ce952aac6fb308"}, + {file = "mypy-0.782-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6bb93479caa6619d21d6e7160c552c1193f6952f0668cdda2f851156e85186fc"}, + {file = "mypy-0.782-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:81c7908b94239c4010e16642c9102bfc958ab14e36048fa77d0be3289dda76ea"}, + {file = "mypy-0.782-cp38-cp38-win_amd64.whl", hash = "sha256:5dd13ff1f2a97f94540fd37a49e5d255950ebcdf446fb597463a40d0df3fac8b"}, + {file = "mypy-0.782-py3-none-any.whl", hash = "sha256:e0b61738ab504e656d1fe4ff0c0601387a5489ca122d55390ade31f9ca0e252d"}, + {file = "mypy-0.782.tar.gz", hash = "sha256:eff7d4a85e9eea55afa34888dfeaccde99e7520b51f867ac28a48492c0b1130c"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] nox = [ {file = "nox-2020.5.24-py3-none-any.whl", hash = "sha256:c4509621fead99473a1401870e680b0aadadce5c88440f0532863595176d64c1"}, @@ -267,14 +919,51 @@ pathspec = [ {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] +pbr = [ + {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"}, + {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, +] +pep8-naming = [ + {file = "pep8-naming-0.9.1.tar.gz", hash = "sha256:a33d38177056321a167decd6ba70b890856ba5025f0a8eca6a3eda607da93caf"}, + {file = "pep8_naming-0.9.1-py2.py3-none-any.whl", hash = "sha256:45f330db8fcfb0fba57458c77385e288e7a3be1d01e8ea4268263ef677ceea5f"}, +] py = [ {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, ] +pycodestyle = [ + {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, + {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, +] +pydocstyle = [ + {file = "pydocstyle-5.0.2-py3-none-any.whl", hash = "sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586"}, + {file = "pydocstyle-5.0.2.tar.gz", hash = "sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"}, +] pyflakes = [ {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, ] +pygments = [ + {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, + {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, +] +pylint = [ + {file = "pylint-2.5.3-py3-none-any.whl", hash = "sha256:d0ece7d223fe422088b0e8f13fa0a1e8eb745ebffcb8ed53d3e95394b6101a1c"}, + {file = "pylint-2.5.3.tar.gz", hash = "sha256:7dd78437f2d8d019717dbf287772d0b2dbdfd13fc016aa7faa08d67bccc46adc"}, +] +pyyaml = [ + {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, + {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, + {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, + {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, + {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, +] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, {file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"}, @@ -298,10 +987,29 @@ regex = [ {file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"}, {file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"}, ] +restructuredtext-lint = [ + {file = "restructuredtext_lint-1.3.1.tar.gz", hash = "sha256:470e53b64817211a42805c3a104d2216f6f5834b22fe7adb637d1de4d6501fb8"}, +] six = [ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] +smmap = [ + {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, + {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, + {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, +] +stevedore = [ + {file = "stevedore-3.2.0-py3-none-any.whl", hash = "sha256:c8f4f0ebbc394e52ddf49de8bcc3cf8ad2b4425ebac494106bbc5e3661ac7633"}, + {file = "stevedore-3.2.0.tar.gz", hash = "sha256:38791aa5bed922b0a844513c5f9ed37774b68edc609e5ab8ab8d8fe0ce4315e5"}, +] +testfixtures = [ + {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"}, + {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"}, +] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, @@ -329,7 +1037,19 @@ typed-ast = [ {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, ] +typing-extensions = [ + {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, + {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, + {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, +] virtualenv = [ {file = "virtualenv-20.0.29-py2.py3-none-any.whl", hash = "sha256:8aa9c37b082664dbce2236fa420759c02d64109d8e6013593ad13914718a30fd"}, {file = "virtualenv-20.0.29.tar.gz", hash = "sha256:f14a0a98ea4397f0d926cff950361766b6a73cd5975ae7eb259d12919f819a25"}, ] +wemake-python-styleguide = [ + {file = "wemake-python-styleguide-0.14.1.tar.gz", hash = "sha256:e13dc580fa56b7b548de8da170bccb8ddff2d4ab026ca987db8a9893bf8a7b5b"}, + {file = "wemake_python_styleguide-0.14.1-py3-none-any.whl", hash = "sha256:73a501e0547275287a2b926515c000cc25026a8bceb9dcc1bf73ef85a223a3c6"}, +] +wrapt = [ + {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, +] diff --git a/pyproject.toml b/pyproject.toml index 8fe4449..b63b74f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ requires = ["poetry>=0.12"] [tool.black] line-length = 88 -skip-string-normalization = true +skip-string-normalization = true # wemake-python-styleguide enforces single quotes target-version = ["py38"] [tool.poetry] @@ -34,4 +34,13 @@ nox = "^2020.5.24" # Code Formatters autoflake = "^1.3.1" black = "^19.10b0" -isort = "^5.2.2" +isort = "^4.3.21" # TODO (isort): not ^5.2.2 due to pylint and wemake-python-styleguide + +# (Static) Code Analyzers +flake8 = "^3.8.3" +flake8-annotations = "^2.3.0" +flake8-black = "^0.2.1" +flake8-expression-complexity = "^0.0.8" +mypy = "^0.782" +pylint = "^2.5.3" +wemake-python-styleguide = "^0.14.1" # flake8 plug-in diff --git a/setup.cfg b/setup.cfg index 534a0f5..93815ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,111 @@ # black's settings are in pyproject.toml => [tool.black] +[flake8] +# Include error classes only explicitly +# to avoid forward compatibility issues. +select = + # ============= + # flake8's base + # ============= + # mccabe => cyclomatic complexity + C901, + # pycodestyle => PEP8 compliance + E, W, + # pyflakes => basic errors + F4, F5, F6, F7, F8, F9 + # ======================== + # wemake-python-styleguide + # Source: https://wemake-python-stylegui.de/en/latest/pages/usage/violations/index.html + # ======================== + WPS1, WPS2, WPS3, WPS4, WPS5, WPS6, + # darglint => docstring matches implementation + DAR0, DAR1, DAR2, DAR3, DAR4, DAR5, + # flake8-bandit => common security issues + S1, S2, S3, S4, S5, S6, S7, + # flake8-broken-line => no \ to end a line + N400, + # flake8-bugbear => opinionated bugs and design flaws + B0, B3, B9, + # flake8-commas => better comma placements + C8, + # flake8-comprehensions => better comprehensions + C4, + # flake8-debugger => no debugger usage + T100, + # flake8-docstrings => PEP257 compliance + D1, D2, D3, D4, + # flake8-eradicate => no commented out code + E800, + # flake8-isort => isort would make changes + I0, + # flake8-rst-docstrings => valid rst in docstrings + RST2, RST3, RST4, + # flake8-string-format => unify usage of str.format() + P1, P2, P3, + # flake8-quotes => use double quotes everywhere (complying with black) + Q0, + # pep8-naming + N8, + # ===== + # other + # ===== + # flake8-annotations => enforce type checking for functions + ANN0, ANN2, ANN3, + # flake8-black => complain if black would make changes + BLK1, BLK9, + # flake8-expression-complexity => not too many expressions at once + ECE001, + +# By default, flake8 ignores some errors. +# Instead, do not ignore anything. +ignore = + +# If --ignore is passed on the command +# line, still ignore the following: +extend-ignore = + # Comply with black's style. + # Source: https://github.com/psf/black/blob/master/docs/compatible_configs.md#flake8 + E203, W503, + # f-strings are ok. + WPS305, + +per-file-ignores = + noxfile.py: + # TODO (isort): Check if still too many module members. + WPS202, + # TODO (isort): Remove after simplifying the nox session "lint". + WPS213, + # No overuse of string constants (e.g., '--version'). + WPS226, + +# Explicitly set mccabe's maximum complexity to 10 as recommended by +# Thomas McCabe, the inventor of the McCabe complexity, and the NIST. +# Source: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Limiting_complexity_during_development +max-complexity = 10 + +# Comply with black's style. +# Source: https://github.com/psf/black/blob/master/docs/the_black_code_style.md#line-length +max-line-length = 88 + +# Preview the code lines that cause errors. +show-source = true + +# =================================== +# wemake-python-styleguide's settings +# =================================== +allowed-domain-names = + result, +min-name-length = 3 +max-name-length = 40 +# darglint +strictness = long +# flake8-docstrings +docstring-convention = google +# flake8-eradicate +eradicate-aggressive = true + + [isort] atomic = true case_sensitive = true @@ -24,3 +129,42 @@ use_parentheses = true # Source: https://google.github.io/styleguide/pyguide.html#313-imports-formatting force_single_line = true single_line_exclusions = typing + + +[mypy] +cache_dir = .cache/mypy + +[mypy-nox.*] +ignore_missing_imports = true + + +[pylint.FORMAT] +# Comply with black's style. +max-line-length = 88 + +[pylint.MESSAGES CONTROL] +disable = + # We use TODO's to indicate locations in the source base + # that must be worked on in the near future. + fixme, + # Comply with black's style. + bad-continuation, bad-whitespace, + # ===================== + # flake8 de-duplication + # Source: https://pylint.pycqa.org/en/latest/faq.html#i-am-using-another-popular-linter-alongside-pylint-which-messages-should-i-disable-to-avoid-duplicates + # ===================== + # mccabe + too-many-branches, + # pep8-naming + bad-classmethod-argument, bad-mcs-classmethod-argument, + invalid-name, no-self-argument, + # pycodestyle + bad-indentation, bare-except, line-too-long, missing-final-newline, + multiple-statements, trailing-whitespace, unnecessary-semicolon, unneeded-not, + # pydocstyle + missing-class-docstring, missing-function-docstring, missing-module-docstring, + # pyflakes + undefined-variable, unused-import, unused-variable, + +[pylint.REPORTS] +score = no