diff options
Diffstat (limited to 'Python/import.c')
-rw-r--r-- | Python/import.c | 415 |
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; |