@@ -95,6 +95,71 @@ def x(self, value): self._x = value
9595 return False
9696
9797
98+ def _extract_register_target (dec : nodes .NodeNG ) -> nodes .NodeNG | None :
99+ """
100+ If decorator `dec` looks like `@func.register(...)` or `@func.register`,
101+ return the `func` target node (Name or Attribute). Otherwise return None.
102+ """
103+ if isinstance (dec , nodes .Call ):
104+ func_part = dec .func
105+ if isinstance (func_part , nodes .Attribute ) and func_part .attrname == "register" :
106+ return func_part .expr
107+ return None
108+
109+ if isinstance (dec , nodes .Attribute ) and dec .attrname == "register" :
110+ return dec .expr
111+
112+ return None
113+
114+
115+ def _inferred_has_singledispatchmethod (target : nodes .NodeNG ) -> bool :
116+ """
117+ Infer `target` and return True if the inferred object has a
118+ @singledispatchmethod decorator.
119+ """
120+ inferred = utils .safe_infer (target )
121+ if not inferred :
122+ return False
123+
124+ if isinstance (inferred , (nodes .FunctionDef , nodes .AsyncFunctionDef )):
125+ decorators = inferred .decorators
126+ if isinstance (decorators , nodes .Decorators ):
127+ for dec in decorators .nodes :
128+ inferred_dec = utils .safe_infer (dec )
129+ if (
130+ inferred_dec
131+ and inferred_dec .qname () == "functools.singledispatchmethod"
132+ ):
133+ return True
134+
135+ return False
136+
137+
138+ def _is_singledispatchmethod_registration (node : nodes .FunctionDef ) -> bool :
139+ """
140+ Return True if `node` is a function decorated like:
141+
142+ @func.register(...)
143+ def _(…): ...
144+
145+ where `func` is a singledispatchmethod (i.e. its base was decorated
146+ with @singledispatchmethod).
147+ """
148+ decorators = node .decorators
149+ if not decorators :
150+ return False
151+
152+ for dec in decorators .nodes :
153+ target = _extract_register_target (dec )
154+ if target is None :
155+ continue
156+
157+ if _inferred_has_singledispatchmethod (target ):
158+ return True
159+
160+ return False
161+
162+
98163class BasicErrorChecker (_BasicChecker ):
99164 msgs = {
100165 "E0100" : (
@@ -536,6 +601,9 @@ def _check_redefinition(
536601 ):
537602 return
538603
604+ if _is_singledispatchmethod_registration (node ):
605+ return
606+
539607 # Skip typing.overload() functions.
540608 if utils .is_overload_stub (node ):
541609 return
@@ -572,9 +640,6 @@ def _check_redefinition(
572640 ):
573641 return
574642
575- dummy_variables_rgx = self .linter .config .dummy_variables_rgx
576- if dummy_variables_rgx and dummy_variables_rgx .match (node .name ):
577- return
578643 self .add_message (
579644 "function-redefined" ,
580645 node = node ,
0 commit comments