summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--CONTRIBUTORS.txt2
-rw-r--r--ChangeLog16
-rw-r--r--pylint/__pkginfo__.py3
-rw-r--r--pylint/checkers/async.py8
-rw-r--r--pylint/checkers/refactoring/recommendation_checker.py2
-rw-r--r--pylint/checkers/utils.py5
-rw-r--r--pylint/checkers/variables.py5
-rw-r--r--tests/functional/c/consider_using_enumerate.py5
-rw-r--r--tests/functional/n/not_async_context_manager_py37.py11
-rw-r--r--tests/functional/s/star_needs_assignment_target_py35.rc1
-rw-r--r--tests/functional/u/undefined_variable_crash_on_attribute.py6
-rw-r--r--tox.ini2
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
diff --git a/ChangeLog b/ChangeLog
index e60d8eef1..b36f488ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/tox.ini b/tox.ini
index 1f88a5335..dd1d0da72 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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]