Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
klen committed Apr 10, 2019
2 parents f5043bc + 7ef650c commit 61ea127
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
@@ -1,6 +1,6 @@
[bumpversion]
commit = True
current_version = 7.6.6
current_version = 7.7.0
files = pylama/__init__.py
tag = True
tag_name = {new_version}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -12,6 +12,7 @@
.tox
.vimrc
/.cache
/.mypy_cache
/.ropeproject
/_
/libs
Expand Down
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -13,6 +13,7 @@ Contributors:
* Gram (https://github.com/orsinium)
* GrandVizierOlaf (https://github.com/grandvizierolaf)
* Grzegorz Śliwiński (https://github.com/fizyk)
* Ian Epperson (https://github.com/ianepperson)
* Jarek Śmiejczak (https://github.com/jotes)
* Jens Persson (https://github.com/MrShark)
* Johan Bloemberg (https://github.com/aequitas)
Expand Down
6 changes: 5 additions & 1 deletion README.rst
Expand Up @@ -13,6 +13,7 @@ Code audit tool for Python and JavaScript. Pylama wraps these tools:
* Radon_ © Michele Lacchia
* gjslint_ © The Closure Linter Authors (should be installed 'pylama_gjslint' module);
* eradicate_ © Steven Myint;
* Mypy_ © Jukka Lehtosalo and contributors;

.. _badges:

Expand Down Expand Up @@ -234,7 +235,9 @@ You could set options for special code checker with pylama configurations.
max_line_length = 100
disable = R

See code-checkers' documentation for more info.
See code-checkers' documentation for more info. Let's notice that dashes are
replaced by underscores (e.g. Pylint's "max-line-length" becomes
"max_line_length").


Set options for file (group of files)
Expand Down Expand Up @@ -400,6 +403,7 @@ Licensed under a `BSD license`_.
.. _gjslint: https://developers.google.com/closure/utilities
.. _klen: http://klen.github.io/
.. _eradicate: https://github.com/myint/eradicate
.. _Mypy: https://github.com/python/mypy

.. |logo| image:: https://raw.github.com/klen/pylama/develop/docs/_static/logo.png
:width: 100
Expand Down
10 changes: 10 additions & 0 deletions dummy.py
Expand Up @@ -125,3 +125,13 @@ def __init__(self, filename, lineno, names):
Message.__init__(self, filename, lineno)
self.message_args = (names,)
error = 1 # noQa and some comments


class BadTyping(Message):
"""Test the MyPy linting."""

message = 'error: No return value expected'

def bad_method(self): # type: () -> None
"""Return type mismatch."""
return 1
2 changes: 1 addition & 1 deletion pylama/__init__.py
Expand Up @@ -4,7 +4,7 @@
:license: BSD, see LICENSE for more details.
"""

__version__ = "7.6.6"
__version__ = "7.7.0"
__project__ = "pylama"
__author__ = "Kirill Klenov <horneds@gmail.com>"
__license__ = "GNU LGPL"
2 changes: 1 addition & 1 deletion pylama/config.py
Expand Up @@ -12,7 +12,7 @@
from .lint.extensions import LINTERS

#: A default checkers
DEFAULT_LINTERS = 'pycodestyle', 'pyflakes', 'mccabe', 'eradicate'
DEFAULT_LINTERS = 'pycodestyle', 'pyflakes', 'mccabe'

CURDIR = os.getcwd()
CONFIG_FILES = 'pylama.ini', 'setup.cfg', 'tox.ini', 'pytest.ini'
Expand Down
6 changes: 6 additions & 0 deletions pylama/lint/extensions.py
Expand Up @@ -46,6 +46,12 @@
except ImportError:
pass

try:
from pylama.lint.pylama_mypy import Linter
LINTERS['mypy'] = Linter()
except ImportError:
pass


from pkg_resources import iter_entry_points

Expand Down
2 changes: 1 addition & 1 deletion pylama/lint/pylama_eradicate.py
Expand Up @@ -29,7 +29,7 @@ def run(path, code=None, params=None, **meta):
lnum=line_number,
offset=len(line) - len(line.rstrip()),
# https://github.com/sobolevn/flake8-eradicate#output-example
text=converter('E800: Found commented out code: ') + line,
text=converter('E800 Found commented out code: ') + line,
# https://github.com/sobolevn/flake8-eradicate#error-codes
type='E800',
))
Expand Down
88 changes: 88 additions & 0 deletions pylama/lint/pylama_mypy.py
@@ -0,0 +1,88 @@
"""MyPy support."""

from mypy import api

from pylama.lint import Linter as Abstract


class _MyPyMessage(object):
"""Parser for a single MyPy output line."""
types = {
'error': 'E',
'warning': 'W',
'note': 'N'
}

def __init__(self, line):
self.filename = None
self.line_num = None
self.column = None
self.text = None
self.note = None
self.message_type = None
self.valid = False

self._parse(line)

def _parse(self, line):
"""Parse the output line"""
try:
result = line.split(':', maxsplit=4)
filename, line_num_txt, column_txt, message_type, text = result
except ValueError:
return

try:
self.line_num = int(line_num_txt.strip())
self.column = int(column_txt.strip())
except ValueError:
return

self.filename = filename
self.message_type = message_type.strip()
self.text = text.strip()
self.valid = True

def add_note(self, note):
"""Add in additional information about this message"""
self.note = note

def to_result(self):
"""Convert to the Linter.run return value"""
text = [self.text]
if self.note:
text.append(self.note)

return {
'lnum': self.line_num,
'col': self.column,
'text': ' - '.join(text),
'type': self.types.get(self.message_type, '')
}


class Linter(Abstract):
"""MyPy runner."""

@staticmethod
def run(path, code=None, params=None, **meta):
"""Check code with mypy.
:return list: List of errors.
"""
args = [path, '--follow-imports=skip', '--show-column-numbers']
stdout, stderr, status = api.run(args)
messages = []
for line in stdout.split('\n'):
line.strip()
if not line:
continue
message = _MyPyMessage(line)
if message.valid:
if message.message_type == 'note':
if messages[-1].line_num == message.line_num:
messages[-1].add_note(message.text)
else:
messages.append(message)

return [m.to_result() for m in messages]
3 changes: 2 additions & 1 deletion requirements-test.txt
Expand Up @@ -2,5 +2,6 @@

ipdb
pytest
eradicate >= 0.2
eradicate >= 1.0
radon >= 1.4.2
mypy ; python_version >= '3.5'
2 changes: 1 addition & 1 deletion setup.cfg
Expand Up @@ -7,7 +7,7 @@ universal = 1
[pylama]
async = 1
ignore = D203,D213,F0401,C0111,E731,I0011
linters = pycodestyle,pyflakes,mccabe,pydocstyle,pylint
linters = pycodestyle,pyflakes,mccabe,pydocstyle,pylint,eradicate
paths = pylama
skip = pylama/inirama.py,pylama/libs/*
verbose = 0
Expand Down
6 changes: 3 additions & 3 deletions tests/test_config.py
Expand Up @@ -19,7 +19,7 @@ def test_config():

options = parse_options('-o dummy dummy.py'.split())
linters, _ = zip(*options.linters)
assert set(linters) == set(['pycodestyle', 'mccabe', 'pyflakes', 'eradicate'])
assert set(linters) == set(['pycodestyle', 'mccabe', 'pyflakes'])
assert options.skip == []


Expand All @@ -28,14 +28,14 @@ def test_ignore_select():
options.ignore = ['E301', 'D102']
options.linters = ['pycodestyle', 'pydocstyle', 'pyflakes', 'mccabe']
errors = run('dummy.py', options=options)
assert len(errors) == 31
assert len(errors) == 32

numbers = [error.number for error in errors]
assert 'D100' in numbers
assert 'E301' not in numbers
assert 'D102' not in numbers

options.ignore = ['E3', 'D', 'E2']
options.ignore = ['E3', 'D', 'E2', 'E8']
errors = run('dummy.py', options=options)
assert not errors

Expand Down
10 changes: 10 additions & 0 deletions tests/test_linters.py
@@ -1,3 +1,5 @@
import sys

from pylama.config import parse_options
from pylama.core import run
from pylama.lint.extensions import LINTERS
Expand Down Expand Up @@ -52,3 +54,11 @@ def test_pydocstyle():
assert len(options.linters) == 1
errors = run('dummy.py', options=options)
assert errors


def test_mypy():
if sys.version_info.major >= 3 and sys.version_info.minor >= 5:
options = parse_options(linters=['mypy'])
assert len(options.linters) == 1
errors = run('dummy.py', options=options)
assert len(errors) == 1

0 comments on commit 61ea127

Please sign in to comment.