global_for_suggestions = None
-class SuggestionFormattingTestBase:
+class SuggestionFormattingTestMixin:
+ attr_function = getattr
+
def get_suggestion(self, obj, attr_name=None):
if attr_name is not None:
def callable():
- getattr(obj, attr_name)
+ self.attr_function(obj, attr_name)
else:
callable = obj
)
return result_lines[0]
- def test_getattr_suggestions(self):
+
+class BaseSuggestionTests(SuggestionFormattingTestMixin):
+ def test_suggestions(self):
class Substitution:
noise = more_noise = a = bc = None
blech = None
actual = self.get_suggestion(cls(), 'bluch')
self.assertIn(suggestion, actual)
- def test_getattr_suggestions_underscored(self):
+ def test_suggestions_underscored(self):
class A:
bluch = None
self.assertIn("'bluch'", self.get_suggestion(A(), '_luch'))
self.assertIn("'bluch'", self.get_suggestion(A(), '_bluch'))
+ attr_function = self.attr_function
class B:
_bluch = None
def method(self, name):
- getattr(self, name)
+ attr_function(self, name)
self.assertIn("'_bluch'", self.get_suggestion(B(), '_blach'))
self.assertIn("'_bluch'", self.get_suggestion(B(), '_luch'))
self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, '_luch')))
self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, 'bluch')))
- def test_getattr_suggestions_do_not_trigger_for_long_attributes(self):
+
+ def test_do_not_trigger_for_long_attributes(self):
class A:
blech = None
actual = self.get_suggestion(A(), 'somethingverywrong')
self.assertNotIn("blech", actual)
- def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names(self):
+ def test_do_not_trigger_for_small_names(self):
class MyClass:
vvv = mom = w = id = pytho = None
for name in ("b", "v", "m", "py"):
with self.subTest(name=name):
- actual = self.get_suggestion(MyClass, name)
+ actual = self.get_suggestion(MyClass(), name)
self.assertNotIn("Did you mean", actual)
self.assertNotIn("'vvv", actual)
self.assertNotIn("'mom'", actual)
self.assertNotIn("'w'", actual)
self.assertNotIn("'pytho'", actual)
- def test_getattr_suggestions_do_not_trigger_for_big_dicts(self):
+ def test_do_not_trigger_for_big_dicts(self):
class A:
blech = None
# A class with a very big __dict__ will not be considered
actual = self.get_suggestion(A(), 'bluch')
self.assertNotIn("blech", actual)
- def test_getattr_suggestions_no_args(self):
+ def test_suggestions_for_same_name(self):
+ class A:
+ def __dir__(self):
+ return ['blech']
+ actual = self.get_suggestion(A(), 'blech')
+ self.assertNotIn("Did you mean", actual)
+
+
+class GetattrSuggestionTests(BaseSuggestionTests):
+ def test_suggestions_no_args(self):
class A:
blech = None
def __getattr__(self, attr):
actual = self.get_suggestion(A(), 'bluch')
self.assertIn("blech", actual)
- def test_getattr_suggestions_invalid_args(self):
+ def test_suggestions_invalid_args(self):
class NonStringifyClass:
__str__ = None
__repr__ = None
actual = self.get_suggestion(cls(), 'bluch')
self.assertIn("blech", actual)
- def test_getattr_suggestions_for_same_name(self):
- class A:
- def __dir__(self):
- return ['blech']
- actual = self.get_suggestion(A(), 'blech')
- self.assertNotIn("Did you mean", actual)
+class DelattrSuggestionTests(BaseSuggestionTests):
+ attr_function = delattr
+
+
+class SuggestionFormattingTestBase(SuggestionFormattingTestMixin):
def test_attribute_error_with_failing_dict(self):
class T:
bluch = 1
"""
+class PurePythonGetattrSuggestionFormattingTests(
+ PurePythonExceptionFormattingMixin,
+ GetattrSuggestionTests,
+ unittest.TestCase,
+):
+ """
+ Same set of tests (for attribute access) as above using the pure Python
+ implementation of traceback printing in traceback.py.
+ """
+
+
+class PurePythonDelattrSuggestionFormattingTests(
+ PurePythonExceptionFormattingMixin,
+ DelattrSuggestionTests,
+ unittest.TestCase,
+):
+ """
+ Same set of tests (for attribute deletion) as above using the pure Python
+ implementation of traceback printing in traceback.py.
+ """
+
+
+@cpython_only
+class CPythonGetattrSuggestionFormattingTests(
+ CAPIExceptionFormattingMixin,
+ GetattrSuggestionTests,
+ unittest.TestCase,
+):
+ """
+ Same set of tests (for attribute access) as above but with Python's
+ internal traceback printing.
+ """
+
+
+@cpython_only
+class CPythonDelattrSuggestionFormattingTests(
+ CAPIExceptionFormattingMixin,
+ DelattrSuggestionTests,
+ unittest.TestCase,
+):
+ """
+ Same set of tests (for attribute deletion) as above but with Python's
+ internal traceback printing.
+ """
+
class MiscTest(unittest.TestCase):
def test_all(self):