Skip to content

Commit faa3dc7

Browse files
gh-143469: enable LOAD_ATTR_MODULE specialization even if __getattr__ is defined (#143470)
1 parent 05406b2 commit faa3dc7

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

Lib/test/test_opcache.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

19131951
if __name__ == "__main__":
19141952
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Enable :opcode:`!LOAD_ATTR_MODULE` specialization even if :func:`!__getattr__` is defined in module.

Python/specialize.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -366,14 +366,8 @@ specialize_module_load_attr_lock_held(PyDictObject *dict, _Py_CODEUNIT *instr, P
366366
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING);
367367
return -1;
368368
}
369-
Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__));
369+
Py_ssize_t index = _PyDict_LookupIndex(dict, name);
370370
assert(index != DKIX_ERROR);
371-
if (index != DKIX_EMPTY) {
372-
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND);
373-
return -1;
374-
}
375-
index = _PyDict_LookupIndex(dict, name);
376-
assert (index != DKIX_ERROR);
377371
if (index != (uint16_t)index) {
378372
SPECIALIZATION_FAIL(LOAD_ATTR,
379373
index == DKIX_EMPTY ?

0 commit comments

Comments
 (0)