77#include "pycore_fileutils.h" // _Py_wgetcwd
88#include "pycore_import.h" // _PyImport_GetNextModuleIndex()
99#include "pycore_interp.h" // PyInterpreterState.importlib
10- #include "pycore_lazyimportobject.h" // _PyLazyImportObject_Check ()
10+ #include "pycore_lazyimportobject.h" // PyLazyImport_CheckExact ()
1111#include "pycore_long.h" // _PyLong_GetOne()
1212#include "pycore_modsupport.h" // _PyModule_CreateInitialized()
1313#include "pycore_moduleobject.h" // _PyModule_GetDefOrNull()
@@ -1299,32 +1299,25 @@ _PyModule_IsPossiblyShadowing(PyObject *origin)
12991299 return result ;
13001300}
13011301
1302- static PyObject *
1303- try_load_lazy_submodule ( PyModuleObject * m , PyObject * name )
1302+ static int
1303+ module_get_resolved_dict_item ( PyObject * dict , PyObject * name , PyObject * * result )
13041304{
1305- PyObject * mod_name ;
1306- int rc = PyDict_GetItemRef (m -> md_dict , & _Py_ID (__name__ ), & mod_name );
1307- if (rc <= 0 ) {
1308- return NULL ;
1309- }
1310- if (!PyUnicode_Check (mod_name )) {
1311- Py_DECREF (mod_name );
1312- return NULL ;
1305+ int rc = PyDict_GetItemRef (dict , name , result );
1306+ if (rc <= 0 || !PyLazyImport_CheckExact (* result )) {
1307+ return rc ;
13131308 }
1314- PyObject * result = NULL ;
1315- _PyLazySubmoduleImportResult status =
1316- _PyImport_TryLoadLazySubmodule (mod_name , name , & result );
1317- Py_DECREF (mod_name );
1318- if (status != _Py_LAZY_SUBMODULE_LOADED ) {
1319- assert (status == _Py_LAZY_SUBMODULE_ERROR ||
1320- status == _Py_LAZY_SUBMODULE_NOT_FOUND );
1321- return NULL ;
1309+ PyThreadState * tstate = PyThreadState_GET ();
1310+ if (_PyLazyImport_IsResolving (tstate , * result )) {
1311+ Py_CLEAR (* result );
1312+ return 0 ;
13221313 }
1323- if (PyDict_SetItem (m -> md_dict , name , result ) < 0 ) {
1324- Py_DECREF (result );
1325- return NULL ;
1314+ PyObject * value = _PyImport_LoadLazyImportTstate (tstate , * result );
1315+ Py_SETREF (* result , value );
1316+ if (value == NULL || PyDict_SetItem (dict , name , value ) < 0 ) {
1317+ Py_CLEAR (* result );
1318+ return -1 ;
13261319 }
1327- return result ;
1320+ return 1 ;
13281321}
13291322
13301323PyObject *
@@ -1333,11 +1326,52 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
13331326 // When suppress=1, this function suppresses AttributeError.
13341327 PyObject * attr , * mod_name , * getattr ;
13351328 attr = _PyObject_GenericGetAttrWithDict ((PyObject * )m , name , NULL , suppress );
1329+ if (attr == NULL ) {
1330+ if (suppress == 1 ) {
1331+ if (PyErr_Occurred ()) {
1332+ // pass up non-AttributeError exception
1333+ return NULL ;
1334+ }
1335+ }
1336+ else {
1337+ if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
1338+ // pass up non-AttributeError exception
1339+ return NULL ;
1340+ }
1341+ PyErr_Clear ();
1342+ }
1343+ assert (m -> md_dict != NULL );
1344+ int recheck_dict ;
1345+ attr = _PyImport_TryLoadLazySubmodule ((PyObject * )m , name , & recheck_dict );
1346+ if (attr != NULL || PyErr_Occurred ()) {
1347+ return attr ;
1348+ }
1349+ // A concurrent load may have bound the child and removed its pending
1350+ // registration after our initial dictionary lookup.
1351+ if (recheck_dict ) {
1352+ if (Py_TYPE (m ) != & PyModule_Type ) {
1353+ PyObject * descr = _PyType_LookupRef (Py_TYPE (m ), name );
1354+ if (descr != NULL ) {
1355+ // Preserve the fallback after a descriptor raised.
1356+ recheck_dict = Py_TYPE (descr )-> tp_descr_get == NULL ;
1357+ Py_DECREF (descr );
1358+ }
1359+ }
1360+ if (recheck_dict &&
1361+ PyDict_GetItemRef (m -> md_dict , name , & attr ) < 0 ) {
1362+ return NULL ;
1363+ }
1364+ }
1365+ }
13361366 if (attr ) {
13371367 if (PyLazyImport_CheckExact (attr )) {
13381368 // gh-144957: Module __getattr__ should get a chance to provide
13391369 // the attribute before resolving a lazy import placeholder.
1340- if (PyDict_GetItemRef (m -> md_dict , & _Py_ID (__getattr__ ), & getattr ) < 0 ) {
1370+ // Resolving __getattr__ itself must not invoke the hook.
1371+ getattr = NULL ;
1372+ if (!_PyUnicode_EqualToASCIIString (name , "__getattr__" ) &&
1373+ module_get_resolved_dict_item (
1374+ m -> md_dict , & _Py_ID (__getattr__ ), & getattr ) < 0 ) {
13411375 Py_DECREF (attr );
13421376 return NULL ;
13431377 }
@@ -1354,17 +1388,14 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
13541388 }
13551389 PyErr_Clear ();
13561390 }
1357- PyObject * new_value = _PyImport_LoadLazyImportTstate (
1358- PyThreadState_GET (), attr );
1391+ PyThreadState * tstate = PyThreadState_GET ();
1392+ if (suppress && _PyLazyImport_IsResolving (tstate , attr )) {
1393+ // Only direct reentry means this attribute is unavailable.
1394+ Py_DECREF (attr );
1395+ return NULL ;
1396+ }
1397+ PyObject * new_value = _PyImport_LoadLazyImportTstate (tstate , attr );
13591398 if (new_value == NULL ) {
1360- if (suppress &&
1361- PyErr_ExceptionMatches (PyExc_ImportCycleError )) {
1362- // ImportCycleError is raised when a lazy object tries
1363- // to import itself. In this case, the error should not
1364- // propagate to the caller and instead treated as if the
1365- // attribute doesn't exist.
1366- PyErr_Clear ();
1367- }
13681399 Py_DECREF (attr );
13691400 return NULL ;
13701401 }
@@ -1377,28 +1408,8 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress)
13771408 }
13781409 return attr ;
13791410 }
1380- if (suppress == 1 ) {
1381- if (PyErr_Occurred ()) {
1382- // pass up non-AttributeError exception
1383- return NULL ;
1384- }
1385- }
1386- else {
1387- if (!PyErr_ExceptionMatches (PyExc_AttributeError )) {
1388- // pass up non-AttributeError exception
1389- return NULL ;
1390- }
1391- PyErr_Clear ();
1392- }
1393- assert (m -> md_dict != NULL );
1394- attr = try_load_lazy_submodule (m , name );
1395- if (attr != NULL ) {
1396- return attr ;
1397- }
1398- if (PyErr_Occurred ()) {
1399- return NULL ;
1400- }
1401- if (PyDict_GetItemRef (m -> md_dict , & _Py_ID (__getattr__ ), & getattr ) < 0 ) {
1411+ if (module_get_resolved_dict_item (
1412+ m -> md_dict , & _Py_ID (__getattr__ ), & getattr ) < 0 ) {
14021413 return NULL ;
14031414 }
14041415 if (getattr ) {
@@ -1589,11 +1600,14 @@ module_dir(PyObject *self, PyObject *args)
15891600
15901601 if (dict != NULL ) {
15911602 if (PyDict_Check (dict )) {
1592- PyObject * dirfunc = PyDict_GetItemWithError (dict , & _Py_ID (__dir__ ));
1593- if (dirfunc ) {
1603+ PyObject * dirfunc ;
1604+ int rc = module_get_resolved_dict_item (
1605+ dict , & _Py_ID (__dir__ ), & dirfunc );
1606+ if (rc > 0 ) {
15941607 result = _PyObject_CallNoArgs (dirfunc );
1608+ Py_DECREF (dirfunc );
15951609 }
1596- else if (! PyErr_Occurred () ) {
1610+ else if (rc == 0 ) {
15971611 result = PyDict_Keys (dict );
15981612 }
15991613 }
0 commit comments