55import linecache
66import sys
77import textwrap
8+ import types
89import warnings
910import codeop
1011import keyword
@@ -1623,12 +1624,29 @@ def _substitution_cost(ch_a, ch_b):
16231624 return _MOVE_COST
16241625
16251626
1627+ def _is_lazy_import (obj , attr_name ):
1628+ """Check if attr_name in obj's __dict__ is a lazy import.
1629+
1630+ Returns True if obj is a module and the attribute is a LazyImportType,
1631+ False otherwise. This avoids triggering module loading when computing
1632+ suggestions for AttributeError.
1633+ """
1634+ if not isinstance (obj , types .ModuleType ):
1635+ return False
1636+ obj_dict = getattr (obj , '__dict__' , None )
1637+ if obj_dict is None :
1638+ return False
1639+ attr_value = obj_dict .get (attr_name )
1640+ return isinstance (attr_value , types .LazyImportType )
1641+
1642+
16261643def _check_for_nested_attribute (obj , wrong_name , attrs ):
16271644 """Check if any attribute of obj has the wrong_name as a nested attribute.
16281645
16291646 Returns the first nested attribute suggestion found, or None.
16301647 Limited to checking 20 attributes.
16311648 Only considers non-descriptor attributes to avoid executing arbitrary code.
1649+ Skips lazy imports to avoid triggering module loading.
16321650 """
16331651 # Check for nested attributes (only one level deep)
16341652 attrs_to_check = [x for x in attrs if not x .startswith ('_' )][:20 ] # Limit number of attributes to check
@@ -1639,6 +1657,10 @@ def _check_for_nested_attribute(obj, wrong_name, attrs):
16391657 if attr_from_class is not None and hasattr (attr_from_class , '__get__' ):
16401658 continue # Skip descriptors to avoid executing arbitrary code
16411659
1660+ # Skip lazy imports to avoid triggering module loading
1661+ if _is_lazy_import (obj , attr_name ):
1662+ continue
1663+
16421664 # Safe to get the attribute since it's not a descriptor
16431665 attr_obj = getattr (obj , attr_name )
16441666
@@ -1662,6 +1684,8 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
16621684 except TypeError : # Attributes are unsortable, e.g. int and str
16631685 d = list (obj .__class__ .__dict__ .keys ()) + list (obj .__dict__ .keys ())
16641686 d = sorted ([x for x in d if isinstance (x , str )])
1687+ # Filter out lazy imports to avoid triggering module loading
1688+ d = [x for x in d if not _is_lazy_import (obj , x )]
16651689 hide_underscored = (wrong_name [:1 ] != '_' )
16661690 if hide_underscored and tb is not None :
16671691 while tb .tb_next is not None :
@@ -1681,6 +1705,8 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
16811705 except TypeError : # Attributes are unsortable, e.g. int and str
16821706 d = list (mod .__dict__ .keys ())
16831707 d = sorted ([x for x in d if isinstance (x , str )])
1708+ # Filter out lazy imports to avoid triggering module loading
1709+ d = [x for x in d if not _is_lazy_import (mod , x )]
16841710 if wrong_name [:1 ] != '_' :
16851711 d = [x for x in d if x [:1 ] != '_' ]
16861712 except Exception :
0 commit comments