Skip to content

Commit 51cee69

Browse files
authored
Fix unprotected accesses to parent.name and add tests (#5675)
1 parent 57a0602 commit 51cee69

File tree

8 files changed

+61
-6
lines changed

8 files changed

+61
-6
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ Release date: TBA
99
..
1010
Put new features here and also in 'doc/whatsnew/2.13.rst'
1111

12+
13+
* Fixed crash from ``arguments-differ`` and ``arguments-renamed`` when methods were
14+
defined outside the top level of a class.
15+
16+
Closes #5648
17+
1218
* Added several checkers to deal with unicode security issues
1319
(see `Trojan Sources <https://trojansource.codes/>`_ and
1420
`PEP 672 <https://www.python.org/dev/peps/pep-0672/>`_ for details) that also

doc/whatsnew/2.13.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ Extensions
7777
Other Changes
7878
=============
7979

80+
* Fixed crash from ``arguments-differ`` and ``arguments-renamed`` when methods were
81+
defined outside the top level of a class.
82+
83+
Closes #5648
84+
8085
* Fixed false positive ``consider-using-dict-comprehension`` when creating a dict
8186
using a list of tuples where key AND value vary depending on the same condition.
8287

pylint/checkers/classes/class_checker.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,7 +1325,7 @@ def _check_invalid_overridden_method(self, function_node, parent_function_node):
13251325
) and self._py38_plus:
13261326
self.add_message(
13271327
"overridden-final-method",
1328-
args=(function_node.name, parent_function_node.parent.name),
1328+
args=(function_node.name, parent_function_node.parent.frame().name),
13291329
node=function_node,
13301330
)
13311331

@@ -1997,24 +1997,24 @@ def _check_signature(self, method1, refmethod, class_type, cls):
19971997
error_type = "arguments-differ"
19981998
msg_args = (
19991999
msg
2000-
+ f"was {total_args_refmethod} in '{refmethod.parent.name}.{refmethod.name}' and "
2000+
+ f"was {total_args_refmethod} in '{refmethod.parent.frame().name}.{refmethod.name}' and "
20012001
f"is now {total_args_method1} in",
20022002
class_type,
2003-
f"{method1.parent.name}.{method1.name}",
2003+
f"{method1.parent.frame().name}.{method1.name}",
20042004
)
20052005
elif "renamed" in msg:
20062006
error_type = "arguments-renamed"
20072007
msg_args = (
20082008
msg,
20092009
class_type,
2010-
f"{method1.parent.name}.{method1.name}",
2010+
f"{method1.parent.frame().name}.{method1.name}",
20112011
)
20122012
else:
20132013
error_type = "arguments-differ"
20142014
msg_args = (
20152015
msg,
20162016
class_type,
2017-
f"{method1.parent.name}.{method1.name}",
2017+
f"{method1.parent.frame().name}.{method1.name}",
20182018
)
20192019
self.add_message(error_type, args=msg_args, node=method1)
20202020
elif (

pylint/checkers/typecheck.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1585,7 +1585,7 @@ def _check_invalid_sequence_index(self, subscript: nodes.Subscript):
15851585
not isinstance(itemmethod, nodes.FunctionDef)
15861586
or itemmethod.root().name != "builtins"
15871587
or not itemmethod.parent
1588-
or itemmethod.parent.name not in SEQUENCE_TYPES
1588+
or itemmethod.parent.frame().name not in SEQUENCE_TYPES
15891589
):
15901590
return None
15911591

tests/functional/a/arguments_renamed.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,29 @@ def test2(self, _arg, ignored_barg): # no error here
7272

7373
def test3(self, dummy_param, arg2): # no error here
7474
print(f"arguments: {arg2}")
75+
76+
# Check for crash on method definitions not at top level of class
77+
# https://github.com/PyCQA/pylint/issues/5648
78+
class FruitConditional:
79+
80+
define_eat = True
81+
82+
def brew(self, fruit_name: str):
83+
print(f"Brewing a fruit named {fruit_name}")
84+
85+
if define_eat:
86+
def eat_with_condiment(self, fruit_name:str, condiment: Condiment):
87+
print(f"Eating a fruit named {fruit_name} with {condiment}")
88+
89+
class FruitOverrideConditional(FruitConditional):
90+
91+
fruit = "orange"
92+
override_condiment = True
93+
94+
if fruit == "orange":
95+
def brew(self, orange_name: str): # [arguments-renamed]
96+
print(f"Brewing an orange named {orange_name}")
97+
98+
if override_condiment:
99+
def eat_with_condiment(self, fruit_name: str, condiment: Condiment, error: str): # [arguments-differ]
100+
print(f"Eating a fruit named {fruit_name} with {condiment}")

tests/functional/a/arguments_renamed.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ arguments-renamed:48:4:49:22:Child2.test:Parameter 'arg' has been renamed to 'va
77
arguments-differ:51:4:52:58:Child2.kwargs_test:Number of parameters was 4 in 'Parent.kwargs_test' and is now 3 in overridden 'Child2.kwargs_test' method:UNDEFINED
88
arguments-renamed:51:4:52:58:Child2.kwargs_test:Parameter 'var2' has been renamed to 'kw2' in overridden 'Child2.kwargs_test' method:UNDEFINED
99
arguments-renamed:67:4:68:56:ChildDefaults.test1:Parameter 'barg' has been renamed to 'param2' in overridden 'ChildDefaults.test1' method:UNDEFINED
10+
arguments-renamed:95:8:96:59:FruitOverrideConditional.brew:Parameter 'fruit_name' has been renamed to 'orange_name' in overridden 'FruitOverrideConditional.brew' method:UNDEFINED
11+
arguments-differ:99:12:100:76:FruitOverrideConditional.eat_with_condiment:Number of parameters was 3 in 'FruitConditional.eat_with_condiment' and is now 4 in overridden 'FruitOverrideConditional.eat_with_condiment' method:UNDEFINED

tests/functional/o/overridden_final_method_py38.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,18 @@ def my_method(self):
1414
class Subclass(Base):
1515
def my_method(self): # [overridden-final-method]
1616
pass
17+
18+
# Check for crash on method definitions not at top level of class
19+
# https://github.com/PyCQA/pylint/issues/5648
20+
class BaseConditional:
21+
22+
create_final_method = True
23+
if create_final_method:
24+
@final
25+
def my_method(self):
26+
pass
27+
28+
class Subclass2(BaseConditional):
29+
30+
def my_method(self): # [overridden-final-method]
31+
pass
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
overridden-final-method:15:4:16:12:Subclass.my_method:Method 'my_method' overrides a method decorated with typing.final which is defined in class 'Base':UNDEFINED
2+
overridden-final-method:30:4:31:12:Subclass2.my_method:Method 'my_method' overrides a method decorated with typing.final which is defined in class 'BaseConditional':UNDEFINED

0 commit comments

Comments
 (0)