diff --git a/.gitignore b/.gitignore index f9524450..72729ff0 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ pip-log.txt .coverage .tox nosetests.xml +.noseids # Translations *.mo @@ -31,9 +32,13 @@ nosetests.xml .project .pydevproject .idea +.vscode # Sphinx docs/_build +# Mypy +.mypy_cache + # emacs TAGS diff --git a/.prospector.yml b/.prospector.yml index a2b27a97..ba374ad0 100644 --- a/.prospector.yml +++ b/.prospector.yml @@ -14,6 +14,12 @@ frosted: pyroma: run: true +mypy: + run: true + options: + ignore-missing-imports: true + follow-imports: skip + pylint: disable: - bad-builtin diff --git a/docs/supported_tools.rst b/docs/supported_tools.rst index 67560836..98ce6a8a 100644 --- a/docs/supported_tools.rst +++ b/docs/supported_tools.rst @@ -10,7 +10,7 @@ Prospector will run with defaults enabled and optional extras disabled unless co To specify an exact list of tools to run, for example, only pylint and pep8:: - prospector --tool pylint --tool pep8 + prospector --tool pylint --tool pep8 Note that this command line option will override values set in :doc:`profiles`. @@ -35,11 +35,11 @@ and is the source of most messages that prospector outputs. `pep8.py `_ ``````````````````````````````````````````````````` -``pep8.py`` is a simple tool to warn about violations of the +``pep8.py`` is a simple tool to warn about violations of the `PEP8 style guide `_. It produces messages for any divergence from the style guide. -Prospector's concept of :doc:`strictness ` turns off various warnings +Prospector's concept of :doc:`strictness ` turns off various warnings depending on the strictness level. By default, several PEP8 errors will be supressed. To adjust this without adjusting the strictness of other tools, you have some options:: @@ -50,7 +50,7 @@ some options:: # turn on complete pep8 checking: prospector --full-pep8 - # change the maximum line length allowed + # change the maximum line length allowed # (the default varies by strictness): prospector --max-line-length 120 @@ -75,7 +75,7 @@ methods. ``````````````````````````````````````````````` Dodgy is a very simple tool designed to find 'dodgy' things which should -not be in a public project, such as secret keys, passwords, AWS tokens or +not be in a public project, such as secret keys, passwords, AWS tokens or source control diffs. `pydocstyle `_ @@ -109,7 +109,7 @@ Optional Extras These extras are integrated into prospector but are not activated by default. This is because their output is not necessarily useful for all projects. -They are also not installed by default. The instructions for installing each tool is in the tool +They are also not installed by default. The instructions for installing each tool is in the tool section below. To install all extras at the same time, install prospector using the ``with_everything`` option:: pip install prospector[with_everything] @@ -118,7 +118,7 @@ section below. To install all extras at the same time, install prospector using `Pyroma `_ ```````````````````````````````````````````````` Pyroma is a tool to check your `setup.py` to ensure it is following best practices -of the Python packaging ecosystem. It will warn you if you are missing any package +of the Python packaging ecosystem. It will warn you if you are missing any package metadata which would improve the quality of your package. This is recommended if you intend to publish your code on PyPI. @@ -133,7 +133,7 @@ To install and use:: Vulture finds unused classes, functions and variables in your code. This could be useful if your project is an application rather than a library, however, if -you do a lot of dynamic access or metaprogramming, Vulture will likely warn +you do a lot of dynamic access or metaprogramming, Vulture will likely warn about unused code that is in fact used. To install and use:: @@ -153,3 +153,16 @@ To install and use:: pip install prospector[with_frosted] prospector --with-tool frosted + + +`mypy `_ +`````````````````````````````````````````````````````` +Mypy is an experimental optional static type checker for Python that aims to combine +the benefits of dynamic (or "duck") typing and static typing. Mypy combines the +expressive power and convenience of Python with a powerful type system and +compile-time type checking. + +To install and use:: + + pip install prospector[with_mypy] + prospector --with-tool mypy diff --git a/prospector/tools/__init__.py b/prospector/tools/__init__.py index e1b2a670..43c5c75a 100644 --- a/prospector/tools/__init__.py +++ b/prospector/tools/__init__.py @@ -46,6 +46,7 @@ def _optional_tool(name, package_name=None, tool_class_name=None, install_option 'frosted': _optional_tool('frosted'), 'vulture': _optional_tool('vulture'), 'pyroma': _optional_tool('pyroma'), + 'mypy': _optional_tool('mypy'), } diff --git a/prospector/tools/mypy/__init__.py b/prospector/tools/mypy/__init__.py new file mode 100644 index 00000000..520c56d0 --- /dev/null +++ b/prospector/tools/mypy/__init__.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +from itertools import islice +from mypy import api + +from prospector.message import Location, Message +from prospector.tools import ToolBase + + +__all__ = ( + 'MypyTool', +) + + +MYPY_OPTIONS = [ + 'allow', + 'check', + 'disallow', + 'no-check', + 'no-warn', + 'warn' +] + + +class MypyTool(ToolBase): + def __init__(self, *args, **kwargs): + super(MypyTool, self).__init__(*args, **kwargs) + self.checker = api + self.options = ['--show-column-numbers'] + + def configure(self, prospector_config, _): + options = prospector_config.tool_options('mypy') + + follow_imports = options.get('follow-imports', 'normal') + ignore_missing_imports = options.get('ignore-missing-imports', False) + implict_optional = options.get('implict-optional', False) + platform = options.get('platform', None) + python_2_mode = options.get('python-2-mode', False) + python_version = options.get('python-version', None) + strict_optional = options.get('strict-optional', False) + + self.options.append('--follow-imports=%s' % follow_imports) + + if ignore_missing_imports: + self.options.append('--ignore-missing-imports') + + if implict_optional: + self.options.append('--implict-optional') + + if platform: + self.options.append('--platform %s' % platform) + + if python_2_mode: + self.options.append('--py2') + + if python_version: + self.options.append('--python-version %s' % python_version) + + if strict_optional: + self.options.append('--strict-optional') + + for list_option in MYPY_OPTIONS: + for entry in options.get(list_option, []): + self.options.append('--%s-%s' % (list_option, entry)) + + def run(self, found_files): + paths = [path for path in found_files.iter_module_paths()] + paths.extend(self.options) + result = self.checker.run(paths) + report, _ = result[0], result[1:] + messages = [] + + for message in report.splitlines(): + iter_message = iter(message.split(':')) + (path, line, char, err_type), err_msg = islice(iter_message, 4), list(message) + location = Location( + path=path, + module=None, + function=None, + line=line, + character=char, + absolute_path=True + ) + message = Message( + source='mypy', + code=err_type, + location=location, + message=''.join(err_msg).strip() + ) + messages.append(message) + + return messages \ No newline at end of file diff --git a/setup.py b/setup.py index 3be30636..97423055 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,8 @@ 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'License :: OSI Approved :: ' 'GNU General Public License v2 or later (GPLv2+)', ) @@ -59,6 +61,10 @@ 'with_vulture': ('vulture>=0.6',), 'with_pyroma': ('pyroma>=2.3',), } + +if sys.version_info >= (3, 3): + _OPTIONAL['with_mypy'] = ('mypy>=0.600',) + with_everything = [req for req_list in _OPTIONAL.values() for req in req_list] _OPTIONAL['with_everything'] = sorted(with_everything)