@@ -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
@@ -4338,7 +4344,7 @@ get_mod_dict(PyObject *module)
43384344// ensure we have the set for the parent module name in sys.lazy_modules.
43394345// Returns a new reference.
43404346static PyObject *
4341- ensure_lazy_submodules (PyDictObject * lazy_modules , PyObject * parent )
4347+ ensure_lazy_pending_submodules (PyDictObject * lazy_modules , PyObject * parent )
43424348{
43434349 PyObject * lazy_submodules ;
43444350 Py_BEGIN_CRITICAL_SECTION (lazy_modules );
@@ -4357,6 +4363,9 @@ ensure_lazy_submodules(PyDictObject *lazy_modules, PyObject *parent)
43574363 return lazy_submodules ;
43584364}
43594365
4366+ // Ensures that we have a LazyImportObject on the parent module for
4367+ // all children modules which have been lazily imported. If the parent
4368+ // module overrides the child attribute then the value is not replaced.
43604369static int
43614370register_lazy_on_parent (PyThreadState * tstate , PyObject * name ,
43624371 PyObject * builtins )
@@ -4368,16 +4377,16 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name,
43684377 PyObject * parent_dict = NULL ;
43694378
43704379 PyInterpreterState * interp = tstate -> interp ;
4371- PyObject * lazy_modules = LAZY_MODULES (interp );
4372- assert (lazy_modules != NULL );
4380+ PyObject * lazy_pending_submodules = LAZY_PENDING_SUBMODULES (interp );
4381+ assert (lazy_pending_submodules != NULL );
43734382
43744383 Py_INCREF (name );
43754384 while (true) {
43764385 Py_ssize_t dot = PyUnicode_FindChar (name , '.' , 0 ,
43774386 PyUnicode_GET_LENGTH (name ), -1 );
43784387 if (dot < 0 ) {
4379- PyObject * lazy_submodules = ensure_lazy_submodules (
4380- (PyDictObject * )lazy_modules , name );
4388+ PyObject * lazy_submodules = ensure_lazy_pending_submodules (
4389+ (PyDictObject * )lazy_pending_submodules , name );
43814390 if (lazy_submodules == NULL ) {
43824391 goto done ;
43834392 }
@@ -4399,8 +4408,8 @@ register_lazy_on_parent(PyThreadState *tstate, PyObject *name,
43994408 }
44004409
44014410 // Record the child as being lazily imported from the parent.
4402- PyObject * lazy_submodules = ensure_lazy_submodules (
4403- (PyDictObject * )lazy_modules , parent );
4411+ PyObject * lazy_submodules = ensure_lazy_pending_submodules (
4412+ (PyDictObject * )lazy_pending_submodules , parent );
44044413 if (lazy_submodules == NULL ) {
44054414 goto done ;
44064415 }
@@ -4463,6 +4472,14 @@ register_from_lazy_on_parent(PyThreadState *tstate, PyObject *abs_name,
44634472 if (fromname == NULL ) {
44644473 return -1 ;
44654474 }
4475+
4476+ // Add the module name to sys.lazy_modules set (PEP 810).
4477+ PyObject * lazy_modules = LAZY_MODULES (tstate -> interp );
4478+ if (PySet_Add (lazy_modules , fromname ) < 0 ) {
4479+ Py_DECREF (fromname );
4480+ return -1 ;
4481+ }
4482+
44664483 int res = register_lazy_on_parent (tstate , fromname , builtins );
44674484 Py_DECREF (fromname );
44684485 return res ;
@@ -4554,6 +4571,13 @@ _PyImport_LazyImportModuleLevelObject(PyThreadState *tstate,
45544571 Py_DECREF (abs_name );
45554572 return NULL ;
45564573 }
4574+
4575+ // Add the module name to sys.lazy_modules set (PEP 810).
4576+ PyObject * lazy_modules = LAZY_MODULES (tstate -> interp );
4577+ if (PySet_Add (lazy_modules , abs_name ) < 0 ) {
4578+ goto error ;
4579+ }
4580+
45574581 if (fromlist && PyUnicode_Check (fromlist )) {
45584582 if (register_from_lazy_on_parent (tstate , abs_name , fromlist ,
45594583 builtins ) < 0 ) {
@@ -4790,6 +4814,7 @@ _PyImport_ClearCore(PyInterpreterState *interp)
47904814 Py_CLEAR (IMPORTLIB (interp ));
47914815 Py_CLEAR (IMPORT_FUNC (interp ));
47924816 Py_CLEAR (LAZY_IMPORT_FUNC (interp ));
4817+ Py_CLEAR (interp -> imports .lazy_pending_submodules );
47934818 Py_CLEAR (interp -> imports .lazy_modules );
47944819 Py_CLEAR (interp -> imports .lazy_importing_modules );
47954820 Py_CLEAR (interp -> imports .lazy_imports_filter );
@@ -5637,11 +5662,13 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj,
56375662 PyThreadState * tstate = _PyThreadState_GET ();
56385663 PyObject * module_dict = NULL ;
56395664 PyObject * ret = NULL ;
5640- PyObject * lazy_modules = LAZY_MODULES (tstate -> interp );
5641- assert (lazy_modules != NULL );
5665+ PyObject * lazy_pending_modules = LAZY_PENDING_SUBMODULES (tstate -> interp );
5666+ assert (lazy_pending_modules != NULL );
56425667
56435668 PyObject * lazy_submodules ;
5644- if (PyDict_GetItemRef (lazy_modules , name , & lazy_submodules ) < 0 ) {
5669+ if (PySet_Discard (LAZY_MODULES (tstate -> interp ), name ) < 0 ) {
5670+ return NULL ;
5671+ } else if (PyDict_GetItemRef (lazy_pending_modules , name , & lazy_submodules ) < 0 ) {
56455672 return NULL ;
56465673 }
56475674 else if (lazy_submodules == NULL ) {
@@ -5660,8 +5687,7 @@ _imp__set_lazy_attributes_impl(PyObject *module, PyObject *modobj,
56605687 Py_END_CRITICAL_SECTION ();
56615688 Py_DECREF (lazy_submodules );
56625689
5663- // once a module is imported it is removed from sys.lazy_modules
5664- if (PyDict_DelItem (lazy_modules , name ) < 0 ) {
5690+ if (PyDict_DelItem (lazy_pending_modules , name ) < 0 ) {
56655691 goto error ;
56665692 }
56675693
0 commit comments