@@ -3710,6 +3710,33 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
37103710
37113711 PyLazyImportObject * lz = (PyLazyImportObject * )lazy_import ;
37123712
3713+ // Check if we are already importing this module, if so, then we want to return an error
3714+ // that indicates we've hit a cycle which will indicate the value isn't yet available.
3715+ PyInterpreterState * interp = tstate -> interp ;
3716+ PyObject * importing = interp -> imports .lazy_importing_modules ;
3717+ if (importing == NULL ) {
3718+ importing = interp -> imports .lazy_importing_modules = PySet_New (NULL );
3719+ if (importing == NULL ) {
3720+ return NULL ;
3721+ }
3722+ }
3723+
3724+ int is_loading = PySet_Contains (importing , lazy_import );
3725+ if (is_loading < 0 ) {
3726+ return NULL ;
3727+ } else if (is_loading == 1 ) {
3728+ PyObject * name = _PyLazyImport_GetName (lazy_import );
3729+ PyObject * errmsg = PyUnicode_FromFormat ("cannot import name %R "
3730+ "(most likely due to a circular import)" ,
3731+ name );
3732+ PyErr_SetImportErrorSubclass (PyExc_ImportCycleError , errmsg , lz -> lz_from , NULL );
3733+ Py_XDECREF (errmsg );
3734+ Py_XDECREF (name );
3735+ return NULL ;
3736+ } else if (PySet_Add (importing , lazy_import ) < 0 ) {
3737+ goto error ;
3738+ }
3739+
37133740 Py_ssize_t dot = -1 ;
37143741 int full = 0 ;
37153742 if (lz -> lz_attr != NULL ) {
@@ -3738,10 +3765,6 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
37383765
37393766 PyObject * globals = PyEval_GetGlobals ();
37403767
3741- // Increment counter to prevent recursive lazy import creation
3742- PyInterpreterState * interp = tstate -> interp ;
3743- interp -> imports .lazy_import_resolution_depth ++ ;
3744-
37453768 if (full ) {
37463769 obj = _PyEval_ImportNameWithImport (tstate ,
37473770 lz -> lz_import_func ,
@@ -3753,7 +3776,6 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
37533776 } else {
37543777 PyObject * name = PyUnicode_Substring (lz -> lz_from , 0 , dot );
37553778 if (name == NULL ) {
3756- interp -> imports .lazy_import_resolution_depth -- ;
37573779 goto error ;
37583780 }
37593781 obj = _PyEval_ImportNameWithImport (tstate ,
@@ -3766,9 +3788,6 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
37663788 Py_DECREF (name );
37673789 }
37683790
3769- // Decrement counter
3770- interp -> imports .lazy_import_resolution_depth -- ;
3771-
37723791 if (obj == NULL ) {
37733792 goto error ;
37743793 }
@@ -3860,6 +3879,11 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate, PyObject *lazy_import)
38603879 }
38613880
38623881ok :
3882+ if (PySet_Discard (importing , lazy_import ) < 0 ) {
3883+ Py_DECREF (obj );
3884+ obj = NULL ;
3885+ }
3886+
38633887 Py_XDECREF (fromlist );
38643888 return obj ;
38653889}
@@ -3950,8 +3974,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
39503974 goto error ;
39513975 }
39523976
3953- // Only check __lazy_modules__ if we're not already resolving a lazy import
3954- if (interp -> imports .lazy_import_resolution_depth == 0 && globals != NULL &&
3977+ if (globals != NULL &&
39553978 PyMapping_GetOptionalItem (globals , & _Py_ID (__lazy_modules__ ), & lazy_modules ) < 0 ) {
39563979 goto error ;
39573980 }
@@ -3974,7 +3997,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
39743997 goto error ;
39753998 }
39763999
3977- if (interp -> imports . lazy_import_resolution_depth == 0 && lazy_modules != NULL ) {
4000+ if (lazy_modules != NULL ) {
39784001 // Check and see if the module is opting in w/o syntax for backwards compatibility
39794002 // with older Python versions.
39804003 int contains = PySequence_Contains (lazy_modules , name );
0 commit comments