self.assertIn("'._bluch'", self.get_suggestion(partial(B().method, '_luch')))
self.assertIn("'._bluch'", self.get_suggestion(partial(B().method, 'bluch')))
+ def test_suggestions_with_custom___dir__(self):
+ class M(type):
+ def __dir__(cls):
+ return [None, "fox"]
+
+ class C0:
+ def __dir__(self):
+ return [..., "bluch"]
+
+ class C1(C0, metaclass=M):
+ pass
+
+ self.assertNotIn("'.bluch'", self.get_suggestion(C0, "blach"))
+ self.assertIn("'.bluch'", self.get_suggestion(C0(), "blach"))
+
+ self.assertIn("'.fox'", self.get_suggestion(C1, "foo"))
+ self.assertNotIn("'.fox'", self.get_suggestion(C1(), "foo"))
+
+ self.assertNotIn("'.bluch'", self.get_suggestion(C1, "blach"))
+ self.assertIn("'.bluch'", self.get_suggestion(C1(), "blach"))
+
def test_do_not_trigger_for_long_attributes(self):
class A:
return None
+def _get_safe___dir__(obj):
+ # Use obj.__dir__() to avoid a TypeError when calling dir(obj).
+ # See gh-131001 and gh-139933.
+ # Also filters out lazy imports to avoid triggering module loading.
+ try:
+ d = obj.__dir__()
+ except TypeError: # when obj is a class
+ d = type(obj).__dir__(obj)
+ return sorted(
+ x for x in d if isinstance(x, str) and not _is_lazy_import(obj, x)
+ )
+
+
def _compute_suggestion_error(exc_value, tb, wrong_name):
if wrong_name is None or not isinstance(wrong_name, str):
return None
if isinstance(exc_value, AttributeError):
obj = exc_value.obj
try:
- try:
- d = dir(obj)
- except TypeError: # Attributes are unsortable, e.g. int and str
- d = list(obj.__class__.__dict__.keys()) + list(obj.__dict__.keys())
- d = sorted([x for x in d if isinstance(x, str)])
- # Filter out lazy imports to avoid triggering module loading
- d = [x for x in d if not _is_lazy_import(obj, x)]
+ d = _get_safe___dir__(obj)
hide_underscored = (wrong_name[:1] != '_')
if hide_underscored and tb is not None:
while tb.tb_next is not None:
elif isinstance(exc_value, ImportError):
try:
mod = __import__(exc_value.name)
- try:
- d = dir(mod)
- except TypeError: # Attributes are unsortable, e.g. int and str
- d = list(mod.__dict__.keys())
- d = sorted([x for x in d if isinstance(x, str)])
- # Filter out lazy imports to avoid triggering module loading
- d = [x for x in d if not _is_lazy_import(mod, x)]
+ d = _get_safe___dir__(mod)
if wrong_name[:1] != '_':
d = [x for x in d if x[:1] != '_']
except Exception: