Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

Update pylama to 7.6.6 (Python 3.7 support) #112

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/pylama/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:license: BSD, see LICENSE for more details.
"""

__version__ = "7.4.3"
__version__ = "7.6.6"
__project__ = "pylama"
__author__ = "Kirill Klenov <horneds@gmail.com>"
__license__ = "GNU LGPL"
File renamed without changes.
41 changes: 26 additions & 15 deletions bin/pylama/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .lint.extensions import LINTERS

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

CURDIR = os.getcwd()
CONFIG_FILES = 'pylama.ini', 'setup.cfg', 'tox.ini', 'pytest.ini'
Expand All @@ -21,7 +21,9 @@
SKIP_PATTERN = re.compile(r'# *noqa\b', re.I).search

# Parse a modelines
MODELINE_RE = re.compile(r'^\s*#\s+(?:pylama:)\s*((?:[\w_]*=[^:\n\s]+:?)+)', re.I | re.M)
MODELINE_RE = re.compile(
r'^\s*#\s+(?:pylama:)\s*((?:[\w_]*=[^:\n\s]+:?)+)',
re.I | re.M)

# Setup a logger
LOGGER = logging.getLogger('pylama')
Expand All @@ -46,7 +48,6 @@ def split_csp_str(val):
""" Split comma separated string into unique values, keeping their order.

:returns: list of splitted values

"""
seen = set()
values = val if isinstance(val, (list, tuple)) else val.strip().split(',')
Expand Down Expand Up @@ -111,7 +112,7 @@ def get_default_config_file(rootdir=None):
"--linters", "-l", default=_Default(','.join(DEFAULT_LINTERS)),
type=parse_linters, help=(
"Select linters. (comma-separated). Choices are %s."
% ','.join(s for s in LINTERS.keys())
% ','.join(s for s in LINTERS)
))

PARSER.add_argument(
Expand All @@ -120,15 +121,16 @@ def get_default_config_file(rootdir=None):

PARSER.add_argument(
"--skip", default=_Default(''),
type=lambda s: [re.compile(fnmatch.translate(p)) for p in s.split(',') if p],
type=lambda s: [re.compile(fnmatch.translate(p))
for p in s.split(',') if p],
help="Skip files by masks (comma-separated, Ex. */messages.py)")

PARSER.add_argument("--report", "-r", help="Send report to file [REPORT]")
PARSER.add_argument(
"--hook", action="store_true", help="Install Git (Mercurial) hook.")

PARSER.add_argument(
"--async", action="store_true",
"--concurrent", "--async", action="store_true",
help="Enable async mode. Useful for checking a lot of files. "
"Unsupported with pylint.")

Expand All @@ -148,10 +150,11 @@ def get_default_config_file(rootdir=None):
help="Use absolute paths in output.")


ACTIONS = dict((a.dest, a) for a in PARSER._actions) # pylint: disable=protected-access
ACTIONS = dict((a.dest, a)
for a in PARSER._actions) # pylint: disable=protected-access


def parse_options(args=None, config=True, rootdir=CURDIR, **overrides): # noqa
def parse_options(args=None, config=True, rootdir=CURDIR, **overrides): # noqa
""" Parse options from command line and configuration files.

:return argparse.Namespace:
Expand All @@ -173,21 +176,24 @@ def parse_options(args=None, config=True, rootdir=CURDIR, **overrides): # noqa
if isinstance(passed_value, _Default):
if opt == 'paths':
val = val.split()
if opt == 'skip':
val = fix_pathname_sep(val)
setattr(options, opt, _Default(val))

# Parse file related options
for name, opts in cfg.sections.items():

if not name.startswith('pylama') or name == cfg.default_section:
if name == cfg.default_section:
continue

name = name[7:]
if name.startswith('pylama'):
name = name[7:]

if name in LINTERS:
options.linters_params[name] = dict(opts)
continue

mask = re.compile(fnmatch.translate(name))
mask = re.compile(fnmatch.translate(fix_pathname_sep(name)))
options.file_params[mask] = dict(opts)

# Override options
Expand All @@ -199,9 +205,9 @@ def parse_options(args=None, config=True, rootdir=CURDIR, **overrides): # noqa
if isinstance(value, _Default):
setattr(options, name, process_value(name, value.value))

if options.async and 'pylint' in options.linters:
if options.concurrent and 'pylint' in options.linters:
LOGGER.warning('Can\'t parse code asynchronously with pylint enabled.')
options.async = False
options.concurrent = False

return options

Expand Down Expand Up @@ -242,7 +248,7 @@ def get_config(ini_path=None, rootdir=None):
config = Namespace()
config.default_section = 'pylama'

if not ini_path or ini_path == 'None':
if not ini_path:
path = get_default_config_file(rootdir)
if path:
config.read(path)
Expand All @@ -260,6 +266,11 @@ def setup_logger(options):
LOGGER.addHandler(logging.FileHandler(options.report, mode='w'))

if options.options:
LOGGER.info('Try to read configuration from: ' + options.options)
LOGGER.info('Try to read configuration from: %r', options.options)


def fix_pathname_sep(val):
"""Fix pathnames for Win."""
return val.replace(os.altsep or "\\", os.sep)

# pylama:ignore=W0212,D210,F0001
50 changes: 36 additions & 14 deletions bin/pylama/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def run(path='', code=None, rootdir=CURDIR, options=None):
for item in params.get('linters') or linters:

if not isinstance(item, tuple):
item = (item, LINTERS.get(item))
item = item, LINTERS.get(item)

