@@ -1909,6 +1909,44 @@ class MyList(list): pass
19091909 self .assert_no_opcode (my_list_append , "CALL_LIST_APPEND" )
19101910 self .assert_no_opcode (my_list_append , "CALL" )
19111911
1912+ @cpython_only
1913+ @requires_specialization_ft
1914+ def test_load_attr_module_with_getattr (self ):
1915+ module = types .ModuleType ("test_module_with_getattr" )
1916+ module .__dict__ ["some_attr" ] = "foo"
1917+
1918+ def module_getattr (name ):
1919+ if name == "missing_attr" :
1920+ return 42
1921+ raise AttributeError (f"module has no attribute { name } " )
1922+
1923+ module .__dict__ ["__getattr__" ] = module_getattr
1924+
1925+ import sys
1926+ sys .modules .pop ("test_module_with_getattr" , None )
1927+ sys .modules ["test_module_with_getattr" ] = module
1928+ try :
1929+ def load_module_attr_present ():
1930+ import test_module_with_getattr
1931+ return test_module_with_getattr .some_attr
1932+
1933+ for _ in range (_testinternalcapi .SPECIALIZATION_THRESHOLD ):
1934+ self .assertEqual (load_module_attr_present (), "foo" )
1935+
1936+ self .assert_specialized (load_module_attr_present , "LOAD_ATTR_MODULE" )
1937+ self .assert_no_opcode (load_module_attr_present , "LOAD_ATTR" )
1938+
1939+ def load_module_attr_missing ():
1940+ import test_module_with_getattr
1941+ return test_module_with_getattr .missing_attr
1942+
1943+ for _ in range (_testinternalcapi .SPECIALIZATION_THRESHOLD ):
1944+ self .assertEqual (load_module_attr_missing (), 42 )
1945+
1946+ self .assert_no_opcode (load_module_attr_missing , "LOAD_ATTR_MODULE" )
1947+ finally :
1948+ sys .modules .pop ("test_module_with_getattr" , None )
1949+
19121950
19131951if __name__ == "__main__" :
19141952 unittest .main ()
0 commit comments