summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2022-10-01 22:06:06 +0200
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2022-10-10 11:15:38 +0200
commit66ae21cd9eaf8f726c306e2176ee1b029e86fe6a (patch)
tree0f3ac87abae7589b0e48b3c55316d0eb7c1b190b
parent983d5fc514e8e67ad0944365087efb8b5df05efe (diff)
downloadpylint-git-66ae21cd9eaf8f726c306e2176ee1b029e86fe6a.tar.gz
Check `` py-version`` for async ``unnecessary-dunder-call`` (#7549)
-rw-r--r--doc/whatsnew/fragments/7529.false_positive4
-rw-r--r--pylint/checkers/dunder_methods.py204
-rw-r--r--tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.py15
-rw-r--r--tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.rc2
-rw-r--r--tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.txt2
-rw-r--r--tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.py15
-rw-r--r--tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.rc2
7 files changed, 147 insertions, 97 deletions
diff --git a/doc/whatsnew/fragments/7529.false_positive b/doc/whatsnew/fragments/7529.false_positive
new file mode 100644
index 000000000..7775d9086
--- /dev/null
+++ b/doc/whatsnew/fragments/7529.false_positive
@@ -0,0 +1,4 @@
+Fix the message for ``unnecessary-dunder-call`` for ``__aiter__`` and ``__aneext__``. Also
+only emit the warning when ``py-version`` >= 3.10.
+
+Closes #7529
diff --git a/pylint/checkers/dunder_methods.py b/pylint/checkers/dunder_methods.py
index d753fceba..1b61be7d4 100644
--- a/pylint/checkers/dunder_methods.py
+++ b/pylint/checkers/dunder_methods.py
@@ -16,101 +16,105 @@ if TYPE_CHECKING:
from pylint.lint import PyLinter
-DUNDER_METHODS: dict[str, str] = {
- "__init__": "Instantiate class directly",
- "__del__": "Use del keyword",
- "__repr__": "Use repr built-in function",
- "__str__": "Use str built-in function",
- "__bytes__": "Use bytes built-in function",
- "__format__": "Use format built-in function, format string method, or f-string",
- "__lt__": "Use < operator",
- "__le__": "Use <= operator",
- "__eq__": "Use == operator",
- "__ne__": "Use != operator",
- "__gt__": "Use > operator",
- "__ge__": "Use >= operator",
- "__hash__": "Use hash built-in function",
- "__bool__": "Use bool built-in function",
- "__getattr__": "Access attribute directly or use getattr built-in function",
- "__getattribute__": "Access attribute directly or use getattr built-in function",
- "__setattr__": "Set attribute directly or use setattr built-in function",
- "__delattr__": "Use del keyword",
- "__dir__": "Use dir built-in function",
- "__get__": "Use get method",
- "__set__": "Use set method",
- "__delete__": "Use del keyword",
- "__instancecheck__": "Use isinstance built-in function",
- "__subclasscheck__": "Use issubclass built-in function",
- "__call__": "Invoke instance directly",
- "__len__": "Use len built-in function",
- "__length_hint__": "Use length_hint method",
- "__getitem__": "Access item via subscript",
- "__setitem__": "Set item via subscript",
- "__delitem__": "Use del keyword",
- "__iter__": "Use iter built-in function",
- "__next__": "Use next built-in function",
- "__reversed__": "Use reversed built-in function",
- "__contains__": "Use in keyword",
- "__add__": "Use + operator",
- "__sub__": "Use - operator",
- "__mul__": "Use * operator",
- "__matmul__": "Use @ operator",
- "__truediv__": "Use / operator",
- "__floordiv__": "Use // operator",
- "__mod__": "Use % operator",
- "__divmod__": "Use divmod built-in function",
- "__pow__": "Use ** operator or pow built-in function",
- "__lshift__": "Use << operator",
- "__rshift__": "Use >> operator",
- "__and__": "Use & operator",
- "__xor__": "Use ^ operator",
- "__or__": "Use | operator",
- "__radd__": "Use + operator",
- "__rsub__": "Use - operator",
- "__rmul__": "Use * operator",
- "__rmatmul__": "Use @ operator",
- "__rtruediv__": "Use / operator",
- "__rfloordiv__": "Use // operator",
- "__rmod__": "Use % operator",
- "__rdivmod__": "Use divmod built-in function",
- "__rpow__": "Use ** operator or pow built-in function",
- "__rlshift__": "Use << operator",
- "__rrshift__": "Use >> operator",
- "__rand__": "Use & operator",
- "__rxor__": "Use ^ operator",
- "__ror__": "Use | operator",
- "__iadd__": "Use += operator",
- "__isub__": "Use -= operator",
- "__imul__": "Use *= operator",
- "__imatmul__": "Use @= operator",
- "__itruediv__": "Use /= operator",
- "__ifloordiv__": "Use //= operator",
- "__imod__": "Use %= operator",
- "__ipow__": "Use **= operator",
- "__ilshift__": "Use <<= operator",
- "__irshift__": "Use >>= operator",
- "__iand__": "Use &= operator",
- "__ixor__": "Use ^= operator",
- "__ior__": "Use |= operator",
- "__neg__": "Multiply by -1 instead",
- "__pos__": "Multiply by +1 instead",
- "__abs__": "Use abs built-in function",
- "__invert__": "Use ~ operator",
- "__complex__": "Use complex built-in function",
- "__int__": "Use int built-in function",
- "__float__": "Use float built-in function",
- "__index__": "Use index method",
- "__round__": "Use round built-in function",
- "__trunc__": "Use math.trunc function",
- "__floor__": "Use math.floor function",
- "__ceil__": "Use math.ceil function",
- "__enter__": "Invoke context manager directly",
- "__aiter__": "Use iter built-in function",
- "__anext__": "Use next built-in function",
- "__aenter__": "Invoke context manager directly",
- "__copy__": "Use copy.copy function",
- "__deepcopy__": "Use copy.deepcopy function",
- "__fspath__": "Use os.fspath function instead",
+DUNDER_METHODS: dict[tuple[int, int], dict[str, str]] = {
+ (0, 0): {
+ "__init__": "Instantiate class directly",
+ "__del__": "Use del keyword",
+ "__repr__": "Use repr built-in function",
+ "__str__": "Use str built-in function",
+ "__bytes__": "Use bytes built-in function",
+ "__format__": "Use format built-in function, format string method, or f-string",
+ "__lt__": "Use < operator",
+ "__le__": "Use <= operator",
+ "__eq__": "Use == operator",
+ "__ne__": "Use != operator",
+ "__gt__": "Use > operator",
+ "__ge__": "Use >= operator",
+ "__hash__": "Use hash built-in function",
+ "__bool__": "Use bool built-in function",
+ "__getattr__": "Access attribute directly or use getattr built-in function",
+ "__getattribute__": "Access attribute directly or use getattr built-in function",
+ "__setattr__": "Set attribute directly or use setattr built-in function",
+ "__delattr__": "Use del keyword",
+ "__dir__": "Use dir built-in function",
+ "__get__": "Use get method",
+ "__set__": "Use set method",
+ "__delete__": "Use del keyword",
+ "__instancecheck__": "Use isinstance built-in function",
+ "__subclasscheck__": "Use issubclass built-in function",
+ "__call__": "Invoke instance directly",
+ "__len__": "Use len built-in function",
+ "__length_hint__": "Use length_hint method",
+ "__getitem__": "Access item via subscript",
+ "__setitem__": "Set item via subscript",
+ "__delitem__": "Use del keyword",
+ "__iter__": "Use iter built-in function",
+ "__next__": "Use next built-in function",
+ "__reversed__": "Use reversed built-in function",
+ "__contains__": "Use in keyword",
+ "__add__": "Use + operator",
+ "__sub__": "Use - operator",
+ "__mul__": "Use * operator",
+ "__matmul__": "Use @ operator",
+ "__truediv__": "Use / operator",
+ "__floordiv__": "Use // operator",
+ "__mod__": "Use % operator",
+ "__divmod__": "Use divmod built-in function",
+ "__pow__": "Use ** operator or pow built-in function",
+ "__lshift__": "Use << operator",
+ "__rshift__": "Use >> operator",
+ "__and__": "Use & operator",
+ "__xor__": "Use ^ operator",
+ "__or__": "Use | operator",
+ "__radd__": "Use + operator",
+ "__rsub__": "Use - operator",
+ "__rmul__": "Use * operator",
+ "__rmatmul__": "Use @ operator",
+ "__rtruediv__": "Use / operator",
+ "__rfloordiv__": "Use // operator",
+ "__rmod__": "Use % operator",
+ "__rdivmod__": "Use divmod built-in function",
+ "__rpow__": "Use ** operator or pow built-in function",
+ "__rlshift__": "Use << operator",
+ "__rrshift__": "Use >> operator",
+ "__rand__": "Use & operator",
+ "__rxor__": "Use ^ operator",
+ "__ror__": "Use | operator",
+ "__iadd__": "Use += operator",
+ "__isub__": "Use -= operator",
+ "__imul__": "Use *= operator",
+ "__imatmul__": "Use @= operator",
+ "__itruediv__": "Use /= operator",
+ "__ifloordiv__": "Use //= operator",
+ "__imod__": "Use %= operator",
+ "__ipow__": "Use **= operator",
+ "__ilshift__": "Use <<= operator",
+ "__irshift__": "Use >>= operator",
+ "__iand__": "Use &= operator",
+ "__ixor__": "Use ^= operator",
+ "__ior__": "Use |= operator",
+ "__neg__": "Multiply by -1 instead",
+ "__pos__": "Multiply by +1 instead",
+ "__abs__": "Use abs built-in function",
+ "__invert__": "Use ~ operator",
+ "__complex__": "Use complex built-in function",
+ "__int__": "Use int built-in function",
+ "__float__": "Use float built-in function",
+ "__index__": "Use index method",
+ "__round__": "Use round built-in function",
+ "__trunc__": "Use math.trunc function",
+ "__floor__": "Use math.floor function",
+ "__ceil__": "Use math.ceil function",
+ "__enter__": "Invoke context manager directly",
+ "__aenter__": "Invoke context manager directly",
+ "__copy__": "Use copy.copy function",
+ "__deepcopy__": "Use copy.deepcopy function",
+ "__fspath__": "Use os.fspath function instead",
+ },
+ (3, 10): {
+ "__aiter__": "Use aiter built-in function",
+ "__anext__": "Use anext built-in function",
+ },
}
@@ -143,6 +147,12 @@ class DunderCallChecker(BaseChecker):
}
options = ()
+ def open(self) -> None:
+ self._dunder_methods: dict[str, str] = {}
+ for since_vers, dunder_methods in DUNDER_METHODS.items():
+ if since_vers <= self.linter.config.py_version:
+ self._dunder_methods.update(dunder_methods)
+
@staticmethod
def within_dunder_def(node: nodes.NodeNG) -> bool:
"""Check if dunder method call is within a dunder method definition."""
@@ -161,7 +171,7 @@ class DunderCallChecker(BaseChecker):
"""Check if method being called is an unnecessary dunder method."""
if (
isinstance(node.func, nodes.Attribute)
- and node.func.attrname in DUNDER_METHODS
+ and node.func.attrname in self._dunder_methods
and not self.within_dunder_def(node)
and not (
isinstance(node.func.expr, nodes.Call)
@@ -177,7 +187,7 @@ class DunderCallChecker(BaseChecker):
self.add_message(
"unnecessary-dunder-call",
node=node,
- args=(node.func.attrname, DUNDER_METHODS[node.func.attrname]),
+ args=(node.func.attrname, self._dunder_methods[node.func.attrname]),
confidence=HIGH,
)
diff --git a/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.py b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.py
new file mode 100644
index 000000000..c2ab58a57
--- /dev/null
+++ b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.py
@@ -0,0 +1,15 @@
+"""Checks for unnecessary-dunder-call on __aiter__/__anext__ with py-version=3.10."""
+
+
+class MyClass:
+ """A class implementing __aiter__ and __anext__."""
+
+ def __aiter__(self):
+ ...
+
+ async def __anext__(self):
+ ...
+
+
+MyClass().__aiter__() # [unnecessary-dunder-call]
+MyClass().__anext__() # [unnecessary-dunder-call]
diff --git a/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.rc b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.rc
new file mode 100644
index 000000000..7d7b7aa0c
--- /dev/null
+++ b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.rc
@@ -0,0 +1,2 @@
+[master]
+py-version=3.10
diff --git a/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.txt b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.txt
new file mode 100644
index 000000000..bcb5647f9
--- /dev/null
+++ b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py310.txt
@@ -0,0 +1,2 @@
+unnecessary-dunder-call:14:0:14:21::Unnecessarily calls dunder method __aiter__. Use aiter built-in function.:HIGH
+unnecessary-dunder-call:15:0:15:21::Unnecessarily calls dunder method __anext__. Use anext built-in function.:HIGH
diff --git a/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.py b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.py
new file mode 100644
index 000000000..589524170
--- /dev/null
+++ b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.py
@@ -0,0 +1,15 @@
+"""Checks for unnecessary-dunder-call on __aiter__/__anext__ with py-version=3.9."""
+
+
+class MyClass:
+ """A class implementing __aiter__ and __anext__."""
+
+ def __aiter__(self):
+ ...
+
+ async def __anext__(self):
+ ...
+
+
+MyClass().__aiter__()
+MyClass().__anext__()
diff --git a/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.rc b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.rc
new file mode 100644
index 000000000..aed012f73
--- /dev/null
+++ b/tests/functional/u/unnecessary/unnecessary_dunder_call_async_py39.rc
@@ -0,0 +1,2 @@
+[MAIN]
+py-version=3.9