bpo-38530: Require 50% similarity in NameError and AttributeError suggestions (GH-25584)
https://github.com/python/cpython/commit/284c52da092438522949d6f96d8c1f9ff37... commit: 284c52da092438522949d6f96d8c1f9ff37f9f00 branch: master author: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> committer: pablogsal <Pablogsal@gmail.com> date: 2021-04-27T01:22:27+01:00 summary: bpo-38530: Require 50% similarity in NameError and AttributeError suggestions (GH-25584) files: M Lib/test/test_exceptions.py M Python/suggestions.c diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index b3c00b04a37621..590935cb6cd624 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1507,6 +1507,61 @@ def f(): self.assertNotIn("somethingverywronghehe", err.getvalue()) + def test_name_error_bad_suggestions_do_not_trigger_for_small_names(self): + vvv = mom = w = id = pytho = None + + with self.subTest(name="b"): + try: + b + except NameError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + with self.subTest(name="v"): + try: + v + except NameError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + with self.subTest(name="m"): + try: + m + except NameError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + with self.subTest(name="py"): + try: + py + except NameError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + def test_name_error_suggestions_do_not_trigger_for_too_many_locals(self): def f(): # Mutating locals() is unreliable, so we need to do it by hand @@ -1661,6 +1716,63 @@ class A: self.assertNotIn("blech", err.getvalue()) + def test_getattr_error_bad_suggestions_do_not_trigger_for_small_names(self): + class MyClass: + vvv = mom = w = id = pytho = None + + with self.subTest(name="b"): + try: + MyClass.b + except AttributeError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + with self.subTest(name="v"): + try: + MyClass.v + except AttributeError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + with self.subTest(name="m"): + try: + MyClass.m + except AttributeError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + with self.subTest(name="py"): + try: + MyClass.py + except AttributeError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + self.assertNotIn("you mean", err.getvalue()) + self.assertNotIn("vvv", err.getvalue()) + self.assertNotIn("mom", err.getvalue()) + self.assertNotIn("'id'", err.getvalue()) + self.assertNotIn("'w'", err.getvalue()) + self.assertNotIn("'pytho'", err.getvalue()) + + def test_getattr_suggestions_do_not_trigger_for_big_dicts(self): class A: blech = None diff --git a/Python/suggestions.c b/Python/suggestions.c index d4e9dc22bbc7b9..2fd6714e847874 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -102,7 +102,10 @@ calculate_suggestions(PyObject *dir, if (current_distance == -1) { return NULL; } - if (current_distance == 0 || current_distance > MAX_DISTANCE) { + if (current_distance == 0 || + current_distance > MAX_DISTANCE || + current_distance * 2 > name_size) + { continue; } if (!suggestion || current_distance < suggestion_distance) {
participants (1)
-
pablogsal