https://github.com/python/cpython/commit/18c935f72d5e391afda16bc45cf49b0f42bff15f
commit: 18c935f72d5e391afda16bc45cf49b0f42bff15f
branch: main
author: Petr Viktorin <[email protected]>
committer: encukou <[email protected]>
date: 2026-10-23T22:01:22+02:00
summary:

gh-157384: Unify `_Py_ext_module_loader_info` initialization (GH-157758)

- Unify `_Py_ext_module_loader_info_init*` functions. The “core” one was 
entirely unused, and the difference between “builtin” and “extension” can be 
expressed in arguments.
- Consolidate getting & checking the module name from spec. (This improves 
error message wording for `imp.create_builtin` with empty name.)
- Allow non-ASCII names.

Core modules (`sys` and `builtins`) still don't go through the routine.

Co-authored-by: Itamar Oren <[email protected]>

files:
A Misc/NEWS.d/next/C_API/2026-09-12-18-37-22.gh-issue-157384.uFbdle.rst
M Include/internal/pycore_global_objects_fini_generated.h
M Include/internal/pycore_global_strings.h
M Include/internal/pycore_importdl.h
M Include/internal/pycore_runtime_init_generated.h
M Include/internal/pycore_unicodeobject_generated.h
M Lib/test/test_embed.py
M Lib/test/test_import/__init__.py
M Programs/_testembed.c
M Python/import.c
M Python/importdl.c

diff --git a/Include/internal/pycore_global_objects_fini_generated.h 
b/Include/internal/pycore_global_objects_fini_generated.h
index 416448a74385b0c..630730fe525f76a 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -250,6 +250,7 @@ _PyStaticObjects_CheckAll(PyInterpreterState *interp) {
     _PyStaticObject_CheckUnicodeSingleton((PyObject 
*)&_Py_ID(_asyncio_future_blocking), "_asyncio_future_blocking", 24);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(_blksize), 
"_blksize", 8);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(_bootstrap), 
"_bootstrap", 10);
+    _PyStaticObject_CheckUnicodeSingleton((PyObject 
*)&_Py_ID(_bootstrap_external), "_bootstrap_external", 19);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(_check_retval_), 
"_check_retval_", 14);
     _PyStaticObject_CheckUnicodeSingleton((PyObject *)&_Py_ID(_dealloc_warn), 
"_dealloc_warn", 13);
     _PyStaticObject_CheckUnicodeSingleton((PyObject 
*)&_Py_ID(_feature_version), "_feature_version", 16);
diff --git a/Include/internal/pycore_global_strings.h 
b/Include/internal/pycore_global_strings.h
index 7a6082035f5c979..321015ac7bce09b 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -262,6 +262,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(_asyncio_future_blocking)
         STRUCT_FOR_ID(_blksize)
         STRUCT_FOR_ID(_bootstrap)
+        STRUCT_FOR_ID(_bootstrap_external)
         STRUCT_FOR_ID(_check_retval_)
         STRUCT_FOR_ID(_dealloc_warn)
         STRUCT_FOR_ID(_feature_version)
