@@ -4064,11 +4064,13 @@ def test_dont_swallow_subexceptions_of_falsey_exceptiongroup(self):
4064
4064
global_for_suggestions = None
4065
4065
4066
4066
4067
- class SuggestionFormattingTestBase :
4067
+ class SuggestionFormattingTestMixin :
4068
+ attr_function = getattr
4069
+
4068
4070
def get_suggestion (self , obj , attr_name = None ):
4069
4071
if attr_name is not None :
4070
4072
def callable ():
4071
- getattr (obj , attr_name )
4073
+ self . attr_function (obj , attr_name )
4072
4074
else :
4073
4075
callable = obj
4074
4076
@@ -4077,7 +4079,9 @@ def callable():
4077
4079
)
4078
4080
return result_lines [0 ]
4079
4081
4080
- def test_getattr_suggestions (self ):
4082
+
4083
+ class BaseSuggestionTests (SuggestionFormattingTestMixin ):
4084
+ def test_suggestions (self ):
4081
4085
class Substitution :
4082
4086
noise = more_noise = a = bc = None
4083
4087
blech = None
@@ -4120,18 +4124,19 @@ class CaseChangeOverSubstitution:
4120
4124
actual = self .get_suggestion (cls (), 'bluch' )
4121
4125
self .assertIn (suggestion , actual )
4122
4126
4123
- def test_getattr_suggestions_underscored (self ):
4127
+ def test_suggestions_underscored (self ):
4124
4128
class A :
4125
4129
bluch = None
4126
4130
4127
4131
self .assertIn ("'bluch'" , self .get_suggestion (A (), 'blach' ))
4128
4132
self .assertIn ("'bluch'" , self .get_suggestion (A (), '_luch' ))
4129
4133
self .assertIn ("'bluch'" , self .get_suggestion (A (), '_bluch' ))
4130
4134
4135
+ attr_function = self .attr_function
4131
4136
class B :
4132
4137
_bluch = None
4133
4138
def method (self , name ):
4134
- getattr (self , name )
4139
+ attr_function (self , name )
4135
4140
4136
4141
self .assertIn ("'_bluch'" , self .get_suggestion (B (), '_blach' ))
4137
4142
self .assertIn ("'_bluch'" , self .get_suggestion (B (), '_luch' ))
@@ -4141,28 +4146,29 @@ def method(self, name):
4141
4146
self .assertIn ("'_bluch'" , self .get_suggestion (partial (B ().method , '_luch' )))
4142
4147
self .assertIn ("'_bluch'" , self .get_suggestion (partial (B ().method , 'bluch' )))
4143
4148
4144
- def test_getattr_suggestions_do_not_trigger_for_long_attributes (self ):
4149
+
4150
+ def test_do_not_trigger_for_long_attributes (self ):
4145
4151
class A :
4146
4152
blech = None
4147
4153
4148
4154
actual = self .get_suggestion (A (), 'somethingverywrong' )
4149
4155
self .assertNotIn ("blech" , actual )
4150
4156
4151
- def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names (self ):
4157
+ def test_do_not_trigger_for_small_names (self ):
4152
4158
class MyClass :
4153
4159
vvv = mom = w = id = pytho = None
4154
4160
4155
4161
for name in ("b" , "v" , "m" , "py" ):
4156
4162
with self .subTest (name = name ):
4157
- actual = self .get_suggestion (MyClass , name )
4163
+ actual = self .get_suggestion (MyClass () , name )
4158
4164
self .assertNotIn ("Did you mean" , actual )
4159
4165
self .assertNotIn ("'vvv" , actual )
4160
4166
self .assertNotIn ("'mom'" , actual )
4161
4167
self .assertNotIn ("'id'" , actual )
4162
4168
self .assertNotIn ("'w'" , actual )
4163
4169
self .assertNotIn ("'pytho'" , actual )
4164
4170
4165
- def test_getattr_suggestions_do_not_trigger_for_big_dicts (self ):
4171
+ def test_do_not_trigger_for_big_dicts (self ):
4166
4172
class A :
4167
4173
blech = None
4168
4174
# A class with a very big __dict__ will not be considered
@@ -4173,7 +4179,16 @@ class A:
4173
4179
actual = self .get_suggestion (A (), 'bluch' )
4174
4180
self .assertNotIn ("blech" , actual )
4175
4181
4176
- def test_getattr_suggestions_no_args (self ):
4182
+ def test_suggestions_for_same_name (self ):
4183
+ class A :
4184
+ def __dir__ (self ):
4185
+ return ['blech' ]
4186
+ actual = self .get_suggestion (A (), 'blech' )
4187
+ self .assertNotIn ("Did you mean" , actual )
4188
+
4189
+
4190
+ class GetattrSuggestionTests (BaseSuggestionTests ):
4191
+ def test_suggestions_no_args (self ):
4177
4192
class A :
4178
4193
blech = None
4179
4194
def __getattr__ (self , attr ):
@@ -4190,7 +4205,7 @@ def __getattr__(self, attr):
4190
4205
actual = self .get_suggestion (A (), 'bluch' )
4191
4206
self .assertIn ("blech" , actual )
4192
4207
4193
- def test_getattr_suggestions_invalid_args (self ):
4208
+ def test_suggestions_invalid_args (self ):
4194
4209
class NonStringifyClass :
4195
4210
__str__ = None
4196
4211
__repr__ = None
@@ -4214,13 +4229,12 @@ def __getattr__(self, attr):
4214
4229
actual = self .get_suggestion (cls (), 'bluch' )
4215
4230
self .assertIn ("blech" , actual )
4216
4231
4217
- def test_getattr_suggestions_for_same_name (self ):
4218
- class A :
4219
- def __dir__ (self ):
4220
- return ['blech' ]
4221
- actual = self .get_suggestion (A (), 'blech' )
4222
- self .assertNotIn ("Did you mean" , actual )
4223
4232
4233
+ class DelattrSuggestionTests (BaseSuggestionTests ):
4234
+ attr_function = delattr
4235
+
4236
+
4237
+ class SuggestionFormattingTestBase (SuggestionFormattingTestMixin ):
4224
4238
def test_attribute_error_with_failing_dict (self ):
4225
4239
class T :
4226
4240
bluch = 1
@@ -4876,6 +4890,51 @@ class CPythonSuggestionFormattingTests(
4876
4890
"""
4877
4891
4878
4892
4893
+ class PurePythonGetattrSuggestionFormattingTests (
4894
+ PurePythonExceptionFormattingMixin ,
4895
+ GetattrSuggestionTests ,
4896
+ unittest .TestCase ,
4897
+ ):
4898
+ """
4899
+ Same set of tests (for attribute access) as above using the pure Python
4900
+ implementation of traceback printing in traceback.py.
4901
+ """
4902
+
4903
+
4904
+ class PurePythonDelattrSuggestionFormattingTests (
4905
+ PurePythonExceptionFormattingMixin ,
4906
+ DelattrSuggestionTests ,
4907
+ unittest .TestCase ,
4908
+ ):
4909
+ """
4910
+ Same set of tests (for attribute deletion) as above using the pure Python
4911
+ implementation of traceback printing in traceback.py.
4912
+ """
4913
+
4914
+
4915
+ @cpython_only
4916
+ class CPythonGetattrSuggestionFormattingTests (
4917
+ CAPIExceptionFormattingMixin ,
4918
+ GetattrSuggestionTests ,
4919
+ unittest .TestCase ,
4920
+ ):
4921
+ """
4922
+ Same set of tests (for attribute access) as above but with Python's
4923
+ internal traceback printing.
4924
+ """
4925
+
4926
+
4927
+ @cpython_only
4928
+ class CPythonDelattrSuggestionFormattingTests (
4929
+ CAPIExceptionFormattingMixin ,
4930
+ DelattrSuggestionTests ,
4931
+ unittest .TestCase ,
4932
+ ):
4933
+ """
4934
+ Same set of tests (for attribute deletion) as above but with Python's
4935
+ internal traceback printing.
4936
+ """
4937
+
4879
4938
class MiscTest (unittest .TestCase ):
4880
4939
4881
4940
def test_all (self ):
0 commit comments