summaryrefslogtreecommitdiffstats
path: root/Python/import.c
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2012-04-14 18:10:13 (GMT)
committerBrett Cannon <brett@python.org>2012-04-14 18:10:13 (GMT)
commitfd0741555b733f66c0a35c698d0cac5e73010ae0 (patch)
tree739b3aeb0a9d31f49dd334e5f57b5376b20d7dc7 /Python/import.c
parentd2cbd9053975d6d6a98adb23b2735b2125ed0626 (diff)
downloadcpython-fd0741555b733f66c0a35c698d0cac5e73010ae0.zip
cpython-fd0741555b733f66c0a35c698d0cac5e73010ae0.tar.gz
cpython-fd0741555b733f66c0a35c698d0cac5e73010ae0.tar.bz2
Issue #2377: Make importlib the implementation of __import__().
importlib._bootstrap is now frozen into Python/importlib.h and stored as _frozen_importlib in sys.modules. Py_Initialize() loads the frozen code along with sys and imp and then uses _frozen_importlib._install() to set builtins.__import__() w/ _frozen_importlib.__import__().
Diffstat (limited to 'Python/import.c')
-rw-r--r--Python/import.c766
1 files changed, 244 insertions, 522 deletions
diff --git a/Python/import.c b/Python/import.c
index 144ca71..87c1214 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -203,17 +203,13 @@ _PyImport_Init(void)
void
_PyImportHooks_Init(void)
{
- PyObject *v, *path_hooks = NULL, *zimpimport;
+ PyObject *v, *path_hooks = NULL;
int err = 0;
- /* adding sys.path_hooks and sys.path_importer_cache, setting up
- zipimport */
if (PyType_Ready(&PyNullImporter_Type) < 0)
goto error;
- if (Py_VerboseFlag)
- PySys_WriteStderr("# installing zipimport hook\n");
-
+ /* adding sys.path_hooks and sys.path_importer_cache */
v = PyList_New(0);
if (v == NULL)
goto error;
@@ -234,11 +230,26 @@ _PyImportHooks_Init(void)
err = PySys_SetObject("path_hooks", path_hooks);
if (err) {
error:
- PyErr_Print();
- Py_FatalError("initializing sys.meta_path, sys.path_hooks, "
- "path_importer_cache, or NullImporter failed"
- );
+ PyErr_Print();
+ Py_FatalError("initializing sys.meta_path, sys.path_hooks, "
+ "path_importer_cache, or NullImporter failed"
+ );
}
+ Py_DECREF(path_hooks);
+}
+
+void
+_PyImportZip_Init(void)
+{
+ PyObject *path_hooks, *zimpimport;
+ int err = 0;
+
+ path_hooks = PySys_GetObject("path_hooks");
+ if (path_hooks == NULL)
+ goto error;
+
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# installing zipimport hook\n");
zimpimport = PyImport_ImportModule("zipimport");
if (zimpimport == NULL) {
@@ -261,14 +272,20 @@ _PyImportHooks_Init(void)
/* sys.path_hooks.append(zipimporter) */
err = PyList_Append(path_hooks, zipimporter);
Py_DECREF(zipimporter);
- if (err)
+ if (err < 0) {
goto error;
+ }
if (Py_VerboseFlag)
PySys_WriteStderr(
"# installed zipimport hook\n");
}
}
- Py_DECREF(path_hooks);
+
+ return;
+
+ error:
+ PyErr_Print();
+ Py_FatalError("initializing zipimport or NullImporter failed");
}
/* Locking primitives to prevent parallel imports of the same module
@@ -2542,8 +2559,6 @@ init_builtin(PyObject *name)
name);
return -1;
}
- if (Py_VerboseFlag)
- PySys_FormatStderr("import %U # builtin\n", name);
mod = (*p->initfunc)();
if (mod == 0)
return -1;
@@ -2654,9 +2669,6 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
ispackage = (size < 0);
if (ispackage)
size = -size;
- if (Py_VerboseFlag)
- PySys_FormatStderr("import %U # frozen%s\n",
- name, ispackage ? " package" : "");
co = PyMarshal_ReadObjectFromString((char *)p->code, size);
if (co == NULL)
return -1;
@@ -2786,568 +2798,278 @@ PyImport_ImportModuleNoBlock(const char *name)
return result;
}
-/* Forward declarations for helper routines */
-static PyObject *get_parent(PyObject *globals,
- PyObject **p_name,
- int level);
-static PyObject *load_next(PyObject *mod, PyObject *altmod,
- PyObject *inputname, PyObject **p_outputname,
- PyObject **p_prefix);
-static int mark_miss(PyObject *name);
-static int ensure_fromlist(PyObject *mod, PyObject *fromlist,
- PyObject *buf, int recursive);
-static PyObject * import_submodule(PyObject *mod, PyObject *name,
- PyObject *fullname);
-
-/* The Magnum Opus of dotted-name import :-) */
-static PyObject *
-import_module_level(PyObject *name, PyObject *globals, PyObject *locals,
- PyObject *fromlist, int level)
+PyObject *
+PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
+ PyObject *locals, PyObject *given_fromlist,
+ int level)
{
- PyObject *parent, *next, *inputname, *outputname;
- PyObject *head = NULL;
- PyObject *tail = NULL;
- PyObject *prefix = NULL;
- PyObject *result = NULL;
- Py_ssize_t sep, altsep;
-
- if (PyUnicode_READY(name))
- return NULL;
-
- sep = PyUnicode_FindChar(name, SEP, 0, PyUnicode_GET_LENGTH(name), 1);
- if (sep == -2)
- return NULL;
-#ifdef ALTSEP
- altsep = PyUnicode_FindChar(name, ALTSEP, 0, PyUnicode_GET_LENGTH(name), 1);
- if (altsep == -2)
- return NULL;
-#else
- altsep = -1;
-#endif
- if (sep != -1 || altsep != -1)
- {
- PyErr_SetString(PyExc_ImportError,
- "Import by filename is not supported.");
- return NULL;
- }
-
- parent = get_parent(globals, &prefix, level);
- if (parent == NULL) {
- return NULL;
- }
-
- if (PyUnicode_READY(prefix))
- return NULL;
-
- head = load_next(parent, level < 0 ? Py_None : parent, name, &outputname,
- &prefix);
- if (head == NULL)
- goto out;
-
- tail = head;
- Py_INCREF(tail);
-
- if (outputname != NULL) {
- while (1) {
- inputname = outputname;
- next = load_next(tail, tail, inputname, &outputname,
- &prefix);
- Py_CLEAR(tail);
- Py_CLEAR(inputname);
- if (next == NULL)
- goto out;
- tail = next;
+ _Py_IDENTIFIER(__import__);
+ _Py_IDENTIFIER(__package__);
+ _Py_IDENTIFIER(__path__);
+ _Py_IDENTIFIER(__name__);
+ _Py_IDENTIFIER(_find_and_load);
+ _Py_IDENTIFIER(_handle_fromlist);
+ _Py_static_string(single_dot, ".");
+ PyObject *abs_name = NULL;
+ PyObject *builtins_import = NULL;
+ PyObject *final_mod = NULL;
+ PyObject *mod = NULL;
+ PyObject *package = NULL;
+ PyObject *globals = NULL;
+ PyObject *fromlist = NULL;
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
- if (outputname == NULL) {
- break;
- }
+ /* Make sure to use default values so as to not have
+ PyObject_CallMethodObjArgs() truncate the parameter list because of a
+ NULL argument. */
+ if (given_globals == NULL) {
+ globals = PyDict_New();
+ if (globals == NULL) {
+ goto error;
}
}
- if (tail == Py_None) {
- /* If tail is Py_None, both get_parent and load_next found
- an empty module name: someone called __import__("") or
- doctored faulty bytecode */
- PyErr_SetString(PyExc_ValueError, "Empty module name");
- goto out;
+ else {
+ /* Only have to care what given_globals is if it will be used
+ fortsomething. */
+ if (level > 0 && !PyDict_Check(given_globals)) {
+ PyErr_SetString(PyExc_TypeError, "globals must be a dict");
+ goto error;
+ }
+ globals = given_globals;
+ Py_INCREF(globals);
}
- if (fromlist != NULL) {
- if (fromlist == Py_None || !PyObject_IsTrue(fromlist))
- fromlist = NULL;
+ if (given_fromlist == NULL) {
+ fromlist = PyList_New(0);
+ if (fromlist == NULL) {
+ goto error;
+ }
}
-
- if (fromlist == NULL) {
- result = head;
- Py_INCREF(result);
- goto out;
+ else {
+ fromlist = given_fromlist;
+ Py_INCREF(fromlist);
}
-
- if (!ensure_fromlist(tail, fromlist, prefix, 0))
- goto out;
-
- result = tail;
- Py_INCREF(result);
- out:
- Py_XDECREF(head);
- Py_XDECREF(tail);
- Py_XDECREF(prefix);
- return result;
-}
-
-PyObject *
-PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
- PyObject *locals, PyObject *fromlist,
- int level)
-{
- PyObject *mod;
- _PyImport_AcquireLock();
- mod = import_module_level(name, globals, locals, fromlist, level);
- if (_PyImport_ReleaseLock() < 0) {
- Py_XDECREF(mod);
- PyErr_SetString(PyExc_RuntimeError,
- "not holding the import lock");
- return NULL;
+ if (name == NULL) {
+ PyErr_SetString(PyExc_ValueError, "Empty module name");
+ goto error;
}
- return mod;
-}
-PyObject *
-PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals,
- PyObject *fromlist, int level)
-{
- PyObject *nameobj, *mod;
- nameobj = PyUnicode_FromString(name);
- if (nameobj == NULL)
- return NULL;
- mod = PyImport_ImportModuleLevelObject(nameobj, globals, locals,
- fromlist, level);
- Py_DECREF(nameobj);
- return mod;
-}
+ /* The below code is importlib.__import__() & _gcd_import(), ported to C
+ for added performance. */
-
-/* Return the package that an import is being performed in. If globals comes
- from the module foo.bar.bat (not itself a package), this returns the
- sys.modules entry for foo.bar. If globals is from a package's __init__.py,
- the package's entry in sys.modules is returned, as a borrowed reference.
-
- The name of the returned package is returned in *p_name.
-
- If globals doesn't come from a package or a module in a package, or a
- corresponding entry is not found in sys.modules, Py_None is returned.
-*/
-static PyObject *
-get_parent(PyObject *globals, PyObject **p_name, int level)
-{
- PyObject *nameobj;
-
- static PyObject *namestr = NULL;
- static PyObject *pathstr = NULL;
- static PyObject *pkgstr = NULL;
- PyObject *pkgname, *modname, *modpath, *modules, *parent;
- int orig_level = level;
-
- if (globals == NULL || !PyDict_Check(globals) || !level)
- goto return_none;
-
- if (namestr == NULL) {
- namestr = PyUnicode_InternFromString("__name__");
- if (namestr == NULL)
- return NULL;
+ if (!PyUnicode_Check(name)) {
+ PyErr_SetString(PyExc_TypeError, "module name must be a string");
+ goto error;
}
- if (pathstr == NULL) {
- pathstr = PyUnicode_InternFromString("__path__");
- if (pathstr == NULL)
- return NULL;
+ else if (PyUnicode_READY(name) < 0) {
+ goto error;
}
- if (pkgstr == NULL) {
- pkgstr = PyUnicode_InternFromString("__package__");
- if (pkgstr == NULL)
- return NULL;
+ if (level < 0) {
+ PyErr_SetString(PyExc_ValueError, "level must be >= 0");
+ goto error;
}
-
- pkgname = PyDict_GetItem(globals, pkgstr);
-
- if ((pkgname != NULL) && (pkgname != Py_None)) {
- /* __package__ is set, so use it */
- if (!PyUnicode_Check(pkgname)) {
- PyErr_SetString(PyExc_ValueError,
- "__package__ set to non-string");
- return NULL;
- }
- if (PyUnicode_GET_LENGTH(pkgname) == 0) {
- if (level > 0) {
- PyErr_SetString(PyExc_ValueError,
- "Attempted relative import in non-package");
- return NULL;
+ else if (level > 0) {
+ package = _PyDict_GetItemId(globals, &PyId___package__);
+ if (package != NULL && package != Py_None) {
+ Py_INCREF(package);
+ if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError, "package must be a string");
+ goto error;
}
- goto return_none;
}
- Py_INCREF(pkgname);
- nameobj = pkgname;
- } else {
- /* __package__ not set, so figure it out and set it */
- modname = PyDict_GetItem(globals, namestr);
- if (modname == NULL || !PyUnicode_Check(modname))
- goto return_none;
-
- modpath = PyDict_GetItem(globals, pathstr);
- if (modpath != NULL) {
- /* __path__ is set, so modname is already the package name */
- int error;
-
- error = PyDict_SetItem(globals, pkgstr, modname);
- if (error) {
- PyErr_SetString(PyExc_ValueError,
- "Could not set __package__");
- return NULL;
+ else {
+ package = _PyDict_GetItemIdWithError(globals, &PyId___name__);
+ if (package == NULL) {
+ goto error;
}
- Py_INCREF(modname);
- nameobj = modname;
- } else {
- /* Normal module, so work out the package name if any */
- Py_ssize_t len;
- len = PyUnicode_FindChar(modname, '.',
- 0, PyUnicode_GET_LENGTH(modname), -1);
- if (len == -2)
- return NULL;
- if (len < 0) {
- if (level > 0) {
- PyErr_SetString(PyExc_ValueError,
- "Attempted relative import in non-package");
- return NULL;
+ else if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
+ }
+ Py_INCREF(package);
+
+ if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
+ PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
+ if (borrowed_dot == NULL) {
+ goto error;
}
- if (PyDict_SetItem(globals, pkgstr, Py_None)) {
- PyErr_SetString(PyExc_ValueError,
- "Could not set __package__");
- return NULL;
+ PyObject *partition = PyUnicode_RPartition(package,
+ borrowed_dot);
+ Py_DECREF(package);
+ if (partition == NULL) {
+ goto error;
}
- goto return_none;
+ package = PyTuple_GET_ITEM(partition, 0);
+ Py_INCREF(package);
+ Py_DECREF(partition);
}
- pkgname = PyUnicode_Substring(modname, 0, len);
- if (pkgname == NULL)
- return NULL;
- if (PyDict_SetItem(globals, pkgstr, pkgname)) {
- Py_DECREF(pkgname);
- PyErr_SetString(PyExc_ValueError,
- "Could not set __package__");
- return NULL;
- }
- nameobj = pkgname;
}
- }
- if (level > 1) {
- Py_ssize_t dot, end = PyUnicode_GET_LENGTH(nameobj);
- PyObject *newname;
- while (--level > 0) {
- dot = PyUnicode_FindChar(nameobj, '.', 0, end, -1);
- if (dot == -2) {
- Py_DECREF(nameobj);
- return NULL;
- }
- if (dot < 0) {
- Py_DECREF(nameobj);
- PyErr_SetString(PyExc_ValueError,
- "Attempted relative import beyond "
- "toplevel package");
- return NULL;
- }
- end = dot;
- }
- newname = PyUnicode_Substring(nameobj, 0, end);
- Py_DECREF(nameobj);
- if (newname == NULL)
- return NULL;
- nameobj = newname;
- }
- modules = PyImport_GetModuleDict();
- parent = PyDict_GetItem(modules, nameobj);
- if (parent == NULL) {
- int err;
-
- if (orig_level >= 1) {
+ if (PyDict_GetItem(interp->modules, package) == NULL) {
PyErr_Format(PyExc_SystemError,
- "Parent module %R not loaded, "
- "cannot perform relative import", nameobj);
- Py_DECREF(nameobj);
- return NULL;
+ "Parent module %R not loaded, cannot perform relative "
+ "import", package);
+ goto error;
}
-
- err = PyErr_WarnFormat(
- PyExc_RuntimeWarning, 1,
- "Parent module %R not found while handling absolute import",
- nameobj);
- Py_DECREF(nameobj);
- if (err)
- return NULL;
-
- goto return_none;
}
- *p_name = nameobj;
- return parent;
- /* We expect, but can't guarantee, if parent != None, that:
- - parent.__name__ == name
- - parent.__dict__ is globals
- If this is violated... Who cares? */
-
-return_none:
- nameobj = PyUnicode_New(0, 0);
- if (nameobj == NULL)
- return NULL;
- *p_name = nameobj;
- return Py_None;
-}
-
-/* altmod is either None or same as mod */
-static PyObject *
-load_next(PyObject *mod, PyObject *altmod,
- PyObject *inputname, PyObject **p_outputname,
- PyObject **p_prefix)
-{
- Py_ssize_t dot;
- Py_ssize_t len;
- PyObject *fullname, *name = NULL, *result;
-
- *p_outputname = NULL;
-
- len = PyUnicode_GET_LENGTH(inputname);
- if (len == 0) {
- /* completely empty module name should only happen in
- 'from . import' (or '__import__("")')*/
- Py_INCREF(mod);
- return mod;
+ else { /* level == 0 */
+ if (PyUnicode_GET_LENGTH(name) == 0) {
+ PyErr_SetString(PyExc_ValueError, "Empty module name");
+ goto error;
+ }
+ package = Py_None;
+ Py_INCREF(package);
}
+ if (level > 0) {
+ Py_ssize_t last_dot = PyUnicode_GET_LENGTH(package);
+ PyObject *base = NULL;
+ int level_up = 1;
- dot = PyUnicode_FindChar(inputname, '.', 0, len, 1);
- if (dot >= 0) {
- len = dot;
- if (len == 0) {
- PyErr_SetString(PyExc_ValueError,
- "Empty module name");
- goto error;
+ for (level_up = 1; level_up < level; level_up += 1) {
+ last_dot = PyUnicode_FindChar(package, '.', 0, last_dot, -1);
+ if (last_dot == -2) {
+ goto error;
+ }
+ else if (last_dot == -1) {
+ PyErr_SetString(PyExc_ValueError,
+ "attempted relative import beyond top-level "
+ "package");
+ goto error;
+ }
}
- }
+ base = PyUnicode_Substring(package, 0, last_dot);
+ if (PyUnicode_GET_LENGTH(name) > 0) {
+ PyObject *borrowed_dot = NULL;
+ PyObject *seq = PyTuple_Pack(2, base, name);
- /* name = inputname[:len] */
- name = PyUnicode_Substring(inputname, 0, len);
- if (name == NULL)
- goto error;
+ borrowed_dot = _PyUnicode_FromId(&single_dot);
+ if (borrowed_dot == NULL || seq == NULL) {
+ goto error;
+ }
- if (PyUnicode_GET_LENGTH(*p_prefix)) {
- /* fullname = prefix + "." + name */
- fullname = PyUnicode_FromFormat("%U.%U", *p_prefix, name);
- if (fullname == NULL)
- goto error;
- }
- else {
- fullname = name;
- Py_INCREF(fullname);
- }
-
- result = import_submodule(mod, name, fullname);
- Py_DECREF(*p_prefix);
- /* Transfer reference. */
- *p_prefix = fullname;
- if (result == Py_None && altmod != mod) {
- Py_DECREF(result);
- /* Here, altmod must be None and mod must not be None */
- result = import_submodule(altmod, name, name);
- if (result != NULL && result != Py_None) {
- if (mark_miss(*p_prefix) != 0) {
- Py_DECREF(result);
+ abs_name = PyUnicode_Join(borrowed_dot, seq);
+ Py_DECREF(seq);
+ if (abs_name == NULL) {
goto error;
}
- Py_DECREF(*p_prefix);
- *p_prefix = name;
- Py_INCREF(*p_prefix);
+ }
+ else {
+ abs_name = base;
}
}
- if (result == NULL)
- goto error;
-
- if (result == Py_None) {
- Py_DECREF(result);
- PyErr_Format(PyExc_ImportError,
- "No module named %R", inputname);
- goto error;
+ else {
+ abs_name = name;
+ Py_INCREF(abs_name);
}
- if (dot >= 0) {
- *p_outputname = PyUnicode_Substring(inputname, dot+1,
- PyUnicode_GET_LENGTH(inputname));
- if (*p_outputname == NULL) {
- Py_DECREF(result);
- goto error;
+#if WITH_THREAD
+ _PyImport_AcquireLock();
+#endif
+ /* From this point forward, goto error_with_unlock! */
+ if (PyDict_Check(globals)) {
+ builtins_import = _PyDict_GetItemId(globals, &PyId___import__);
+ }
+ if (builtins_import == NULL) {
+ builtins_import = _PyDict_GetItemId(interp->builtins, &PyId___import__);
+ if (builtins_import == NULL) {
+ Py_FatalError("__import__ missing");
}
}
+ Py_INCREF(builtins_import);
- Py_DECREF(name);
- return result;
-
-error:
- Py_XDECREF(name);
- return NULL;
-}
+ mod = PyDict_GetItem(interp->modules, abs_name);
+ if (mod == Py_None) {
+ PyErr_Format(PyExc_ImportError,
+ "import of %R halted; None in sys.modules", abs_name);
+ goto error_with_unlock;
+ }
+ else if (mod != NULL) {
+ Py_INCREF(mod);
+ }
+ else {
+ mod = _PyObject_CallMethodObjIdArgs(interp->importlib,
+ &PyId__find_and_load, abs_name,
+ builtins_import, NULL);
+ if (mod == NULL) {
+ goto error_with_unlock;
+ }
+ }
-static int
-mark_miss(PyObject *name)
-{
- PyObject *modules = PyImport_GetModuleDict();
- return PyDict_SetItem(modules, name, Py_None);
-}
+ if (PyObject_Not(fromlist)) {
+ if (level == 0 || PyUnicode_GET_LENGTH(name) > 0) {
+ PyObject *front = NULL;
+ PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
-static int
-ensure_fromlist(PyObject *mod, PyObject *fromlist, PyObject *name,
- int recursive)
-{
- int i;
- PyObject *fullname;
- Py_ssize_t fromlist_len;
+ if (borrowed_dot == NULL) {
+ goto error_with_unlock;
+ }
- if (!_PyObject_HasAttrId(mod, &PyId___path__))
- return 1;
+ PyObject *partition = PyUnicode_Partition(name, borrowed_dot);
+ if (partition == NULL) {
+ goto error_with_unlock;
+ }
- fromlist_len = PySequence_Size(fromlist);
+ front = PyTuple_GET_ITEM(partition, 0);
+ Py_INCREF(front);
+ Py_DECREF(partition);
- for (i = 0; i < fromlist_len; i++) {
- PyObject *item = PySequence_GetItem(fromlist, i);
- int hasit;
- if (item == NULL)
- return 0;
- if (!PyUnicode_Check(item)) {
- PyErr_SetString(PyExc_TypeError,
- "Item in ``from list'' not a string");
- Py_DECREF(item);
- return 0;
- }
- if (PyUnicode_READ_CHAR(item, 0) == '*') {
- PyObject *all;
- _Py_IDENTIFIER(__all__);
- Py_DECREF(item);
- /* See if the package defines __all__ */
- if (recursive)
- continue; /* Avoid endless recursion */
- all = _PyObject_GetAttrId(mod, &PyId___all__);
- if (all == NULL)
- PyErr_Clear();
+ if (level == 0) {
+ final_mod = PyDict_GetItemWithError(interp->modules, front);
+ Py_DECREF(front);
+ Py_XINCREF(final_mod);
+ }
else {
- int ret = ensure_fromlist(mod, all, name, 1);
- Py_DECREF(all);
- if (!ret)
- return 0;
+ Py_ssize_t cut_off = PyUnicode_GetLength(name) -
+ PyUnicode_GetLength(front);
+ Py_ssize_t abs_name_len = PyUnicode_GetLength(abs_name);
+ PyObject *to_return = PyUnicode_Substring(name, 0,
+ abs_name_len - cut_off);
+
+ final_mod = PyDict_GetItem(interp->modules, to_return);
+ Py_INCREF(final_mod);
+ Py_DECREF(to_return);
}
- continue;
}
- hasit = PyObject_HasAttr(mod, item);
- if (!hasit) {
- PyObject *submod;
- fullname = PyUnicode_FromFormat("%U.%U", name, item);
- if (fullname != NULL) {
- submod = import_submodule(mod, item, fullname);
- Py_DECREF(fullname);
- }
- else
- submod = NULL;
- Py_XDECREF(submod);
- if (submod == NULL) {
- Py_DECREF(item);
- return 0;
- }
+ else {
+ final_mod = mod;
+ Py_INCREF(mod);
}
- Py_DECREF(item);
- }
-
- return 1;
-}
-
-static int
-add_submodule(PyObject *mod, PyObject *submod, PyObject *fullname,
- PyObject *subname, PyObject *modules)
-{
- if (mod == Py_None)
- return 1;
- /* Irrespective of the success of this load, make a
- reference to it in the parent package module. A copy gets
- saved in the modules dictionary under the full name, so get a
- reference from there, if need be. (The exception is when the
- load failed with a SyntaxError -- then there's no trace in
- sys.modules. In that case, of course, do nothing extra.) */
- if (submod == NULL) {
- submod = PyDict_GetItem(modules, fullname);
- if (submod == NULL)
- return 1;
- }
- if (PyModule_Check(mod)) {
- /* We can't use setattr here since it can give a
- * spurious warning if the submodule name shadows a
- * builtin name */
- PyObject *dict = PyModule_GetDict(mod);
- if (!dict)
- return 0;
- if (PyDict_SetItem(dict, subname, submod) < 0)
- return 0;
}
else {
- if (PyObject_SetAttr(mod, subname, submod) < 0)
- return 0;
+ final_mod = _PyObject_CallMethodObjIdArgs(interp->importlib,
+ &PyId__handle_fromlist, mod,
+ fromlist, builtins_import,
+ NULL);
}
- return 1;
+ error_with_unlock:
+#if WITH_THREAD
+ if (_PyImport_ReleaseLock() < 0) {
+ PyErr_SetString(PyExc_RuntimeError, "not holding the import lock");
+ }
+#endif
+ error:
+ Py_XDECREF(abs_name);
+ Py_XDECREF(builtins_import);
+ Py_XDECREF(mod);
+ Py_XDECREF(package);
+ Py_XDECREF(globals);
+ Py_XDECREF(fromlist);
+ return final_mod;
}
-static PyObject *
-import_submodule(PyObject *mod, PyObject *subname, PyObject *fullname)
+PyObject *
+PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals,
+ PyObject *fromlist, int level)
{
- PyObject *modules = PyImport_GetModuleDict();
- PyObject *m = NULL, *bufobj, *path_list, *loader;
- struct filedescr *fdp;
- FILE *fp;
-
- /* Require:
- if mod == None: subname == fullname
- else: mod.__name__ + "." + subname == fullname
- */
-
- if ((m = PyDict_GetItem(modules, fullname)) != NULL) {
- Py_INCREF(m);
- return m;
- }
-
- if (mod == Py_None)
- path_list = NULL;
- else {
- path_list = _PyObject_GetAttrId(mod, &PyId___path__);
- if (path_list == NULL) {
- PyErr_Clear();
- Py_INCREF(Py_None);
- return Py_None;
- }
- }
-
- fdp = find_module(fullname, subname, path_list,
- &bufobj, &fp, &loader);
- Py_XDECREF(path_list);
- if (fdp == NULL) {
- if (!PyErr_ExceptionMatches(PyExc_ImportError))
- return NULL;
- PyErr_Clear();
- Py_INCREF(Py_None);
- return Py_None;
- }
- m = load_module(fullname, fp, bufobj, fdp->type, loader);
- Py_XDECREF(bufobj);
- Py_XDECREF(loader);
- if (fp)
- fclose(fp);
- if (m == NULL)
- return NULL;
- if (!add_submodule(mod, m, fullname, subname, modules)) {
- Py_XDECREF(m);
+ PyObject *nameobj, *mod;
+ nameobj = PyUnicode_FromString(name);
+ if (nameobj == NULL)
return NULL;
- }
- return m;
+ mod = PyImport_ImportModuleLevelObject(nameobj, globals, locals,
+ fromlist, level);
+ Py_DECREF(nameobj);
+ return mod;
}