diff --git a/Include/internal/pycore_importdl.h 
b/Include/internal/pycore_importdl.h
index 9ed87a544234c59..e89686d4ae5884e 100644
--- a/Include/internal/pycore_importdl.h
+++ b/Include/internal/pycore_importdl.h
@@ -51,9 +51,9 @@ typedef enum ext_module_kind {
 } _Py_ext_module_kind;
 
 typedef enum ext_module_origin {
-    _Py_ext_module_origin_CORE = 1,
-    _Py_ext_module_origin_BUILTIN = 2,
-    _Py_ext_module_origin_DYNAMIC = 3,
+    _Py_ext_module_origin_CORE = 1,  // 'sys' & 'builtins'
+    _Py_ext_module_origin_BUILTIN = 2,  // inittab or 
PyImport_CreateModuleFromInitfunc
+    _Py_ext_module_origin_DYNAMIC = 3,  // loaded dynamically
 } _Py_ext_module_origin;
 
 struct hook_prefixes {
@@ -79,21 +79,10 @@ struct _Py_ext_module_loader_info {
 extern void _Py_ext_module_loader_info_clear(
     struct _Py_ext_module_loader_info *info);
 extern int _Py_ext_module_loader_info_init(
-    struct _Py_ext_module_loader_info *info,
+    struct _Py_ext_module_loader_info *p_info,
     PyObject *name,
-    PyObject *filename,
+    PyObject *spec,
     _Py_ext_module_origin origin);
-extern int _Py_ext_module_loader_info_init_for_core(
-    struct _Py_ext_module_loader_info *p_info,
-    PyObject *name);
-extern int _Py_ext_module_loader_info_init_for_builtin(
-    struct _Py_ext_module_loader_info *p_info,
-    PyObject *name);
-#ifdef HAVE_DYNAMIC_LOADING
-extern int _Py_ext_module_loader_info_init_from_spec(
-    struct _Py_ext_module_loader_info *info,
-    PyObject *spec);
-#endif
 
 /* The result from running an extension module's init function.
  * Not used for modules defined via PyModExport (slots array).
diff --git a/Include/internal/pycore_runtime_init_generated.h 
b/Include/internal/pycore_runtime_init_generated.h
index e9fce38ac8c4ac3..69eb481472f2bcd 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -1537,6 +1537,7 @@ extern "C" {
     INIT_ID(_asyncio_future_blocking), \
     INIT_ID(_blksize), \
     INIT_ID(_bootstrap), \
+    INIT_ID(_bootstrap_external), \
     INIT_ID(_check_retval_), \
     INIT_ID(_dealloc_warn), \
     INIT_ID(_feature_version), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h 
b/Include/internal/pycore_unicodeobject_generated.h
index ac814a8de84c3d3..80473d20a42da3d 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -214,6 +214,7 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
         offsetof(struct _Py_global_strings, 
identifiers._py__asyncio_future_blocking._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py__blksize._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py__bootstrap._ascii.ob_base),
+        offsetof(struct _Py_global_strings, 
identifiers._py__bootstrap_external._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py__check_retval_._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py__dealloc_warn._ascii.ob_base),
         offsetof(struct _Py_global_strings, 
identifiers._py__feature_version._ascii.ob_base),
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 8ef2bcc3249b8b5..6c51b79bc44a0f5 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -293,6 +293,12 @@ def test_create_module_from_initfunc(self):
             "sp_pkg.sp_submod.__name__='sp_pkg.sp_submod'\n"
             "sys.modules[\"sp_pkg.sp_submod\"] is sp_pkg.sp_submod=True\n"
             "\"sp_submod\" in sys.modules=False\n"
+            # Module with non-ASCII name. (The SystemError shows the internal
+            # punycode-encoded name: not ideal, but also not horrible.)
+            "created nonascii_mp_\N{SNAKE}: in sys.modules=False\n"
+            "ascii(mp.__name__)=\"'nonascii_mp_\\\\U0001f40d'\" 
mp.executed='yes'\n"
+            "SystemError: 'initialization of nonascii_sp__rf17k "
+            "did not return PyModuleDef'\n"
         )
 
     def test_inittab_submodule_multiphase(self):
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index 17b1e03470dd048..6ff688aea61d6a8 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -1264,6 +1264,13 @@ class Spec2:
                 origin = "a\x00b"
             _imp.create_dynamic(Spec2())
 
+
+    def test_create_dynamic_no_origin(self):
+        with self.assertRaisesRegex(AttributeError, "no attribute 'origin'"):
+            class Spec:
+                name = "abc"
+            _imp.create_dynamic(Spec())
+
     def test_create_builtin(self):
         class Spec:
             pass
@@ -1273,7 +1280,7 @@ class Spec:
         self.assertIs(_imp.create_builtin(spec), sys)
 
         spec.name = None
-        with self.assertRaisesRegex(TypeError, 'name must be string, not 
NoneType'):
+        with self.assertRaisesRegex(TypeError, 'module name must be a string, 
not NoneType'):
             _imp.create_builtin(spec)
 
         # gh-142029
@@ -1283,7 +1290,7 @@ class Spec:
 
         # gh-142029
         spec.name = ""
-        with self.assertRaisesRegex(ValueError, 'name must not be empty'):
+        with self.assertRaisesRegex(ValueError, 'module name must not be 
empty'):
             _imp.create_builtin(spec)
 
     def test_filter_syntax_warnings_by_module(self):
diff --git 
a/Misc/NEWS.d/next/C_API/2026-09-12-18-37-22.gh-issue-157384.uFbdle.rst 
b/Misc/NEWS.d/next/C_API/2026-09-12-18-37-22.gh-issue-157384.uFbdle.rst
new file mode 100644
index 000000000000000..0ba43518705c50a
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2026-09-12-18-37-22.gh-issue-157384.uFbdle.rst
@@ -0,0 +1,3 @@
+:c:func:`PyImport_CreateModuleFromInitfunc` now accepts non-ASCII module
+names for multi-phase init modules, instead of raising
+:exc:`UnicodeEncodeError`.
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 2c5940a0755398a..08bbcd4cfec1543 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -2460,6 +2460,40 @@ PyInit_cmfi_sp_pkg(void)
     return PyModuleDef_Init(&cmfi_sp_pkg_def);
 }
 
+
+// Modules with non-ASCII names: multi-phase init is supported,
+// single-phase init is not.
+static PyModuleDef_Slot cmfi_nonascii_mp_slots[] = {
+    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
+    {0, NULL},
+};
+
+static PyModuleDef cmfi_nonascii_mp_def = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "nonascii_mp_\xf0\x9f\x90\x8d",
+    .m_size = 0,
+    .m_slots = cmfi_nonascii_mp_slots,
+};
+
+static PyObject*
+PyInit_cmfi_nonascii_mp(void)
+{
+    return PyModuleDef_Init(&cmfi_nonascii_mp_def);
+}
+
+static PyModuleDef cmfi_nonascii_sp_def = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "nonascii_sp_\xf0\x9f\x90\x8d",
+    .m_size = -1,
+};
+
+static PyObject*
+PyInit_cmfi_nonascii_sp(void)
+{
+    return PyModule_Create(&cmfi_nonascii_sp_def);
+}
+
 static PyObject*
 create_module(PyObject* self, PyObject* spec)
 {
@@ -2487,6 +2521,14 @@ create_module(PyObject* self, PyObject* spec)
         Py_DECREF(name);
         return PyImport_CreateModuleFromInitfunc(spec, PyInit_cmfi_sp_submod);
     }
+    if (PyUnicode_EqualToUTF8(name, "nonascii_mp_\xf0\x9f\x90\x8d")) {
+        Py_DECREF(name);
+        return PyImport_CreateModuleFromInitfunc(spec, 
PyInit_cmfi_nonascii_mp);
+    }
+    if (PyUnicode_EqualToUTF8(name, "nonascii_sp_\xf0\x9f\x90\x8d")) {
+        Py_DECREF(name);
+        return PyImport_CreateModuleFromInitfunc(spec, 
PyInit_cmfi_nonascii_sp);
+    }
     PyErr_Format(PyExc_LookupError, "static module %R not found", name);
     Py_DECREF(name);
     return NULL;
@@ -2548,6 +2590,11 @@ test_create_module_from_initfunc(void)
         L"print(f'{sp_pkg.sp_submod.__name__=}');"
         L"print(f'{sys.modules[\"sp_pkg.sp_submod\"] is sp_pkg.sp_submod=}');"
         L"print(f'{\"sp_submod\" in sys.modules=}');"
+        // Non-ASCII names: multi-phase init works, single-phase init doesn't
+        L"import importlib;"
+        L"mp = importlib.import_module('nonascii_mp_\\N{SNAKE}');"
+        L"print(f'{ascii(mp.__name__)=} {mp.executed=}');"
+        L"try_import('nonascii_sp_\\N{SNAKE}');"
     };
     PyConfig config;
     if (PyImport_AppendInittab("create_static_module",
@@ -2568,7 +2615,10 @@ test_create_module_from_initfunc(void)
         "   @classmethod\n"
         "   def find_spec(cls, fullname, path, target=None):\n"
         "       if fullname in {'my_test_extension', 'embedded_ext',\n"
-        "                       'sp_pkg', 'sp_pkg.sp_submod'}:\n"
+        "                       'sp_pkg', 'sp_pkg.sp_submod',\n"
+        "                       'nonascii_mp_\\N{SNAKE}',\n"
+        "                       'nonascii_sp_\\N{SNAKE}',\n"
+        "       }:\n"
         "           return spec_from_loader(fullname, cls, 
origin=cls._ORIGIN,\n"
         "                                   is_package=(fullname == 
'sp_pkg'))\n"
         "       return None\n"
@@ -2583,6 +2633,13 @@ test_create_module_from_initfunc(void)
         "       create_static_module.exec_module(module)\n"
         "       module.executed = 'yes'\n"
         "sys.meta_path.append(StaticExtensionImporter)\n"
+        "def try_import(name):\n"
+        "   try:\n"
+        "       importlib.import_module(name)\n"
+        "   except SystemError as exc:\n"
+        "       print(f'SystemError: {ascii(str(exc))}')\n"
+        "   else:\n"
+        "       print(f'no SystemError for {ascii(name)}!')\n"
     );
     if (result < 0) {
         fprintf(stderr, "PyRun_SimpleString() failed\n");
diff --git a/Python/import.c b/Python/import.c
index 88d4980991f16a6..8f4cec08ef765cd 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -2507,27 +2507,16 @@ lookup_inittab_entry(const struct 
_Py_ext_module_loader_info* info)
 
 static PyObject*
 create_builtin(
-    PyThreadState *tstate, PyObject *name,
+    PyThreadState *tstate,
+    PyObject *name, /* if NULL, get from spec */
     PyObject *spec,
     PyModInitFunction initfunc)
 {
     struct _Py_ext_module_loader_info info;
-    if (_Py_ext_module_loader_info_init_for_builtin(&info, name) < 0) {
+    _Py_ext_module_origin origin = _Py_ext_module_origin_BUILTIN;
+    if (_Py_ext_module_loader_info_init(&info, name, spec, origin) < 0) {
         return NULL;
     }
-    if (initfunc != NULL) {
-        /* An explicitly provided init function (see
-         * PyImport_CreateModuleFromInitfunc()) may belong to a submodule
-         * whose single-phase init creates the module using only the last
-         * component of the name (as e.g. pybind11 does).  Set the package
-         * context so that PyModule_Create() resolves the full name, the
-         * same as for dynamically loaded extensions. */
-        info.newcontext = PyUnicode_AsUTF8(info.name);
-        if (info.newcontext == NULL) {
-            _Py_ext_module_loader_info_clear(&info);
-            return NULL;
-        }
-    }
 
     struct extensions_cache_value *cached = NULL;
     PyObject *mod = import_find_extension(tstate, &info, &cached);
@@ -2558,7 +2547,7 @@ create_builtin(
         struct _inittab *entry = lookup_inittab_entry(&info);
         if (entry == NULL) {
             mod = NULL;
-            _PyErr_SetModuleNotFoundError(name);
+            _PyErr_SetModuleNotFoundError(info.name);
             goto finally;
         }
 
@@ -2610,20 +2599,7 @@ PyImport_CreateModuleFromInitfunc(
 
     PyThreadState *tstate = _PyThreadState_GET();
 
-    PyObject *name = PyObject_GetAttr(spec, &_Py_ID(name));
-    if (name == NULL) {
-        return NULL;
-    }
-
-    if (!PyUnicode_Check(name)) {
-        PyErr_Format(PyExc_TypeError,
-                     "spec name must be string, not %T", name);
-        Py_DECREF(name);
-        return NULL;
-    }
-
-    PyObject *mod = create_builtin(tstate, name, spec, initfunc);
-    Py_DECREF(name);
+    PyObject *mod = create_builtin(tstate, NULL, spec, initfunc);
     return mod;
 }
 
@@ -2835,8 +2811,8 @@ PyImport_ExecCodeModuleWithPathnames(const char *name, 
PyObject *co,
             Py_FatalError("no current interpreter");
         }
 
-        external= PyObject_GetAttrString(IMPORTLIB(interp),
-                                         "_bootstrap_external");
+        external= PyObject_GetAttr(IMPORTLIB(interp),
+                                   &_Py_ID(_bootstrap_external));
         if (external != NULL) {
             pathobj = PyObject_CallMethodOneArg(
                 external, &_Py_ID(_get_sourcefile), cpathobj);
@@ -2920,8 +2896,8 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject 
*co, PyObject *pathname,
     if (pathname == NULL) {
         pathname = ((PyCodeObject *)co)->co_filename;
     }
-    external = PyObject_GetAttrString(IMPORTLIB(tstate->interp),
-                                      "_bootstrap_external");
+    external = PyObject_GetAttr(IMPORTLIB(tstate->interp),
+                                &_Py_ID(_bootstrap_external));
     if (external == NULL) {
         Py_DECREF(d);
         return NULL;
@@ -3499,8 +3475,8 @@ PyObject *
 _PyImport_GetImportlibExternalLoader(PyInterpreterState *interp,
                                      const char *loader_name)
 {
-    PyObject *bootstrap = PyObject_GetAttrString(IMPORTLIB(interp),
-                                                 "_bootstrap_external");
+    PyObject *bootstrap = PyObject_GetAttr(IMPORTLIB(interp),
+                                           &_Py_ID(_bootstrap_external));
     if (bootstrap == NULL) {
         return NULL;
     }
@@ -3513,8 +3489,8 @@ _PyImport_GetImportlibExternalLoader(PyInterpreterState 
*interp,
 PyObject *
 _PyImport_BlessMyLoader(PyInterpreterState *interp, PyObject *module_globals)
 {
-    PyObject *external = PyObject_GetAttrString(IMPORTLIB(interp),
-                                                "_bootstrap_external");
+    PyObject *external = PyObject_GetAttr(IMPORTLIB(interp),
+                                          &_Py_ID(_bootstrap_external));
     if (external == NULL) {
         return NULL;
     }
@@ -5085,27 +5061,7 @@ _imp_create_builtin(PyObject *module, PyObject *spec)
 {
     PyThreadState *tstate = _PyThreadState_GET();
 
-    PyObject *name = PyObject_GetAttrString(spec, "name");
-    if (name == NULL) {
-        return NULL;
-    }
-
-    if (!PyUnicode_Check(name)) {
-        PyErr_Format(PyExc_TypeError,
-                     "name must be string, not %.200s",
-                     Py_TYPE(name)->tp_name);
-        Py_DECREF(name);
-        return NULL;
-    }
-
-    if (PyUnicode_GetLength(name) == 0) {
-        PyErr_Format(PyExc_ValueError, "name must not be empty");
-        Py_DECREF(name);
-        return NULL;
-    }
-
-    PyObject *mod = create_builtin(tstate, name, spec, NULL);
-    Py_DECREF(name);
+    PyObject *mod = create_builtin(tstate, NULL, spec, NULL);
     return mod;
 }
 
@@ -5437,7 +5393,8 @@ _imp_create_dynamic_impl(PyObject *module, PyObject 
*spec, PyObject *file)
     PyThreadState *tstate = _PyThreadState_GET();
 
     struct _Py_ext_module_loader_info info;
-    if (_Py_ext_module_loader_info_init_from_spec(&info, spec) < 0) {
+    _Py_ext_module_origin origin = _Py_ext_module_origin_DYNAMIC;
+    if (_Py_ext_module_loader_info_init(&info, NULL, spec, origin) < 0) {
         return NULL;
     }
 
diff --git a/Python/importdl.c b/Python/importdl.c
index 537e8d869dc93ca..dbcf5c98ceb69b2 100644
--- a/Python/importdl.c
+++ b/Python/importdl.c
@@ -8,6 +8,7 @@
 #include "pycore_moduleobject.h"  // _PyModule_GetDefOrNull()
 #include "pycore_pyerrors.h"      // _PyErr_FormatFromCause()
 #include "pycore_runtime.h"       // _Py_ID()
+#include "pycore_global_objects.h"  // _Py_SINGLETON()
 
 
 /***********************************/
@@ -28,8 +29,6 @@ static const struct hook_prefixes nonascii_prefixes = {
 static PyObject *
 get_encoded_name(PyObject *name, const struct hook_prefixes **hook_prefixes) {
     PyObject *tmp;
-    PyObject *encoded = NULL;
-    PyObject *modname = NULL;
     Py_ssize_t name_len, lastdot;
 
     /* Get the short name (substring after last dot) */
@@ -51,33 +50,38 @@ get_encoded_name(PyObject *name, const struct hook_prefixes 
**hook_prefixes) {
     }
 
     /* Encode to ASCII or Punycode, as needed */
-    encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
-    if (encoded != NULL) {
+    PyObject *encoded;
+    if (PyUnicode_IS_ASCII(name)) {
         *hook_prefixes = &ascii_only_prefixes;
+        encoded = PyUnicode_AsASCIIString(name);
     } else {
-        if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
-            PyErr_Clear();
-            encoded = PyUnicode_AsEncodedString(name, "punycode", NULL);
-            if (encoded == NULL) {
-                goto error;
-            }
-            *hook_prefixes = &nonascii_prefixes;
-        } else {
-            goto error;
-        }
+        *hook_prefixes = &nonascii_prefixes;
+        encoded = PyUnicode_AsEncodedString(name, "punycode", NULL);
+    }
+    if (encoded == NULL) {
+        goto error;
     }
 
-    /* Replace '-' by '_' */
-    modname = _PyObject_CallMethod(encoded, &_Py_ID(replace), "cc", '-', '_');
-    if (modname == NULL)
+    /* Call encoded.replace('-', '_') */
+    PyObject *modname = PyObject_VectorcallMethod(
+        &_Py_ID(replace),
+        (PyObject*[3]) {
+            encoded,
+            (PyObject *)&_Py_SINGLETON(bytes_characters)['-'],
+            (PyObject *)&_Py_SINGLETON(bytes_characters)['_'],
+        },
+        3 | PY_VECTORCALL_ARGUMENTS_OFFSET,
+        NULL);
+    Py_CLEAR(encoded);
+
+    if (modname == NULL) {
         goto error;
+    }
 
     Py_DECREF(name);
-    Py_DECREF(encoded);
     return modname;
 error:
     Py_DECREF(name);
-    Py_XDECREF(encoded);
     return NULL;
 }
 
@@ -94,122 +98,81 @@ _Py_ext_module_loader_info_clear(struct 
_Py_ext_module_loader_info *info)
 
 int
 _Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info,
-                                PyObject *name, PyObject *filename,
+                                PyObject *name,
+                                PyObject *spec,
                                 _Py_ext_module_origin origin)
 {
     struct _Py_ext_module_loader_info info = {
         .origin=origin,
     };
 
-    assert(name != NULL);
-    if (!PyUnicode_Check(name)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "module name must be a string");
-        _Py_ext_module_loader_info_clear(&info);
-        return -1;
+    if (name == NULL) {
+        assert(spec != NULL);
+        info.name = PyObject_GetAttr(spec, &_Py_ID(name));
+        if (info.name == NULL) {
+            goto error;
+        }
+    }
+    else {
+        info.name = Py_NewRef(name);
+    }
+
+    if (!PyUnicode_Check(info.name)) {
+        PyErr_Format(PyExc_TypeError,
+                     "module name must be a string, not %T",
+                     info.name);
+        goto error;
+    }
+
+    if (PyUnicode_GetLength(info.name) == 0) {
+        PyErr_Format(PyExc_ValueError, "module name must not be empty");
+        goto error;
     }
-    assert(PyUnicode_GetLength(name) > 0);
-    info.name = Py_NewRef(name);
 
     info.name_encoded = get_encoded_name(info.name, &info.hook_prefixes);
     if (info.name_encoded == NULL) {
-        _Py_ext_module_loader_info_clear(&info);
-        return -1;
+        goto error;
     }
 
     info.newcontext = PyUnicode_AsUTF8(info.name);
     if (info.newcontext == NULL) {
-        _Py_ext_module_loader_info_clear(&info);
-        return -1;
+        goto error;
     }
 
-    if (filename != NULL) {
-        if (!PyUnicode_Check(filename)) {
+    if (origin == _Py_ext_module_origin_DYNAMIC) {
+        assert(spec != NULL);
+        info.filename = PyObject_GetAttr(spec, &_Py_ID(origin));
+        if (info.filename == NULL) {
+            goto error;
+        }
+
+        if (!PyUnicode_Check(info.filename)) {
             PyErr_SetString(PyExc_TypeError,
                             "module filename must be a string");
-            _Py_ext_module_loader_info_clear(&info);
-            return -1;
+            goto error;
         }
-        info.filename = Py_NewRef(filename);
 
 #ifndef MS_WINDOWS
         info.filename_encoded = PyUnicode_EncodeFSDefault(info.filename);
         if (info.filename_encoded == NULL) {
-            _Py_ext_module_loader_info_clear(&info);
-            return -1;
+            goto error;
         }
 #endif
 
         info.path = info.filename;
     }
     else {
+        info.filename = NULL;
         info.path = info.name;
     }
 
     *p_info = info;
     return 0;
-}
 
-int
-_Py_ext_module_loader_info_init_for_builtin(
-                            struct _Py_ext_module_loader_info *info,
-                            PyObject *name)
-{
-    assert(PyUnicode_Check(name));
-    assert(PyUnicode_GetLength(name) > 0);
-
-    PyObject *name_encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
-    if (name_encoded == NULL) {
-        return -1;
-    }
-
-    *info = (struct _Py_ext_module_loader_info){
-        .name=Py_NewRef(name),
-        .name_encoded=name_encoded,
-        /* We won't need filename. */
-        .path=name,
-        .origin=_Py_ext_module_origin_BUILTIN,
-        .hook_prefixes=&ascii_only_prefixes,
-        .newcontext=NULL,
-    };
-    return 0;
-}
-
-int
-_Py_ext_module_loader_info_init_for_core(
-                            struct _Py_ext_module_loader_info *info,
-                            PyObject *name)
-{
-    if (_Py_ext_module_loader_info_init_for_builtin(info, name) < 0) {
-        return -1;
-    }
-    info->origin = _Py_ext_module_origin_CORE;
-    return 0;
-}
-
-#ifdef HAVE_DYNAMIC_LOADING
-int
-_Py_ext_module_loader_info_init_from_spec(
-                            struct _Py_ext_module_loader_info *p_info,
-                            PyObject *spec)
-{
-    PyObject *name = PyObject_GetAttrString(spec, "name");
-    if (name == NULL) {
-        return -1;
-    }
-    PyObject *filename = PyObject_GetAttrString(spec, "origin");
-    if (filename == NULL) {
-        Py_DECREF(name);
-        return -1;
-    }
-    /* We could also accommodate builtin modules here without much trouble. */
-    _Py_ext_module_origin origin = _Py_ext_module_origin_DYNAMIC;
-    int err = _Py_ext_module_loader_info_init(p_info, name, filename, origin);
-    Py_DECREF(name);
-    Py_DECREF(filename);
-    return err;
+error:
+    _Py_ext_module_loader_info_clear(&info);
+    return -1;
 }
-#endif /* HAVE_DYNAMIC_LOADING */
 
 
 /********************************/

_______________________________________________
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]

Reply via email to