Summary -- Release highlights

  • Dropped support for Python 2. This release will work only on Python 3.4+.

    If you need to use pylint with Python 2, you can use Pylint 1.9+. We'll continue to do bug releases until 2020, when Python 2 goes officially EOL. pylint will gain the ability to analyze Python 2 files, but some checks might not work as they will assume that their running environment is Python 2.

  • Given the dropping of Python 2, the Python 3 porting mode (enabled via --py3k) can now also run with Python 3.

    The porting mode used to be a no-op on Python 3, but most of the messages can now be emitted when the running interpreter is Python 3. The only messages that won't be emitted are those that rely on a particular syntax specific to Python 2, for instance print as a statement.

New checkers

  • A new check was added, useless-object-inheritance.

    This refactoring message is emitted when pylint detects that a class inherits from object, which is redundant as in Python 3, every class implicitly inherits from object.

    class A(object):
        pass
    
    class A:    # better
        pass
    
  • A new check was added, comparison-with-callable.

    This refactoring message is emitted when pylint detects that a comparison with a callable was made, which might suggest that some parenthesis were omitted, resulting in potential unwanted behaviour.

    def foo():
        return None
    
    def goo():
        return None
    
    if foo == 786:  # bad
        pass
    
    if foo() == 786:    # good
        pass
    
  • A new check was added, chained-comparison.

    This refactoring message is emitted if a boolean operation can be simplified by chaining some of its operations. check below example:

    if a < b and b < c:
        pass
    
    if a < b < c:   # better
        pass
    
  • A new check was added, useless-import-alias.

    This refactoring message is emitted when an import alias does not rename the original package.

    import numpy as numpy # bad
    import numpy as np # good
    from collection import OrderedDict as OrderedDict # bad
    from collection import OrderedDict as ordered_dict # good
    
  • A new check was added, comparison-with-itself.

    This refactoring message is emitted when a variable is compared against itself.

    if variable == variable:  # bad
        pass
    
  • A new check was added, consider-using-in.

    This refactoring message is emitted when a variable is compared against multiple values concatenated by ors instead of using the faster, more idiomatic "in" check.

    if variable == 1 or variable == 2 or variable == 3:  # bad
        pass
    
    if variable in (1, 2, 3):  # good
        pass
    
  • A new check was added, consider-using-get.

    This refactoring message is emitted when manually checking if a key is in a dictionary and getting its value if it is (and optionally a default if not) instead of the more idiomatic dict.get.

    if 'key' in dictionary:  # bad
        variable = dictionary['key']
    else:
        variable = 'default'
    
    variable = dictionary.get('key', 'default')  # good
    
  • A new check was added, consider-using-join.

    This refactoring message is emitted when using a for loop over an iterable to join strings instead of the faster, less memory consuming and more idiomatic str.join(sequence).

    result = ''  # bad
    for number in ['1', '2', '3']:
        result += number
    
    result = ''.join(['1', '2', '3'])  # good
    
  • New useless-return message when function or method ends with a "return" or "return None" statement and this is the only return statement in the body.

  • New use-symbolic-message-instead message when a message is activated or deactivated by id instead of symbol. The use of symbol is more explicit and easier to remind.

  • A new check was added, consider-swap-variables.

    This refactoring message is emitted when using a temporary variable in order to swap the values of two variables instead of the shorter, more idiomatic approach with tuple-unpacking.

    Instead of a temporary variable, the one-line syntax with commas should be used.

    See this style guide document or the Pycon 2007 swap values presentation for details.

    temp = a  # the wrong way
    a = b
    b = temp
    
    a, b = b, a  # the right way
    
  • Two new checks, invalid-envvar-value and invalid-envvar-default, were added.

    The former is trigger whenever pylint detects that environment variable manipulation functions uses a different type than strings, while the latter is emitted whenever the said functions are using a default variable of different type than expected.

  • A new check was added, subprocess-popen-preexec-fn,

    This refactoring message is emitted when using the keyword argument preexec_fn when creating subprocess.Popen instances which may be unsafe when used in the presence of threads.

    See subprocess.Popen for full warning details.

  • New try-except-raise message when an except handler block has a bare raise statement as its first operator or the exception type being raised is the same as the one being handled.

  • New possibly-unused-variable check added.

This is similar to unused-variable, the only difference is that it is emitted when we detect a locals() call in the scope of the unused variable. The locals() call could potentially use the said variable, by consuming all values that are present up to the point of the call. This new check allows to disable this error when the user intentionally uses locals() to consume everything.

For instance, the following code will now trigger this new error:

