diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2018-12-06 08:58:46 +0100 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2018-12-06 08:58:46 +0100 |
commit | c320b0e0d77f34972631a82a7088b368d9002dd7 (patch) | |
tree | 3675a1ab1f51562b15da6b6492f329fc799109b4 | |
parent | 95bc362f59476a41538a8d17e3232ad893e004ff (diff) | |
download | pylint-git-c320b0e0d77f34972631a82a7088b368d9002dd7.tar.gz |
Fix false positive with `not-async-context-manager` caused by not understanding `contextlib.asynccontextmanager`
Close #2440
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | pylint/checkers/async.py | 26 | ||||
-rw-r--r-- | pylint/test/functional/not_async_context_manager_py37.py | 12 | ||||
-rw-r--r-- | pylint/test/functional/not_async_context_manager_py37.rc | 2 | ||||
-rw-r--r-- | pylint/test/functional/not_async_context_manager_py37.txt | 0 |
5 files changed, 35 insertions, 9 deletions
@@ -7,6 +7,10 @@ What's New in Pylint 2.3.0? Release date: TBA +* Fix false positive with `not-async-context-manager` caused by not understanding `contextlib.asynccontextmanager` + + Close #2440 + * Refactor ``bad-reversed-sequence`` to account for more objects that can define ``__reversed__`` One such object would be an enum class, for which ``__reversed__`` yields each individual enum. diff --git a/pylint/checkers/async.py b/pylint/checkers/async.py index 881b29daf..21feba035 100644 --- a/pylint/checkers/async.py +++ b/pylint/checkers/async.py @@ -9,12 +9,14 @@ import sys import astroid +from astroid import bases from astroid import exceptions from pylint import checkers from pylint.checkers import utils as checker_utils from pylint import interfaces from pylint import utils +from pylint.checkers.utils import decorated_with class AsyncChecker(checkers.BaseChecker): @@ -41,6 +43,7 @@ class AsyncChecker(checkers.BaseChecker): self._ignore_mixin_members = utils.get_global_option( self, "ignore-mixin-members" ) + self._async_generators = ["contextlib.asynccontextmanager"] @checker_utils.check_messages("yield-inside-async-function") def visit_asyncfunctiondef(self, node): @@ -53,29 +56,34 @@ class AsyncChecker(checkers.BaseChecker): @checker_utils.check_messages("not-async-context-manager") def visit_asyncwith(self, node): for ctx_mgr, _ in node.items: - infered = checker_utils.safe_infer(ctx_mgr) - if infered is None or infered is astroid.Uninferable: + inferred = checker_utils.safe_infer(ctx_mgr) + if inferred is None or inferred is astroid.Uninferable: continue - if isinstance(infered, astroid.Instance): + if isinstance(inferred, bases.AsyncGenerator): + # Check if we are dealing with a function decorated + # with contextlib.asynccontextmanager. + if decorated_with(inferred.parent, self._async_generators): + continue + else: try: - infered.getattr("__aenter__") - infered.getattr("__aexit__") + inferred.getattr("__aenter__") + inferred.getattr("__aexit__") except exceptions.NotFoundError: - if isinstance(infered, astroid.Instance): + if isinstance(inferred, astroid.Instance): # If we do not know the bases of this class, # just skip it. - if not checker_utils.has_known_bases(infered): + if not checker_utils.has_known_bases(inferred): continue # Just ignore mixin classes. if self._ignore_mixin_members: - if infered.name[-5:].lower() == "mixin": + if inferred.name[-5:].lower() == "mixin": continue else: continue self.add_message( - "not-async-context-manager", node=node, args=(infered.name,) + "not-async-context-manager", node=node, args=(inferred.name,) ) diff --git a/pylint/test/functional/not_async_context_manager_py37.py b/pylint/test/functional/not_async_context_manager_py37.py new file mode 100644 index 000000000..705e5afc9 --- /dev/null +++ b/pylint/test/functional/not_async_context_manager_py37.py @@ -0,0 +1,12 @@ +# pylint: disable=missing-docstring + +from contextlib import asynccontextmanager + + +@asynccontextmanager +async def context_manager(value): + yield value + + +async with context_manager(42) as ans: + assert ans == 42 diff --git a/pylint/test/functional/not_async_context_manager_py37.rc b/pylint/test/functional/not_async_context_manager_py37.rc new file mode 100644 index 000000000..a17bb22da --- /dev/null +++ b/pylint/test/functional/not_async_context_manager_py37.rc @@ -0,0 +1,2 @@ +[testoptions] +min_pyver=3.7 diff --git a/pylint/test/functional/not_async_context_manager_py37.txt b/pylint/test/functional/not_async_context_manager_py37.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/pylint/test/functional/not_async_context_manager_py37.txt |