summaryrefslogtreecommitdiff
path: root/Python/import.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/import.c')
-rw-r--r--Python/import.c415
1 files changed, 199 insertions, 216 deletions
diff --git a/Python/import.c b/Python/import.c
index 5025e755f4..f3aa9d4397 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -38,14 +38,6 @@ module _imp
#include "clinic/import.c.h"
-/*[python input]
-class fs_unicode_converter(CConverter):
- type = 'PyObject *'
- converter = 'PyUnicode_FSDecoder'
-
-[python start generated code]*/
-/*[python end generated code: output=da39a3ee5e6b4b0d input=9d6786230166006e]*/
-
/* Initialize things */
void
@@ -320,7 +312,7 @@ PyImport_GetModuleDict(void)
/* List of names to clear in sys */
-static char* sys_deletes[] = {
+static const char * const sys_deletes[] = {
"path", "argv", "ps1", "ps2",
"last_type", "last_value", "last_traceback",
"path_hooks", "path_importer_cache", "meta_path",
@@ -330,7 +322,7 @@ static char* sys_deletes[] = {
NULL
};
-static char* sys_files[] = {
+static const char * const sys_files[] = {
"stdin", "__stdin__",
"stdout", "__stdout__",
"stderr", "__stderr__",
@@ -347,7 +339,7 @@ PyImport_Cleanup(void)
PyInterpreterState *interp = PyThreadState_GET()->interp;
PyObject *modules = interp->modules;
PyObject *weaklist = NULL;
- char **p;
+ const char * const *p;
if (modules == NULL)
return; /* Already done */
@@ -883,10 +875,8 @@ update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname)
if (PyUnicode_Compare(co->co_filename, oldname))
return;
- tmp = co->co_filename;
- co->co_filename = newname;
- Py_INCREF(co->co_filename);
- Py_DECREF(tmp);
+ Py_INCREF(newname);
+ Py_XSETREF(co->co_filename, newname);
constants = co->co_consts;
n = PyTuple_GET_SIZE(constants);
@@ -960,12 +950,13 @@ is_builtin(PyObject *name)
}
-/* Return an importer object for a sys.path/pkg.__path__ item 'p',
+/* Return a finder object for a sys.path/pkg.__path__ item 'p',
possibly by fetching it from the path_importer_cache dict. If it
wasn't yet cached, traverse path_hooks until a hook is found
that can handle the path item. Return None if no hook could;
- this tells our caller it should fall back to the builtin
- import mechanism. Cache the result in path_importer_cache.
+ this tells our caller that the path based finder could not find
+ a finder for this path item. Cache the result in
+ path_importer_cache.
Returns a borrowed reference. */
static PyObject *
@@ -1331,10 +1322,8 @@ remove_importlib_frames(void)
(always_trim ||
PyUnicode_CompareWithASCIIString(code->co_name,
remove_frames) == 0)) {
- PyObject *tmp = *outer_link;
- *outer_link = next;
Py_XINCREF(next);
- Py_DECREF(tmp);
+ Py_XSETREF(*outer_link, next);
prev_link = outer_link;
}
else {
@@ -1347,61 +1336,170 @@ done:
}
-PyObject *
-PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
- PyObject *locals, PyObject *given_fromlist,
- int level)
+static PyObject *
+resolve_name(PyObject *name, PyObject *globals, int level)
{
- _Py_IDENTIFIER(__import__);
_Py_IDENTIFIER(__spec__);
- _Py_IDENTIFIER(_initializing);
_Py_IDENTIFIER(__package__);
_Py_IDENTIFIER(__path__);
_Py_IDENTIFIER(__name__);
- _Py_IDENTIFIER(_find_and_load);
- _Py_IDENTIFIER(_handle_fromlist);
- _Py_IDENTIFIER(_lock_unlock_module);
- _Py_static_string(single_dot, ".");
- PyObject *abs_name = NULL;
- PyObject *builtins_import = NULL;
- PyObject *final_mod = NULL;
- PyObject *mod = NULL;
+ _Py_IDENTIFIER(parent);
+ PyObject *abs_name;
PyObject *package = NULL;
- PyObject *globals = NULL;
- PyObject *fromlist = NULL;
+ PyObject *spec;
PyInterpreterState *interp = PyThreadState_GET()->interp;
- int has_from;
+ Py_ssize_t last_dot;
+ PyObject *base;
+ int level_up;
+
+ if (globals == NULL) {
+ PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
+ goto error;
+ }
+ if (!PyDict_Check(globals)) {
+ PyErr_SetString(PyExc_TypeError, "globals must be a dict");
+ goto error;
+ }
+ package = _PyDict_GetItemId(globals, &PyId___package__);
+ if (package == Py_None) {
+ package = NULL;
+ }
+ spec = _PyDict_GetItemId(globals, &PyId___spec__);
+
+ if (package != NULL) {
+ Py_INCREF(package);
+ if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError, "package must be a string");
+ goto error;
+ }
+ else if (spec != NULL && spec != Py_None) {
+ int equal;
+ PyObject *parent = _PyObject_GetAttrId(spec, &PyId_parent);
+ if (parent == NULL) {
+ goto error;
+ }
- /* 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) {
+ equal = PyObject_RichCompareBool(package, parent, Py_EQ);
+ Py_DECREF(parent);
+ if (equal < 0) {
+ goto error;
+ }
+ else if (equal == 0) {
+ if (PyErr_WarnEx(PyExc_ImportWarning,
+ "__package__ != __spec__.parent", 1) < 0) {
+ goto error;
+ }
+ }
+ }
+ }
+ else if (spec != NULL && spec != Py_None) {
+ package = _PyObject_GetAttrId(spec, &PyId_parent);
+ if (package == NULL) {
+ goto error;
+ }
+ else if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__spec__.parent must be a string");
goto error;
}
}
else {
- /* Only have to care what given_globals is if it will be used
- for something. */
- if (level > 0 && !PyDict_Check(given_globals)) {
- PyErr_SetString(PyExc_TypeError, "globals must be a dict");
+ if (PyErr_WarnEx(PyExc_ImportWarning,
+ "can't resolve package from __spec__ or __package__, "
+ "falling back on __name__ and __path__", 1) < 0) {
goto error;
}
- globals = given_globals;
- Py_INCREF(globals);
+
+ package = _PyDict_GetItemId(globals, &PyId___name__);
+ if (package == NULL) {
+ PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
+ goto error;
+ }
+
+ Py_INCREF(package);
+ if (!PyUnicode_Check(package)) {
+ PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
+ goto error;
+ }
+
+ if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
+ Py_ssize_t dot;
+
+ if (PyUnicode_READY(package) < 0) {
+ goto error;
+ }
+
+ dot = PyUnicode_FindChar(package, '.',
+ 0, PyUnicode_GET_LENGTH(package), -1);
+ if (dot == -2) {
+ goto error;
+ }
+
+ if (dot >= 0) {
+ PyObject *substr = PyUnicode_Substring(package, 0, dot);
+ if (substr == NULL) {
+ goto error;
+ }
+ Py_SETREF(package, substr);
+ }
+ }
+ }
+
+ last_dot = PyUnicode_GET_LENGTH(package);
+ if (last_dot == 0) {
+ PyErr_SetString(PyExc_ImportError,
+ "attempted relative import with no known parent package");
+ goto error;
+ }
+ else if (PyDict_GetItem(interp->modules, package) == NULL) {
+ PyErr_Format(PyExc_SystemError,
+ "Parent module %R not loaded, cannot perform relative "
+ "import", package);
+ goto error;
}
- if (given_fromlist == NULL) {
- fromlist = PyList_New(0);
- if (fromlist == NULL) {
+ 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;
}
}
- else {
- fromlist = given_fromlist;
- Py_INCREF(fromlist);
+
+ base = PyUnicode_Substring(package, 0, last_dot);
+ Py_DECREF(package);
+ if (base == NULL || PyUnicode_GET_LENGTH(name) == 0) {
+ return base;
}
+
+ abs_name = PyUnicode_FromFormat("%U.%U", base, name);
+ Py_DECREF(base);
+ return abs_name;
+
+ error:
+ Py_XDECREF(package);
+ return NULL;
+}
+
+PyObject *
+PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
+ PyObject *locals, PyObject *fromlist,
+ int level)
+{
+ _Py_IDENTIFIER(_find_and_load);
+ _Py_IDENTIFIER(_handle_fromlist);
+ PyObject *abs_name = NULL;
+ PyObject *final_mod = NULL;
+ PyObject *mod = NULL;
+ PyObject *package = NULL;
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ int has_from;
+
if (name == NULL) {
PyErr_SetString(PyExc_ValueError, "Empty module name");
goto error;
@@ -1414,128 +1512,28 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
PyErr_SetString(PyExc_TypeError, "module name must be a string");
goto error;
}
- else if (PyUnicode_READY(name) < 0) {
+ if (PyUnicode_READY(name) < 0) {
goto error;
}
if (level < 0) {
PyErr_SetString(PyExc_ValueError, "level must be >= 0");
goto error;
}
- 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;
- }
- }
- else {
- package = _PyDict_GetItemId(globals, &PyId___name__);
- if (package == NULL) {
- PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
- goto error;
- }
- else if (!PyUnicode_Check(package)) {
- PyErr_SetString(PyExc_TypeError, "__name__ must be a string");
- goto error;
- }
- Py_INCREF(package);
-
- if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
- PyObject *partition = NULL;
- PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
- if (borrowed_dot == NULL) {
- goto error;
- }
- partition = PyUnicode_RPartition(package, borrowed_dot);
- Py_DECREF(package);
- if (partition == NULL) {
- goto error;
- }
- package = PyTuple_GET_ITEM(partition, 0);
- Py_INCREF(package);
- Py_DECREF(partition);
- }
- }
- if (PyDict_GetItem(interp->modules, package) == NULL) {
- PyErr_Format(PyExc_SystemError,
- "Parent module %R not loaded, cannot perform relative "
- "import", package);
+ if (level > 0) {
+ abs_name = resolve_name(name, globals, level);
+ if (abs_name == NULL)
goto error;
- }
}
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;
-
- 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 (base == NULL)
- goto error;
-
- if (PyUnicode_GET_LENGTH(name) > 0) {
- PyObject *borrowed_dot, *seq = NULL;
-
- borrowed_dot = _PyUnicode_FromId(&single_dot);
- seq = PyTuple_Pack(2, base, name);
- Py_DECREF(base);
- if (borrowed_dot == NULL || seq == NULL) {
- goto error;
- }
-
- abs_name = PyUnicode_Join(borrowed_dot, seq);
- Py_DECREF(seq);
- if (abs_name == NULL) {
- goto error;
- }
- }
- else {
- abs_name = base;
- }
- }
- else {
abs_name = name;
Py_INCREF(abs_name);
}
-#ifdef WITH_THREAD
- _PyImport_AcquireLock();
-#endif
- /* From this point forward, goto error_with_unlock! */
- /* XXX interp->builtins_copy is NULL in subinterpreter! */
- builtins_import = _PyDict_GetItemId(interp->builtins_copy ?
- interp->builtins_copy :
- interp->builtins, &PyId___import__);
- if (builtins_import == NULL) {
- PyErr_SetString(PyExc_ImportError, "__import__ not found");
- goto error_with_unlock;
- }
- Py_INCREF(builtins_import);
-
mod = PyDict_GetItem(interp->modules, abs_name);
if (mod == Py_None) {
PyObject *msg = PyUnicode_FromFormat("import of %R halted; "
@@ -1545,9 +1543,12 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
Py_DECREF(msg);
}
mod = NULL;
- goto error_with_unlock;
+ goto error;
}
else if (mod != NULL) {
+ _Py_IDENTIFIER(__spec__);
+ _Py_IDENTIFIER(_initializing);
+ _Py_IDENTIFIER(_lock_unlock_module);
PyObject *value = NULL;
PyObject *spec;
int initializing = 0;
@@ -1570,91 +1571,83 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
Py_DECREF(value);
if (initializing == -1)
PyErr_Clear();
- }
- if (initializing > 0) {
- /* _bootstrap._lock_unlock_module() releases the import lock */
- value = _PyObject_CallMethodIdObjArgs(interp->importlib,
- &PyId__lock_unlock_module, abs_name,
- NULL);
- if (value == NULL)
- goto error;
- Py_DECREF(value);
- }
- else {
+ if (initializing > 0) {
#ifdef WITH_THREAD
- if (_PyImport_ReleaseLock() < 0) {
- PyErr_SetString(PyExc_RuntimeError, "not holding the import lock");
- goto error;
- }
+ _PyImport_AcquireLock();
#endif
+ /* _bootstrap._lock_unlock_module() releases the import lock */
+ value = _PyObject_CallMethodIdObjArgs(interp->importlib,
+ &PyId__lock_unlock_module, abs_name,
+ NULL);
+ if (value == NULL)
+ goto error;
+ Py_DECREF(value);
+ }
}
}
else {
+#ifdef WITH_THREAD
+ _PyImport_AcquireLock();
+#endif
/* _bootstrap._find_and_load() releases the import lock */
mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
&PyId__find_and_load, abs_name,
- builtins_import, NULL);
+ interp->import_func, NULL);
if (mod == NULL) {
goto error;
}
}
- /* From now on we don't hold the import lock anymore. */
- has_from = PyObject_IsTrue(fromlist);
- if (has_from < 0)
- goto error;
+ has_from = 0;
+ if (fromlist != NULL && fromlist != Py_None) {
+ has_from = PyObject_IsTrue(fromlist);
+ if (has_from < 0)
+ goto error;
+ }
if (!has_from) {
- if (level == 0 || PyUnicode_GET_LENGTH(name) > 0) {
- PyObject *front = NULL;
- PyObject *partition = NULL;
- PyObject *borrowed_dot = _PyUnicode_FromId(&single_dot);
-
- if (borrowed_dot == NULL) {
- goto error;
- }
+ Py_ssize_t len = PyUnicode_GET_LENGTH(name);
+ if (level == 0 || len > 0) {
+ Py_ssize_t dot;
- partition = PyUnicode_Partition(name, borrowed_dot);
- if (partition == NULL) {
+ dot = PyUnicode_FindChar(name, '.', 0, len, 1);
+ if (dot == -2) {
goto error;
}
- if (PyUnicode_GET_LENGTH(PyTuple_GET_ITEM(partition, 1)) == 0) {
+ if (dot == -1) {
/* No dot in module name, simple exit */
- Py_DECREF(partition);
final_mod = mod;
Py_INCREF(mod);
goto error;
}
- front = PyTuple_GET_ITEM(partition, 0);
- Py_INCREF(front);
- Py_DECREF(partition);
-
if (level == 0) {
- final_mod = PyObject_CallFunctionObjArgs(builtins_import, front, NULL);
+ PyObject *front = PyUnicode_Substring(name, 0, dot);
+ if (front == NULL) {
+ goto error;
+ }
+
+ final_mod = PyImport_ImportModuleLevelObject(front, NULL, NULL, NULL, 0);
Py_DECREF(front);
}
else {
- Py_ssize_t cut_off = PyUnicode_GET_LENGTH(name) -
- PyUnicode_GET_LENGTH(front);
+ Py_ssize_t cut_off = len - dot;
Py_ssize_t abs_name_len = PyUnicode_GET_LENGTH(abs_name);
PyObject *to_return = PyUnicode_Substring(abs_name, 0,
abs_name_len - cut_off);
- Py_DECREF(front);
if (to_return == NULL) {
goto error;
}
final_mod = PyDict_GetItem(interp->modules, to_return);
+ Py_DECREF(to_return);
if (final_mod == NULL) {
PyErr_Format(PyExc_KeyError,
"%R not in sys.modules as expected",
to_return);
+ goto error;
}
- else {
- Py_INCREF(final_mod);
- }
- Py_DECREF(to_return);
+ Py_INCREF(final_mod);
}
}
else {
@@ -1665,24 +1658,14 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
else {
final_mod = _PyObject_CallMethodIdObjArgs(interp->importlib,
&PyId__handle_fromlist, mod,
- fromlist, builtins_import,
+ fromlist, interp->import_func,
NULL);
}
- goto error;
- error_with_unlock:
-#ifdef 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);
if (final_mod == NULL)
remove_importlib_frames();
return final_mod;