def func():
    some_value = some_call()
    return locals()
  • New unhashable-dict-key check added to detect dict lookups using unhashable keys such as lists or dicts.

  • New self-cls-assignment warning check added.

    This is warning if the first argument of an instance/ class method gets assigned

    class Foo(object):
        def foo(self, bar):
            self = bar
    
  • New verbose mode option --verbose to display of extra non-checker-related output. Disabled by default.

  • Two new checks were added for recommending dict and set comprehensions where possible.

    These two checks are going to flag the following examples:

    dict([(k, v) for (k, v) in ...]) # better as {k: v for k, v in ...}
    set([k for k in ...]) # better as {k for k in ...}
    

Other Changes

  • A couple of performance improvements brought to astroid should make pylint should be a bit faster as well.

    We added a new flag, max_inferable_values on astroid.MANAGER for limiting the maximum amount of values that astroid can infer when inferring values. This change should improve the performance when dealing with large frameworks such as django. You can also control this behaviour with pylint --limit-inference-results

    We also rewrote how nodes_of_class and get_children methods operate which should result in a performance boost for a couple of checks.

  • Fix a false positive inconsistent-return-statements message when exception is raised inside an else statement.

  • Don't warn for missing-type-doc and/or missing-return-type-doc, if type annotations exist on the function signature for a parameter and/or return type.

  • Fix a false positive inconsistent-return-statements message when if statement is inside try/except.

  • Fix a false positive inconsistent-return-statements message when while loop are used.

  • Fix emission of false positive no-member message for class with "private" attributes whose name is mangled.

  • Fix unused-argument false positives with overshadowed variable in dictionary comprehension.

  • Fixing false positive inconsistent-return-statements when never returning functions are used (i.e such as sys.exit).

  • Fix false positive inconsistent-return-statements message when a function is defined under an if statement.

  • Fix false positive inconsistent-return-statements message by avoiding useless exception inference if the exception is not handled.

  • Fix false positive undefined-variable for lambda argument in class definitions

  • Suppress false-positive not-callable messages from certain staticmethod descriptors

  • Expand ignored-argument-names include starred arguments and keyword arguments

  • singleton-comparison will suggest better boolean conditions for negative conditions.

  • undefined-loop-variable takes in consideration non-empty iterred objects before emitting.

    For instance, if the loop iterable is not empty, this check will no longer be emitted.

  • Enum classes no longer trigger too-few-methods

  • Special methods now count towards too-few-methods, and are considered part of the public API. They are still not counted towards the number of methods for too-many-methods.

  • docparams extension allows abstract methods to document returns documentation even if the default implementation does not return something. They also no longer need to document raising a NotImplementedError.

  • Skip wildcard import check for __init__.py.

  • Don't warn 'useless-super-delegation' if the subclass method has different type annotations.

  • Don't warn that a global variable is unused if it is defined by an import

    def func():
        global sys
        import sys
    
  • Added basic support for postponed evaluation of function annotations.

    If pylint detects the corresponding from __future__ import annotations import, it will not emit used-before-assignment and undefined-variable in the cases triggered by the annotations.

    More details on the postponed evaluation of annotations can be read in PEP 563.

  • A new command line option was added, --exit-zero, for the use of continuous integration scripts which abort if a command returns a non-zero status code. If the option is specified, and Pylint runs successfully, it will exit with 0 regardless of the number of lint issues detected.

    Configuration errors, parse errors, and calling Pylint with invalid command-line options all still return a non-zero error code, even if --exit-zero is specified.

  • Don't emit unused-import anymore for typing imports used in type comments. For instance, in the following example pylint used to complain that Any and List are not used, while they should be considered used by a type checker.

    from typing import Any, List
    a = 1 # type: List[Any]
    
  • Fix false positive line-too-long for commented lines at the end of module

  • Fix emitting useless-super-delegation when changing the default value of keyword arguments.

  • Support typing.TYPE_CHECKING for unused-import errors

    When modules are imported under typing.TYPE_CHECKING guard, pylint will no longer emit unused-import.

  • Fix false positive unused-variable in lambda default arguments

  • assignment-from-no-return considers methods as well as functions.

    If you have a method that doesn't return a value, but later on you assign a value to a function call to that method (so basically it will be None), then pylint is going to emit an assignment-from-no-return error.

  • A new flag was added, --ignore-none which controls the no-member behaviour with respect to None values.

    Previously pylint was not emitting no-member if it inferred that the owner of an attribute access is a None value. In some cases, this might actually cause bugs, so if you want to check for None values as well, pass --ignore-none=n to pylint.

  • Fix false-positive bad-continuation for with statements

  • Fix false-positive bad-whitespace message for typing annoatations with ellipses in them

  • Fix false-positive undefined-variable for nested lambdas