lname, linter = item

Expand All @@ -60,39 +60,46 @@ def run(path='', code=None, rootdir=CURDIR, options=None):
lparams = linters_params.get(lname, dict())
LOGGER.info("Run %s %s", lname, lparams)

ignore, select = merge_params(params, lparams)

linter_errors = linter.run(
path, code=code, ignore=params.get("ignore", set()),
select=params.get("select", set()), params=lparams)
if linter_errors:
for er in linter_errors:
errors.append(Error(filename=path, linter=lname, **er))
path, code=code, ignore=ignore, select=select, params=lparams)
if not linter_errors:
continue

errors += filter_errors([
Error(filename=path, linter=lname, **er) for er in linter_errors
], ignore=ignore, select=select)

except IOError as e:
LOGGER.debug("IOError %s", e)
LOGGER.error("IOError %s", e)
errors.append(Error(text=str(e), filename=path, linter=lname))

except SyntaxError as e:
LOGGER.debug("SyntaxError %s", e)
LOGGER.error("SyntaxError %s", e)
errors.append(
Error(linter='pylama', lnum=e.lineno, col=e.offset,
text='E0100 SyntaxError: {}'.format(e.args[0]),
filename=path))

except Exception as e: # noqa
except Exception as e: # noqa
import traceback
LOGGER.info(traceback.format_exc())

errors = filter_errors(errors, **params) # noqa
LOGGER.error(traceback.format_exc())

errors = list(remove_duplicates(errors))

if code and errors:
errors = filter_skiplines(code, errors)

key = lambda e: e.lnum
if options and options.sort:
sort = dict((v, n) for n, v in enumerate(options.sort, 1))
key = lambda e: (sort.get(e.type, 999), e.lnum)

def key(e):
return (sort.get(e.type, 999), e.lnum)
else:
def key(e):
return e.lnum

return sorted(errors, key=key)


Expand Down Expand Up @@ -124,6 +131,8 @@ def prepare_params(modeline, fileconfig, options):
for key in ('ignore', 'select', 'linters'):
params[key] += process_value(key, config.get(key, []))
params['skip'] = bool(int(config.get('skip', False)))
# TODO: skip what? This is causing erratic behavior for linters.
params['skip'] = False

params['ignore'] = set(params['ignore'])
params['select'] = set(params['select'])
Expand Down Expand Up @@ -174,6 +183,19 @@ def filter_skiplines(code, errors):
return errors


def merge_params(params, lparams):
"""Merge global ignore/select with linter local params."""
ignore = params.get('ignore', set())
if 'ignore' in lparams:
ignore = ignore | set(lparams['ignore'])

select = params.get('select', set())
if 'select' in lparams:
select = select | set(lparams['select'])

return ignore, select


class CodeContext(object):
"""Read file if code is None. """

Expand Down
28 changes: 15 additions & 13 deletions bin/pylama/lint/extensions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
"""Load extensions."""

import os
import sys

CURDIR = os.path.dirname(__file__)
sys.path.insert(
0, os.path.abspath(os.path.join(CURDIR, '..', '..', 'deps')))


LINTERS = {}

try:
Expand All @@ -16,6 +8,12 @@
except ImportError:
pass

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

try:
from pylama.lint.pylama_pydocstyle import Linter
LINTERS['pep257'] = Linter() # for compatibility
Expand Down Expand Up @@ -48,10 +46,14 @@
except ImportError:
pass

try:
from isort.pylama_isort import Linter
LINTERS['isort'] = Linter()
except ImportError:
pass

from pkg_resources import iter_entry_points

for entry in iter_entry_points('pylama.linter'):
if entry.name not in LINTERS:
try:
LINTERS[entry.name] = entry.load()()
except ImportError:
pass

# pylama:ignore=E0611
36 changes: 36 additions & 0 deletions bin/pylama/lint/pylama_eradicate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Commented-out code checking."""
from eradicate import commented_out_code_line_numbers
from pylama.lint import Linter as Abstract

try:
converter = unicode
except NameError:
converter = str


class Linter(Abstract):

"""Run commented-out code checking."""

@staticmethod
def run(path, code=None, params=None, **meta):
"""Eradicate code checking.

:return list: List of errors.
"""
code = converter(code)
line_numbers = commented_out_code_line_numbers(code)
lines = code.split('\n')

result = []
for line_number in line_numbers:
line = lines[line_number - 1]
result.append(dict(
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,
# https://github.com/sobolevn/flake8-eradicate#error-codes
type='E800',
))
return result
12 changes: 8 additions & 4 deletions bin/pylama/lint/pylama_pycodestyle.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""pycodestyle support."""
from pycodestyle import BaseReport, StyleGuide, get_parser
from pycodestyle import BaseReport, StyleGuide, get_parser, _parse_multi_options

from pylama.lint import Linter as Abstract

Expand All @@ -24,9 +24,13 @@ def run(path, code=None, params=None, **meta):
for option in parser.option_list:
if option.dest and option.dest in params:
value = params[option.dest]
if not isinstance(value, str):
continue
params[option.dest] = option.convert_value(option, params[option.dest])
if isinstance(value, str):
params[option.dest] = option.convert_value(option, value)

for key in ["filename", "exclude", "select", "ignore"]:
if key in params and isinstance(params[key], str):
params[key] = _parse_multi_options(params[key])

P8Style = StyleGuide(reporter=_PycodestyleReport, **params)
buf = StringIO(code)
return P8Style.input_file(path, lines=buf.readlines())
Expand Down
Loading