Skip to content
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 77 additions & 18 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -3976,7 +3976,7 @@ def callable():
)
return result_lines[0]

def test_getattr_suggestions(self):
def run_suggestion_tests(self, operation):
class Substitution:
noise = more_noise = a = bc = None
blech = None
Expand Down Expand Up @@ -4016,62 +4016,121 @@ class CaseChangeOverSubstitution:
(EliminationOverAddition, "'bluc'?"),
(CaseChangeOverSubstitution, "'BLuch'?"),
]:
actual = self.get_suggestion(cls(), 'bluch')
obj = cls()

if operation == "getattr":
actual = self.get_suggestion(obj, 'bluch')
elif operation == "delattr":
actual = self.get_suggestion(lambda: delattr(obj, 'bluch'))

self.assertIn(suggestion, actual)

def test_getattr_suggestions_underscored(self):
def test_getattr_suggestions(self):
self.run_suggestion_tests("getattr")

def test_delattr_suggestions(self):
self.run_suggestion_tests("delattr")

def run_underscored_tests(self, operation):
class A:
bluch = None

self.assertIn("'bluch'", self.get_suggestion(A(), 'blach'))
self.assertIn("'bluch'", self.get_suggestion(A(), '_luch'))
self.assertIn("'bluch'", self.get_suggestion(A(), '_bluch'))
obj = A()
if operation == "getattr":
self.assertIn("'bluch'", self.get_suggestion(obj, 'blach'))
self.assertIn("'bluch'", self.get_suggestion(obj, '_luch'))
self.assertIn("'bluch'", self.get_suggestion(obj, '_bluch'))
elif operation == "delattr":
self.assertIn("'bluch'", self.get_suggestion(lambda: delattr(obj, 'blach')))
self.assertIn("'bluch'", self.get_suggestion(lambda: delattr(obj, '_luch')))
self.assertIn("'bluch'", self.get_suggestion(lambda: delattr(obj, '_bluch')))

class B:
_bluch = None
def method(self, name):
getattr(self, name)

self.assertIn("'_bluch'", self.get_suggestion(B(), '_blach'))
self.assertIn("'_bluch'", self.get_suggestion(B(), '_luch'))
self.assertNotIn("'_bluch'", self.get_suggestion(B(), 'bluch'))
obj = B()
if operation == "getattr":
self.assertIn("'_bluch'", self.get_suggestion(obj, '_blach'))
self.assertIn("'_bluch'", self.get_suggestion(obj, '_luch'))
self.assertNotIn("'_bluch'", self.get_suggestion(obj, 'bluch'))
self.assertIn("'_bluch'", self.get_suggestion(partial(obj.method, '_blach')))
self.assertIn("'_bluch'", self.get_suggestion(partial(obj.method, '_luch')))
self.assertIn("'_bluch'", self.get_suggestion(partial(obj.method, 'bluch')))
elif operation == "delattr":
self.assertIn("'_bluch'", self.get_suggestion(lambda: delattr(obj, '_blach')))
self.assertIn("'_bluch'", self.get_suggestion(lambda: delattr(obj, '_luch')))
self.assertNotIn("'_bluch'", self.get_suggestion(lambda: delattr(obj, 'bluch')))

self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, '_blach')))
self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, '_luch')))
self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, 'bluch')))
def test_getattr_suggestions_underscored(self):
self.run_underscored_tests("getattr")

def test_getattr_suggestions_do_not_trigger_for_long_attributes(self):
def test_delattr_suggestions_underscored(self):
self.run_underscored_tests("delattr")

def run_do_not_trigger_for_long_attributes_tests(self, operation):
class A:
blech = None

actual = self.get_suggestion(A(), 'somethingverywrong')
obj = A()
if operation == "getattr":
actual = self.get_suggestion(obj, 'somethingverywrong')
elif operation == "delattr":
actual = self.get_suggestion(lambda: delattr(obj, 'somethingverywrong'))
self.assertNotIn("blech", actual)

def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names(self):
def test_getattr_suggestions_do_not_trigger_for_long_attributes(self):
self.run_do_not_trigger_for_long_attributes_tests("getattr")

def test_delattr_suggestions_do_not_trigger_for_long_attributes(self):
self.run_do_not_trigger_for_long_attributes_tests("delattr")

def run_do_not_trigger_for_small_names_tests(self, operation):
class MyClass:
vvv = mom = w = id = pytho = None

obj = MyClass()
for name in ("b", "v", "m", "py"):
with self.subTest(name=name):
actual = self.get_suggestion(MyClass, name)
if operation == "getattr":
actual = self.get_suggestion(MyClass, name)
elif operation == "delattr":
actual = self.get_suggestion(lambda: delattr(obj, name))
self.assertNotIn("Did you mean", actual)
self.assertNotIn("'vvv", actual)
self.assertNotIn("'mom'", actual)
self.assertNotIn("'id'", actual)
self.assertNotIn("'w'", actual)
self.assertNotIn("'pytho'", actual)

def test_getattr_suggestions_do_not_trigger_for_big_dicts(self):
def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names(self):
self.run_do_not_trigger_for_small_names_tests("getattr")

def test_delattr_error_bad_suggestions_do_not_trigger_for_small_names(self):
self.run_do_not_trigger_for_small_names_tests("delattr")

def run_do_not_trigger_for_big_dicts_tests(self, operation):
class A:
blech = None
# A class with a very big __dict__ will not be considered
# for suggestions.
for index in range(2000):
setattr(A, f"index_{index}", None)

actual = self.get_suggestion(A(), 'bluch')
obj = A()
if operation == "getattr":
actual = self.get_suggestion(obj, 'bluch')
elif operation == "delattr":
actual = self.get_suggestion(lambda: delattr(obj, 'bluch'))
self.assertNotIn("blech", actual)

def test_getattr_suggestions_do_not_trigger_for_big_dicts(self):
self.run_do_not_trigger_for_big_dicts_tests("getattr")

def test_delattr_suggestions_do_not_trigger_for_big_dicts(self):
self.run_do_not_trigger_for_big_dicts_tests("delattr")

def test_getattr_suggestions_no_args(self):
class A:
blech = None
Expand Down
Loading