https://github.com/python/cpython/commit/faa3dc7c64b7bda4e74c7630be4c873e0b58a569
commit: faa3dc7c64b7bda4e74c7630be4c873e0b58a569
branch: main
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-01-06T22:09:18+05:30
summary:
gh-143469: enable `LOAD_ATTR_MODULE` specialization even if `__getattr__` is
defined (#143470)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-01-06-12-30-03.gh-issue-143469.vHVhEY.rst
M Lib/test/test_opcache.py
M Python/specialize.c
diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index be9b52b8bc45e2..0344f08faecce7 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -1909,6 +1909,44 @@ class MyList(list): pass
self.assert_no_opcode(my_list_append, "CALL_LIST_APPEND")
self.assert_no_opcode(my_list_append, "CALL")
+ @cpython_only
+ @requires_specialization_ft
+ def test_load_attr_module_with_getattr(self):
+ module = types.ModuleType("test_module_with_getattr")
+ module.__dict__["some_attr"] = "foo"
+
+ def module_getattr(name):
+ if name == "missing_attr":
+ return 42
+ raise AttributeError(f"module has no attribute {name}")
+
+ module.__dict__["__getattr__"] = module_getattr
+
+ import sys
+ sys.modules.pop("test_module_with_getattr", None)
+ sys.modules["test_module_with_getattr"] = module
+ try:
+ def load_module_attr_present():
+ import test_module_with_getattr
+ return test_module_with_getattr.some_attr
+
+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+ self.assertEqual(load_module_attr_present(), "foo")
+
+ self.assert_specialized(load_module_attr_present,
"LOAD_ATTR_MODULE")
+ self.assert_no_opcode(load_module_attr_present, "LOAD_ATTR")
+
+ def load_module_attr_missing():
+ import test_module_with_getattr
+ return test_module_with_getattr.missing_attr
+
+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+ self.assertEqual(load_module_attr_missing(), 42)
+
+ self.assert_no_opcode(load_module_attr_missing, "LOAD_ATTR_MODULE")
+ finally:
+ sys.modules.pop("test_module_with_getattr", None)
+
if __name__ == "__main__":
unittest.main()
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-06-12-30-03.gh-issue-143469.vHVhEY.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-06-12-30-03.gh-issue-143469.vHVhEY.rst
new file mode 100644
index 00000000000000..9bac54497f8998
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-06-12-30-03.gh-issue-143469.vHVhEY.rst
@@ -0,0 +1 @@
+Enable :opcode:`!LOAD_ATTR_MODULE` specialization even if :func:`!__getattr__`
is defined in module.
diff --git a/Python/specialize.c b/Python/specialize.c
index 62f0373a4c274d..b7fa5f8ad4c04e 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -366,14 +366,8 @@ specialize_module_load_attr_lock_held(PyDictObject *dict,
_Py_CODEUNIT *instr, P
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING);
return -1;
}
- Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__));
+ Py_ssize_t index = _PyDict_LookupIndex(dict, name);
assert(index != DKIX_ERROR);
- if (index != DKIX_EMPTY) {
- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND);
- return -1;
- }
- index = _PyDict_LookupIndex(dict, name);
- assert (index != DKIX_ERROR);
if (index != (uint16_t)index) {
SPECIALIZATION_FAIL(LOAD_ATTR,
index == DKIX_EMPTY ?
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]