diff --git a/.prospector.yml b/.prospector.yml index 33603979..58d72412 100644 --- a/.prospector.yml +++ b/.prospector.yml @@ -16,9 +16,9 @@ pyroma: pylint: disable: - - W0141 - - R0903 - - C0111 + - bad-builtin + - too-few-public-methods + - missing-docstring pep8: full: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 0198f9be..2cef42dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Prospector Changelog ======= ## Version 0.9 +* Messages now use Pylint error symbols ('star-args') instead of codes ('W0142'). This makes it much more obvious what each message means and what is happening when errors are suppressed or ignored in profiles. The old error codes will continue to work in profiles. * The way that profiles are handled and parsed has completely been rewritten to avoid several bugs and introduce 'shorthand' options to profiles. This allows profiles to specify simple options like 'doc-warnings: true' inside profiles and configure anything that can be configured as a command line argument. Profiles can now use options like 'strictness: high' or 'doc-warnings: true' as a shortcut for inheriting the built-in prospector profiles. * A new `--show-profile` option is available to dump the calculated profile, which is helpful for figuring out what prospector thinks it is doing. * Profiles now have separate `ignore-paths` and `ignore-patterns` directives to match the command line arguments. The old `ignore` directive remains in place for backwards compatibility and will be deprecated in the future. diff --git a/docs/profiles.rst b/docs/profiles.rst index cac101a6..51475ad7 100644 --- a/docs/profiles.rst +++ b/docs/profiles.rst @@ -260,15 +260,15 @@ The typical desired action is to disable messages:: pylint: disable: - - E0202 - - E0203 + - method-hidden + - access-member-before-definition However, you can also enable messages which were disabled by parent profiles:: pylint: enable: - - E0202 - - E0203 + - method-hidden + - access-member-before-definition Tool Options diff --git a/prospector/autodetect.py b/prospector/autodetect.py index 08fbec95..8a9c2fc0 100644 --- a/prospector/autodetect.py +++ b/prospector/autodetect.py @@ -135,7 +135,7 @@ def autodetect_libraries(path): try: libraries = find_from_requirements(path) - # pylint: disable=W0704 + # pylint: disable=pointless-except except RequirementsNotFound: pass diff --git a/prospector/blender.py b/prospector/blender.py index b3a172f0..21c2b30e 100644 --- a/prospector/blender.py +++ b/prospector/blender.py @@ -61,15 +61,16 @@ def blend_line(messages, blend_combos=None): if blend_list[0] not in blended: # We may have already added this message if it represents # several messages in other tools which are not being run - - # for example, pylint C0111 is blended with pep257 D100, D101 + # for example, pylint missing-docstring is blended with pep257 D100, D101 # and D102, but should not appear 3 times! blended.append(blend_list[0]) # Some messages from a tool point out an error that in another tool is handled by two - # different errors or more. For example, pylint emits the same warning (C0321) for "two statements on a line" - # separated by a colon and a semi-colon, while pep8 has E701 and E702 for those cases respectively. In - # this case, the pylint error will not be 'blended' as it will appear in two blend_lists. Therefore we - # mark anything not taken from the blend list as "consumed" and then filter later, to avoid such cases. + # different errors or more. For example, pylint emits the same warning (multiple-statements) + # for "two statements on a line" separated by a colon and a semi-colon, while pep8 has E701 + # and E702 for those cases respectively. In this case, the pylint error will not be 'blended' as + # it will appear in two blend_lists. Therefore we mark anything not taken from the blend list + # as "consumed" and then filter later, to avoid such cases. for now_used in blend_list[1:]: now_used.used = True diff --git a/prospector/blender_combinations.yaml b/prospector/blender_combinations.yaml index 15a616e5..5f2dc511 100644 --- a/prospector/blender_combinations.yaml +++ b/prospector/blender_combinations.yaml @@ -7,25 +7,25 @@ combinations: - # Unused Import - - pylint: W0611 + - pylint: unused-import - pyflakes: FL0001 - frosted: E101 - # Syntax Error - dodgy: diff - - pylint: E0001 + - pylint: syntax-error - pyflakes: FL9998 - pep8: E901 - mccabe: MC0000 - frosted: E402 - # Undefined local variable - - pylint: E0602 + - pylint: undefined-variable - pyflakes: FL0006 - frosted: E303 - # Unused variable - - pylint: W0612 + - pylint: unused-variable - vulture: unused-variable - pyflakes: FL0013 - frosted: E307 @@ -33,83 +33,83 @@ combinations: - # Mixed tabs and spaces - pep257: D206 - pep8: E101 - - pylint: W0313 + - pylint: indentation-mixture - # Import from __future__ not first import - - pylint: W0410 + - pylint: misplaced-future - pyflakes: FL0012 - frosted: E207 - # Line too long - pep8: E501 - - pylint: C0301 + - pylint: line-too-long - # Trailing whitespace - pep8: W291 - - pylint: C0303 + - pylint: trailing-whitespace - # Blank line contains whitespace - pep8: W293 - - pylint: C0303 + - pylint: trailing-whitespace - # No newline at end of file - pep8: W292 - - pylint: C0304 + - pylint: missing-final-newline - # line ends with semi-colon - pep8: E703 - - pylint: W0301 + - pylint: unnecessary-semicolon - # multiple statements on one line (colon) - pep8: E701 - - pylint: C0321 + - pylint: multiple-statements - # multiple statements on one line (semicolon) - pep8: E702 - - pylint: C0321 + - pylint: multiple-statements - # incorrect indendation - pep257: D207 - pep8: E111 - - pylint: W0311 + - pylint: bad-indentation - # incorrect indendation - pep257: D208 - pep8: E111 - - pylint: W0311 + - pylint: bad-indentation - # comma not followed by a space - pep8: E231 - pylint: C0324 - - pylint: C0326 + - pylint: bad-whitespace - # missing whitespace around operator - pep8: E225 - pylint: C0322 - - pylint: C0326 + - pylint: bad-whitespace - # missing whitespace around operator - pep8: E225 - pylint: C0323 - - pylint: C0326 + - pylint: bad-whitespace - # undefined name in __all__ - - pylint: E0603 + - pylint: undefined-all-variable - pyflakes: FL0008 - frosted: E304 - # duplicate argument in function definition - - pylint: E0108 + - pylint: duplicate-argument-name - pyflakes: FL0010 - frosted: E206 - # redefinition of unused function - pyflakes: FL0002 - - pylint: E0102 + - pylint: function-redefined - # first argument of a classmethod should be named 'cls' - pep8: N804 - - pylint: C0202 + - pylint: bad-classmethod-argument - # '<>' is deprecated, use '!=' - pep8: W603 @@ -120,42 +120,42 @@ combinations: - pylint: W0333 - # Redefining name from outer scope - - pylint: W0621 + - pylint: redefined-outer-name - pyflakes: FL0011 - frosted: E306 - # Wildcard import - - pylint: W0401 + - pylint: wildcard-import - pyflakes: FL0005 - frosted: E103 - # Return with argument inside generator - - pylint: E0106 + - pylint: return-arg-in-generator - frosted: E208 - # Too many positional arguments for function call - - pylint: E1121 + - pylint: too-many-function-args - frosted: E203 - # Passing unexpected keyword argument - - pylint: E1123 + - pylint: unexpected-keyword-arg - frosted: E204 - # Missing mandatory keyword argument - - pylint: E1125 + - pylint: missing-kwoa - frosted: E205 - # No exception type(s) specified - - pylint: W0702 + - pylint: bare-except - frosted: W101 - # Spaces around keyword/paramater equals - pep8: E251 - - pylint: C0326 + - pylint: bad-whitespace - # Missing space after a comma - pep8: E231 - - pylint: C0326 + - pylint: bad-whitespace - # redefinition of unused %r from line %r - pyflakes: FL0002 @@ -178,29 +178,29 @@ combinations: - frosted: E305 - # pep8-naming incorrectly suggests that the first argument of a metaclass __new__ method should be 'cls' - - pylint: C0204 + - pylint: bad-mcs-classmethod-argument - pep8: N804 - # class names should be camelcase - pep8: N801 - - pylint: C0103 + - pylint: invalid-name - # too complex - mccabe: MC0001 - - pylint: R0912 + - pylint: too-many-branches - # pep257 takes preference over pylint documentation warnings - pep257: D100 - - pylint: C0111 + - pylint: missing-docstring - - pep257: D101 - - pylint: C0111 + - pylint: missing-docstring - - pep257: D102 - - pylint: C0111 + - pylint: missing-docstring - - pep257: D103 - - pylint: C0111 \ No newline at end of file + - pylint: missing-docstring \ No newline at end of file diff --git a/prospector/formatters/base.py b/prospector/formatters/base.py index 0ef5f1b6..2f90235c 100644 --- a/prospector/formatters/base.py +++ b/prospector/formatters/base.py @@ -4,7 +4,7 @@ ) -# pylint: disable=R0903 +# pylint: disable=too-few-public-methods class Formatter(object): def __init__(self, summary, messages, profile): self.summary = summary diff --git a/prospector/formatters/grouped.py b/prospector/formatters/grouped.py index 3f30ab2f..65e41600 100644 --- a/prospector/formatters/grouped.py +++ b/prospector/formatters/grouped.py @@ -16,7 +16,7 @@ def render_messages(self): '', ] - # pylint: disable=W0108 + # pylint: disable=unnecessary-lambda groups = defaultdict(lambda: defaultdict(list)) for message in self.messages: diff --git a/prospector/formatters/json.py b/prospector/formatters/json.py index 8e45072c..0a331567 100644 --- a/prospector/formatters/json.py +++ b/prospector/formatters/json.py @@ -12,7 +12,7 @@ ) -# pylint: disable=R0903 +# pylint: disable=too-few-public-methods class JsonFormatter(Formatter): def render(self, summary=True, messages=True, profile=False): output = {} diff --git a/prospector/formatters/pylint.py b/prospector/formatters/pylint.py index 654d16f1..a2685b76 100644 --- a/prospector/formatters/pylint.py +++ b/prospector/formatters/pylint.py @@ -25,7 +25,7 @@ def render(self, summary=True, messages=True, profile=False): output.append(header) # ={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} - # prospector/configuration.py:65: [C0111(missing-docstring), build_default_sources] \ + # prospector/configuration.py:65: [missing-docstring(missing-docstring), build_default_sources] \ # Missing function docstring template = '%(path)s:%(line)s: [%(code)s(%(source)s), %(function)s] %(message)s' diff --git a/prospector/formatters/text.py b/prospector/formatters/text.py index 6bbebc60..43e1e791 100644 --- a/prospector/formatters/text.py +++ b/prospector/formatters/text.py @@ -6,7 +6,7 @@ ) -# pylint: disable=W0108 +# pylint: disable=unnecessary-lambda class TextFormatter(Formatter): @@ -48,7 +48,7 @@ def render_summary(self): return '\n'.join(output) - # pylint: disable=R0201 + # pylint: disable=no-self-use def render_message(self, message): output = [] diff --git a/prospector/formatters/yaml.py b/prospector/formatters/yaml.py index 65e1cea2..e98bdbb3 100644 --- a/prospector/formatters/yaml.py +++ b/prospector/formatters/yaml.py @@ -10,7 +10,7 @@ ) -# pylint: disable=R0903 +# pylint: disable=too-few-public-methods class YamlFormatter(Formatter): def render(self, summary=True, messages=True, profile=False): output = {} diff --git a/prospector/postfilter.py b/prospector/postfilter.py index 88eab4c3..85fc5108 100644 --- a/prospector/postfilter.py +++ b/prospector/postfilter.py @@ -2,7 +2,7 @@ import re -_I0020_REGEXP = re.compile(r'^Suppressed \'([a-z0-9-]+)\' \(from line \d+\)$') +_SUPPRESSED_MESSAGE_REGEXP = re.compile(r'^Suppressed \'([a-z0-9-]+)\' \(from line \d+\)$') _SUPPRESS_IF = { 'pyflakes': { @@ -18,14 +18,16 @@ def _get_pylint_informational(messages): remainder = [] informational = defaultdict(lambda: defaultdict(list)) for message in messages: - if message.source == 'pylint' and message.code.startswith('I'): - if message.code == 'I0020': + if message.source == 'pylint': + if message.code == 'suppressed-message': # this is a message indicating that a message was raised # by pylint but suppressed by configuration in the file - match = _I0020_REGEXP.match(message.message) + match = _SUPPRESSED_MESSAGE_REGEXP.match(message.message) suppressed_code = match.group(1) line_dict = informational[message.location.path] line_dict[message.location.line].append(suppressed_code) + elif message.code not in ('file-ignored',): + remainder.append(message) else: remainder.append(message) return informational, remainder @@ -42,7 +44,7 @@ def filter_messages(messages): For example: - import banana # pylint:disable=W0611 + import banana # pylint:disable=unused-import In this situation, pylint will not warn about an unused import as there is inline configuration to disable the warning. Pyflakes will still raise that @@ -54,7 +56,7 @@ def filter_messages(messages): filtered = [] for message in messages: - # if this message is not one which we may supress, we can skip the next steps + # if this message is not one which we may suppress, we can skip the next steps suppress_if = _SUPPRESS_IF.get(message.source, {}).get(message.code, None) if suppress_if is None or message.location.path not in informational: filtered.append(message) @@ -68,12 +70,12 @@ def filter_messages(messages): # now figure out if any of the information on this line is suppressing # this current message - for supress_code in info: - if supress_code in suppress_if: + for suppress_code in info: + if suppress_code in suppress_if: # this means that a message was suppressed with a code which # matches the current message's purpose - eg, pylint has # suppressed an 'unused-import', and this message also represents - # an unused import, so should be supressed too + # an unused import, so should be suppressed too break else: filtered.append(message) diff --git a/prospector/profiles/profiles/no_doc_warnings.yaml b/prospector/profiles/profiles/no_doc_warnings.yaml index adde40c9..cf0812fb 100644 --- a/prospector/profiles/profiles/no_doc_warnings.yaml +++ b/prospector/profiles/profiles/no_doc_warnings.yaml @@ -5,8 +5,8 @@ ignore-patterns: pylint: disable: - - C0112 - - C0111 + - empty-docstring + - missing-docstring pyflakes: disable: diff --git a/prospector/profiles/profiles/no_pep8.yaml b/prospector/profiles/profiles/no_pep8.yaml index 67b27507..2296043d 100644 --- a/prospector/profiles/profiles/no_pep8.yaml +++ b/prospector/profiles/profiles/no_pep8.yaml @@ -2,12 +2,12 @@ allow-shorthand: false pylint: disable: - - C0301 - - C0302 - - C0303 - - C0304 - - W0301 - - C0321 + - line-too-long + - too-many-lines + - trailing-whitespace + - missing-final-newline + - unnecessary-semicolon + - multiple-statements - C0322 - C0323 - C0324 diff --git a/prospector/profiles/profiles/strictness_high.yaml b/prospector/profiles/profiles/strictness_high.yaml index e3406e5f..3b9160ff 100644 --- a/prospector/profiles/profiles/strictness_high.yaml +++ b/prospector/profiles/profiles/strictness_high.yaml @@ -8,16 +8,16 @@ ignore-patterns: pylint: disable: - - C0303 - - C0304 - - R0903 - - R0904 - - W0110 - - W0141 - - W0142 - - W0603 - - W1111 - - W1301 + - trailing-whitespace + - missing-final-newline + - too-few-public-methods + - too-many-public-methods + - deprecated-lambda + - bad-builtin + - star-args + - global-statement + - assignment-from-none + - unused-format-string-key - W5103 options: diff --git a/prospector/profiles/profiles/strictness_low.yaml b/prospector/profiles/profiles/strictness_low.yaml index 8e6204cf..e52bb36b 100644 --- a/prospector/profiles/profiles/strictness_low.yaml +++ b/prospector/profiles/profiles/strictness_low.yaml @@ -5,37 +5,37 @@ inherits: pylint: disable: - - C0102 - - C0111 - - C0301 + - blacklisted-name + - missing-docstring + - line-too-long - E1103 - - R0801 - - R0912 - - R0913 - - R0914 - - R0915 + - duplicate-code + - too-many-branches + - too-many-arguments + - too-many-locals + - too-many-statements - R0924 - - W0107 - - W0108 - - W0109 - - W0123 - - W0150 - - W0211 - - W0212 - - W0222 - - W0332 - - W0402 - - W0602 - - W0611 - - W0612 - - W0613 - - W0614 - - W0622 - - W0623 - - W0702 - - W1201 - - W1300 - - W1402 + - unnecessary-pass + - unnecessary-lambda + - duplicate-key + - eval-used + - lost-exception + - bad-staticmethod-argument + - protected-access + - signature-differs + - lowercase-l-suffix + - deprecated-module + - global-variable-not-assigned + - unused-import + - unused-variable + - unused-argument + - unused-wildcard-import + - redefined-builtin + - redefine-in-handler + - bare-except + - logging-not-lazy + - bad-format-string-key + - anomalous-unicode-escape-in-string - W5101 pyflakes: diff --git a/prospector/profiles/profiles/strictness_medium.yaml b/prospector/profiles/profiles/strictness_medium.yaml index 075e0491..7e4a0d76 100644 --- a/prospector/profiles/profiles/strictness_medium.yaml +++ b/prospector/profiles/profiles/strictness_medium.yaml @@ -5,42 +5,42 @@ inherits: pylint: disable: - - C0103 - - C0202 - - C0203 - - C0204 - - C0302 - - C0321 + - invalid-name + - bad-classmethod-argument + - bad-mcs-method-argument + - bad-mcs-classmethod-argument + - too-many-lines + - multiple-statements - C0322 - C0323 - C0324 - - C0325 - - C0326 - - C0330 - - E0213 + - superfluous-parens + - bad-whitespace + - bad-continuation + - no-self-argument - E1103 - I0014 - - R0201 - - R0901 - - R0902 - - R0911 - - R0922 - - W0122 - - W0201 - - W0223 - - W0231 - - W0232 - - W0301 - - W0401 - - W0403 - - W0601 - - W0621 + - no-self-use + - too-many-ancestors + - too-many-instance-attributes + - too-many-return-statements + - abstract-class-little-used + - exec-used + - attribute-defined-outside-init + - abstract-method + - super-init-not-called + - no-init + - unnecessary-semicolon + - wildcard-import + - relative-import + - global-variable-undefined + - redefined-outer-name - W0701 - - W0703 - - W0704 + - broad-except + - pointless-except - W0713 - - W1001 - - W1401 + - property-on-old-class + - anomalous-backslash-in-string options: max-line-length: 159 diff --git a/prospector/profiles/profiles/strictness_veryhigh.yaml b/prospector/profiles/profiles/strictness_veryhigh.yaml index e7779217..0687694d 100644 --- a/prospector/profiles/profiles/strictness_veryhigh.yaml +++ b/prospector/profiles/profiles/strictness_veryhigh.yaml @@ -6,8 +6,8 @@ ignore-patterns: pylint: disable: - - W0511 - - C0330 + - fixme + - bad-continuation options: max-locals: 15 diff --git a/prospector/profiles/profiles/strictness_verylow.yaml b/prospector/profiles/profiles/strictness_verylow.yaml index 2436c200..37d1ae42 100644 --- a/prospector/profiles/profiles/strictness_verylow.yaml +++ b/prospector/profiles/profiles/strictness_verylow.yaml @@ -5,31 +5,31 @@ inherits: pylint: disable: - - C0112 - - C1001 - - E0711 - - C0121 - - E1002 - - E1101 - - E1102 - - E1111 - - E1302 - - R0921 - - R0923 - - W0104 - - W0105 - - W0106 + - empty-docstring + - old-style-class + - notimplemented-raised + - missing-module-attribute + - super-on-old-class + - no-member + - not-callable + - assignment-from-no-return + - mixed-format-string + - abstract-class-not-used + - interface-not-implemented + - pointless-statement + - pointless-string-statement + - expression-not-assigned - W0121 - - W0199 - - W0201 - - W0221 - - W0234 + - assert-on-tuple + - attribute-defined-outside-init + - arguments-differ + - non-iterator-returned - W0331 - W0333 - - W0404 - - W0604 - - W0632 - - W0710 + - reimported + - global-at-module-level + - unbalanced-tuple-unpacking + - nonstandard-exception - W0712 mccabe: diff --git a/prospector/run.py b/prospector/run.py index 88aeb5ef..438506e8 100644 --- a/prospector/run.py +++ b/prospector/run.py @@ -49,7 +49,7 @@ def execute(self): for tool in self.config.get_tools(found_files): try: messages += tool.run(found_files) - except Exception: # pylint: disable=W0703 + except Exception: # pylint: disable=broad-except if self.config.die_on_tool_error: raise else: diff --git a/prospector/tools/base.py b/prospector/tools/base.py index 22e72c15..48d66131 100644 --- a/prospector/tools/base.py +++ b/prospector/tools/base.py @@ -4,7 +4,7 @@ class ToolBase(object): # This is an 'abstract' base class, used to provide an indication of # how to create a new tool class. Therefore, the arguments will be unused, # so that is suppressed here. - # pylint: disable=W0613 + # pylint: disable=unused-argument def configure(self, prospector_config, found_files): """ @@ -19,7 +19,7 @@ def configure(self, prospector_config, found_files): """ # We don't want Pylint to tell us that this method should be a function, # it's an "abstract" class after all. - # pylint: disable=R0201 + # pylint: disable=no-self-use return None def run(self, found_files): diff --git a/prospector/tools/frosted/__init__.py b/prospector/tools/frosted/__init__.py index f5b65bc9..26b9fe6c 100644 --- a/prospector/tools/frosted/__init__.py +++ b/prospector/tools/frosted/__init__.py @@ -16,7 +16,7 @@ def __init__(self, ignore=None): self._messages = [] self.ignore = ignore or () - # pylint: disable=R0913 + # pylint: disable=too-many-arguments def record_message( self, filename=None, diff --git a/prospector/tools/pep8/__init__.py b/prospector/tools/pep8/__init__.py index f472836f..96466e96 100644 --- a/prospector/tools/pep8/__init__.py +++ b/prospector/tools/pep8/__init__.py @@ -124,7 +124,7 @@ def configure(self, prospector_config, found_files): # This means that we don't have existing config to use. # Make sure pep8's code ignores are fully reset to zero before # adding prospector-flavoured configuration. - # pylint: disable=W0201 + # pylint: disable=attribute-defined-outside-init self.checker.options.select = () self.checker.options.ignore = tuple(prospector_config.get_disabled_messages('pep8')) diff --git a/prospector/tools/profile_validator/__init__.py b/prospector/tools/profile_validator/__init__.py index 7418fd7f..653121a0 100644 --- a/prospector/tools/profile_validator/__init__.py +++ b/prospector/tools/profile_validator/__init__.py @@ -39,7 +39,7 @@ def configure(self, prospector_config, found_files): def tool_names(self): # TODO: this is currently a circular import, which is why it is not at the top of # the module. However, there's no obvious way to get around this right now... - # pylint: disable=R0401 + # pylint: disable=cyclic-import from prospector.tools import TOOLS return TOOLS.keys() diff --git a/prospector/tools/pyflakes/__init__.py b/prospector/tools/pyflakes/__init__.py index 59d12eea..f31167ce 100644 --- a/prospector/tools/pyflakes/__init__.py +++ b/prospector/tools/pyflakes/__init__.py @@ -35,7 +35,7 @@ def __init__(self, ignore=None): self._messages = [] self.ignore = ignore or () - # pylint: disable=R0913 + # pylint: disable=too-many-arguments def record_message( self, filename=None, @@ -70,7 +70,7 @@ def unexpectedError(self, filename, msg): # noqa message=msg, ) - # pylint: disable=R0913 + # pylint: disable=too-many-arguments def syntaxError(self, filename, msg, lineno, offset, text): # noqa self.record_message( filename=filename, diff --git a/prospector/tools/pylint/__init__.py b/prospector/tools/pylint/__init__.py index 3ab53eeb..c989eee7 100644 --- a/prospector/tools/pylint/__init__.py +++ b/prospector/tools/pylint/__init__.py @@ -11,7 +11,7 @@ from prospector.tools.pylint.linter import ProspectorLinter -_W0614_RE = re.compile(r'^Unused import (.*) from wildcard import$') +_UNUSED_WILDCARD_IMPORT_RE = re.compile(r'^Unused import (.*) from wildcard import$') class DummyStream(object): @@ -30,7 +30,7 @@ def flush(self): # The class name here is lowercase as it is a context manager, which # typically tend to me lowercase. -class stdout_wrapper(object): # noqa pylint:disable=C0103 +class stdout_wrapper(object): # noqa pylint:disable=invalid-name def __init__(self, hide_stdout): self.hide_stdout = hide_stdout @@ -73,7 +73,7 @@ def _prospector_configure(self, prospector_config, linter): for msg_id in prospector_config.get_disabled_messages('pylint'): try: linter.disable(msg_id) - # pylint: disable=W0704 + # pylint: disable=pointless-except except UnknownMessage: # If the msg_id doesn't exist in PyLint any more, # don't worry about it. @@ -90,20 +90,20 @@ def _prospector_configure(self, prospector_config, linter): # The warnings about disabling warnings are useful for figuring out # with other tools to suppress messages from. For example, an unused - # import which is disabled with 'pylint disable=W0611' will still + # import which is disabled with 'pylint disable=unused-import' will still # generate an 'FL0001' unused import warning from pyflakes. Using the # information from these messages, we can figure out what was disabled. - linter.disable('I0011') # notification about disabling a message - linter.disable('I0012') # notification about enabling a message - linter.enable('I0013') # notification about disabling an entire file - linter.enable('I0020') # notification about a message being supressed - linter.disable('I0021') # notification about message supressed which was not raised - linter.disable('I0022') # notification about use of deprecated 'pragma' option + linter.disable('locally-disabled') # notification about disabling a message + linter.disable('locally-enabled') # notification about enabling a message + linter.enable('file-ignored') # notification about disabling an entire file + linter.enable('suppressed-message') # notification about a message being supressed + linter.disable('useless-suppression') # notification about message supressed which was not raised + linter.disable('deprecated-pragma') # notification about use of deprecated 'pragma' option # disable the 'mixed indentation' warning, since it actually will only allow # the indentation specified in the pylint configuration file; we replace it # instead with our own version which is more lenient and configurable - linter.disable('W0312') + linter.disable('mixed-indentation') indent_checker = IndentChecker(linter) linter.register_checker(indent_checker) @@ -204,7 +204,7 @@ def configure(self, prospector_config, found_files): # use the collector 'reporter' to simply gather the messages # given by PyLint - self._collector = Collector() + self._collector = Collector(linter.msgs_store) linter.set_reporter(self._collector) self._linter = linter @@ -219,7 +219,7 @@ def _combine_w0614(self, messages): out = [] for message in messages: - if message.code == 'W0614': + if message.code == 'unused-wildcard-import': by_loc[message.location].append(message) else: out.append(message) @@ -227,10 +227,10 @@ def _combine_w0614(self, messages): for location, message_list in by_loc.items(): names = [] for msg in message_list: - names.append(_W0614_RE.match(msg.message).group(1)) + names.append(_UNUSED_WILDCARD_IMPORT_RE.match(msg.message).group(1)) msgtxt = 'Unused imports from wildcard import: %s' % ', '.join(names) - combined_message = Message('pylint', 'W0614', location, msgtxt) + combined_message = Message('pylint', 'unused-wildcard-import', location, msgtxt) out.append(combined_message) return out diff --git a/prospector/tools/pylint/collector.py b/prospector/tools/pylint/collector.py index b11e1541..b023b90e 100644 --- a/prospector/tools/pylint/collector.py +++ b/prospector/tools/pylint/collector.py @@ -1,5 +1,6 @@ from __future__ import absolute_import from pylint.reporters import BaseReporter +from pylint.utils import UnknownMessage from prospector.message import Location, Message @@ -7,15 +8,28 @@ class Collector(BaseReporter): name = 'collector' - def __init__(self): + def __init__(self, message_store): BaseReporter.__init__(self, output=None) + self._message_store = message_store self._messages = [] def add_message(self, msg_id, location, msg): # (* magic is acceptable here) - # pylint: disable=W0142 + # pylint: disable=star-args loc = Location(*location) - message = Message('pylint', msg_id, loc, msg) + # At this point pylint will give us the code but we want the + # more user-friendly symbol + try: + msg_data = self._message_store.check_message_id(msg_id) + except UnknownMessage: + # this shouldn't happen, as all pylint errors should be + # in the message store, but just in case we'll fall back + # to using the code. + msg_symbol = msg_id + else: + msg_symbol = msg_data.symbol + + message = Message('pylint', msg_symbol, loc, msg) self._messages.append(message) def _display(self, layout): diff --git a/prospector/tools/pylint/indent_checker.py b/prospector/tools/pylint/indent_checker.py index 73eedc74..b34fe869 100644 --- a/prospector/tools/pylint/indent_checker.py +++ b/prospector/tools/pylint/indent_checker.py @@ -39,15 +39,15 @@ def process_tokens(self, tokens): if line.startswith('\t'): if self.config.indent_strict_spaces: # we have tabs but are configured to only allow spaces - self.add_message('W0314', line=line_num, args=('tabs', 'spaces')) + self.add_message('incorrect-indentation', line=line_num, args=('tabs', 'spaces')) tab_count += 1 if line.startswith(' '): if self.config.indent_strict_tabs: # we have tabs but are configured to only allow spaces - self.add_message('W0314', line=line_num, args=('spaces', 'tabs')) + self.add_message('incorrect-indentation', line=line_num, args=('spaces', 'tabs')) space_count += 1 if tab_count > 0 and space_count > 0: # this file has mixed indentation! - self.add_message('W0313', line=-1) + self.add_message('indentation-mixture', line=-1) diff --git a/prospector/tools/pylint/linter.py b/prospector/tools/pylint/linter.py index 241ea5ca..028c446c 100644 --- a/prospector/tools/pylint/linter.py +++ b/prospector/tools/pylint/linter.py @@ -4,7 +4,7 @@ from pylint.lint import PyLinter -class ProspectorLinter(PyLinter): # pylint: disable=R0901,R0904 +class ProspectorLinter(PyLinter): # pylint: disable=too-many-ancestors,too-many-public-methods def __init__(self, found_files, *args, **kwargs): self._files = found_files @@ -15,7 +15,7 @@ def __init__(self, found_files, *args, **kwargs): def reset_options(self): # for example, we want to re-initialise the OptionsManagerMixin # to supress the config error warning - # pylint: disable=W0233 + # pylint: disable=non-parent-init-called OptionsManagerMixIn.__init__(self, usage=PyLinter.__doc__, quiet=True) def expand_files(self, modules): diff --git a/tests/profiles/profiles/inheritance/precedence/base2.yaml b/tests/profiles/profiles/inheritance/precedence/base2.yaml index 2c538439..b4dacdd7 100644 --- a/tests/profiles/profiles/inheritance/precedence/base2.yaml +++ b/tests/profiles/profiles/inheritance/precedence/base2.yaml @@ -4,5 +4,5 @@ inherits: pylint: run: true disable: - - C0111 - - W0106 + - missing-docstring + - expression-not-assigned diff --git a/tests/profiles/profiles/inheritance/precedence/start.yaml b/tests/profiles/profiles/inheritance/precedence/start.yaml index 82b97d3a..d359bcf3 100644 --- a/tests/profiles/profiles/inheritance/precedence/start.yaml +++ b/tests/profiles/profiles/inheritance/precedence/start.yaml @@ -6,4 +6,4 @@ inherits: pylint: run: true enable: - - C0111 \ No newline at end of file + - missing-docstring \ No newline at end of file diff --git a/tests/profiles/profiles/inherittest1.yaml b/tests/profiles/profiles/inherittest1.yaml index 517bf6db..5214bc7a 100644 --- a/tests/profiles/profiles/inherittest1.yaml +++ b/tests/profiles/profiles/inherittest1.yaml @@ -3,4 +3,4 @@ inherits: pylint: disable: - - I0001 \ No newline at end of file + - raw-checker-failed \ No newline at end of file diff --git a/tests/profiles/test_profile.py b/tests/profiles/test_profile.py index f2c41796..8aa68274 100644 --- a/tests/profiles/test_profile.py +++ b/tests/profiles/test_profile.py @@ -58,7 +58,7 @@ def test_simple_inheritance(self): profile = ProspectorProfile.load('inherittest3', self._profile_path, allow_shorthand=False) disable = profile.pylint['disable'] disable.sort() - self.assertEqual(['I0001', 'I0002', 'I0003'], disable) + self.assertEqual(['I0002', 'I0003', 'raw-checker-failed'], disable) def test_disable_tool_inheritance(self): profile = ProspectorProfile.load('pep8_and_pylint_disabled', self._profile_path) @@ -68,7 +68,7 @@ def test_disable_tool_inheritance(self): def test_precedence(self): profile = self._load('precedence') self.assertTrue(profile.is_tool_enabled('pylint')) - self.assertTrue('W0106' in profile.get_disabled_messages('pylint')) + self.assertTrue('expression-not-assigned' in profile.get_disabled_messages('pylint')) def test_strictness_equivalence(self): profile = self._load('strictness_equivalence') diff --git a/tests/test_autodetect.py b/tests/test_autodetect.py index 092f0de9..e69de29b 100644 --- a/tests/test_autodetect.py +++ b/tests/test_autodetect.py @@ -1,184 +0,0 @@ -# coding: utf8 -import os -import sys -import codecs -import warnings -import tempfile -import contextlib -from unittest import TestCase -try: - from unittest.util import safe_repr -except ImportError: - # python2.6 - safe_repr = repr - -from prospector.autodetect import ( - autodetect_libraries, - find_from_imports, - find_from_path, -) - -class FindFromImportsTest(TestCase): - - def _test(self, contents, *expected_names): - names = find_from_imports(contents) - self.assertEqual(set(expected_names), names) - - def test_simple_imports(self): - """ imports related to django are discovered. """ - self._test('from django.db import models', 'django') - self._test('import django', 'django') - - def test_compound_discovered(self): - """ compound imports containing several items of interest are discovered. """ - self._test('from django import db\nfrom celery import task', 'django', 'celery') - - def test_nothing_of_interest(self): - """ imports containing nothing of interest return an empty set. """ - self._test('import codecs') - - def test_multiple_imports(self): - """ django is discovered in 'from ...' multi-import statements. """ - self._test('from django.db import (models, \n' - ' some, other, stuff)', 'django') - - def test_indented_imports(self): - """ django is discovered from function-local import statements. """ - self._test('def lala(self):\n' - 'from django.db import models\n' - 'return models.Model', 'django') - - def test_same_line_two_imports(self): - """ importing two modules of interest on same line are discovered. """ - self._test('import django, celery', 'django', 'celery') - - -class ImportCodingsTest(TestCase): - - def SetUp(self): - warnings.simplefilter(action='always', category=ImportWarning) - TestCase.setUp(self) - - def tearDown(self): - warnings.resetwarnings() - TestCase.tearDown(self) - - if sys.version_info < (2, 7): - # backport assertGreaterEqual and assertIn for python2.6. - - def assertGreaterEqual(self, a, b, msg=None): - """Just like self.assertTrue(a >= b), but with a nicer default message.""" - if not a >= b: - standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b)) - self.fail(self._formatMessage(msg, standardMsg)) - - def assertIn(self, member, container, msg=None): - """Just like self.assertTrue(a in b), but with a nicer default message.""" - if member not in container: - standardMsg = '%s not found in %s' % (safe_repr(member), - safe_repr(container)) - self.fail(self._formatMessage(msg, standardMsg)) - - @contextlib.contextmanager - def make_pypath(self, bindata): - tmp_folder = tempfile.mkdtemp(prefix='prospector-') - tmp_fp = tempfile.NamedTemporaryFile(suffix='.py', dir=tmp_folder, delete=False) - tmp_file = tmp_fp.name - tmp_fp.write(bindata) - tmp_fp.close() - try: - yield tmp_folder - finally: - os.unlink(tmp_file) - os.rmdir(tmp_folder) - - def test_latin1_coding_line2(self): - """ - File containing latin1 at line 2 with 'coding' declaration at line 1. - """ - # given, - bindata = (u'# coding: latin1\n' - u'# latin1 character: ®\n' - u'import django\n' - ).encode('latin1') - expected_names = ('django',) - with self.make_pypath(bindata=bindata) as path: - # exercise, - names = find_from_path(path=path) - # verify. - self.assertEqual(set(expected_names), names) - - def test_negative_latin1(self): - """ Negative test: file containing latin1 without 'coding' declaration. """ - # given, - bindata = u'# latin1 character: ®'.encode('latin1') - - with self.make_pypath(bindata=bindata) as path: - # exercise, - with warnings.catch_warnings(record=True) as warned: - find_from_path(path=path) - # verify. - self.assertGreaterEqual(len(warned), 1) - self.assertIn(ImportWarning, [_w.category for _w in warned]) - - def test_negative_lookuperror(self): - """ File declares an unknown coding. """ - # given, - bindata = u'# coding: unknown\n'.encode('ascii') - - with self.make_pypath(bindata=bindata) as path: - # exercise, - with warnings.catch_warnings(record=True) as warned: - find_from_path(path=path) - # verify. - self.assertGreaterEqual(len(warned), 1) - self.assertIn(ImportWarning, [_w.category for _w in warned]) - - def test_bom_encoded_filepath(self): - """ File containing only a UTF32_BE byte order mark still decodes. """ - # given, - bindata = codecs.BOM_UTF32_BE - bindata += (u'import django\n' - u'# UTF-32-BE character: ®\n' - ).encode('UTF-32BE') - expected_names = ('django',) - with self.make_pypath(bindata=bindata) as path: - # exercise, - names = find_from_path(path=path) - # verify. - self.assertEqual(set(expected_names), names) - - def test_negative_misleading_bom(self): - """ Negative test: file containing BOM that is not the correct encoding. """ - # given, - bindata = codecs.BOM_UTF32_BE - bindata += u'# latin1 character: ®'.encode('latin1') - - with self.make_pypath(bindata=bindata) as path: - # exercise, - with warnings.catch_warnings(record=True) as warned: - find_from_path(path=path) - # verify. - self.assertGreaterEqual(len(warned), 1) - self.assertIn(ImportWarning, [_w.category for _w in warned]) - - -class AdaptersTest(TestCase): - - """ Adapters detection requires a true project, we just use only our own. """ - - def test_autodetect_adapters_of_prospector(self): - """ Use prospector's base proj. folder, discovers nothing. """ - # Given - tgt_path = os.path.join(os.path.dirname(__file__), os.path.pardir) - - # Exercise - detected = autodetect_libraries(tgt_path) - - # Verify - self.assertEqual(set(), detected) - - -if __name__ == '__main__': - import unittest - unittest.main()