diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | CONTRIBUTORS.txt | 2 | ||||
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | pylint/__pkginfo__.py | 3 | ||||
-rw-r--r-- | pylint/checkers/async.py | 8 | ||||
-rw-r--r-- | pylint/checkers/refactoring/recommendation_checker.py | 2 | ||||
-rw-r--r-- | pylint/checkers/utils.py | 5 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 5 | ||||
-rw-r--r-- | tests/functional/c/consider_using_enumerate.py | 5 | ||||
-rw-r--r-- | tests/functional/n/not_async_context_manager_py37.py | 11 | ||||
-rw-r--r-- | tests/functional/s/star_needs_assignment_target_py35.rc | 1 | ||||
-rw-r--r-- | tests/functional/u/undefined_variable_crash_on_attribute.py | 6 | ||||
-rw-r--r-- | tox.ini | 2 |
13 files changed, 63 insertions, 5 deletions
diff --git a/.travis.yml b/.travis.yml index 61d78d4d8..de982a62f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,8 @@ jobs: env: TOXENV=py37 - python: 3.8 env: TOXENV=py38 + - python: 3.9 + env: TOXENV=py39 - stage: tests-pypy python: pypy3 env: TOXENV=pypy diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 166910b66..808b87da6 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -435,3 +435,5 @@ contributors: * Sorin Sbarnea: contributor * Gergely Kalmár: contributor + +* Batuhan Taskaya: contributor @@ -19,11 +19,23 @@ Pylint's ChangeLog * Add missing checks for deprecated functions. +* Postponed evaluation of annotations are now recognized by default if python version is above 3.10 + + Closes #3992 + What's New in Pylint 2.6.1? =========================== Release date: TBA +* Fix a crash in `undefined-variable` caused by chained attributes in metaclass + + Close #3742 + +* Fix false positive for `not-async-context-manager` when `contextlib.asynccontextmanager` is used + + Close #3862 + * Fix linter multiprocessing pool shutdown (triggered warnings when runned in parallels with other pytest plugins) Closes #3779 @@ -87,6 +99,10 @@ Release date: TBA Close #3737 +* Fix a crash in `consider-using-enumerate` when encountering `range()` without arguments + + Close #3735 + What's New in Pylint 2.6.0? =========================== diff --git a/pylint/__pkginfo__.py b/pylint/__pkginfo__.py index 621748c38..82b503610 100644 --- a/pylint/__pkginfo__.py +++ b/pylint/__pkginfo__.py @@ -40,7 +40,7 @@ if dev_version is not None: version += "-dev" + str(dev_version) install_requires = [ - "astroid>=2.4.0,<=2.5", + "astroid>=2.4.0,<=2.6", "isort>=4.2.5,<6", "mccabe>=0.6,<0.7", "toml>=0.7.1", @@ -72,6 +72,7 @@ classifiers = [ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", diff --git a/pylint/checkers/async.py b/pylint/checkers/async.py index 1b581c0f1..420c0e211 100644 --- a/pylint/checkers/async.py +++ b/pylint/checkers/async.py @@ -58,7 +58,12 @@ class AsyncChecker(checkers.BaseChecker): if inferred is None or inferred is astroid.Uninferable: continue - if isinstance(inferred, bases.AsyncGenerator): + if isinstance(inferred, astroid.AsyncFunctionDef): + # Check if we are dealing with a function decorated + # with contextlib.asynccontextmanager. + if decorated_with(inferred, self._async_generators): + continue + elif isinstance(inferred, bases.AsyncGenerator): # Check if we are dealing with a function decorated # with contextlib.asynccontextmanager. if decorated_with(inferred.parent, self._async_generators): @@ -79,7 +84,6 @@ class AsyncChecker(checkers.BaseChecker): continue else: continue - self.add_message( "not-async-context-manager", node=node, args=(inferred.name,) ) diff --git a/pylint/checkers/refactoring/recommendation_checker.py b/pylint/checkers/refactoring/recommendation_checker.py index 0ca907f32..1617c934c 100644 --- a/pylint/checkers/refactoring/recommendation_checker.py +++ b/pylint/checkers/refactoring/recommendation_checker.py @@ -67,6 +67,8 @@ class RecommendationChecker(checkers.BaseChecker): return if not self._is_builtin(node.iter.func, "range"): return + if not node.iter.args: + return is_constant_zero = ( isinstance(node.iter.args[0], astroid.Const) and node.iter.args[0].value == 0 diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 23836f909..6c707e10f 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -50,6 +50,7 @@ import itertools import numbers import re import string +import sys from functools import lru_cache, partial from typing import Callable, Dict, Iterable, List, Match, Optional, Set, Tuple, Union @@ -212,6 +213,7 @@ SPECIAL_METHODS_PARAMS = { for name in methods # type: ignore } PYMETHODS = set(SPECIAL_METHODS_PARAMS) +PY310_PLUS = sys.version_info[:2] >= (3, 10) class NoSuchArgumentError(Exception): @@ -1264,6 +1266,9 @@ def get_node_last_lineno(node: astroid.node_classes.NodeNG) -> int: def is_postponed_evaluation_enabled(node: astroid.node_classes.NodeNG) -> bool: """Check if the postponed evaluation of annotations is enabled""" + if PY310_PLUS: + return True + module = node.root() return "annotations" in module.future_imports diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index b6a2978a5..986f76fd2 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2037,7 +2037,10 @@ class VariablesChecker(BaseChecker): if isinstance(klass._metaclass, astroid.Name): name = klass._metaclass.name elif isinstance(klass._metaclass, astroid.Attribute) and klass._metaclass.expr: - name = klass._metaclass.expr.name + attr = klass._metaclass.expr + while not isinstance(attr, astroid.Name): + attr = attr.expr + name = attr.name elif metaclass: name = metaclass.root().name diff --git a/tests/functional/c/consider_using_enumerate.py b/tests/functional/c/consider_using_enumerate.py index cff00aeec..2ac382b18 100644 --- a/tests/functional/c/consider_using_enumerate.py +++ b/tests/functional/c/consider_using_enumerate.py @@ -66,3 +66,8 @@ class Good(object): # Should not suggest enumerate on self
for i in range(len(self)):
yield self[i]
+
+
+def does_not_crash_on_range_without_args():
+ for elem in range():
+ print(elem)
diff --git a/tests/functional/n/not_async_context_manager_py37.py b/tests/functional/n/not_async_context_manager_py37.py index 705e5afc9..c1ca26976 100644 --- a/tests/functional/n/not_async_context_manager_py37.py +++ b/tests/functional/n/not_async_context_manager_py37.py @@ -10,3 +10,14 @@ async def context_manager(value): async with context_manager(42) as ans: assert ans == 42 + + +def async_context_manager(): + @asynccontextmanager + async def wrapper(): + pass + return wrapper + +async def func(): + async with async_context_manager(): + pass diff --git a/tests/functional/s/star_needs_assignment_target_py35.rc b/tests/functional/s/star_needs_assignment_target_py35.rc index 71de8b630..b743e8f28 100644 --- a/tests/functional/s/star_needs_assignment_target_py35.rc +++ b/tests/functional/s/star_needs_assignment_target_py35.rc @@ -1,2 +1,3 @@ [testoptions] min_pyver=3.5 +max_pyver=3.8 diff --git a/tests/functional/u/undefined_variable_crash_on_attribute.py b/tests/functional/u/undefined_variable_crash_on_attribute.py new file mode 100644 index 000000000..571efab1c --- /dev/null +++ b/tests/functional/u/undefined_variable_crash_on_attribute.py @@ -0,0 +1,6 @@ +# pylint: disable=import-error,missing-module-docstring,missing-class-docstring,too-few-public-methods +import unknown + + +class Cls(metaclass=unknown.path.MetaFoo): + pass @@ -1,6 +1,6 @@ [tox] minversion = 2.4 -envlist = py35, py36, py37, py38, pypy, pylint, benchmark +envlist = py35, py36, py37, py38, py39, pypy, pylint, benchmark skip_missing_interpreters = true [testenv:pylint] |