@@ -1414,6 +1414,165 @@ class TestException(MemoryError):
14141414 gc_collect ()
14151415
14161416
1417+ class AttributeErrorTests (unittest .TestCase ):
1418+ def test_attributes (self ):
1419+ # Setting 'attr' should not be a problem.
1420+ exc = AttributeError ('Ouch!' )
1421+ self .assertIsNone (exc .name )
1422+ self .assertIsNone (exc .obj )
1423+
1424+ sentinel = object ()
1425+ exc = AttributeError ('Ouch' , name = 'carry' , obj = sentinel )
1426+ self .assertEqual (exc .name , 'carry' )
1427+ self .assertIs (exc .obj , sentinel )
1428+
1429+ def test_getattr_has_name_and_obj (self ):
1430+ class A :
1431+ blech = None
1432+
1433+ obj = A ()
1434+ try :
1435+ obj .bluch
1436+ except AttributeError as exc :
1437+ self .assertEqual ("bluch" , exc .name )
1438+ self .assertEqual (obj , exc .obj )
1439+
1440+ def test_getattr_has_name_and_obj_for_method (self ):
1441+ class A :
1442+ def blech (self ):
1443+ return
1444+
1445+ obj = A ()
1446+ try :
1447+ obj .bluch ()
1448+ except AttributeError as exc :
1449+ self .assertEqual ("bluch" , exc .name )
1450+ self .assertEqual (obj , exc .obj )
1451+
1452+ def test_getattr_suggestions (self ):
1453+ class Substitution :
1454+ noise = more_noise = a = bc = None
1455+ blech = None
1456+
1457+ class Elimination :
1458+ noise = more_noise = a = bc = None
1459+ blch = None
1460+
1461+ class Addition :
1462+ noise = more_noise = a = bc = None
1463+ bluchin = None
1464+
1465+ class SubstitutionOverElimination :
1466+ blach = None
1467+ bluc = None
1468+
1469+ class SubstitutionOverAddition :
1470+ blach = None
1471+ bluchi = None
1472+
1473+ class EliminationOverAddition :
1474+ blucha = None
1475+ bluc = None
1476+
1477+ for cls , suggestion in [(Substitution , "blech?" ),
1478+ (Elimination , "blch?" ),
1479+ (Addition , "bluchin?" ),
1480+ (EliminationOverAddition , "bluc?" ),
1481+ (SubstitutionOverElimination , "blach?" ),
1482+ (SubstitutionOverAddition , "blach?" )]:
1483+ try :
1484+ cls ().bluch
1485+ except AttributeError as exc :
1486+ with support .captured_stderr () as err :
1487+ sys .__excepthook__ (* sys .exc_info ())
1488+
1489+ self .assertIn (suggestion , err .getvalue ())
1490+
1491+ def test_getattr_suggestions_do_not_trigger_for_long_attributes (self ):
1492+ class A :
1493+ blech = None
1494+
1495+ try :
1496+ A ().somethingverywrong
1497+ except AttributeError as exc :
1498+ with support .captured_stderr () as err :
1499+ sys .__excepthook__ (* sys .exc_info ())
1500+
1501+ self .assertNotIn ("blech" , err .getvalue ())
1502+
1503+ def test_getattr_suggestions_do_not_trigger_for_big_dicts (self ):
1504+ class A :
1505+ blech = None
1506+ # A class with a very big __dict__ will not be consider
1507+ # for suggestions.
1508+ for index in range (101 ):
1509+ setattr (A , f"index_{ index } " , None )
1510+
1511+ try :
1512+ A ().bluch
1513+ except AttributeError as exc :
1514+ with support .captured_stderr () as err :
1515+ sys .__excepthook__ (* sys .exc_info ())
1516+
1517+ self .assertNotIn ("blech" , err .getvalue ())
1518+
1519+ def test_getattr_suggestions_no_args (self ):
1520+ class A :
1521+ blech = None
1522+ def __getattr__ (self , attr ):
1523+ raise AttributeError ()
1524+
1525+ try :
1526+ A ().bluch
1527+ except AttributeError as exc :
1528+ with support .captured_stderr () as err :
1529+ sys .__excepthook__ (* sys .exc_info ())
1530+
1531+ self .assertIn ("blech" , err .getvalue ())
1532+
1533+ class A :
1534+ blech = None
1535+ def __getattr__ (self , attr ):
1536+ raise AttributeError
1537+
1538+ try :
1539+ A ().bluch
1540+ except AttributeError as exc :
1541+ with support .captured_stderr () as err :
1542+ sys .__excepthook__ (* sys .exc_info ())
1543+
1544+ self .assertIn ("blech" , err .getvalue ())
1545+
1546+ def test_getattr_suggestions_invalid_args (self ):
1547+ class NonStringifyClass :
1548+ __str__ = None
1549+ __repr__ = None
1550+
1551+ class A :
1552+ blech = None
1553+ def __getattr__ (self , attr ):
1554+ raise AttributeError (NonStringifyClass ())
1555+
1556+ class B :
1557+ blech = None
1558+ def __getattr__ (self , attr ):
1559+ raise AttributeError ("Error" , 23 )
1560+
1561+ class C :
1562+ blech = None
1563+ def __getattr__ (self , attr ):
1564+ raise AttributeError (23 )
1565+
1566+ for cls in [A , B , C ]:
1567+ try :
1568+ cls ().bluch
1569+ except AttributeError as exc :
1570+ with support .captured_stderr () as err :
1571+ sys .__excepthook__ (* sys .exc_info ())
1572+
1573+ self .assertIn ("blech" , err .getvalue ())
1574+
1575+
14171576class ImportErrorTests (unittest .TestCase ):
14181577
14191578 def test_attributes (self ):
0 commit comments