99from astroid import Instance , Uninferable , nodes
1010
1111from pylint .checkers import BaseChecker
12- from pylint .checkers .utils import only_required_for_messages , safe_infer
12+ from pylint .checkers .utils import safe_infer
13+ from pylint .constants import DUNDER_METHODS
1314from pylint .interfaces import HIGH
1415
1516if TYPE_CHECKING :
1617 from pylint .lint import PyLinter
1718
1819
19- DUNDER_METHODS : dict [tuple [int , int ], dict [str , str ]] = {
20- (0 , 0 ): {
21- "__init__" : "Instantiate class directly" ,
22- "__del__" : "Use del keyword" ,
23- "__repr__" : "Use repr built-in function" ,
24- "__str__" : "Use str built-in function" ,
25- "__bytes__" : "Use bytes built-in function" ,
26- "__format__" : "Use format built-in function, format string method, or f-string" ,
27- "__lt__" : "Use < operator" ,
28- "__le__" : "Use <= operator" ,
29- "__eq__" : "Use == operator" ,
30- "__ne__" : "Use != operator" ,
31- "__gt__" : "Use > operator" ,
32- "__ge__" : "Use >= operator" ,
33- "__hash__" : "Use hash built-in function" ,
34- "__bool__" : "Use bool built-in function" ,
35- "__getattr__" : "Access attribute directly or use getattr built-in function" ,
36- "__getattribute__" : "Access attribute directly or use getattr built-in function" ,
37- "__setattr__" : "Set attribute directly or use setattr built-in function" ,
38- "__delattr__" : "Use del keyword" ,
39- "__dir__" : "Use dir built-in function" ,
40- "__get__" : "Use get method" ,
41- "__set__" : "Use set method" ,
42- "__delete__" : "Use del keyword" ,
43- "__instancecheck__" : "Use isinstance built-in function" ,
44- "__subclasscheck__" : "Use issubclass built-in function" ,
45- "__call__" : "Invoke instance directly" ,
46- "__len__" : "Use len built-in function" ,
47- "__length_hint__" : "Use length_hint method" ,
48- "__getitem__" : "Access item via subscript" ,
49- "__setitem__" : "Set item via subscript" ,
50- "__delitem__" : "Use del keyword" ,
51- "__iter__" : "Use iter built-in function" ,
52- "__next__" : "Use next built-in function" ,
53- "__reversed__" : "Use reversed built-in function" ,
54- "__contains__" : "Use in keyword" ,
55- "__add__" : "Use + operator" ,
56- "__sub__" : "Use - operator" ,
57- "__mul__" : "Use * operator" ,
58- "__matmul__" : "Use @ operator" ,
59- "__truediv__" : "Use / operator" ,
60- "__floordiv__" : "Use // operator" ,
61- "__mod__" : "Use % operator" ,
62- "__divmod__" : "Use divmod built-in function" ,
63- "__pow__" : "Use ** operator or pow built-in function" ,
64- "__lshift__" : "Use << operator" ,
65- "__rshift__" : "Use >> operator" ,
66- "__and__" : "Use & operator" ,
67- "__xor__" : "Use ^ operator" ,
68- "__or__" : "Use | operator" ,
69- "__radd__" : "Use + operator" ,
70- "__rsub__" : "Use - operator" ,
71- "__rmul__" : "Use * operator" ,
72- "__rmatmul__" : "Use @ operator" ,
73- "__rtruediv__" : "Use / operator" ,
74- "__rfloordiv__" : "Use // operator" ,
75- "__rmod__" : "Use % operator" ,
76- "__rdivmod__" : "Use divmod built-in function" ,
77- "__rpow__" : "Use ** operator or pow built-in function" ,
78- "__rlshift__" : "Use << operator" ,
79- "__rrshift__" : "Use >> operator" ,
80- "__rand__" : "Use & operator" ,
81- "__rxor__" : "Use ^ operator" ,
82- "__ror__" : "Use | operator" ,
83- "__iadd__" : "Use += operator" ,
84- "__isub__" : "Use -= operator" ,
85- "__imul__" : "Use *= operator" ,
86- "__imatmul__" : "Use @= operator" ,
87- "__itruediv__" : "Use /= operator" ,
88- "__ifloordiv__" : "Use //= operator" ,
89- "__imod__" : "Use %= operator" ,
90- "__ipow__" : "Use **= operator" ,
91- "__ilshift__" : "Use <<= operator" ,
92- "__irshift__" : "Use >>= operator" ,
93- "__iand__" : "Use &= operator" ,
94- "__ixor__" : "Use ^= operator" ,
95- "__ior__" : "Use |= operator" ,
96- "__neg__" : "Multiply by -1 instead" ,
97- "__pos__" : "Multiply by +1 instead" ,
98- "__abs__" : "Use abs built-in function" ,
99- "__invert__" : "Use ~ operator" ,
100- "__complex__" : "Use complex built-in function" ,
101- "__int__" : "Use int built-in function" ,
102- "__float__" : "Use float built-in function" ,
103- "__round__" : "Use round built-in function" ,
104- "__trunc__" : "Use math.trunc function" ,
105- "__floor__" : "Use math.floor function" ,
106- "__ceil__" : "Use math.ceil function" ,
107- "__enter__" : "Invoke context manager directly" ,
108- "__aenter__" : "Invoke context manager directly" ,
109- "__copy__" : "Use copy.copy function" ,
110- "__deepcopy__" : "Use copy.deepcopy function" ,
111- "__fspath__" : "Use os.fspath function instead" ,
112- },
113- (3 , 10 ): {
114- "__aiter__" : "Use aiter built-in function" ,
115- "__anext__" : "Use anext built-in function" ,
116- },
117- }
118-
119-
120- EXTRA_DUNDER_METHODS = [
121- "__new__" ,
122- "__subclasses__" ,
123- "__init_subclass__" ,
124- "__set_name__" ,
125- "__class_getitem__" ,
126- "__missing__" ,
127- "__exit__" ,
128- "__await__" ,
129- "__aexit__" ,
130- "__getnewargs_ex__" ,
131- "__getnewargs__" ,
132- "__getstate__" ,
133- "__setstate__" ,
134- "__reduce__" ,
135- "__reduce_ex__" ,
136- "__post_init__" , # part of `dataclasses` module
137- ]
138-
139- DUNDER_PROPERTIES = [
140- "__class__" ,
141- "__dict__" ,
142- "__doc__" ,
143- "__format__" ,
144- "__module__" ,
145- "__sizeof__" ,
146- "__subclasshook__" ,
147- "__weakref__" ,
148- ]
149-
150-
151- class DunderChecker (BaseChecker ):
152- """Checks related to dunder methods.
20+ class DunderCallChecker (BaseChecker ):
21+ """Check for unnecessary dunder method calls.
15322
15423 Docs: https://docs.python.org/3/reference/datamodel.html#basic-customization
155-
156- For `unnecessary-dunder-call` we exclude dunder names in list
157- `EXTRA_DUNDER_METHODS` since these either have no alternative
158- method of being called or have a genuine use case for being called manually.
24+ We exclude names in list pylint.constants.EXTRA_DUNDER_METHODS such as
25+ __index__ (see https://github.com/PyCQA/pylint/issues/6795)
26+ since these either have no alternative method of being called or
27+ have a genuine use case for being called manually.
15928
16029 Additionally, we exclude classes that are not instantiated since these
16130 might be used to access the dunder methods of a base class of an instance.
16231 We also exclude dunder method calls on super() since
16332 these can't be written in an alternative manner.
16433 """
16534
166- name = "dunder"
35+ name = "unnecessary- dunder-call "
16736 priority = - 1
16837 msgs = {
16938 "C2801" : (
@@ -172,12 +41,6 @@ class DunderChecker(BaseChecker):
17241 "Used when a dunder method is manually called instead "
17342 "of using the corresponding function/method/operator." ,
17443 ),
175- "C2802" : (
176- "Bad or misspelled dunder method name %s." ,
177- "bad-dunder-name" ,
178- "Used when a dunder method is misspelled or defined with a name "
179- "not within the predefined list of dunder names." ,
180- ),
18144 }
18245 options = ()
18346
@@ -201,30 +64,6 @@ def within_dunder_def(node: nodes.NodeNG) -> bool:
20164 parent = parent .parent
20265 return False
20366
204- @only_required_for_messages ("bad-dunder-name" )
205- def visit_functiondef (self , node : nodes .FunctionDef ) -> None :
206- """Check if known dunder method is misspelled or dunder name is not one
207- of the pre-defined names.
208- """
209- # ignore module-level functions
210- if not node .is_method ():
211- return
212-
213- # Detect something that could be a bad dunder method
214- if (
215- node .name .startswith ("_" )
216- and node .name .endswith ("_" )
217- and node .name not in self ._dunder_methods
218- and node .name not in EXTRA_DUNDER_METHODS + DUNDER_PROPERTIES
219- ):
220- self .add_message (
221- "bad-dunder-name" ,
222- node = node ,
223- args = (node .name ),
224- confidence = HIGH ,
225- )
226-
227- @only_required_for_messages ("unnecessary-dunder-call" )
22867 def visit_call (self , node : nodes .Call ) -> None :
22968 """Check if method being called is an unnecessary dunder method."""
23069 if (
@@ -251,4 +90,4 @@ def visit_call(self, node: nodes.Call) -> None:
25190
25291
25392def register (linter : PyLinter ) -> None :
254- linter .register_checker (DunderChecker (linter ))
93+ linter .register_checker (DunderCallChecker (linter ))
0 commit comments