@@ -94,6 +94,8 @@ static struct _inittab *inittab_copy = NULL;
9494 (interp)->imports.modules_by_index
9595#define LAZY_MODULES (interp ) \
9696 (interp)->imports.lazy_modules
97+ #define LAZY_PENDING_SUBMODULES (interp ) \
98+ (interp)->imports.lazy_pending_submodules
9799#define IMPORTLIB (interp ) \
98100 (interp)->imports.importlib
99101#define OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK (interp ) \
@@ -271,15 +273,19 @@ import_get_module(PyThreadState *tstate, PyObject *name)
271273PyObject *
272274_PyImport_InitLazyModules (PyInterpreterState * interp )
273275{
274- assert (LAZY_MODULES (interp ) == NULL );
275- LAZY_MODULES (interp ) = PyDict_New ();
276+ assert (LAZY_MODULES (interp ) == NULL &&
277+ LAZY_PENDING_SUBMODULES (interp ) == NULL );
278+
279+ LAZY_PENDING_SUBMODULES (interp ) = PyDict_New ();
280+ LAZY_MODULES (interp ) = PySet_New (0 );
276281 return LAZY_MODULES (interp );
277282}
278283
279284void
280285_PyImport_ClearLazyModules (PyInterpreterState * interp )
281286{
282287 Py_CLEAR (LAZY_MODULES (interp ));
288+ Py_CLEAR (LAZY_PENDING_SUBMODULES (interp ));
283289}
284290
285291static int
@@ -4339,7 +4345,7 @@ get_mod_dict(PyObject *module)
43394345// ensure we have the set for the parent module name in sys.lazy_modules.
43404346// Returns a new reference.
43414347static PyObject *
4342- ensure_lazy_submodules (PyDictObject * lazy_modules , PyObject * parent )
4348+ ensure_lazy_pending_submodules (PyDictObject * lazy_modules , PyObject * parent )
43434349{
43444350 PyObject * lazy_submodules ;
43454351 Py_BEGIN_CRITICAL_SECTION (lazy_modules );
@@ -4358,6 +4364,9 @@ ensure_lazy_submodules(PyDictObject *lazy_modules, PyObject *parent)
43584364 return lazy_submodules ;
43594365}
43604366
4367+ // Ensures that we have a LazyImportObject on the parent module for
4368+ // all children modules which have been lazily imported. If the parent
4369+ // module overrides the child attribute then the value is not replaced.
43614370static int
43624371register_lazy_on_parent (PyThreadState * tstate , PyObject * name ,
43634372 PyObject * builtins )
@@ -4369,16 +4378,16 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name,
43694378 PyObject * parent_dict = NULL ;
43704379
43714380 PyInterpreterState * interp = tstate -> interp ;
4372- PyObject * lazy_modules = LAZY_MODULES (interp );
4373- assert (lazy_modules != NULL );
4381+ PyObject * lazy_pending_submodules = LAZY_PENDING_SUBMODULES (interp );
4382+ assert (lazy_pending_submodules != NULL );
43744383
43754384 Py_INCREF (name );
43764385 while (true) {
43774386 Py_ssize_t dot = PyUnicode_FindChar (name , '.' , 0 ,
43784387 PyUnicode_GET_LENGTH (name ), -1 );
43794388 if (dot < 0 ) {
4380- PyObject * lazy_submodules = ensure_lazy_submodules (
4381- (PyDictObject * )lazy_modules , name );
4389+ PyObject * lazy_submodules = ensure_lazy_pending_submodules (
4390+ (PyDictObject * )lazy_pending_submodules , name );
43824391 if (lazy_submodules == NULL ) {
43834392 goto done ;
43844393 }
@@ -4400,8 +4409,8 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name,
44004409 }
44014410
44024411 // Record the child as being lazily imported from the parent.
4403- PyObject * lazy_submodules = ensure_lazy_submodules (
4404- (PyDictObject * )lazy_modules , parent );
4412+ PyObject * lazy_submodules = ensure_lazy_pending_submodules (
4413+ (PyDictObject * )lazy_pending_submodules , parent );
44054414 if (lazy_submodules == NULL ) {
44064415 goto done ;
44074416 }
@@ -4464,6 +4473,14 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name,
44644473 if (fromname == NULL ) {
44654474 return -1 ;
44664475 }
4476+
4477+ // Add the module name to sys.lazy_modules set (PEP 810).
4478+ PyObject * lazy_modules = LAZY_MODULES (tstate -> interp );
4479+ if (PySet_Add (lazy_modules , fromname ) < 0 ) {
4480+ Py_DECREF (fromname );
4481+ return -1 ;
4482+ }
4483+
44674484 int res = register_lazy_on_parent (tstate , fromname , builtins );
44684485 Py_DECREF (fromname );
44694486 return res ;
@@ -4555,6 +4572,13 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate,
45554572 Py_DECREF (abs_name );
45564573 return NULL ;
45574574 }
4575+
4576+ // Add the module name to sys.lazy_modules set (PEP 810).
4577+ PyObject * lazy_modules = LAZY_MODULES (tstate -> interp );
4578+ if (PySet_Add (lazy_modules , abs_name ) < 0 ) {
4579+ goto error ;
4580+ }
4581+
45584582 if (fromlist && PyUnicode_Check (fromlist )) {
45594583 if (register_from_lazy_on_parent (tstate , abs_name , fromlist ,
45604584 builtins ) < 0 ) {
@@ -4791,6 +4815,7 @@ _PyImport_ClearCore(PyInterpreterState *interp)
47914815 Py_CLEAR (IMPORTLIB (interp ));
47924816 Py_CLEAR (IMPORT_FUNC (interp ));
47934817 Py_CLEAR (LAZY_IMPORT_FUNC (interp ));
4818+ Py_CLEAR (interp -> imports .lazy_pending_submodules );
47944819 Py_CLEAR (interp -> imports .lazy_modules );
47954820 Py_CLEAR (interp -> imports .lazy_importing_modules );
47964821 Py_CLEAR (interp -> imports .lazy_imports_filter );
@@ -5636,11 +5661,13 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj,
56365661 PyThreadState * tstate = _PyThreadState_GET ();
56375662 PyObject * module_dict = NULL ;
56385663 PyObject * ret = NULL ;
5639- PyObject * lazy_modules = LAZY_MODULES (tstate -> interp );
5640- assert (lazy_modules != NULL );
5664+ PyObject * lazy_pending_modules = LAZY_PENDING_SUBMODULES (tstate -> interp );
5665+ assert (lazy_pending_modules != NULL );
56415666
56425667 PyObject * lazy_submodules ;
5643- if (PyDict_GetItemRef (lazy_modules , name , & lazy_submodules ) < 0 ) {
5668+ if (PySet_Discard (LAZY_MODULES (tstate -> interp ), name ) < 0 ) {
5669+ return NULL ;
5670+ } else if (PyDict_GetItemRef (lazy_pending_modules , name , & lazy_submodules ) < 0 ) {
56445671 return NULL ;
56455672 }
56465673 else if (lazy_submodules == NULL ) {
@@ -5659,8 +5686,7 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj,
56595686 Py_END_CRITICAL_SECTION ();
56605687 Py_DECREF (lazy_submodules );
56615688
5662- // once a module is imported it is removed from sys.lazy_modules
5663- if (PyDict_DelItem (lazy_modules , name ) < 0 ) {
5689+ if (PyDict_DelItem (lazy_pending_modules , name ) < 0 ) {
56645690 goto error ;
56655691 }
56665692
0 commit comments