diff options
Diffstat (limited to 'Python/import.c')
-rw-r--r-- | Python/import.c | 4304 |
1 files changed, 2663 insertions, 1641 deletions
diff --git a/Python/import.c b/Python/import.c index 045b6d0..b79354b 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1,22 +1,19 @@ + /* Module definition and import implementation */ #include "Python.h" #include "Python-ast.h" -#undef Yield /* undefine macro conflicting with <winbase.h> */ -#include "pycore_initconfig.h" -#include "pycore_pyerrors.h" -#include "pycore_pyhash.h" -#include "pycore_pylifecycle.h" -#include "pycore_pymem.h" -#include "pycore_pystate.h" +#undef Yield /* undefine macro conflicting with winbase.h */ +#include "pyarena.h" +#include "pythonrun.h" #include "errcode.h" #include "marshal.h" #include "code.h" -#include "frameobject.h" +#include "compile.h" +#include "eval.h" #include "osdefs.h" #include "importdl.h" -#include "pydtrace.h" #ifdef HAVE_FCNTL_H #include <fcntl.h> @@ -25,36 +22,194 @@ extern "C" { #endif -#define CACHEDIR "__pycache__" +#ifdef MS_WINDOWS +/* for stat.st_mode */ +typedef unsigned short mode_t; +#endif + + +/* Magic word to reject .pyc files generated by other Python versions. + It should change for each incompatible change to the bytecode. + + The value of CR and LF is incorporated so if you ever read or write + a .pyc file in text mode the magic number will be wrong; also, the + Apple MPW compiler swaps their values, botching string constants. + + The magic numbers must be spaced apart atleast 2 values, as the + -U interpeter flag will cause MAGIC+1 being used. They have been + odd numbers for some time now. + + There were a variety of old schemes for setting the magic number. + The current working scheme is to increment the previous value by + 10. + + Known values: + Python 1.5: 20121 + Python 1.5.1: 20121 + Python 1.5.2: 20121 + Python 1.6: 50428 + Python 2.0: 50823 + Python 2.0.1: 50823 + Python 2.1: 60202 + Python 2.1.1: 60202 + Python 2.1.2: 60202 + Python 2.2: 60717 + Python 2.3a0: 62011 + Python 2.3a0: 62021 + Python 2.3a0: 62011 (!) + Python 2.4a0: 62041 + Python 2.4a3: 62051 + Python 2.4b1: 62061 + Python 2.5a0: 62071 + Python 2.5a0: 62081 (ast-branch) + Python 2.5a0: 62091 (with) + Python 2.5a0: 62092 (changed WITH_CLEANUP opcode) + Python 2.5b3: 62101 (fix wrong code: for x, in ...) + Python 2.5b3: 62111 (fix wrong code: x += yield) + Python 2.5c1: 62121 (fix wrong lnotab with for loops and + storing constants that should have been removed) + Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp) + Python 2.6a0: 62151 (peephole optimizations and STORE_MAP opcode) + Python 2.6a1: 62161 (WITH_CLEANUP optimization) + Python 2.7a0: 62171 (optimize list comprehensions/change LIST_APPEND) + Python 2.7a0: 62181 (optimize conditional branches: + introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE) + Python 2.7a0 62191 (introduce SETUP_WITH) + Python 2.7a0 62201 (introduce BUILD_SET) + Python 2.7a0 62211 (introduce MAP_ADD and SET_ADD) +. +*/ +#define MAGIC (62211 | ((long)'\r'<<16) | ((long)'\n'<<24)) -/* Forward references */ -static PyObject *import_add_module(PyThreadState *tstate, PyObject *name); +/* Magic word as global; note that _PyImport_Init() can change the + value of this global to accommodate for alterations of how the + compiler works which are enabled by command line switches. */ +static long pyc_magic = MAGIC; -/* See _PyImport_FixupExtensionObject() below */ +/* See _PyImport_FixupExtension() below */ static PyObject *extensions = NULL; /* This table is defined in config.c: */ extern struct _inittab _PyImport_Inittab[]; struct _inittab *PyImport_Inittab = _PyImport_Inittab; -static struct _inittab *inittab_copy = NULL; -/*[clinic input] -module _imp -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9c332475d8686284]*/ +/* these tables define the module suffixes that Python recognizes */ +struct filedescr * _PyImport_Filetab = NULL; + +#ifdef RISCOS +static const struct filedescr _PyImport_StandardFiletab[] = { + {"/py", "U", PY_SOURCE}, + {"/pyc", "rb", PY_COMPILED}, + {0, 0} +}; +#else +static const struct filedescr _PyImport_StandardFiletab[] = { + {".py", "U", PY_SOURCE}, +#ifdef MS_WINDOWS + {".pyw", "U", PY_SOURCE}, +#endif + {".pyc", "rb", PY_COMPILED}, + {0, 0} +}; +#endif -#include "clinic/import.c.h" +#ifdef MS_WINDOWS +static int isdir(char *path) { + DWORD rv; + /* see issue1293 and issue3677: + * stat() on Windows doesn't recognise paths like + * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs. + * Also reference issue6727: + * stat() on Windows is broken and doesn't resolve symlinks properly. + */ + rv = GetFileAttributesA(path); + return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY; +} +#else +#ifdef HAVE_STAT +static int isdir(char *path) { + struct stat statbuf; + return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode); +} +#else +#ifdef RISCOS +/* with RISCOS, isdir is in unixstuff */ +#else +int isdir(char *path) { + return 0; +} +#endif /* RISCOS */ +#endif /* HAVE_STAT */ +#endif /* MS_WINDOWS */ /* Initialize things */ -PyStatus -_PyImportHooks_Init(PyThreadState *tstate) +void +_PyImport_Init(void) +{ + const struct filedescr *scan; + struct filedescr *filetab; + int countD = 0; + int countS = 0; + + /* prepare _PyImport_Filetab: copy entries from + _PyImport_DynLoadFiletab and _PyImport_StandardFiletab. + */ +#ifdef HAVE_DYNAMIC_LOADING + for (scan = _PyImport_DynLoadFiletab; scan->suffix != NULL; ++scan) + ++countD; +#endif + for (scan = _PyImport_StandardFiletab; scan->suffix != NULL; ++scan) + ++countS; + filetab = PyMem_NEW(struct filedescr, countD + countS + 1); + if (filetab == NULL) + Py_FatalError("Can't initialize import file table."); +#ifdef HAVE_DYNAMIC_LOADING + memcpy(filetab, _PyImport_DynLoadFiletab, + countD * sizeof(struct filedescr)); +#endif + memcpy(filetab + countD, _PyImport_StandardFiletab, + countS * sizeof(struct filedescr)); + filetab[countD + countS].suffix = NULL; + + _PyImport_Filetab = filetab; + + if (Py_OptimizeFlag) { + /* Replace ".pyc" with ".pyo" in _PyImport_Filetab */ + for (; filetab->suffix != NULL; filetab++) { +#ifndef RISCOS + if (strcmp(filetab->suffix, ".pyc") == 0) + filetab->suffix = ".pyo"; +#else + if (strcmp(filetab->suffix, "/pyc") == 0) + filetab->suffix = "/pyo"; +#endif + } + } + + if (Py_UnicodeFlag) { + /* Fix the pyc_magic so that byte compiled code created + using the all-Unicode method doesn't interfere with + code created in normal operation mode. */ + pyc_magic = MAGIC + 1; + } +} + +void +_PyImportHooks_Init(void) { - PyObject *v, *path_hooks = NULL; + PyObject *v, *path_hooks = NULL, *zimpimport; int err = 0; - /* adding sys.path_hooks and sys.path_importer_cache */ + /* 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"); + v = PyList_New(0); if (v == NULL) goto error; @@ -74,88 +229,70 @@ _PyImportHooks_Init(PyThreadState *tstate) goto error; err = PySys_SetObject("path_hooks", path_hooks); if (err) { - goto error; - } - Py_DECREF(path_hooks); - return _PyStatus_OK(); - error: - _PyErr_Print(tstate); - return _PyStatus_ERR("initializing sys.meta_path, sys.path_hooks, " - "or path_importer_cache failed"); -} - -PyStatus -_PyImportZip_Init(PyThreadState *tstate) -{ - PyObject *path_hooks, *zipimport; - int err = 0; - - path_hooks = PySys_GetObject("path_hooks"); - if (path_hooks == NULL) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "unable to get sys.path_hooks"); - goto error; - } - - int verbose = tstate->interp->config.verbose; - if (verbose) { - PySys_WriteStderr("# installing zipimport hook\n"); + PyErr_Print(); + Py_FatalError("initializing sys.meta_path, sys.path_hooks, " + "path_importer_cache, or NullImporter failed" + ); } - zipimport = PyImport_ImportModule("zipimport"); - if (zipimport == NULL) { - _PyErr_Clear(tstate); /* No zip import module -- okay */ - if (verbose) { + zimpimport = PyImport_ImportModule("zipimport"); + if (zimpimport == NULL) { + PyErr_Clear(); /* No zip import module -- okay */ + if (Py_VerboseFlag) PySys_WriteStderr("# can't import zipimport\n"); - } } else { - _Py_IDENTIFIER(zipimporter); - PyObject *zipimporter = _PyObject_GetAttrId(zipimport, - &PyId_zipimporter); - Py_DECREF(zipimport); + PyObject *zipimporter = PyObject_GetAttrString(zimpimport, + "zipimporter"); + Py_DECREF(zimpimport); if (zipimporter == NULL) { - _PyErr_Clear(tstate); /* No zipimporter object -- okay */ - if (verbose) { - PySys_WriteStderr("# can't import zipimport.zipimporter\n"); - } + PyErr_Clear(); /* No zipimporter object -- okay */ + if (Py_VerboseFlag) + PySys_WriteStderr( + "# can't import zipimport.zipimporter\n"); } else { - /* sys.path_hooks.insert(0, zipimporter) */ - err = PyList_Insert(path_hooks, 0, zipimporter); + /* sys.path_hooks.append(zipimporter) */ + err = PyList_Append(path_hooks, zipimporter); Py_DECREF(zipimporter); - if (err < 0) { + if (err) goto error; - } - if (verbose) { - PySys_WriteStderr("# installed zipimport hook\n"); - } + if (Py_VerboseFlag) + PySys_WriteStderr( + "# installed zipimport hook\n"); } } + Py_DECREF(path_hooks); +} - return _PyStatus_OK(); - - error: - PyErr_Print(); - return _PyStatus_ERR("initializing zipimport failed"); +void +_PyImport_Fini(void) +{ + Py_XDECREF(extensions); + extensions = NULL; + PyMem_DEL(_PyImport_Filetab); + _PyImport_Filetab = NULL; } + /* Locking primitives to prevent parallel imports of the same module in different threads to return with a partially loaded module. These calls are serialized by the global interpreter lock. */ +#ifdef WITH_THREAD + #include "pythread.h" static PyThread_type_lock import_lock = 0; -static unsigned long import_lock_thread = PYTHREAD_INVALID_THREAD_ID; +static long import_lock_thread = -1; static int import_lock_level = 0; void _PyImport_AcquireLock(void) { - unsigned long me = PyThread_get_thread_ident(); - if (me == PYTHREAD_INVALID_THREAD_ID) + long me = PyThread_get_thread_ident(); + if (me == -1) return; /* Too bad */ if (import_lock == NULL) { import_lock = PyThread_allocate_lock(); @@ -166,14 +303,12 @@ _PyImport_AcquireLock(void) import_lock_level++; return; } - if (import_lock_thread != PYTHREAD_INVALID_THREAD_ID || - !PyThread_acquire_lock(import_lock, 0)) + if (import_lock_thread != -1 || !PyThread_acquire_lock(import_lock, 0)) { PyThreadState *tstate = PyEval_SaveThread(); PyThread_acquire_lock(import_lock, 1); PyEval_RestoreThread(tstate); } - assert(import_lock_level == 0); import_lock_thread = me; import_lock_level = 1; } @@ -181,21 +316,20 @@ _PyImport_AcquireLock(void) int _PyImport_ReleaseLock(void) { - unsigned long me = PyThread_get_thread_ident(); - if (me == PYTHREAD_INVALID_THREAD_ID || import_lock == NULL) + long me = PyThread_get_thread_ident(); + if (me == -1 || import_lock == NULL) return 0; /* Too bad */ if (import_lock_thread != me) return -1; import_lock_level--; - assert(import_lock_level >= 0); if (import_lock_level == 0) { - import_lock_thread = PYTHREAD_INVALID_THREAD_ID; + import_lock_thread = -1; PyThread_release_lock(import_lock); } return 1; } -/* This function is called from PyOS_AfterFork_Child to ensure that newly +/* This function is called from PyOS_AfterFork to ensure that newly created child processes do not share locks with the parent. We now acquire the import lock around fork() calls but on some platforms (Solaris 9 and earlier? see isue7242) that still left us with problems. */ @@ -209,95 +343,52 @@ _PyImport_ReInitLock(void) Py_FatalError("PyImport_ReInitLock failed to create a new lock"); } } - if (import_lock_level > 1) { - /* Forked as a side effect of import */ - unsigned long me = PyThread_get_thread_ident(); - /* The following could fail if the lock is already held, but forking as - a side-effect of an import is a) rare, b) nuts, and c) difficult to - do thanks to the lock only being held when doing individual module - locks per import. */ - PyThread_acquire_lock(import_lock, NOWAIT_LOCK); - import_lock_thread = me; - import_lock_level--; - } else { - import_lock_thread = PYTHREAD_INVALID_THREAD_ID; - import_lock_level = 0; - } + import_lock_thread = -1; + import_lock_level = 0; } -/*[clinic input] -_imp.lock_held - -Return True if the import lock is currently held, else False. - -On platforms without threads, return False. -[clinic start generated code]*/ +#endif static PyObject * -_imp_lock_held_impl(PyObject *module) -/*[clinic end generated code: output=8b89384b5e1963fc input=9b088f9b217d9bdf]*/ +imp_lock_held(PyObject *self, PyObject *noargs) { - return PyBool_FromLong(import_lock_thread != PYTHREAD_INVALID_THREAD_ID); +#ifdef WITH_THREAD + return PyBool_FromLong(import_lock_thread != -1); +#else + return PyBool_FromLong(0); +#endif } -/*[clinic input] -_imp.acquire_lock - -Acquires the interpreter's import lock for the current thread. - -This lock should be used by import hooks to ensure thread-safety when importing -modules. On platforms without threads, this function does nothing. -[clinic start generated code]*/ - static PyObject * -_imp_acquire_lock_impl(PyObject *module) -/*[clinic end generated code: output=1aff58cb0ee1b026 input=4a2d4381866d5fdc]*/ +imp_acquire_lock(PyObject *self, PyObject *noargs) { +#ifdef WITH_THREAD _PyImport_AcquireLock(); - Py_RETURN_NONE; +#endif + Py_INCREF(Py_None); + return Py_None; } -/*[clinic input] -_imp.release_lock - -Release the interpreter's import lock. - -On platforms without threads, this function does nothing. -[clinic start generated code]*/ - static PyObject * -_imp_release_lock_impl(PyObject *module) -/*[clinic end generated code: output=7faab6d0be178b0a input=934fb11516dd778b]*/ +imp_release_lock(PyObject *self, PyObject *noargs) { +#ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { PyErr_SetString(PyExc_RuntimeError, "not holding the import lock"); return NULL; } - Py_RETURN_NONE; -} - -void -_PyImport_Fini(void) -{ - Py_CLEAR(extensions); - if (import_lock != NULL) { - PyThread_free_lock(import_lock); - import_lock = NULL; - } +#endif + Py_INCREF(Py_None); + return Py_None; } -void -_PyImport_Fini2(void) +static void +imp_modules_reloading_clear(void) { - /* Use the same memory allocator than PyImport_ExtendInittab(). */ - PyMemAllocatorEx old_alloc; - _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - - /* Free memory allocated by PyImport_ExtendInittab() */ - PyMem_RawFree(inittab_copy); - - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules_reloading != NULL) + PyDict_Clear(interp->modules_reloading); } /* Helper for sys */ @@ -305,135 +396,45 @@ _PyImport_Fini2(void) PyObject * PyImport_GetModuleDict(void) { - PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE(); - if (interp->modules == NULL) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + if (interp->modules == NULL) Py_FatalError("PyImport_GetModuleDict: no module dictionary!"); - } return interp->modules; } -/* In some corner cases it is important to be sure that the import - machinery has been initialized (or not cleaned up yet). For - example, see issue #4236 and PyModule_Create2(). */ - -int -_PyImport_IsInitialized(PyInterpreterState *interp) -{ - if (interp->modules == NULL) - return 0; - return 1; -} - -PyObject * -_PyImport_GetModuleId(struct _Py_Identifier *nameid) -{ - PyObject *name = _PyUnicode_FromId(nameid); /* borrowed */ - if (name == NULL) { - return NULL; - } - return PyImport_GetModule(name); -} - -int -_PyImport_SetModule(PyObject *name, PyObject *m) -{ - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *modules = tstate->interp->modules; - return PyObject_SetItem(modules, name, m); -} - -int -_PyImport_SetModuleString(const char *name, PyObject *m) -{ - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *modules = tstate->interp->modules; - return PyMapping_SetItemString(modules, name, m); -} - -static PyObject * -import_get_module(PyThreadState *tstate, PyObject *name) -{ - PyObject *modules = tstate->interp->modules; - if (modules == NULL) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "unable to get sys.modules"); - return NULL; - } - - PyObject *m; - Py_INCREF(modules); - if (PyDict_CheckExact(modules)) { - m = PyDict_GetItemWithError(modules, name); /* borrowed */ - Py_XINCREF(m); - } - else { - m = PyObject_GetItem(modules, name); - if (m == NULL && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - _PyErr_Clear(tstate); - } - } - Py_DECREF(modules); - return m; -} - - -static int -import_ensure_initialized(PyThreadState *tstate, PyObject *mod, PyObject *name) -{ - PyInterpreterState *interp = tstate->interp; - PyObject *spec; - - _Py_IDENTIFIER(__spec__); - _Py_IDENTIFIER(_lock_unlock_module); - - /* Optimization: only call _bootstrap._lock_unlock_module() if - __spec__._initializing is true. - NOTE: because of this, initializing must be set *before* - stuffing the new module in sys.modules. - */ - spec = _PyObject_GetAttrId(mod, &PyId___spec__); - int busy = _PyModuleSpec_IsInitializing(spec); - Py_XDECREF(spec); - if (busy) { - /* Wait until module is done importing. */ - PyObject *value = _PyObject_CallMethodIdOneArg( - interp->importlib, &PyId__lock_unlock_module, name); - if (value == NULL) { - return -1; - } - Py_DECREF(value); - } - return 0; -} - /* List of names to clear in sys */ -static const char * const sys_deletes[] = { - "path", "argv", "ps1", "ps2", +static char* sys_deletes[] = { + "path", "argv", "ps1", "ps2", "exitfunc", + "exc_type", "exc_value", "exc_traceback", "last_type", "last_value", "last_traceback", "path_hooks", "path_importer_cache", "meta_path", - "__interactivehook__", + /* misc stuff */ + "flags", "float_info", NULL }; -static const char * const sys_files[] = { +static char* sys_files[] = { "stdin", "__stdin__", "stdout", "__stdout__", "stderr", "__stderr__", NULL }; + /* Un-initialize things, as good as we can */ void -_PyImport_Cleanup(PyThreadState *tstate) +PyImport_Cleanup(void) { - PyInterpreterState *interp = tstate->interp; + Py_ssize_t pos, ndone; + char *name; + PyObject *key, *value, *dict; + PyInterpreterState *interp = PyThreadState_GET()->interp; PyObject *modules = interp->modules; - if (modules == NULL) { - /* Already done */ - return; - } + + if (modules == NULL) + return; /* Already done */ /* Delete some special variables first. These are common places where user values hide and people complain when their @@ -441,400 +442,212 @@ _PyImport_Cleanup(PyThreadState *tstate) deleted *last* of all, they would come too late in the normal destruction order. Sigh. */ - /* XXX Perhaps these precautions are obsolete. Who knows? */ - - int verbose = interp->config.verbose; - if (verbose) { - PySys_WriteStderr("# clear builtins._\n"); - } - if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) { - PyErr_WriteUnraisable(NULL); - } - - const char * const *p; - for (p = sys_deletes; *p != NULL; p++) { - if (verbose) { - PySys_WriteStderr("# clear sys.%s\n", *p); - } - if (PyDict_SetItemString(interp->sysdict, *p, Py_None) < 0) { - PyErr_WriteUnraisable(NULL); + value = PyDict_GetItemString(modules, "__builtin__"); + if (value != NULL && PyModule_Check(value)) { + dict = PyModule_GetDict(value); + if (Py_VerboseFlag) + PySys_WriteStderr("# clear __builtin__._\n"); + if (PyDict_SetItemString(dict, "_", Py_None) < 0) { + PyErr_Clear(); } } - for (p = sys_files; *p != NULL; p+=2) { - if (verbose) { - PySys_WriteStderr("# restore sys.%s\n", *p); - } - PyObject *value = _PyDict_GetItemStringWithError(interp->sysdict, - *(p+1)); - if (value == NULL) { - if (_PyErr_Occurred(tstate)) { - PyErr_WriteUnraisable(NULL); + value = PyDict_GetItemString(modules, "sys"); + if (value != NULL && PyModule_Check(value)) { + char **p; + PyObject *v; + dict = PyModule_GetDict(value); + for (p = sys_deletes; *p != NULL; p++) { + if (Py_VerboseFlag) + PySys_WriteStderr("# clear sys.%s\n", *p); + if (PyDict_SetItemString(dict, *p, Py_None) < 0) { + PyErr_Clear(); } - value = Py_None; - } - if (PyDict_SetItemString(interp->sysdict, *p, value) < 0) { - PyErr_WriteUnraisable(NULL); - } - } - - /* We prepare a list which will receive (name, weakref) tuples of - modules when they are removed from sys.modules. The name is used - for diagnosis messages (in verbose mode), while the weakref helps - detect those modules which have been held alive. */ - PyObject *weaklist = PyList_New(0); - if (weaklist == NULL) { - PyErr_WriteUnraisable(NULL); - } - -#define STORE_MODULE_WEAKREF(name, mod) \ - if (weaklist != NULL) { \ - PyObject *wr = PyWeakref_NewRef(mod, NULL); \ - if (wr) { \ - PyObject *tup = PyTuple_Pack(2, name, wr); \ - if (!tup || PyList_Append(weaklist, tup) < 0) { \ - PyErr_WriteUnraisable(NULL); \ - } \ - Py_XDECREF(tup); \ - Py_DECREF(wr); \ - } \ - else { \ - PyErr_WriteUnraisable(NULL); \ - } \ - } -#define CLEAR_MODULE(name, mod) \ - if (PyModule_Check(mod)) { \ - if (verbose && PyUnicode_Check(name)) { \ - PySys_FormatStderr("# cleanup[2] removing %U\n", name); \ - } \ - STORE_MODULE_WEAKREF(name, mod); \ - if (PyObject_SetItem(modules, name, Py_None) < 0) { \ - PyErr_WriteUnraisable(NULL); \ - } \ - } - - /* Remove all modules from sys.modules, hoping that garbage collection - can reclaim most of them. */ - if (PyDict_CheckExact(modules)) { - Py_ssize_t pos = 0; - PyObject *key, *value; - while (PyDict_Next(modules, &pos, &key, &value)) { - CLEAR_MODULE(key, value); - } - } - else { - PyObject *iterator = PyObject_GetIter(modules); - if (iterator == NULL) { - PyErr_WriteUnraisable(NULL); } - else { - PyObject *key; - while ((key = PyIter_Next(iterator))) { - PyObject *value = PyObject_GetItem(modules, key); - if (value == NULL) { - PyErr_WriteUnraisable(NULL); - continue; - } - CLEAR_MODULE(key, value); - Py_DECREF(value); - Py_DECREF(key); - } - if (PyErr_Occurred()) { - PyErr_WriteUnraisable(NULL); + for (p = sys_files; *p != NULL; p+=2) { + if (Py_VerboseFlag) + PySys_WriteStderr("# restore sys.%s\n", *p); + v = PyDict_GetItemString(dict, *(p+1)); + if (v == NULL) + v = Py_None; + if (PyDict_SetItemString(dict, *p, v) < 0) { + PyErr_Clear(); } - Py_DECREF(iterator); } } - /* Clear the modules dict. */ - if (PyDict_CheckExact(modules)) { - PyDict_Clear(modules); + /* First, delete __main__ */ + value = PyDict_GetItemString(modules, "__main__"); + if (value != NULL && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup __main__\n"); + _PyModule_Clear(value); + if (PyDict_SetItemString(modules, "__main__", Py_None) < 0) { + PyErr_Clear(); + } } - else { - _Py_IDENTIFIER(clear); - if (_PyObject_CallMethodIdNoArgs(modules, &PyId_clear) == NULL) { - PyErr_WriteUnraisable(NULL); - } - } - /* Restore the original builtins dict, to ensure that any - user data gets cleared. */ - PyObject *dict = PyDict_Copy(interp->builtins); - if (dict == NULL) { - PyErr_WriteUnraisable(NULL); - } - PyDict_Clear(interp->builtins); - if (PyDict_Update(interp->builtins, interp->builtins_copy)) { - _PyErr_Clear(tstate); - } - Py_XDECREF(dict); - /* Clear module dict copies stored in the interpreter state */ - _PyInterpreterState_ClearModules(interp); - /* Collect references */ - _PyGC_CollectNoFail(); - /* Dump GC stats before it's too late, since it uses the warnings - machinery. */ - _PyGC_DumpShutdownStats(tstate); - - /* Now, if there are any modules left alive, clear their globals to - minimize potential leaks. All C extension modules actually end - up here, since they are kept alive in the interpreter state. - - The special treatment of "builtins" here is because even + + /* The special treatment of __builtin__ here is because even when it's not referenced as a module, its dictionary is referenced by almost every module's __builtins__. Since deleting a module clears its dictionary (even if there are - references left to it), we need to delete the "builtins" + references left to it), we need to delete the __builtin__ module last. Likewise, we don't delete sys until the very - end because it is implicitly referenced (e.g. by print). */ - if (weaklist != NULL) { - Py_ssize_t i; - /* Since dict is ordered in CPython 3.6+, modules are saved in - importing order. First clear modules imported later. */ - for (i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) { - PyObject *tup = PyList_GET_ITEM(weaklist, i); - PyObject *name = PyTuple_GET_ITEM(tup, 0); - PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); - if (mod == Py_None) + end because it is implicitly referenced (e.g. by print). + + Also note that we 'delete' modules by replacing their entry + in the modules dict with None, rather than really deleting + them; this avoids a rehash of the modules dictionary and + also marks them as "non existent" so they won't be + re-imported. */ + + /* Next, repeatedly delete modules with a reference count of + one (skipping __builtin__ and sys) and delete them */ + do { + ndone = 0; + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (value->ob_refcnt != 1) + continue; + if (PyString_Check(key) && PyModule_Check(value)) { + name = PyString_AS_STRING(key); + if (strcmp(name, "__builtin__") == 0) + continue; + if (strcmp(name, "sys") == 0) + continue; + if (Py_VerboseFlag) + PySys_WriteStderr( + "# cleanup[1] %s\n", name); + _PyModule_Clear(value); + if (PyDict_SetItem(modules, key, Py_None) < 0) { + PyErr_Clear(); + } + ndone++; + } + } + if (PyErr_Occurred()) { + PyErr_Clear(); + } + } while (ndone > 0); + + /* Next, delete all modules (still skipping __builtin__ and sys) */ + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (PyString_Check(key) && PyModule_Check(value)) { + name = PyString_AS_STRING(key); + if (strcmp(name, "__builtin__") == 0) continue; - assert(PyModule_Check(mod)); - dict = PyModule_GetDict(mod); - if (dict == interp->builtins || dict == interp->sysdict) + if (strcmp(name, "sys") == 0) continue; - Py_INCREF(mod); - if (verbose && PyUnicode_Check(name)) { - PySys_FormatStderr("# cleanup[3] wiping %U\n", name); + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup[2] %s\n", name); + _PyModule_Clear(value); + if (PyDict_SetItem(modules, key, Py_None) < 0) { + PyErr_Clear(); } - _PyModule_Clear(mod); - Py_DECREF(mod); } - Py_DECREF(weaklist); + if (PyErr_Occurred()) { + PyErr_Clear(); + } } - /* Next, delete sys and builtins (in that order) */ - if (verbose) { - PySys_FormatStderr("# cleanup[3] wiping sys\n"); + /* Next, delete sys and __builtin__ (in that order) */ + value = PyDict_GetItemString(modules, "sys"); + if (value != NULL && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup sys\n"); + _PyModule_Clear(value); + if (PyDict_SetItemString(modules, "sys", Py_None) < 0) { + PyErr_Clear(); + } } - _PyModule_ClearDict(interp->sysdict); - if (verbose) { - PySys_FormatStderr("# cleanup[3] wiping builtins\n"); + value = PyDict_GetItemString(modules, "__builtin__"); + if (value != NULL && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup __builtin__\n"); + _PyModule_Clear(value); + if (PyDict_SetItemString(modules, "__builtin__", Py_None) < 0) { + PyErr_Clear(); + } } - _PyModule_ClearDict(interp->builtins); - /* Clear and delete the modules directory. Actual modules will - still be there only if imported during the execution of some - destructor. */ + /* Finally, clear and delete the modules directory */ + PyDict_Clear(modules); interp->modules = NULL; Py_DECREF(modules); - - /* Once more */ - _PyGC_CollectNoFail(); - -#undef CLEAR_MODULE -#undef STORE_MODULE_WEAKREF + Py_CLEAR(interp->modules_reloading); } -/* Helper for pythonrun.c -- return magic number and tag. */ +/* Helper for pythonrun.c -- return magic number */ long PyImport_GetMagicNumber(void) { - long res; - PyInterpreterState *interp = _PyInterpreterState_Get(); - PyObject *external, *pyc_magic; - - external = PyObject_GetAttrString(interp->importlib, "_bootstrap_external"); - if (external == NULL) - return -1; - pyc_magic = PyObject_GetAttrString(external, "_RAW_MAGIC_NUMBER"); - Py_DECREF(external); - if (pyc_magic == NULL) - return -1; - res = PyLong_AsLong(pyc_magic); - Py_DECREF(pyc_magic); - return res; -} - - -extern const char * _PySys_ImplCacheTag; - -const char * -PyImport_GetMagicTag(void) -{ - return _PySys_ImplCacheTag; + return pyc_magic; } /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than - once, we keep a static dictionary 'extensions' keyed by the tuple - (module name, module name) (for built-in modules) or by - (filename, module name) (for dynamically loaded modules), containing these - modules. A copy of the module's dictionary is stored by calling - _PyImport_FixupExtensionObject() immediately after the module initialization - function succeeds. A copy can be retrieved from there by calling - _PyImport_FindExtensionObject(). - - Modules which do support multiple initialization set their m_size - field to a non-negative number (indicating the size of the - module-specific state). They are still recorded in the extensions - dictionary, to avoid loading shared libraries twice. -*/ - -int -_PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, - PyObject *filename, PyObject *modules) -{ - if (mod == NULL || !PyModule_Check(mod)) { - PyErr_BadInternalCall(); - return -1; - } - - struct PyModuleDef *def = PyModule_GetDef(mod); - if (!def) { - PyErr_BadInternalCall(); - return -1; - } - - PyThreadState *tstate = _PyThreadState_GET(); - if (PyObject_SetItem(modules, name, mod) < 0) { - return -1; - } - if (_PyState_AddModule(tstate, mod, def) < 0) { - PyMapping_DelItem(modules, name); - return -1; - } - - if (_Py_IsMainInterpreter(tstate)) { - if (def->m_size == -1) { - if (def->m_base.m_copy) { - /* Somebody already imported the module, - likely under a different name. - XXX this should really not happen. */ - Py_CLEAR(def->m_base.m_copy); - } - PyObject *dict = PyModule_GetDict(mod); - if (dict == NULL) { - return -1; - } - def->m_base.m_copy = PyDict_Copy(dict); - if (def->m_base.m_copy == NULL) { - return -1; - } - } + once, we keep a static dictionary 'extensions' keyed by module name + (for built-in modules) or by filename (for dynamically loaded + modules), containing these modules. A copy of the module's + dictionary is stored by calling _PyImport_FixupExtension() + immediately after the module initialization function succeeds. A + copy can be retrieved from there by calling + _PyImport_FindExtension(). */ - if (extensions == NULL) { - extensions = PyDict_New(); - if (extensions == NULL) { - return -1; - } - } - - PyObject *key = PyTuple_Pack(2, filename, name); - if (key == NULL) { - return -1; - } - int res = PyDict_SetItem(extensions, key, (PyObject *)def); - Py_DECREF(key); - if (res < 0) { - return -1; - } - } - - return 0; -} - -int -_PyImport_FixupBuiltin(PyObject *mod, const char *name, PyObject *modules) -{ - int res; - PyObject *nameobj; - nameobj = PyUnicode_InternFromString(name); - if (nameobj == NULL) - return -1; - res = _PyImport_FixupExtensionObject(mod, nameobj, nameobj, modules); - Py_DECREF(nameobj); - return res; -} - -static PyObject * -import_find_extension(PyThreadState *tstate, PyObject *name, - PyObject *filename) +PyObject * +_PyImport_FixupExtension(char *name, char *filename) { + PyObject *modules, *mod, *dict, *copy; if (extensions == NULL) { - return NULL; + extensions = PyDict_New(); + if (extensions == NULL) + return NULL; } - - PyObject *key = PyTuple_Pack(2, filename, name); - if (key == NULL) { + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, name); + if (mod == NULL || !PyModule_Check(mod)) { + PyErr_Format(PyExc_SystemError, + "_PyImport_FixupExtension: module %.200s not loaded", name); return NULL; } - PyModuleDef* def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); - Py_DECREF(key); - if (def == NULL) { + dict = PyModule_GetDict(mod); + if (dict == NULL) return NULL; - } - - PyObject *mod, *mdict; - PyObject *modules = tstate->interp->modules; - - if (def->m_size == -1) { - /* Module does not support repeated initialization */ - if (def->m_base.m_copy == NULL) - return NULL; - mod = import_add_module(tstate, name); - if (mod == NULL) - return NULL; - mdict = PyModule_GetDict(mod); - if (mdict == NULL) - return NULL; - if (PyDict_Update(mdict, def->m_base.m_copy)) - return NULL; - } - else { - if (def->m_base.m_init == NULL) - return NULL; - mod = def->m_base.m_init(); - if (mod == NULL) - return NULL; - if (PyObject_SetItem(modules, name, mod) == -1) { - Py_DECREF(mod); - return NULL; - } - Py_DECREF(mod); - } - if (_PyState_AddModule(tstate, mod, def) < 0) { - PyMapping_DelItem(modules, name); + copy = PyDict_Copy(dict); + if (copy == NULL) return NULL; - } - - int verbose = tstate->interp->config.verbose; - if (verbose) { - PySys_FormatStderr("import %U # previously loaded (%R)\n", - name, filename); - } - return mod; + PyDict_SetItemString(extensions, filename, copy); + Py_DECREF(copy); + return copy; } PyObject * -_PyImport_FindExtensionObject(PyObject *name, PyObject *filename) +_PyImport_FindExtension(char *name, char *filename) { - PyThreadState *tstate = _PyThreadState_GET(); - return import_find_extension(tstate, name, filename); -} - - -PyObject * -_PyImport_FindBuiltin(PyThreadState *tstate, const char *name) -{ - PyObject *res, *nameobj; - nameobj = PyUnicode_InternFromString(name); - if (nameobj == NULL) + PyObject *dict, *mod, *mdict; + if (extensions == NULL) return NULL; - res = import_find_extension(tstate, nameobj, nameobj); - Py_DECREF(nameobj); - return res; + dict = PyDict_GetItemString(extensions, filename); + if (dict == NULL) + return NULL; + mod = PyImport_AddModule(name); + if (mod == NULL) + return NULL; + mdict = PyModule_GetDict(mod); + if (mdict == NULL) + return NULL; + if (PyDict_Update(mdict, dict)) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # previously loaded (%s)\n", + name, filename); + return mod; } + /* Get the module object corresponding to a module name. First check the modules dictionary if there's one there, if not, create a new one and insert it in the modules dictionary. @@ -842,259 +655,356 @@ _PyImport_FindBuiltin(PyThreadState *tstate, const char *name) 'NEW' REFERENCE! */ static PyObject * -import_add_module(PyThreadState *tstate, PyObject *name) +_PyImport_AddModuleObject(PyObject *name) { - PyObject *modules = tstate->interp->modules; - if (modules == NULL) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "no import module dictionary"); - return NULL; - } - + PyObject *modules = PyImport_GetModuleDict(); PyObject *m; - if (PyDict_CheckExact(modules)) { - m = PyDict_GetItemWithError(modules, name); - } - else { - m = PyObject_GetItem(modules, name); - // For backward-compatibility we copy the behavior - // of PyDict_GetItemWithError(). - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - _PyErr_Clear(tstate); - } + + if ((m = _PyDict_GetItemWithError(modules, name)) != NULL && + PyModule_Check(m)) { + return m; } - if (_PyErr_Occurred(tstate)) { + if (PyErr_Occurred()) { return NULL; } - if (m != NULL && PyModule_Check(m)) { - return m; - } - m = PyModule_NewObject(name); - if (m == NULL) + m = PyModule_New(PyString_AS_STRING(name)); + if (m == NULL) { return NULL; - if (PyObject_SetItem(modules, name, m) != 0) { + } + if (PyDict_SetItem(modules, name, m) != 0) { Py_DECREF(m); return NULL; } + assert(Py_REFCNT(m) > 1); Py_DECREF(m); /* Yes, it still exists, in modules! */ return m; } PyObject * -PyImport_AddModuleObject(PyObject *name) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return import_add_module(tstate, name); -} - - -PyObject * PyImport_AddModule(const char *name) { - PyObject *nameobj = PyUnicode_FromString(name); - if (nameobj == NULL) { + PyObject *nameobj, *module; + nameobj = PyString_FromString(name); + if (nameobj == NULL) return NULL; - } - PyObject *module = PyImport_AddModuleObject(nameobj); + module = _PyImport_AddModuleObject(nameobj); Py_DECREF(nameobj); return module; } - /* Remove name from sys.modules, if it's there. */ static void -remove_module(PyThreadState *tstate, PyObject *name) +remove_module(const char *name) { - PyObject *type, *value, *traceback; - _PyErr_Fetch(tstate, &type, &value, &traceback); - - PyObject *modules = tstate->interp->modules; - if (!PyMapping_HasKey(modules, name)) { - goto out; - } - if (PyMapping_DelItem(modules, name) < 0) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "deleting key in sys.modules failed"); - _PyErr_ChainExceptions(type, value, traceback); + PyObject *modules = PyImport_GetModuleDict(); + if (PyDict_GetItemString(modules, name) == NULL) return; - } - -out: - _PyErr_Restore(tstate, type, value, traceback); + if (PyDict_DelItemString(modules, name) < 0) + Py_FatalError("import: deleting existing key in " + "sys.modules failed"); } - /* Execute a code object in a module and return the module object * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is * removed from sys.modules, to avoid leaving damaged module objects * in sys.modules. The caller may wish to restore the original * module object (if any) in this case; PyImport_ReloadModule is an * example. - * - * Note that PyImport_ExecCodeModuleWithPathnames() is the preferred, richer - * interface. The other two exist primarily for backward compatibility. */ PyObject * -PyImport_ExecCodeModule(const char *name, PyObject *co) -{ - return PyImport_ExecCodeModuleWithPathnames( - name, co, (char *)NULL, (char *)NULL); -} - -PyObject * -PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) +PyImport_ExecCodeModule(char *name, PyObject *co) { - return PyImport_ExecCodeModuleWithPathnames( - name, co, pathname, (char *)NULL); + return PyImport_ExecCodeModuleEx(name, co, (char *)NULL); } PyObject * -PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, - const char *pathname, - const char *cpathname) +PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname) { - PyObject *m = NULL; - PyObject *nameobj, *pathobj = NULL, *cpathobj = NULL, *external= NULL; + PyObject *modules = PyImport_GetModuleDict(); + PyObject *m, *d, *v; - nameobj = PyUnicode_FromString(name); - if (nameobj == NULL) + m = PyImport_AddModule(name); + if (m == NULL) return NULL; - - if (cpathname != NULL) { - cpathobj = PyUnicode_DecodeFSDefault(cpathname); - if (cpathobj == NULL) + /* If the module is being reloaded, we get the old module back + and re-use its dict to exec the new code. */ + d = PyModule_GetDict(m); + if (PyDict_GetItemString(d, "__builtins__") == NULL) { + if (PyDict_SetItemString(d, "__builtins__", + PyEval_GetBuiltins()) != 0) goto error; } - else - cpathobj = NULL; - + /* Remember the filename as the __file__ attribute */ + v = NULL; if (pathname != NULL) { - pathobj = PyUnicode_DecodeFSDefault(pathname); - if (pathobj == NULL) - goto error; + v = PyString_FromString(pathname); + if (v == NULL) + PyErr_Clear(); } - else if (cpathobj != NULL) { - PyInterpreterState *interp = _PyInterpreterState_GET_UNSAFE(); - _Py_IDENTIFIER(_get_sourcefile); + if (v == NULL) { + v = ((PyCodeObject *)co)->co_filename; + Py_INCREF(v); + } + if (PyDict_SetItemString(d, "__file__", v) != 0) + PyErr_Clear(); /* Not important enough to report */ + Py_DECREF(v); - if (interp == NULL) { - Py_FatalError("PyImport_ExecCodeModuleWithPathnames: " - "no interpreter!"); - } + v = PyEval_EvalCode((PyCodeObject *)co, d, d); + if (v == NULL) + goto error; + Py_DECREF(v); - external= PyObject_GetAttrString(interp->importlib, - "_bootstrap_external"); - if (external != NULL) { - pathobj = _PyObject_CallMethodIdOneArg( - external, &PyId__get_sourcefile, cpathobj); - Py_DECREF(external); - } - if (pathobj == NULL) - PyErr_Clear(); + if ((m = PyDict_GetItemString(modules, name)) == NULL) { + PyErr_Format(PyExc_ImportError, + "Loaded module %.200s not found in sys.modules", + name); + return NULL; } - else - pathobj = NULL; - m = PyImport_ExecCodeModuleObject(nameobj, co, pathobj, cpathobj); -error: - Py_DECREF(nameobj); - Py_XDECREF(pathobj); - Py_XDECREF(cpathobj); + Py_INCREF(m); + return m; + + error: + remove_module(name); + return NULL; } -static PyObject * -module_dict_for_exec(PyThreadState *tstate, PyObject *name) + +/* Given a pathname for a Python source file, fill a buffer with the + pathname for the corresponding compiled file. Return the pathname + for the compiled file, or NULL if there's no space in the buffer. + Doesn't set an exception. */ + +static char * +make_compiled_pathname(char *pathname, char *buf, size_t buflen) { - _Py_IDENTIFIER(__builtins__); - PyObject *m, *d = NULL; + size_t len = strlen(pathname); + if (len+2 > buflen) + return NULL; - m = import_add_module(tstate, name); - if (m == NULL) +#ifdef MS_WINDOWS + /* Treat .pyw as if it were .py. The case of ".pyw" must match + that used in _PyImport_StandardFiletab. */ + if (len >= 4 && strcmp(&pathname[len-4], ".pyw") == 0) + --len; /* pretend 'w' isn't there */ +#endif + memcpy(buf, pathname, len); + buf[len] = Py_OptimizeFlag ? 'o' : 'c'; + buf[len+1] = '\0'; + + return buf; +} + + +/* Given a pathname for a Python source file, its time of last + modification, and a pathname for a compiled file, check whether the + compiled file represents the same version of the source. If so, + return a FILE pointer for the compiled file, positioned just after + the header; if not, return NULL. + Doesn't set an exception. */ + +static FILE * +check_compiled_module(char *pathname, time_t mtime, char *cpathname) +{ + FILE *fp; + long magic; + long pyc_mtime; + + fp = fopen(cpathname, "rb"); + if (fp == NULL) + return NULL; + magic = PyMarshal_ReadLongFromFile(fp); + if (magic != pyc_magic) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad magic\n", cpathname); + fclose(fp); return NULL; - /* If the module is being reloaded, we get the old module back - and re-use its dict to exec the new code. */ - d = PyModule_GetDict(m); - if (_PyDict_GetItemIdWithError(d, &PyId___builtins__) == NULL) { - if (_PyErr_Occurred(tstate) || - _PyDict_SetItemId(d, &PyId___builtins__, - PyEval_GetBuiltins()) != 0) - { - remove_module(tstate, name); - return NULL; - } } - - return d; /* Return a borrowed reference. */ + pyc_mtime = PyMarshal_ReadLongFromFile(fp); + if (pyc_mtime != mtime) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad mtime\n", cpathname); + fclose(fp); + return NULL; + } + if (Py_VerboseFlag) + PySys_WriteStderr("# %s matches %s\n", cpathname, pathname); + return fp; } -static PyObject * -exec_code_in_module(PyThreadState *tstate, PyObject *name, - PyObject *module_dict, PyObject *code_object) + +/* Read a code object from a file and check it for validity */ + +static PyCodeObject * +read_compiled_module(char *cpathname, FILE *fp) { - PyObject *v, *m; + PyObject *co; - v = PyEval_EvalCode(code_object, module_dict, module_dict); - if (v == NULL) { - remove_module(tstate, name); + co = PyMarshal_ReadLastObjectFromFile(fp); + if (co == NULL) + return NULL; + if (!PyCode_Check(co)) { + PyErr_Format(PyExc_ImportError, + "Non-code object in %.200s", cpathname); + Py_DECREF(co); return NULL; } - Py_DECREF(v); + return (PyCodeObject *)co; +} + + +/* Load a module from a compiled file, execute it, and return its + module object WITH INCREMENTED REFERENCE COUNT */ + +static PyObject * +load_compiled_module(char *name, char *cpathname, FILE *fp) +{ + long magic; + PyCodeObject *co; + PyObject *m; - m = import_get_module(tstate, name); - if (m == NULL && !_PyErr_Occurred(tstate)) { - _PyErr_Format(tstate, PyExc_ImportError, - "Loaded module %R not found in sys.modules", - name); + magic = PyMarshal_ReadLongFromFile(fp); + if (magic != pyc_magic) { + PyErr_Format(PyExc_ImportError, + "Bad magic number in %.200s", cpathname); + return NULL; } + (void) PyMarshal_ReadLongFromFile(fp); + co = read_compiled_module(cpathname, fp); + if (co == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # precompiled from %s\n", + name, cpathname); + m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, cpathname); + Py_DECREF(co); return m; } -PyObject* -PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, - PyObject *cpathname) -{ - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *d, *external, *res; - _Py_IDENTIFIER(_fix_up_module); +/* Parse a source file and return the corresponding code object */ - d = module_dict_for_exec(tstate, name); - if (d == NULL) { +static PyCodeObject * +parse_source_module(const char *pathname, FILE *fp) +{ + PyCodeObject *co = NULL; + mod_ty mod; + PyCompilerFlags flags; + PyArena *arena = PyArena_New(); + if (arena == NULL) return NULL; - } - if (pathname == NULL) { - pathname = ((PyCodeObject *)co)->co_filename; + flags.cf_flags = 0; + + mod = PyParser_ASTFromFile(fp, pathname, Py_file_input, 0, 0, &flags, + NULL, arena); + if (mod) { + co = PyAST_Compile(mod, pathname, NULL, arena); } - external = PyObject_GetAttrString(tstate->interp->importlib, - "_bootstrap_external"); - if (external == NULL) + PyArena_Free(arena); + return co; +} + + +/* Helper to open a bytecode file for writing in exclusive mode */ + +static FILE * +open_exclusive(char *filename, mode_t mode) +{ +#if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC) + /* Use O_EXCL to avoid a race condition when another process tries to + write the same file. When that happens, our open() call fails, + which is just fine (since it's only a cache). + XXX If the file exists and is writable but the directory is not + writable, the file will never be written. Oh well. + */ + int fd; + (void) unlink(filename); + fd = open(filename, O_EXCL|O_CREAT|O_WRONLY|O_TRUNC +#ifdef O_BINARY + |O_BINARY /* necessary for Windows */ +#endif +#ifdef __VMS + , mode, "ctxt=bin", "shr=nil" +#else + , mode +#endif + ); + if (fd < 0) return NULL; - res = _PyObject_CallMethodIdObjArgs(external, - &PyId__fix_up_module, - d, name, pathname, cpathname, NULL); - Py_DECREF(external); - if (res != NULL) { - Py_DECREF(res); - res = exec_code_in_module(tstate, name, d, co); - } - return res; + return fdopen(fd, "wb"); +#else + /* Best we can do -- on Windows this can't happen anyway */ + return fopen(filename, "wb"); +#endif } +/* Write a compiled module to a file, placing the time of last + modification of its source into the header. + Errors are ignored, if a write error occurs an attempt is made to + remove the file. */ + +static void +write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, time_t mtime) +{ + FILE *fp; +#ifdef MS_WINDOWS /* since Windows uses different permissions */ + mode_t mode = srcstat->st_mode & ~S_IEXEC; + /* Issue #6074: We ensure user write access, so we can delete it later + * when the source file changes. (On POSIX, this only requires write + * access to the directory, on Windows, we need write access to the file + * as well) + */ + mode |= _S_IWRITE; +#else + mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH; +#endif + + fp = open_exclusive(cpathname, mode); + if (fp == NULL) { + if (Py_VerboseFlag) + PySys_WriteStderr( + "# can't create %s\n", cpathname); + return; + } + PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION); + /* First write a 0 for mtime */ + PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION); + PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION); + if (fflush(fp) != 0 || ferror(fp)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# can't write %s\n", cpathname); + /* Don't keep partial file */ + fclose(fp); + (void) unlink(cpathname); + return; + } + /* Now write the true mtime (as a 32-bit field) */ + fseek(fp, 4L, 0); + assert(mtime <= 0xFFFFFFFF); + PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION); + fflush(fp); + fclose(fp); + if (Py_VerboseFlag) + PySys_WriteStderr("# wrote %s\n", cpathname); +} + static void update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname) { PyObject *constants, *tmp; Py_ssize_t i, n; - if (PyUnicode_Compare(co->co_filename, oldname)) + if (!_PyString_Eq(co->co_filename, oldname)) return; - Py_INCREF(newname); - Py_XSETREF(co->co_filename, newname); + tmp = co->co_filename; + co->co_filename = newname; + Py_INCREF(co->co_filename); + Py_DECREF(tmp); constants = co->co_consts; n = PyTuple_GET_SIZE(constants); @@ -1106,57 +1016,221 @@ update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname) } } -static void -update_compiled_module(PyCodeObject *co, PyObject *newname) +static int +update_compiled_module(PyCodeObject *co, char *pathname) { - PyObject *oldname; + PyObject *oldname, *newname; - if (PyUnicode_Compare(co->co_filename, newname) == 0) - return; + if (strcmp(PyString_AsString(co->co_filename), pathname) == 0) + return 0; + + newname = PyString_FromString(pathname); + if (newname == NULL) + return -1; oldname = co->co_filename; Py_INCREF(oldname); update_code_filenames(co, oldname, newname); Py_DECREF(oldname); + Py_DECREF(newname); + return 1; } -/*[clinic input] -_imp._fix_co_filename +#ifdef MS_WINDOWS - code: object(type="PyCodeObject *", subclass_of="&PyCode_Type") - Code object to change. +/* Seconds between 1.1.1601 and 1.1.1970 */ +static __int64 secs_between_epochs = 11644473600; - path: unicode - File path to use. - / +/* Get mtime from file pointer. */ -Changes code.co_filename to specify the passed-in file path. -[clinic start generated code]*/ +static time_t +win32_mtime(FILE *fp, char *pathname) +{ + __int64 filetime; + HANDLE fh; + BY_HANDLE_FILE_INFORMATION file_information; + + fh = (HANDLE)_get_osfhandle(fileno(fp)); + if (fh == INVALID_HANDLE_VALUE || + !GetFileInformationByHandle(fh, &file_information)) { + PyErr_Format(PyExc_RuntimeError, + "unable to get file status from '%s'", + pathname); + return -1; + } + /* filetime represents the number of 100ns intervals since + 1.1.1601 (UTC). Convert to seconds since 1.1.1970 (UTC). */ + filetime = (__int64)file_information.ftLastWriteTime.dwHighDateTime << 32 | + file_information.ftLastWriteTime.dwLowDateTime; + return filetime / 10000000 - secs_between_epochs; +} + +#endif /* #ifdef MS_WINDOWS */ -static PyObject * -_imp__fix_co_filename_impl(PyObject *module, PyCodeObject *code, - PyObject *path) -/*[clinic end generated code: output=1d002f100235587d input=895ba50e78b82f05]*/ +/* Load a source module from a given file and return its module + object WITH INCREMENTED REFERENCE COUNT. If there's a matching + byte-compiled file, use that instead. */ + +static PyObject * +load_source_module(char *name, char *pathname, FILE *fp) { - update_compiled_module(code, path); + struct stat st; + FILE *fpc; + char *buf; + char *cpathname; + PyCodeObject *co = NULL; + PyObject *m; + time_t mtime; - Py_RETURN_NONE; + if (fstat(fileno(fp), &st) != 0) { + PyErr_Format(PyExc_RuntimeError, + "unable to get file status from '%s'", + pathname); + return NULL; + } + +#ifdef MS_WINDOWS + mtime = win32_mtime(fp, pathname); + if (mtime == (time_t)-1 && PyErr_Occurred()) + return NULL; +#else + mtime = st.st_mtime; +#endif + if (sizeof mtime > 4) { + /* Python's .pyc timestamp handling presumes that the timestamp fits + in 4 bytes. Since the code only does an equality comparison, + ordering is not important and we can safely ignore the higher bits + (collisions are extremely unlikely). + */ + mtime &= 0xFFFFFFFF; + } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } + cpathname = make_compiled_pathname(pathname, buf, + (size_t)MAXPATHLEN + 1); + if (cpathname != NULL && + (fpc = check_compiled_module(pathname, mtime, cpathname))) { + co = read_compiled_module(cpathname, fpc); + fclose(fpc); + if (co == NULL) + goto error_exit; + if (update_compiled_module(co, pathname) < 0) + goto error_exit; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # precompiled from %s\n", + name, cpathname); + pathname = cpathname; + } + else { + co = parse_source_module(pathname, fp); + if (co == NULL) + goto error_exit; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # from %s\n", + name, pathname); + if (cpathname) { + PyObject *ro = PySys_GetObject("dont_write_bytecode"); + int b = (ro == NULL) ? 0 : PyObject_IsTrue(ro); + if (b < 0) + goto error_exit; + if (!b) + write_compiled_module(co, cpathname, &st, mtime); + } + } + m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); + Py_DECREF(co); + + PyMem_FREE(buf); + return m; + +error_exit: + Py_XDECREF(co); + PyMem_FREE(buf); + return NULL; } /* Forward */ -static const struct _frozen * find_frozen(PyObject *); +static PyObject *load_module(char *, FILE *, char *, int, PyObject *); +static struct filedescr *find_module(char *, char *, PyObject *, + char *, size_t, FILE **, PyObject **); +static struct _frozen *find_frozen(char *name); + +/* Load a package and return its module object WITH INCREMENTED + REFERENCE COUNT */ + +static PyObject * +load_package(char *name, char *pathname) +{ + PyObject *m, *d; + PyObject *file = NULL; + PyObject *path = NULL; + int err; + char *buf = NULL; + FILE *fp = NULL; + struct filedescr *fdp; + + m = PyImport_AddModule(name); + if (m == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # directory %s\n", + name, pathname); + d = PyModule_GetDict(m); + file = PyString_FromString(pathname); + if (file == NULL) + goto error; + path = Py_BuildValue("[O]", file); + if (path == NULL) + goto error; + err = PyDict_SetItemString(d, "__file__", file); + if (err == 0) + err = PyDict_SetItemString(d, "__path__", path); + if (err != 0) + goto error; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } + buf[0] = '\0'; + fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL); + if (fdp == NULL) { + if (PyErr_ExceptionMatches(PyExc_ImportError)) { + PyErr_Clear(); + Py_INCREF(m); + } + else + m = NULL; + goto cleanup; + } + m = load_module(name, fp, buf, fdp->type, NULL); + if (fp != NULL) + fclose(fp); + goto cleanup; + + error: + m = NULL; + cleanup: + if (buf) + PyMem_FREE(buf); + Py_XDECREF(path); + Py_XDECREF(file); + return m; +} /* Helper to test for built-in module */ static int -is_builtin(PyObject *name) +is_builtin(char *name) { int i; for (i = 0; PyImport_Inittab[i].name != NULL; i++) { - if (_PyUnicode_EqualToASCIIString(name, PyImport_Inittab[i].name)) { + if (strcmp(name, PyImport_Inittab[i].name) == 0) { if (PyImport_Inittab[i].initfunc == NULL) return -1; else @@ -1167,18 +1241,17 @@ is_builtin(PyObject *name) } -/* Return a finder object for a sys.path/pkg.__path__ item 'p', +/* Return an importer 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 that the path based finder could not find - a finder for this path item. Cache the result in - path_importer_cache. + this tells our caller it should fall back to the builtin + import mechanism. Cache the result in path_importer_cache. Returns a borrowed reference. */ static PyObject * -get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, - PyObject *path_hooks, PyObject *p) +get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks, + PyObject *p) { PyObject *importer; Py_ssize_t j, nhooks; @@ -1191,8 +1264,8 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, if (nhooks < 0) return NULL; /* Shouldn't happen */ - importer = PyDict_GetItemWithError(path_importer_cache, p); - if (importer != NULL || _PyErr_Occurred(tstate)) + importer = PyDict_GetItem(path_importer_cache, p); + if (importer != NULL) return importer; /* set path_importer_cache[p] to None to avoid recursion */ @@ -1203,17 +1276,25 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, PyObject *hook = PyList_GetItem(path_hooks, j); if (hook == NULL) return NULL; - importer = _PyObject_CallOneArg(hook, p); + importer = PyObject_CallFunctionObjArgs(hook, p, NULL); if (importer != NULL) break; - if (!_PyErr_ExceptionMatches(tstate, PyExc_ImportError)) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) { return NULL; } - _PyErr_Clear(tstate); + PyErr_Clear(); } if (importer == NULL) { - return Py_None; + importer = PyObject_CallFunctionObjArgs( + (PyObject *)&PyNullImporter_Type, p, NULL + ); + if (importer == NULL) { + if (PyErr_ExceptionMatches(PyExc_ImportError)) { + PyErr_Clear(); + return Py_None; + } + } } if (importer != NULL) { int err = PyDict_SetItem(path_importer_cache, p, importer); @@ -1224,249 +1305,858 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, return importer; } -PyObject * -PyImport_GetImporter(PyObject *path) -{ - PyThreadState *tstate = _PyThreadState_GET(); +PyAPI_FUNC(PyObject *) +PyImport_GetImporter(PyObject *path) { PyObject *importer=NULL, *path_importer_cache=NULL, *path_hooks=NULL; - path_importer_cache = PySys_GetObject("path_importer_cache"); - path_hooks = PySys_GetObject("path_hooks"); - if (path_importer_cache != NULL && path_hooks != NULL) { - importer = get_path_importer(tstate, path_importer_cache, - path_hooks, path); + if ((path_importer_cache = PySys_GetObject("path_importer_cache"))) { + if ((path_hooks = PySys_GetObject("path_hooks"))) { + importer = get_path_importer(path_importer_cache, + path_hooks, path); + } } Py_XINCREF(importer); /* get_path_importer returns a borrowed reference */ return importer; } -/*[clinic input] -_imp.create_builtin - - spec: object - / +/* Search the path (default sys.path) for a module. Return the + corresponding filedescr struct, and (via return arguments) the + pathname and an open file. Return NULL if the module is not found. */ -Create an extension module. -[clinic start generated code]*/ +#ifdef MS_COREDLL +extern FILE *PyWin_FindRegisteredModule(const char *, struct filedescr **, + char *, Py_ssize_t); +#endif -static PyObject * -_imp_create_builtin(PyObject *module, PyObject *spec) -/*[clinic end generated code: output=ace7ff22271e6f39 input=37f966f890384e47]*/ -{ - PyThreadState *tstate = _PyThreadState_GET(); - struct _inittab *p; - PyObject *name; - const char *namestr; - PyObject *mod; +static int case_ok(char *, Py_ssize_t, Py_ssize_t, char *); +static int find_init_module(char *); /* Forward */ +static struct filedescr importhookdescr = {"", "", IMP_HOOK}; + +static struct filedescr * +find_module(char *fullname, char *subname, PyObject *path, char *buf, + size_t buflen, FILE **p_fp, PyObject **p_loader) +{ + Py_ssize_t i, npath; + size_t len, namelen; + struct filedescr *fdp = NULL; + char *filemode; + FILE *fp = NULL; + PyObject *path_hooks, *path_importer_cache; + static struct filedescr fd_frozen = {"", "", PY_FROZEN}; + static struct filedescr fd_builtin = {"", "", C_BUILTIN}; + static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; + char *name; +#if defined(PYOS_OS2) + size_t saved_len; + size_t saved_namelen; + char *saved_buf = NULL; +#endif + if (p_loader != NULL) + *p_loader = NULL; - name = PyObject_GetAttrString(spec, "name"); + if (strlen(subname) > MAXPATHLEN) { + PyErr_SetString(PyExc_OverflowError, + "module name is too long"); + return NULL; + } + name = PyMem_MALLOC(MAXPATHLEN+1); if (name == NULL) { + PyErr_NoMemory(); return NULL; } + strcpy(name, subname); - mod = _PyImport_FindExtensionObject(name, name); - if (mod || _PyErr_Occurred(tstate)) { - Py_DECREF(name); - Py_XINCREF(mod); - return mod; + /* sys.meta_path import hook */ + if (p_loader != NULL) { + PyObject *meta_path; + + meta_path = PySys_GetObject("meta_path"); + if (meta_path == NULL || !PyList_Check(meta_path)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.meta_path must be a list of " + "import hooks"); + goto error_exit; + } + Py_INCREF(meta_path); /* zap guard */ + npath = PyList_Size(meta_path); + for (i = 0; i < npath; i++) { + PyObject *loader; + PyObject *hook = PyList_GetItem(meta_path, i); + loader = PyObject_CallMethod(hook, "find_module", + "sO", fullname, + path != NULL ? + path : Py_None); + if (loader == NULL) { + Py_DECREF(meta_path); + goto error_exit; /* true error */ + } + if (loader != Py_None) { + /* a loader was found */ + *p_loader = loader; + Py_DECREF(meta_path); + PyMem_FREE(name); + return &importhookdescr; + } + Py_DECREF(loader); + } + Py_DECREF(meta_path); } - namestr = PyUnicode_AsUTF8(name); - if (namestr == NULL) { - Py_DECREF(name); - return NULL; + if (path != NULL && PyString_Check(path)) { + /* The only type of submodule allowed inside a "frozen" + package are other frozen modules or packages. */ + if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) { + PyErr_SetString(PyExc_ImportError, + "full frozen module name too long"); + goto error_exit; + } + strcpy(buf, PyString_AsString(path)); + strcat(buf, "."); + strcat(buf, name); + strcpy(name, buf); + if (find_frozen(name) != NULL) { + strcpy(buf, name); + PyMem_FREE(name); + return &fd_frozen; + } + PyErr_Format(PyExc_ImportError, + "No frozen submodule named %.200s", name); + goto error_exit; } + if (path == NULL) { + if (is_builtin(name)) { + strcpy(buf, name); + PyMem_FREE(name); + return &fd_builtin; + } + if ((find_frozen(name)) != NULL) { + strcpy(buf, name); + PyMem_FREE(name); + return &fd_frozen; + } - PyObject *modules = tstate->interp->modules; - for (p = PyImport_Inittab; p->name != NULL; p++) { - PyModuleDef *def; - if (_PyUnicode_EqualToASCIIString(name, p->name)) { - if (p->initfunc == NULL) { - /* Cannot re-init internal module ("sys" or "builtins") */ - mod = PyImport_AddModule(namestr); - Py_DECREF(name); - return mod; +#ifdef MS_COREDLL + fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); + if (fp != NULL) { + *p_fp = fp; + PyMem_FREE(name); + return fdp; + } +#endif + path = PySys_GetObject("path"); + } + if (path == NULL || !PyList_Check(path)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.path must be a list of directory names"); + goto error_exit; + } + + path_hooks = PySys_GetObject("path_hooks"); + if (path_hooks == NULL || !PyList_Check(path_hooks)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.path_hooks must be a list of " + "import hooks"); + goto error_exit; + } + path_importer_cache = PySys_GetObject("path_importer_cache"); + if (path_importer_cache == NULL || + !PyDict_Check(path_importer_cache)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.path_importer_cache must be a dict"); + goto error_exit; + } + + npath = PyList_Size(path); + namelen = strlen(name); + for (i = 0; i < npath; i++) { + PyObject *copy = NULL; + PyObject *v = PyList_GetItem(path, i); + if (!v) + goto error_exit; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(v)) { + copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL); + if (copy == NULL) + goto error_exit; + v = copy; + } + else +#endif + if (!PyString_Check(v)) + continue; + len = PyString_GET_SIZE(v); + if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) { + Py_XDECREF(copy); + continue; /* Too long */ + } + strcpy(buf, PyString_AS_STRING(v)); + if (strlen(buf) != len) { + Py_XDECREF(copy); + continue; /* v contains '\0' */ + } + + /* sys.path_hooks import hook */ + if (p_loader != NULL) { + PyObject *importer; + + importer = get_path_importer(path_importer_cache, + path_hooks, v); + if (importer == NULL) { + Py_XDECREF(copy); + goto error_exit; } - mod = (*p->initfunc)(); - if (mod == NULL) { - Py_DECREF(name); - return NULL; + /* Note: importer is a borrowed reference */ + if (importer != Py_None) { + PyObject *loader; + loader = PyObject_CallMethod(importer, + "find_module", + "s", fullname); + Py_XDECREF(copy); + if (loader == NULL) + goto error_exit; /* error */ + if (loader != Py_None) { + /* a loader was found */ + *p_loader = loader; + PyMem_FREE(name); + return &importhookdescr; + } + Py_DECREF(loader); + continue; } - if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) { - Py_DECREF(name); - return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec); - } else { - /* Remember pointer to module init function. */ - def = PyModule_GetDef(mod); - if (def == NULL) { - Py_DECREF(name); - return NULL; + } + /* no hook was found, use builtin import */ + + if (len > 0 && buf[len-1] != SEP +#ifdef ALTSEP + && buf[len-1] != ALTSEP +#endif + ) + buf[len++] = SEP; + strcpy(buf+len, name); + len += namelen; + + /* Check for package import (buf holds a directory name, + and there's an __init__ module in that directory */ + if (isdir(buf) && /* it's an existing directory */ + case_ok(buf, len, namelen, name)) { /* case matches */ + if (find_init_module(buf)) { /* and has __init__.py */ + Py_XDECREF(copy); + PyMem_FREE(name); + return &fd_package; + } + else { + char warnstr[MAXPATHLEN+80]; + sprintf(warnstr, "Not importing directory " + "'%.*s': missing __init__.py", + MAXPATHLEN, buf); + if (PyErr_Warn(PyExc_ImportWarning, + warnstr)) { + Py_XDECREF(copy); + goto error_exit; } - def->m_base.m_init = p->initfunc; - if (_PyImport_FixupExtensionObject(mod, name, name, - modules) < 0) { - Py_DECREF(name); - return NULL; + } + } +#if defined(PYOS_OS2) + /* take a snapshot of the module spec for restoration + * after the 8 character DLL hackery + */ + saved_buf = strdup(buf); + saved_len = len; + saved_namelen = namelen; +#endif /* PYOS_OS2 */ + for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { +#if defined(PYOS_OS2) && defined(HAVE_DYNAMIC_LOADING) + /* OS/2 limits DLLs to 8 character names (w/o + extension) + * so if the name is longer than that and its a + * dynamically loaded module we're going to try, + * truncate the name before trying + */ + if (strlen(subname) > 8) { + /* is this an attempt to load a C extension? */ + const struct filedescr *scan; + scan = _PyImport_DynLoadFiletab; + while (scan->suffix != NULL) { + if (!strcmp(scan->suffix, fdp->suffix)) + break; + else + scan++; + } + if (scan->suffix != NULL) { + /* yes, so truncate the name */ + namelen = 8; + len -= strlen(subname) - namelen; + buf[len] = '\0'; + } + } +#endif /* PYOS_OS2 */ + strcpy(buf+len, fdp->suffix); + if (Py_VerboseFlag > 1) + PySys_WriteStderr("# trying %s\n", buf); + filemode = fdp->mode; + if (filemode[0] == 'U') + filemode = "r" PY_STDIOTEXTMODE; + fp = fopen(buf, filemode); + if (fp != NULL) { + if (case_ok(buf, len, namelen, name)) + break; + else { /* continue search */ + fclose(fp); + fp = NULL; } - Py_DECREF(name); - return mod; } +#if defined(PYOS_OS2) + /* restore the saved snapshot */ + strcpy(buf, saved_buf); + len = saved_len; + namelen = saved_namelen; +#endif } +#if defined(PYOS_OS2) + /* don't need/want the module name snapshot anymore */ + if (saved_buf) + { + free(saved_buf); + saved_buf = NULL; + } +#endif + Py_XDECREF(copy); + if (fp != NULL) + break; } - Py_DECREF(name); - Py_RETURN_NONE; + if (fp == NULL) { + PyErr_Format(PyExc_ImportError, + "No module named %.200s", name); + goto error_exit; + } + *p_fp = fp; + PyMem_FREE(name); + return fdp; + +error_exit: + PyMem_FREE(name); + return NULL; } +/* Helpers for main.c + * Find the source file corresponding to a named module + */ +struct filedescr * +_PyImport_FindModule(const char *name, PyObject *path, char *buf, + size_t buflen, FILE **p_fp, PyObject **p_loader) +{ + return find_module((char *) name, (char *) name, path, + buf, buflen, p_fp, p_loader); +} -/* Frozen modules */ +PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr * fd) +{ + return fd->type == PY_SOURCE || fd->type == PY_COMPILED; +} -static const struct _frozen * -find_frozen(PyObject *name) +/* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name) + * The arguments here are tricky, best shown by example: + * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 + * ^ ^ ^ ^ + * |--------------------- buf ---------------------| + * |------------------- len ------------------| + * |------ name -------| + * |----- namelen -----| + * buf is the full path, but len only counts up to (& exclusive of) the + * extension. name is the module name, also exclusive of extension. + * + * We've already done a successful stat() or fopen() on buf, so know that + * there's some match, possibly case-insensitive. + * + * case_ok() is to return 1 if there's a case-sensitive match for + * name, else 0. case_ok() is also to return 1 if envar PYTHONCASEOK + * exists. + * + * case_ok() is used to implement case-sensitive import semantics even + * on platforms with case-insensitive filesystems. It's trivial to implement + * for case-sensitive filesystems. It's pretty much a cross-platform + * nightmare for systems with case-insensitive filesystems. + */ + +/* First we may need a pile of platform-specific header files; the sequence + * of #if's here should match the sequence in the body of case_ok(). + */ +#if defined(MS_WINDOWS) +#include <windows.h> + +#elif defined(DJGPP) +#include <dir.h> + +#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) +#include <sys/types.h> +#include <dirent.h> + +#elif defined(PYOS_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_NOPMAPI +#include <os2.h> + +#elif defined(RISCOS) +#include "oslib/osfscontrol.h" +#endif + +static int +case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name) { - const struct _frozen *p; +/* Pick a platform-specific implementation; the sequence of #if's here should + * match the sequence just above. + */ - if (name == NULL) - return NULL; +/* MS_WINDOWS */ +#if defined(MS_WINDOWS) + WIN32_FIND_DATA data; + HANDLE h; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + h = FindFirstFile(buf, &data); + if (h == INVALID_HANDLE_VALUE) { + PyErr_Format(PyExc_NameError, + "Can't find file for module %.100s\n(filename %.300s)", + name, buf); + return 0; + } + FindClose(h); + return strncmp(data.cFileName, name, namelen) == 0; + +/* DJGPP */ +#elif defined(DJGPP) + struct ffblk ffblk; + int done; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC); + if (done) { + PyErr_Format(PyExc_NameError, + "Can't find file for module %.100s\n(filename %.300s)", + name, buf); + return 0; + } + return strncmp(ffblk.ff_name, name, namelen) == 0; + +/* new-fangled macintosh (macosx) or Cygwin */ +#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) + DIR *dirp; + struct dirent *dp; + char dirname[MAXPATHLEN + 1]; + const int dirlen = len - namelen - 1; /* don't want trailing SEP */ + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + /* Copy the dir component into dirname; substitute "." if empty */ + if (dirlen <= 0) { + dirname[0] = '.'; + dirname[1] = '\0'; + } + else { + assert(dirlen <= MAXPATHLEN); + memcpy(dirname, buf, dirlen); + dirname[dirlen] = '\0'; + } + /* Open the directory and search the entries for an exact match. */ + dirp = opendir(dirname); + if (dirp) { + char *nameWithExt = buf + len - namelen; + while ((dp = readdir(dirp)) != NULL) { + const int thislen = +#ifdef _DIRENT_HAVE_D_NAMELEN + dp->d_namlen; +#else + strlen(dp->d_name); +#endif + if (thislen >= namelen && + strcmp(dp->d_name, nameWithExt) == 0) { + (void)closedir(dirp); + return 1; /* Found */ + } + } + (void)closedir(dirp); + } + return 0 ; /* Not found */ + +/* RISC OS */ +#elif defined(RISCOS) + char canon[MAXPATHLEN+1]; /* buffer for the canonical form of the path */ + char buf2[MAXPATHLEN+2]; + char *nameWithExt = buf+len-namelen; + int canonlen; + os_error *e; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + /* workaround: + append wildcard, otherwise case of filename wouldn't be touched */ + strcpy(buf2, buf); + strcat(buf2, "*"); + + e = xosfscontrol_canonicalise_path(buf2,canon,0,0,MAXPATHLEN+1,&canonlen); + canonlen = MAXPATHLEN+1-canonlen; + if (e || canonlen<=0 || canonlen>(MAXPATHLEN+1) ) + return 0; + if (strcmp(nameWithExt, canon+canonlen-strlen(nameWithExt))==0) + return 1; /* match */ + + return 0; + +/* OS/2 */ +#elif defined(PYOS_OS2) + HDIR hdir = 1; + ULONG srchcnt = 1; + FILEFINDBUF3 ffbuf; + APIRET rc; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + rc = DosFindFirst(buf, + &hdir, + FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, + &ffbuf, sizeof(ffbuf), + &srchcnt, + FIL_STANDARD); + if (rc != NO_ERROR) + return 0; + return strncmp(ffbuf.achName, name, namelen) == 0; + +/* assuming it's a case-sensitive filesystem, so there's nothing to do! */ +#else + return 1; + +#endif +} + + +#ifdef HAVE_STAT +/* Helper to look for __init__.py or __init__.py[co] in potential package */ +static int +find_init_module(char *buf) +{ + const size_t save_len = strlen(buf); + size_t i = save_len; + char *pname; /* pointer to start of __init__ */ + struct stat statbuf; + +/* For calling case_ok(buf, len, namelen, name): + * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 + * ^ ^ ^ ^ + * |--------------------- buf ---------------------| + * |------------------- len ------------------| + * |------ name -------| + * |----- namelen -----| + */ + if (save_len + 13 >= MAXPATHLEN) + return 0; + buf[i++] = SEP; + pname = buf + i; + strcpy(pname, "__init__.py"); + if (stat(buf, &statbuf) == 0) { + if (case_ok(buf, + save_len + 9, /* len("/__init__") */ + 8, /* len("__init__") */ + pname)) { + buf[save_len] = '\0'; + return 1; + } + } + i += strlen(pname); + strcpy(buf+i, Py_OptimizeFlag ? "o" : "c"); + if (stat(buf, &statbuf) == 0) { + if (case_ok(buf, + save_len + 9, /* len("/__init__") */ + 8, /* len("__init__") */ + pname)) { + buf[save_len] = '\0'; + return 1; + } + } + buf[save_len] = '\0'; + return 0; +} + +#else + +#ifdef RISCOS +static int +find_init_module(buf) + char *buf; +{ + int save_len = strlen(buf); + int i = save_len; + + if (save_len + 13 >= MAXPATHLEN) + return 0; + buf[i++] = SEP; + strcpy(buf+i, "__init__/py"); + if (isfile(buf)) { + buf[save_len] = '\0'; + return 1; + } + + if (Py_OptimizeFlag) + strcpy(buf+i, "o"); + else + strcpy(buf+i, "c"); + if (isfile(buf)) { + buf[save_len] = '\0'; + return 1; + } + buf[save_len] = '\0'; + return 0; +} +#endif /*RISCOS*/ + +#endif /* HAVE_STAT */ + + +static int init_builtin(char *); /* Forward */ + +/* Load an external module using the default search path and return + its module object WITH INCREMENTED REFERENCE COUNT */ + +static PyObject * +load_module(char *name, FILE *fp, char *pathname, int type, PyObject *loader) +{ + PyObject *modules; + PyObject *m; + int err; + + /* First check that there's an open file (if we need one) */ + switch (type) { + case PY_SOURCE: + case PY_COMPILED: + if (fp == NULL) { + PyErr_Format(PyExc_ValueError, + "file object required for import (type code %d)", + type); + return NULL; + } + } + + switch (type) { + + case PY_SOURCE: + m = load_source_module(name, pathname, fp); + break; + + case PY_COMPILED: + m = load_compiled_module(name, pathname, fp); + break; + +#ifdef HAVE_DYNAMIC_LOADING + case C_EXTENSION: + m = _PyImport_LoadDynamicModule(name, pathname, fp); + break; +#endif + + case PKG_DIRECTORY: + m = load_package(name, pathname); + break; + + case C_BUILTIN: + case PY_FROZEN: + if (pathname != NULL && pathname[0] != '\0') + name = pathname; + if (type == C_BUILTIN) + err = init_builtin(name); + else + err = PyImport_ImportFrozenModule(name); + if (err < 0) + return NULL; + if (err == 0) { + PyErr_Format(PyExc_ImportError, + "Purported %s module %.200s not found", + type == C_BUILTIN ? + "builtin" : "frozen", + name); + return NULL; + } + modules = PyImport_GetModuleDict(); + m = PyDict_GetItemString(modules, name); + if (m == NULL) { + PyErr_Format( + PyExc_ImportError, + "%s module %.200s not properly initialized", + type == C_BUILTIN ? + "builtin" : "frozen", + name); + return NULL; + } + Py_INCREF(m); + break; + + case IMP_HOOK: { + if (loader == NULL) { + PyErr_SetString(PyExc_ImportError, + "import hook without loader"); + return NULL; + } + m = PyObject_CallMethod(loader, "load_module", "s", name); + break; + } + + default: + PyErr_Format(PyExc_ImportError, + "Don't know how to import %.200s (type code %d)", + name, type); + m = NULL; + + } + + return m; +} + + +/* Initialize a built-in module. + Return 1 for success, 0 if the module is not found, and -1 with + an exception set if the initialization failed. */ + +static int +init_builtin(char *name) +{ + struct _inittab *p; + + if (_PyImport_FindExtension(name, name) != NULL) + return 1; + + for (p = PyImport_Inittab; p->name != NULL; p++) { + if (strcmp(name, p->name) == 0) { + if (p->initfunc == NULL) { + PyErr_Format(PyExc_ImportError, + "Cannot re-init internal module %.200s", + name); + return -1; + } + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # builtin\n", name); + (*p->initfunc)(); + if (PyErr_Occurred()) + return -1; + if (_PyImport_FixupExtension(name, name) == NULL) + return -1; + return 1; + } + } + return 0; +} + + +/* Frozen modules */ + +static struct _frozen * +find_frozen(char *name) +{ + struct _frozen *p; for (p = PyImport_FrozenModules; ; p++) { if (p->name == NULL) return NULL; - if (_PyUnicode_EqualToASCIIString(name, p->name)) + if (strcmp(p->name, name) == 0) break; } return p; } static PyObject * -get_frozen_object(PyObject *name) +get_frozen_object(char *name) { - const struct _frozen *p = find_frozen(name); + struct _frozen *p = find_frozen(name); int size; if (p == NULL) { PyErr_Format(PyExc_ImportError, - "No such frozen object named %R", + "No such frozen object named %.200s", name); return NULL; } if (p->code == NULL) { PyErr_Format(PyExc_ImportError, - "Excluded frozen object named %R", + "Excluded frozen object named %.200s", name); return NULL; } size = p->size; if (size < 0) size = -size; - return PyMarshal_ReadObjectFromString((const char *)p->code, size); + return PyMarshal_ReadObjectFromString((char *)p->code, size); } -static PyObject * -is_frozen_package(PyObject *name) -{ - const struct _frozen *p = find_frozen(name); - int size; - - if (p == NULL) { - PyErr_Format(PyExc_ImportError, - "No such frozen object named %R", - name); - return NULL; - } - - size = p->size; - - if (size < 0) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - /* Initialize a frozen module. - Return 1 for success, 0 if the module is not found, and -1 with + Return 1 for succes, 0 if the module is not found, and -1 with an exception set if the initialization failed. This function is also used from frozenmain.c */ int -PyImport_ImportFrozenModuleObject(PyObject *name) +PyImport_ImportFrozenModule(char *name) { - PyThreadState *tstate = _PyThreadState_GET(); - const struct _frozen *p; - PyObject *co, *m, *d; + struct _frozen *p = find_frozen(name); + PyObject *co; + PyObject *m; int ispackage; int size; - p = find_frozen(name); - if (p == NULL) return 0; if (p->code == NULL) { - _PyErr_Format(tstate, PyExc_ImportError, - "Excluded frozen object named %R", - name); + PyErr_Format(PyExc_ImportError, + "Excluded frozen object named %.200s", + name); return -1; } size = p->size; ispackage = (size < 0); if (ispackage) size = -size; - co = PyMarshal_ReadObjectFromString((const char *)p->code, size); + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # frozen%s\n", + name, ispackage ? " package" : ""); + co = PyMarshal_ReadObjectFromString((char *)p->code, size); if (co == NULL) return -1; if (!PyCode_Check(co)) { - _PyErr_Format(tstate, PyExc_TypeError, - "frozen object %R is not a code object", - name); + PyErr_Format(PyExc_TypeError, + "frozen object %.200s is not a code object", + name); goto err_return; } if (ispackage) { - /* Set __path__ to the empty list */ - PyObject *l; + /* Set __path__ to the package name */ + PyObject *d, *s; int err; - m = import_add_module(tstate, name); + m = PyImport_AddModule(name); if (m == NULL) goto err_return; d = PyModule_GetDict(m); - l = PyList_New(0); - if (l == NULL) { + s = PyString_InternFromString(name); + if (s == NULL) goto err_return; - } - err = PyDict_SetItemString(d, "__path__", l); - Py_DECREF(l); + err = PyDict_SetItemString(d, "__path__", s); + Py_DECREF(s); if (err != 0) goto err_return; } - d = module_dict_for_exec(tstate, name); - if (d == NULL) { - goto err_return; - } - m = exec_code_in_module(tstate, name, d, co); - if (m == NULL) { + m = PyImport_ExecCodeModuleEx(name, co, "<frozen>"); + if (m == NULL) goto err_return; - } Py_DECREF(co); Py_DECREF(m); return 1; - err_return: Py_DECREF(co); return -1; } -int -PyImport_ImportFrozenModule(const char *name) -{ - PyObject *nameobj; - int ret; - nameobj = PyUnicode_InternFromString(name); - if (nameobj == NULL) - return -1; - ret = PyImport_ImportFrozenModuleObject(nameobj); - Py_DECREF(nameobj); - return ret; -} - /* Import a module, either built-in, frozen, or external, and return its module object WITH INCREMENTED REFERENCE COUNT */ @@ -1477,7 +2167,7 @@ PyImport_ImportModule(const char *name) PyObject *pname; PyObject *result; - pname = PyUnicode_FromString(name); + pname = PyString_FromString(name); if (pname == NULL) return NULL; result = PyImport_Import(pname); @@ -1485,7 +2175,6 @@ PyImport_ImportModule(const char *name) return result; } - /* Import a module without blocking * * At first it tries to fetch the module from sys.modules. If the module was @@ -1498,477 +2187,575 @@ PyImport_ImportModule(const char *name) PyObject * PyImport_ImportModuleNoBlock(const char *name) { - return PyImport_ImportModule(name); -} - - -/* Remove importlib frames from the traceback, - * except in Verbose mode. */ -static void -remove_importlib_frames(PyThreadState *tstate) -{ - const char *importlib_filename = "<frozen importlib._bootstrap>"; - const char *external_filename = "<frozen importlib._bootstrap_external>"; - const char *remove_frames = "_call_with_frames_removed"; - int always_trim = 0; - int in_importlib = 0; - PyObject *exception, *value, *base_tb, *tb; - PyObject **prev_link, **outer_link = NULL; - - /* Synopsis: if it's an ImportError, we trim all importlib chunks - from the traceback. We always trim chunks - which end with a call to "_call_with_frames_removed". */ - - _PyErr_Fetch(tstate, &exception, &value, &base_tb); - if (!exception || tstate->interp->config.verbose) { - goto done; - } - - if (PyType_IsSubtype((PyTypeObject *) exception, - (PyTypeObject *) PyExc_ImportError)) - always_trim = 1; - - prev_link = &base_tb; - tb = base_tb; - while (tb != NULL) { - PyTracebackObject *traceback = (PyTracebackObject *)tb; - PyObject *next = (PyObject *) traceback->tb_next; - PyFrameObject *frame = traceback->tb_frame; - PyCodeObject *code = frame->f_code; - int now_in_importlib; - - assert(PyTraceBack_Check(tb)); - now_in_importlib = _PyUnicode_EqualToASCIIString(code->co_filename, importlib_filename) || - _PyUnicode_EqualToASCIIString(code->co_filename, external_filename); - if (now_in_importlib && !in_importlib) { - /* This is the link to this chunk of importlib tracebacks */ - outer_link = prev_link; - } - in_importlib = now_in_importlib; - - if (in_importlib && - (always_trim || - _PyUnicode_EqualToASCIIString(code->co_name, remove_frames))) { - Py_XINCREF(next); - Py_XSETREF(*outer_link, next); - prev_link = outer_link; - } - else { - prev_link = (PyObject **) &traceback->tb_next; - } - tb = next; - } -done: - _PyErr_Restore(tstate, exception, value, base_tb); -} + PyObject *result; + PyObject *modules; +#ifdef WITH_THREAD + long me; +#endif + /* Try to get the module from sys.modules[name] */ + modules = PyImport_GetModuleDict(); + if (modules == NULL) + return NULL; -static PyObject * -resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level) -{ - _Py_IDENTIFIER(__spec__); - _Py_IDENTIFIER(__package__); - _Py_IDENTIFIER(__path__); - _Py_IDENTIFIER(__name__); - _Py_IDENTIFIER(parent); - PyObject *abs_name; - PyObject *package = NULL; - PyObject *spec; - Py_ssize_t last_dot; - PyObject *base; - int level_up; - - if (globals == NULL) { - _PyErr_SetString(tstate, PyExc_KeyError, "'__name__' not in globals"); - goto error; + result = PyDict_GetItemString(modules, name); + if (result != NULL) { + Py_INCREF(result); + return result; } - if (!PyDict_Check(globals)) { - _PyErr_SetString(tstate, PyExc_TypeError, "globals must be a dict"); - goto error; - } - package = _PyDict_GetItemIdWithError(globals, &PyId___package__); - if (package == Py_None) { - package = NULL; - } - else if (package == NULL && _PyErr_Occurred(tstate)) { - goto error; - } - spec = _PyDict_GetItemIdWithError(globals, &PyId___spec__); - if (spec == NULL && _PyErr_Occurred(tstate)) { - goto error; - } - - if (package != NULL) { - Py_INCREF(package); - if (!PyUnicode_Check(package)) { - _PyErr_SetString(tstate, 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; - } - - 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 { + PyErr_Clear(); } - 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(tstate, PyExc_TypeError, - "__spec__.parent must be a string"); - goto error; - } +#ifdef WITH_THREAD + /* check the import lock + * me might be -1 but I ignore the error here, the lock function + * takes care of the problem */ + me = PyThread_get_thread_ident(); + if (import_lock_thread == -1 || import_lock_thread == me) { + /* no thread or me is holding the lock */ + return PyImport_ImportModule(name); } else { - if (PyErr_WarnEx(PyExc_ImportWarning, - "can't resolve package from __spec__ or __package__, " - "falling back on __name__ and __path__", 1) < 0) { - goto error; - } - - package = _PyDict_GetItemIdWithError(globals, &PyId___name__); - if (package == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_KeyError, - "'__name__' not in globals"); - } - goto error; - } - - Py_INCREF(package); - if (!PyUnicode_Check(package)) { - _PyErr_SetString(tstate, PyExc_TypeError, - "__name__ must be a string"); - goto error; - } + PyErr_Format(PyExc_ImportError, + "Failed to import %.200s because the import lock" + "is held by another thread.", + name); + return NULL; + } +#else + return PyImport_ImportModule(name); +#endif +} - if (_PyDict_GetItemIdWithError(globals, &PyId___path__) == NULL) { - Py_ssize_t dot; +/* Forward declarations for helper routines */ +static PyObject *get_parent(PyObject *globals, char *buf, + Py_ssize_t *p_buflen, int level); +static PyObject *load_next(PyObject *mod, PyObject *altmod, + char **p_name, char *buf, Py_ssize_t *p_buflen); +static int mark_miss(char *name); +static int ensure_fromlist(PyObject *mod, PyObject *fromlist, + char *buf, Py_ssize_t buflen, int recursive); +static PyObject * import_submodule(PyObject *mod, char *name, char *fullname); - if (_PyErr_Occurred(tstate) || PyUnicode_READY(package) < 0) { - goto error; - } +/* The Magnum Opus of dotted-name import :-) */ - dot = PyUnicode_FindChar(package, '.', - 0, PyUnicode_GET_LENGTH(package), -1); - if (dot == -2) { - goto error; - } - else if (dot == -1) { - goto no_parent_error; - } - PyObject *substr = PyUnicode_Substring(package, 0, dot); - if (substr == NULL) { - goto error; - } - Py_SETREF(package, substr); - } - } +static PyObject * +import_module_level(char *name, PyObject *globals, PyObject *locals, + PyObject *fromlist, int level) +{ + char *buf; + Py_ssize_t buflen = 0; + PyObject *parent, *head, *next, *tail; - last_dot = PyUnicode_GET_LENGTH(package); - if (last_dot == 0) { - goto no_parent_error; + if (strchr(name, '/') != NULL +#ifdef MS_WINDOWS + || strchr(name, '\\') != NULL +#endif + ) { + PyErr_SetString(PyExc_ImportError, + "Import by filename is not supported."); + return 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; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } + parent = get_parent(globals, buf, &buflen, level); + if (parent == NULL) + goto error_exit; + + Py_INCREF(parent); + head = load_next(parent, level < 0 ? Py_None : parent, &name, buf, + &buflen); + Py_DECREF(parent); + if (head == NULL) + goto error_exit; + + tail = head; + Py_INCREF(tail); + while (name) { + next = load_next(tail, tail, &name, buf, &buflen); + Py_DECREF(tail); + if (next == NULL) { + Py_DECREF(head); + goto error_exit; } - else if (last_dot == -1) { - _PyErr_SetString(tstate, PyExc_ImportError, - "attempted relative import beyond top-level " - "package"); - goto error; + tail = next; + } + 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 */ + Py_DECREF(tail); + Py_DECREF(head); + PyErr_SetString(PyExc_ValueError, + "Empty module name"); + goto error_exit; + } + + if (fromlist != NULL) { + int b = (fromlist == Py_None) ? 0 : PyObject_IsTrue(fromlist); + if (b < 0) { + Py_DECREF(tail); + Py_DECREF(head); + goto error_exit; } + if (!b) + fromlist = NULL; } - base = PyUnicode_Substring(package, 0, last_dot); - Py_DECREF(package); - if (base == NULL || PyUnicode_GET_LENGTH(name) == 0) { - return base; + if (fromlist == NULL) { + Py_DECREF(tail); + PyMem_FREE(buf); + return head; } - abs_name = PyUnicode_FromFormat("%U.%U", base, name); - Py_DECREF(base); - return abs_name; + Py_DECREF(head); + if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { + Py_DECREF(tail); + goto error_exit; + } - no_parent_error: - _PyErr_SetString(tstate, PyExc_ImportError, - "attempted relative import " - "with no known parent package"); + PyMem_FREE(buf); + return tail; - error: - Py_XDECREF(package); +error_exit: + PyMem_FREE(buf); return NULL; } -static PyObject * -import_find_and_load(PyThreadState *tstate, PyObject *abs_name) +PyObject * +PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals, + PyObject *fromlist, int level) { - _Py_IDENTIFIER(_find_and_load); - PyObject *mod = NULL; - PyInterpreterState *interp = tstate->interp; - int import_time = interp->config.import_time; - static int import_level; - static _PyTime_t accumulated; - - _PyTime_t t1 = 0, accumulated_copy = accumulated; - - PyObject *sys_path = PySys_GetObject("path"); - PyObject *sys_meta_path = PySys_GetObject("meta_path"); - PyObject *sys_path_hooks = PySys_GetObject("path_hooks"); - if (PySys_Audit("import", "OOOOO", - abs_name, Py_None, sys_path ? sys_path : Py_None, - sys_meta_path ? sys_meta_path : Py_None, - sys_path_hooks ? sys_path_hooks : Py_None) < 0) { + PyObject *result; + _PyImport_AcquireLock(); + result = import_module_level(name, globals, locals, fromlist, level); + if (_PyImport_ReleaseLock() < 0) { + Py_XDECREF(result); + PyErr_SetString(PyExc_RuntimeError, + "not holding the import lock"); return NULL; } + return result; +} +/* 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. - /* XOptions is initialized after first some imports. - * So we can't have negative cache before completed initialization. - * Anyway, importlib._find_and_load is much slower than - * _PyDict_GetItemIdWithError(). - */ - if (import_time) { - static int header = 1; - if (header) { - fputs("import time: self [us] | cumulative | imported package\n", - stderr); - header = 0; - } - - import_level++; - t1 = _PyTime_GetPerfCounter(); - accumulated = 0; - } - - if (PyDTrace_IMPORT_FIND_LOAD_START_ENABLED()) - PyDTrace_IMPORT_FIND_LOAD_START(PyUnicode_AsUTF8(abs_name)); - - mod = _PyObject_CallMethodIdObjArgs(interp->importlib, - &PyId__find_and_load, abs_name, - interp->import_func, NULL); - - if (PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED()) - PyDTrace_IMPORT_FIND_LOAD_DONE(PyUnicode_AsUTF8(abs_name), - mod != NULL); + The *name* of the returned package is returned in buf, with the length of + the name in *p_buflen. - if (import_time) { - _PyTime_t cum = _PyTime_GetPerfCounter() - t1; + 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, char *buf, Py_ssize_t *p_buflen, int level) +{ + static PyObject *namestr = NULL; + static PyObject *pathstr = NULL; + static PyObject *pkgstr = NULL; + PyObject *pkgname, *modname, *modpath, *modules, *parent; + int orig_level = level; - import_level--; - fprintf(stderr, "import time: %9ld | %10ld | %*s%s\n", - (long)_PyTime_AsMicroseconds(cum - accumulated, _PyTime_ROUND_CEILING), - (long)_PyTime_AsMicroseconds(cum, _PyTime_ROUND_CEILING), - import_level*2, "", PyUnicode_AsUTF8(abs_name)); + if (globals == NULL || !PyDict_Check(globals) || !level) + return Py_None; - accumulated = accumulated_copy + cum; + if (namestr == NULL) { + namestr = PyString_InternFromString("__name__"); + if (namestr == NULL) + return NULL; + } + if (pathstr == NULL) { + pathstr = PyString_InternFromString("__path__"); + if (pathstr == NULL) + return NULL; + } + if (pkgstr == NULL) { + pkgstr = PyString_InternFromString("__package__"); + if (pkgstr == NULL) + return NULL; } - return mod; -} - -PyObject * -PyImport_GetModule(PyObject *name) -{ - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *mod; + *buf = '\0'; + *p_buflen = 0; + pkgname = PyDict_GetItem(globals, pkgstr); - mod = import_get_module(tstate, name); - if (mod != NULL && mod != Py_None) { - if (import_ensure_initialized(tstate, mod, name) < 0) { - Py_DECREF(mod); - remove_importlib_frames(tstate); + if ((pkgname != NULL) && (pkgname != Py_None)) { + /* __package__ is set, so use it */ + Py_ssize_t len; + if (!PyString_Check(pkgname)) { + PyErr_SetString(PyExc_ValueError, + "__package__ set to non-string"); + return NULL; + } + len = PyString_GET_SIZE(pkgname); + if (len == 0) { + if (level > 0) { + PyErr_SetString(PyExc_ValueError, + "Attempted relative import in non-package"); + return NULL; + } + return Py_None; + } + if (len > MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Package name too long"); return NULL; } + strcpy(buf, PyString_AS_STRING(pkgname)); + } else { + /* __package__ not set, so figure it out and set it */ + modname = PyDict_GetItem(globals, namestr); + if (modname == NULL || !PyString_Check(modname)) + return Py_None; + + modpath = PyDict_GetItem(globals, pathstr); + if (modpath != NULL) { + /* __path__ is set, so modname is already the package name */ + Py_ssize_t len = PyString_GET_SIZE(modname); + int error; + if (len > MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strcpy(buf, PyString_AS_STRING(modname)); + error = PyDict_SetItem(globals, pkgstr, modname); + if (error) { + PyErr_SetString(PyExc_ValueError, + "Could not set __package__"); + return NULL; + } + } else { + /* Normal module, so work out the package name if any */ + char *start = PyString_AS_STRING(modname); + char *lastdot = strrchr(start, '.'); + size_t len; + int error; + if (lastdot == NULL && level > 0) { + PyErr_SetString(PyExc_ValueError, + "Attempted relative import in non-package"); + return NULL; + } + if (lastdot == NULL) { + error = PyDict_SetItem(globals, pkgstr, Py_None); + if (error) { + PyErr_SetString(PyExc_ValueError, + "Could not set __package__"); + return NULL; + } + return Py_None; + } + len = lastdot - start; + if (len >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + memcpy(buf, start, len); + buf[len] = '\0'; + pkgname = PyString_FromString(buf); + if (pkgname == NULL) { + return NULL; + } + error = PyDict_SetItem(globals, pkgstr, pkgname); + Py_DECREF(pkgname); + if (error) { + PyErr_SetString(PyExc_ValueError, + "Could not set __package__"); + return NULL; + } + } } - return mod; + while (--level > 0) { + char *dot = strrchr(buf, '.'); + if (dot == NULL) { + PyErr_SetString(PyExc_ValueError, + "Attempted relative import beyond " + "toplevel package"); + return NULL; + } + *dot = '\0'; + } + *p_buflen = strlen(buf); + + modules = PyImport_GetModuleDict(); + parent = PyDict_GetItemString(modules, buf); + if (parent == NULL) { + if (orig_level < 1) { + PyObject *err_msg = PyString_FromFormat( + "Parent module '%.200s' not found " + "while handling absolute import", buf); + if (err_msg == NULL) { + return NULL; + } + if (!PyErr_WarnEx(PyExc_RuntimeWarning, + PyString_AsString(err_msg), 1)) { + *buf = '\0'; + *p_buflen = 0; + parent = Py_None; + } + Py_DECREF(err_msg); + } else { + PyErr_Format(PyExc_SystemError, + "Parent module '%.200s' not loaded, " + "cannot perform relative import", buf); + } + } + return parent; + /* We expect, but can't guarantee, if parent != None, that: + - parent.__name__ == buf + - parent.__dict__ is globals + If this is violated... Who cares? */ } -PyObject * -PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, - PyObject *locals, PyObject *fromlist, - int level) -{ - PyThreadState *tstate = _PyThreadState_GET(); - _Py_IDENTIFIER(_handle_fromlist); - PyObject *abs_name = NULL; - PyObject *final_mod = NULL; - PyObject *mod = NULL; - PyObject *package = NULL; - PyInterpreterState *interp = tstate->interp; - int has_from; +/* altmod is either None or same as mod */ +static PyObject * +load_next(PyObject *mod, PyObject *altmod, char **p_name, char *buf, + Py_ssize_t *p_buflen) +{ + char *name = *p_name; + char *dot = strchr(name, '.'); + size_t len; + char *p; + PyObject *result; - if (name == NULL) { - _PyErr_SetString(tstate, PyExc_ValueError, "Empty module name"); - goto error; + if (strlen(name) == 0) { + /* completely empty module name should only happen in + 'from . import' (or '__import__("")')*/ + Py_INCREF(mod); + *p_name = NULL; + return mod; } - /* The below code is importlib.__import__() & _gcd_import(), ported to C - for added performance. */ - - if (!PyUnicode_Check(name)) { - _PyErr_SetString(tstate, PyExc_TypeError, - "module name must be a string"); - goto error; + if (dot == NULL) { + *p_name = NULL; + len = strlen(name); } - if (PyUnicode_READY(name) < 0) { - goto error; + else { + *p_name = dot+1; + len = dot-name; } - if (level < 0) { - _PyErr_SetString(tstate, PyExc_ValueError, "level must be >= 0"); - goto error; + if (len == 0) { + PyErr_SetString(PyExc_ValueError, + "Empty module name"); + return NULL; } - if (level > 0) { - abs_name = resolve_name(tstate, name, globals, level); - if (abs_name == NULL) - goto error; + p = buf + *p_buflen; + if (p != buf) + *p++ = '.'; + if (p+len-buf >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; } - else { /* level == 0 */ - if (PyUnicode_GET_LENGTH(name) == 0) { - _PyErr_SetString(tstate, PyExc_ValueError, "Empty module name"); - goto error; + memcpy(p, name, len); + p[len] = '\0'; + *p_buflen = p+len-buf; + + result = import_submodule(mod, p, buf); + if (result == Py_None && altmod != mod) { + Py_DECREF(result); + /* Here, altmod must be None and mod must not be None */ + result = import_submodule(altmod, p, p); + if (result != NULL && result != Py_None) { + if (mark_miss(buf) != 0) { + Py_DECREF(result); + return NULL; + } + memcpy(buf, name, len); + buf[len] = '\0'; + *p_buflen = len; } - abs_name = name; - Py_INCREF(abs_name); - } - - mod = import_get_module(tstate, abs_name); - if (mod == NULL && _PyErr_Occurred(tstate)) { - goto error; } + if (result == NULL) + return NULL; - if (mod != NULL && mod != Py_None) { - if (import_ensure_initialized(tstate, mod, name) < 0) { - goto error; - } - } - else { - Py_XDECREF(mod); - mod = import_find_and_load(tstate, abs_name); - if (mod == NULL) { - goto error; - } + if (result == Py_None) { + Py_DECREF(result); + PyErr_Format(PyExc_ImportError, + "No module named %.200s", name); + return NULL; } - has_from = 0; - if (fromlist != NULL && fromlist != Py_None) { - has_from = PyObject_IsTrue(fromlist); - if (has_from < 0) - goto error; - } - if (!has_from) { - Py_ssize_t len = PyUnicode_GET_LENGTH(name); - if (level == 0 || len > 0) { - Py_ssize_t dot; + return result; +} - dot = PyUnicode_FindChar(name, '.', 0, len, 1); - if (dot == -2) { - goto error; - } +static int +mark_miss(char *name) +{ + PyObject *modules = PyImport_GetModuleDict(); + return PyDict_SetItemString(modules, name, Py_None); +} - if (dot == -1) { - /* No dot in module name, simple exit */ - final_mod = mod; - Py_INCREF(mod); - goto error; - } +static int +ensure_fromlist(PyObject *mod, PyObject *fromlist, char *buf, Py_ssize_t buflen, + int recursive) +{ + int i; - if (level == 0) { - PyObject *front = PyUnicode_Substring(name, 0, dot); - if (front == NULL) { - goto error; - } + if (!PyObject_HasAttrString(mod, "__path__")) + return 1; - final_mod = PyImport_ImportModuleLevelObject(front, NULL, NULL, NULL, 0); - Py_DECREF(front); + for (i = 0; ; i++) { + PyObject *item = PySequence_GetItem(fromlist, i); + int hasit; + if (item == NULL) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) { + PyErr_Clear(); + return 1; } + return 0; + } + if (!PyString_Check(item)) { + PyErr_Format(PyExc_TypeError, + "Item in ``from list'' must be str, not %.200s", + Py_TYPE(item)->tp_name); + Py_DECREF(item); + return 0; + } + if (PyString_AS_STRING(item)[0] == '*') { + PyObject *all; + Py_DECREF(item); + /* See if the package defines __all__ */ + if (recursive) + continue; /* Avoid endless recursion */ + all = PyObject_GetAttrString(mod, "__all__"); + if (all == NULL) + PyErr_Clear(); else { - 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); - if (to_return == NULL) { - goto error; - } - - final_mod = import_get_module(tstate, to_return); - Py_DECREF(to_return); - if (final_mod == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_Format(tstate, PyExc_KeyError, - "%R not in sys.modules as expected", - to_return); - } - goto error; - } + int ret = ensure_fromlist(mod, all, buf, buflen, 1); + Py_DECREF(all); + if (!ret) + return 0; } + continue; } - else { - final_mod = mod; - Py_INCREF(mod); + hasit = PyObject_HasAttr(mod, item); + if (!hasit) { + char *subname = PyString_AS_STRING(item); + PyObject *submod; + char *p; + if (buflen + strlen(subname) >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + Py_DECREF(item); + return 0; + } + p = buf + buflen; + *p++ = '.'; + strcpy(p, subname); + submod = import_submodule(mod, subname, buf); + Py_XDECREF(submod); + if (submod == NULL) { + Py_DECREF(item); + return 0; + } } + Py_DECREF(item); + } + + /* NOTREACHED */ +} + +static int +add_submodule(PyObject *mod, PyObject *submod, char *fullname, char *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_GetItemString(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_SetItemString(dict, subname, submod) < 0) + return 0; } else { - _Py_IDENTIFIER(__path__); - PyObject *path; - if (_PyObject_LookupAttrId(mod, &PyId___path__, &path) < 0) { - goto error; + if (PyObject_SetAttrString(mod, subname, submod) < 0) + return 0; + } + return 1; +} + +static PyObject * +import_submodule(PyObject *mod, char *subname, char *fullname) +{ + PyObject *modules = PyImport_GetModuleDict(); + PyObject *m = NULL; + + /* Require: + if mod == None: subname == fullname + else: mod.__name__ + "." + subname == fullname + */ + + if ((m = PyDict_GetItemString(modules, fullname)) != NULL) { + Py_INCREF(m); + } + else { + PyObject *path, *loader = NULL; + char *buf; + struct filedescr *fdp; + FILE *fp = NULL; + + if (mod == Py_None) + path = NULL; + else { + path = PyObject_GetAttrString(mod, "__path__"); + if (path == NULL) { + PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } } - if (path) { - Py_DECREF(path); - final_mod = _PyObject_CallMethodIdObjArgs( - interp->importlib, &PyId__handle_fromlist, - mod, fromlist, interp->import_func, NULL); + + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); } - else { - final_mod = mod; - Py_INCREF(mod); + buf[0] = '\0'; + fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, + &fp, &loader); + Py_XDECREF(path); + if (fdp == NULL) { + PyMem_FREE(buf); + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + return NULL; + PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; } + m = load_module(fullname, fp, buf, fdp->type, loader); + Py_XDECREF(loader); + if (fp) + fclose(fp); + if (!add_submodule(mod, m, fullname, subname, modules)) { + Py_XDECREF(m); + m = NULL; + } + PyMem_FREE(buf); } - error: - Py_XDECREF(abs_name); - Py_XDECREF(mod); - Py_XDECREF(package); - if (final_mod == NULL) { - remove_importlib_frames(tstate); - } - return final_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; + return m; } @@ -1978,24 +2765,103 @@ PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals PyObject * PyImport_ReloadModule(PyObject *m) { - _Py_IDENTIFIER(imp); - _Py_IDENTIFIER(reload); - PyObject *reloaded_module = NULL; - PyObject *imp = _PyImport_GetModuleId(&PyId_imp); - if (imp == NULL) { - if (PyErr_Occurred()) { + PyInterpreterState *interp = PyThreadState_Get()->interp; + PyObject *modules_reloading = interp->modules_reloading; + PyObject *modules = PyImport_GetModuleDict(); + PyObject *path = NULL, *loader = NULL, *existing_m = NULL; + char *name, *subname; + char *buf; + struct filedescr *fdp; + FILE *fp = NULL; + PyObject *newm; + + if (modules_reloading == NULL) { + Py_FatalError("PyImport_ReloadModule: " + "no modules_reloading dictionary!"); + return NULL; + } + + if (m == NULL || !PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "reload() argument must be module"); + return NULL; + } + name = PyModule_GetName(m); + if (name == NULL) + return NULL; + if (m != PyDict_GetItemString(modules, name)) { + PyErr_Format(PyExc_ImportError, + "reload(): module %.200s not in sys.modules", + name); + return NULL; + } + existing_m = PyDict_GetItemString(modules_reloading, name); + if (existing_m != NULL) { + /* Due to a recursive reload, this module is already + being reloaded. */ + Py_INCREF(existing_m); + return existing_m; + } + if (PyDict_SetItemString(modules_reloading, name, m) < 0) + return NULL; + + subname = strrchr(name, '.'); + if (subname == NULL) + subname = name; + else { + PyObject *parentname, *parent; + parentname = PyString_FromStringAndSize(name, (subname-name)); + if (parentname == NULL) { + imp_modules_reloading_clear(); return NULL; } - - imp = PyImport_ImportModule("imp"); - if (imp == NULL) { + parent = PyDict_GetItem(modules, parentname); + if (parent == NULL) { + PyErr_Format(PyExc_ImportError, + "reload(): parent %.200s not in sys.modules", + PyString_AS_STRING(parentname)); + Py_DECREF(parentname); + imp_modules_reloading_clear(); return NULL; } + Py_DECREF(parentname); + subname++; + path = PyObject_GetAttrString(parent, "__path__"); + if (path == NULL) + PyErr_Clear(); + } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + Py_XDECREF(path); + return PyErr_NoMemory(); } + buf[0] = '\0'; + fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); + Py_XDECREF(path); - reloaded_module = _PyObject_CallMethodIdOneArg(imp, &PyId_reload, m); - Py_DECREF(imp); - return reloaded_module; + if (fdp == NULL) { + Py_XDECREF(loader); + imp_modules_reloading_clear(); + PyMem_FREE(buf); + return NULL; + } + + newm = load_module(name, fp, buf, fdp->type, loader); + Py_XDECREF(loader); + + if (fp) + fclose(fp); + if (newm == NULL) { + /* load_module probably removed name from modules because of + * the error. Put back the original module object. We're + * going to return NULL in this case regardless of whether + * replacing name succeeds, so the return value is ignored. + */ + PyDict_SetItemString(modules, name, m); + } + imp_modules_reloading_clear(); + PyMem_FREE(buf); + return newm; } @@ -2003,15 +2869,14 @@ PyImport_ReloadModule(PyObject *m) more accurately -- it invokes the __import__() function from the builtins of the current globals. This means that the import is done using whatever import hooks are installed in the current - environment. + environment, e.g. by "rexec". A dummy list ["__doc__"] is passed as the 4th argument so that - e.g. PyImport_Import(PyUnicode_FromString("win32com.client.gencache")) + e.g. PyImport_Import(PyString_FromString("win32com.client.gencache")) will return <module "gencache"> instead of <module "win32com">. */ PyObject * PyImport_Import(PyObject *module_name) { - PyThreadState *tstate = _PyThreadState_GET(); static PyObject *silly_list = NULL; static PyObject *builtins_str = NULL; static PyObject *import_str = NULL; @@ -2022,13 +2887,13 @@ PyImport_Import(PyObject *module_name) /* Initialize constant string objects */ if (silly_list == NULL) { - import_str = PyUnicode_InternFromString("__import__"); + import_str = PyString_InternFromString("__import__"); if (import_str == NULL) return NULL; - builtins_str = PyUnicode_InternFromString("__builtins__"); + builtins_str = PyString_InternFromString("__builtins__"); if (builtins_str == NULL) return NULL; - silly_list = PyList_New(0); + silly_list = Py_BuildValue("[s]", "__doc__"); if (silly_list == NULL) return NULL; } @@ -2043,7 +2908,7 @@ PyImport_Import(PyObject *module_name) } else { /* No globals -- use standard builtins, and fake globals */ - builtins = PyImport_ImportModuleLevel("builtins", + builtins = PyImport_ImportModuleLevel("__builtin__", NULL, NULL, NULL, 0); if (builtins == NULL) return NULL; @@ -2055,9 +2920,8 @@ PyImport_Import(PyObject *module_name) /* Get the __import__ function from the builtins */ if (PyDict_Check(builtins)) { import = PyObject_GetItem(builtins, import_str); - if (import == NULL) { - _PyErr_SetObject(tstate, PyExc_KeyError, import_str); - } + if (import == NULL) + PyErr_SetObject(PyExc_KeyError, import_str); } else import = PyObject_GetAttr(builtins, import_str); @@ -2065,18 +2929,9 @@ PyImport_Import(PyObject *module_name) goto err; /* Call the __import__ function with the proper argument list - Always use absolute import here. - Calling for side-effect of import. */ + * Always use absolute import here. */ r = PyObject_CallFunction(import, "OOOOi", module_name, globals, globals, silly_list, 0, NULL); - if (r == NULL) - goto err; - Py_DECREF(r); - - r = import_get_module(tstate, module_name); - if (r == NULL && !_PyErr_Occurred(tstate)) { - _PyErr_SetObject(tstate, PyExc_KeyError, module_name); - } err: Py_XDECREF(globals); @@ -2086,27 +2941,36 @@ PyImport_Import(PyObject *module_name) return r; } -/*[clinic input] -_imp.extension_suffixes -Returns the list of file suffixes used to identify extension modules. -[clinic start generated code]*/ +/* Module 'imp' provides Python access to the primitives used for + importing modules. +*/ + +static PyObject * +imp_get_magic(PyObject *self, PyObject *noargs) +{ + char buf[4]; + + buf[0] = (char) ((pyc_magic >> 0) & 0xff); + buf[1] = (char) ((pyc_magic >> 8) & 0xff); + buf[2] = (char) ((pyc_magic >> 16) & 0xff); + buf[3] = (char) ((pyc_magic >> 24) & 0xff); + + return PyString_FromStringAndSize(buf, 4); +} static PyObject * -_imp_extension_suffixes_impl(PyObject *module) -/*[clinic end generated code: output=0bf346e25a8f0cd3 input=ecdeeecfcb6f839e]*/ +imp_get_suffixes(PyObject *self, PyObject *noargs) { PyObject *list; + struct filedescr *fdp; list = PyList_New(0); if (list == NULL) return NULL; -#ifdef HAVE_DYNAMIC_LOADING - const char *suffix; - unsigned int index = 0; - - while ((suffix = _PyImport_DynLoadFiletab[index])) { - PyObject *item = PyUnicode_FromString(suffix); + for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { + PyObject *item = Py_BuildValue("ssi", + fdp->suffix, fdp->mode, fdp->type); if (item == NULL) { Py_DECREF(list); return NULL; @@ -2117,317 +2981,489 @@ _imp_extension_suffixes_impl(PyObject *module) return NULL; } Py_DECREF(item); - index += 1; } -#endif return list; } -/*[clinic input] -_imp.init_frozen +static PyObject * +call_find_module(char *name, PyObject *path) +{ + extern int fclose(FILE *); + PyObject *fob, *ret; + struct filedescr *fdp; + char *pathname; + FILE *fp = NULL; - name: unicode - / + pathname = PyMem_MALLOC(MAXPATHLEN+1); + if (pathname == NULL) { + return PyErr_NoMemory(); + } + pathname[0] = '\0'; + if (path == Py_None) + path = NULL; + fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); + if (fdp == NULL) { + PyMem_FREE(pathname); + return NULL; + } + if (fp != NULL) { + fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose); + if (fob == NULL) { + PyMem_FREE(pathname); + return NULL; + } + } + else { + fob = Py_None; + Py_INCREF(fob); + } + ret = Py_BuildValue("Os(ssi)", + fob, pathname, fdp->suffix, fdp->mode, fdp->type); + Py_DECREF(fob); + PyMem_FREE(pathname); + return ret; +} -Initializes a frozen module. -[clinic start generated code]*/ +static PyObject * +imp_find_module(PyObject *self, PyObject *args) +{ + char *name; + PyObject *path = NULL; + if (!PyArg_ParseTuple(args, "s|O:find_module", &name, &path)) + return NULL; + return call_find_module(name, path); +} static PyObject * -_imp_init_frozen_impl(PyObject *module, PyObject *name) -/*[clinic end generated code: output=fc0511ed869fd69c input=13019adfc04f3fb3]*/ +imp_init_builtin(PyObject *self, PyObject *args) { - PyThreadState *tstate = _PyThreadState_GET(); + char *name; int ret; PyObject *m; - - ret = PyImport_ImportFrozenModuleObject(name); + if (!PyArg_ParseTuple(args, "s:init_builtin", &name)) + return NULL; + ret = init_builtin(name); if (ret < 0) return NULL; if (ret == 0) { - Py_RETURN_NONE; + Py_INCREF(Py_None); + return Py_None; } - m = import_add_module(tstate, name); + m = PyImport_AddModule(name); Py_XINCREF(m); return m; } -/*[clinic input] -_imp.get_frozen_object - - name: unicode - / - -Create a code object for a frozen module. -[clinic start generated code]*/ - static PyObject * -_imp_get_frozen_object_impl(PyObject *module, PyObject *name) -/*[clinic end generated code: output=2568cc5b7aa0da63 input=ed689bc05358fdbd]*/ +imp_init_frozen(PyObject *self, PyObject *args) { - return get_frozen_object(name); + char *name; + int ret; + PyObject *m; + if (!PyArg_ParseTuple(args, "s:init_frozen", &name)) + return NULL; + ret = PyImport_ImportFrozenModule(name); + if (ret < 0) + return NULL; + if (ret == 0) { + Py_INCREF(Py_None); + return Py_None; + } + m = PyImport_AddModule(name); + Py_XINCREF(m); + return m; } -/*[clinic input] -_imp.is_frozen_package - - name: unicode - / - -Returns True if the module name is of a frozen package. -[clinic start generated code]*/ - static PyObject * -_imp_is_frozen_package_impl(PyObject *module, PyObject *name) -/*[clinic end generated code: output=e70cbdb45784a1c9 input=81b6cdecd080fbb8]*/ +imp_get_frozen_object(PyObject *self, PyObject *args) { - return is_frozen_package(name); -} + char *name; -/*[clinic input] -_imp.is_builtin - - name: unicode - / - -Returns True if the module name corresponds to a built-in module. -[clinic start generated code]*/ + if (!PyArg_ParseTuple(args, "s:get_frozen_object", &name)) + return NULL; + return get_frozen_object(name); +} static PyObject * -_imp_is_builtin_impl(PyObject *module, PyObject *name) -/*[clinic end generated code: output=3bfd1162e2d3be82 input=86befdac021dd1c7]*/ +imp_is_builtin(PyObject *self, PyObject *args) { - return PyLong_FromLong(is_builtin(name)); + char *name; + if (!PyArg_ParseTuple(args, "s:is_builtin", &name)) + return NULL; + return PyInt_FromLong(is_builtin(name)); } -/*[clinic input] -_imp.is_frozen - - name: unicode - / - -Returns True if the module name corresponds to a frozen module. -[clinic start generated code]*/ - static PyObject * -_imp_is_frozen_impl(PyObject *module, PyObject *name) -/*[clinic end generated code: output=01f408f5ec0f2577 input=7301dbca1897d66b]*/ +imp_is_frozen(PyObject *self, PyObject *args) { - const struct _frozen *p; - + char *name; + struct _frozen *p; + if (!PyArg_ParseTuple(args, "s:is_frozen", &name)) + return NULL; p = find_frozen(name); return PyBool_FromLong((long) (p == NULL ? 0 : p->size)); } -/* Common implementation for _imp.exec_dynamic and _imp.exec_builtin */ -static int -exec_builtin_or_dynamic(PyObject *mod) { - PyModuleDef *def; - void *state; - - if (!PyModule_Check(mod)) { - return 0; - } - - def = PyModule_GetDef(mod); - if (def == NULL) { - return 0; +static FILE * +get_file(char *pathname, PyObject *fob, char *mode) +{ + FILE *fp; + if (fob == NULL) { + if (mode[0] == 'U') + mode = "r" PY_STDIOTEXTMODE; + fp = fopen(pathname, mode); + if (fp == NULL) + PyErr_SetFromErrno(PyExc_IOError); } - - state = PyModule_GetState(mod); - if (state) { - /* Already initialized; skip reload */ - return 0; + else { + fp = PyFile_AsFile(fob); + if (fp == NULL) + PyErr_SetString(PyExc_ValueError, + "bad/closed file object"); } + return fp; +} - return PyModule_ExecDef(mod, def); +static PyObject * +imp_load_compiled(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + PyObject *fob = NULL; + PyObject *m; + FILE *fp; + if (!PyArg_ParseTuple(args, "ss|O!:load_compiled", &name, &pathname, + &PyFile_Type, &fob)) + return NULL; + fp = get_file(pathname, fob, "rb"); + if (fp == NULL) + return NULL; + m = load_compiled_module(name, pathname, fp); + if (fob == NULL) + fclose(fp); + return m; } #ifdef HAVE_DYNAMIC_LOADING -/*[clinic input] -_imp.create_dynamic - - spec: object - file: object = NULL - / +static PyObject * +imp_load_dynamic(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + PyObject *fob = NULL; + PyObject *m; + FILE *fp = NULL; + if (!PyArg_ParseTuple(args, "ss|O!:load_dynamic", &name, &pathname, + &PyFile_Type, &fob)) + return NULL; + if (fob) { + fp = get_file(pathname, fob, "r"); + if (fp == NULL) + return NULL; + } + m = _PyImport_LoadDynamicModule(name, pathname, fp); + return m; +} -Create an extension module. -[clinic start generated code]*/ +#endif /* HAVE_DYNAMIC_LOADING */ static PyObject * -_imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) -/*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ +imp_load_source(PyObject *self, PyObject *args) { - PyObject *mod, *name, *path; + char *name; + char *pathname; + PyObject *fob = NULL; + PyObject *m; FILE *fp; - - name = PyObject_GetAttrString(spec, "name"); - if (name == NULL) { + if (!PyArg_ParseTuple(args, "ss|O!:load_source", &name, &pathname, + &PyFile_Type, &fob)) return NULL; - } - - path = PyObject_GetAttrString(spec, "origin"); - if (path == NULL) { - Py_DECREF(name); + fp = get_file(pathname, fob, "r"); + if (fp == NULL) return NULL; - } + m = load_source_module(name, pathname, fp); + if (fob == NULL) + fclose(fp); + return m; +} - mod = _PyImport_FindExtensionObject(name, path); - if (mod != NULL || PyErr_Occurred()) { - Py_DECREF(name); - Py_DECREF(path); - Py_XINCREF(mod); - return mod; - } +static PyObject * +imp_load_module(PyObject *self, PyObject *args) +{ + char *name; + PyObject *fob; + char *pathname; + char *suffix; /* Unused */ + char *mode; + int type; + FILE *fp; - if (file != NULL) { - fp = _Py_fopen_obj(path, "r"); - if (fp == NULL) { - Py_DECREF(name); - Py_DECREF(path); + if (!PyArg_ParseTuple(args, "sOs(ssi):load_module", + &name, &fob, &pathname, + &suffix, &mode, &type)) + return NULL; + if (*mode) { + /* Mode must start with 'r' or 'U' and must not contain '+'. + Implicit in this test is the assumption that the mode + may contain other modifiers like 'b' or 't'. */ + + if (!(*mode == 'r' || *mode == 'U') || strchr(mode, '+')) { + PyErr_Format(PyExc_ValueError, + "invalid file open mode %.200s", mode); return NULL; } } - else + if (fob == Py_None) fp = NULL; - - mod = _PyImport_LoadDynamicModuleWithSpec(spec, fp); - - Py_DECREF(name); - Py_DECREF(path); - if (fp) - fclose(fp); - return mod; + else { + if (!PyFile_Check(fob)) { + PyErr_SetString(PyExc_ValueError, + "load_module arg#2 should be a file or None"); + return NULL; + } + fp = get_file(pathname, fob, mode); + if (fp == NULL) + return NULL; + } + return load_module(name, fp, pathname, type, NULL); } -/*[clinic input] -_imp.exec_dynamic -> int - - mod: object - / - -Initialize an extension module. -[clinic start generated code]*/ +static PyObject * +imp_load_package(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + if (!PyArg_ParseTuple(args, "ss:load_package", &name, &pathname)) + return NULL; + return load_package(name, pathname); +} -static int -_imp_exec_dynamic_impl(PyObject *module, PyObject *mod) -/*[clinic end generated code: output=f5720ac7b465877d input=9fdbfcb250280d3a]*/ +static PyObject * +imp_new_module(PyObject *self, PyObject *args) { - return exec_builtin_or_dynamic(mod); + char *name; + if (!PyArg_ParseTuple(args, "s:new_module", &name)) + return NULL; + return PyModule_New(name); } +static PyObject * +imp_reload(PyObject *self, PyObject *v) +{ + return PyImport_ReloadModule(v); +} -#endif /* HAVE_DYNAMIC_LOADING */ -/*[clinic input] -_imp.exec_builtin -> int +/* Doc strings */ - mod: object - / +PyDoc_STRVAR(doc_imp, +"This module provides the components needed to build your own\n\ +__import__ function. Undocumented functions are obsolete."); + +PyDoc_STRVAR(doc_reload, +"reload(module) -> module\n\ +\n\ +Reload the module. The module must have been successfully imported before."); + +PyDoc_STRVAR(doc_find_module, +"find_module(name, [path]) -> (file, filename, (suffix, mode, type))\n\ +Search for a module. If path is omitted or None, search for a\n\ +built-in, frozen or special module and continue search in sys.path.\n\ +The module name cannot contain '.'; to search for a submodule of a\n\ +package, pass the submodule name and the package's __path__."); + +PyDoc_STRVAR(doc_load_module, +"load_module(name, file, filename, (suffix, mode, type)) -> module\n\ +Load a module, given information returned by find_module().\n\ +The module name must include the full package name, if any."); + +PyDoc_STRVAR(doc_get_magic, +"get_magic() -> string\n\ +Return the magic number for .pyc or .pyo files."); + +PyDoc_STRVAR(doc_get_suffixes, +"get_suffixes() -> [(suffix, mode, type), ...]\n\ +Return a list of (suffix, mode, type) tuples describing the files\n\ +that find_module() looks for."); + +PyDoc_STRVAR(doc_new_module, +"new_module(name) -> module\n\ +Create a new module. Do not enter it in sys.modules.\n\ +The module name must include the full package name, if any."); + +PyDoc_STRVAR(doc_lock_held, +"lock_held() -> boolean\n\ +Return True if the import lock is currently held, else False.\n\ +On platforms without threads, return False."); + +PyDoc_STRVAR(doc_acquire_lock, +"acquire_lock() -> None\n\ +Acquires the interpreter's import lock for the current thread.\n\ +This lock should be used by import hooks to ensure thread-safety\n\ +when importing modules.\n\ +On platforms without threads, this function does nothing."); + +PyDoc_STRVAR(doc_release_lock, +"release_lock() -> None\n\ +Release the interpreter's import lock.\n\ +On platforms without threads, this function does nothing."); -Initialize a built-in module. -[clinic start generated code]*/ +static PyMethodDef imp_methods[] = { + {"reload", imp_reload, METH_O, doc_reload}, + {"find_module", imp_find_module, METH_VARARGS, doc_find_module}, + {"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic}, + {"get_suffixes", imp_get_suffixes, METH_NOARGS, doc_get_suffixes}, + {"load_module", imp_load_module, METH_VARARGS, doc_load_module}, + {"new_module", imp_new_module, METH_VARARGS, doc_new_module}, + {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held}, + {"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock}, + {"release_lock", imp_release_lock, METH_NOARGS, doc_release_lock}, + /* The rest are obsolete */ + {"get_frozen_object", imp_get_frozen_object, METH_VARARGS}, + {"init_builtin", imp_init_builtin, METH_VARARGS}, + {"init_frozen", imp_init_frozen, METH_VARARGS}, + {"is_builtin", imp_is_builtin, METH_VARARGS}, + {"is_frozen", imp_is_frozen, METH_VARARGS}, + {"load_compiled", imp_load_compiled, METH_VARARGS}, +#ifdef HAVE_DYNAMIC_LOADING + {"load_dynamic", imp_load_dynamic, METH_VARARGS}, +#endif + {"load_package", imp_load_package, METH_VARARGS}, + {"load_source", imp_load_source, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; static int -_imp_exec_builtin_impl(PyObject *module, PyObject *mod) -/*[clinic end generated code: output=0262447b240c038e input=7beed5a2f12a60ca]*/ +setint(PyObject *d, char *name, int value) { - return exec_builtin_or_dynamic(mod); + PyObject *v; + int err; + + v = PyInt_FromLong((long)value); + err = PyDict_SetItemString(d, name, v); + Py_XDECREF(v); + return err; } -/*[clinic input] -_imp.source_hash +typedef struct { + PyObject_HEAD +} NullImporter; - key: long - source: Py_buffer -[clinic start generated code]*/ +static int +NullImporter_init(NullImporter *self, PyObject *args, PyObject *kwds) +{ + char *path; + Py_ssize_t pathlen; -static PyObject * -_imp_source_hash_impl(PyObject *module, long key, Py_buffer *source) -/*[clinic end generated code: output=edb292448cf399ea input=9aaad1e590089789]*/ -{ - union { - uint64_t x; - char data[sizeof(uint64_t)]; - } hash; - hash.x = _Py_KeyedHash((uint64_t)key, source->buf, source->len); -#if !PY_LITTLE_ENDIAN - // Force to little-endian. There really ought to be a succinct standard way - // to do this. - for (size_t i = 0; i < sizeof(hash.data)/2; i++) { - char tmp = hash.data[i]; - hash.data[i] = hash.data[sizeof(hash.data) - i - 1]; - hash.data[sizeof(hash.data) - i - 1] = tmp; + if (!_PyArg_NoKeywords("NullImporter()", kwds)) + return -1; + + if (!PyArg_ParseTuple(args, "s:NullImporter", + &path)) + return -1; + + pathlen = strlen(path); + if (pathlen == 0) { + PyErr_SetString(PyExc_ImportError, "empty pathname"); + return -1; + } else { + if(isdir(path)) { + PyErr_SetString(PyExc_ImportError, + "existing directory"); + return -1; + } } -#endif - return PyBytes_FromStringAndSize(hash.data, sizeof(hash.data)); + return 0; } +static PyObject * +NullImporter_find_module(NullImporter *self, PyObject *args) +{ + Py_RETURN_NONE; +} -PyDoc_STRVAR(doc_imp, -"(Extremely) low-level import machinery bits as used by importlib and imp."); - -static PyMethodDef imp_methods[] = { - _IMP_EXTENSION_SUFFIXES_METHODDEF - _IMP_LOCK_HELD_METHODDEF - _IMP_ACQUIRE_LOCK_METHODDEF - _IMP_RELEASE_LOCK_METHODDEF - _IMP_GET_FROZEN_OBJECT_METHODDEF - _IMP_IS_FROZEN_PACKAGE_METHODDEF - _IMP_CREATE_BUILTIN_METHODDEF - _IMP_INIT_FROZEN_METHODDEF - _IMP_IS_BUILTIN_METHODDEF - _IMP_IS_FROZEN_METHODDEF - _IMP_CREATE_DYNAMIC_METHODDEF - _IMP_EXEC_DYNAMIC_METHODDEF - _IMP_EXEC_BUILTIN_METHODDEF - _IMP__FIX_CO_FILENAME_METHODDEF - _IMP_SOURCE_HASH_METHODDEF - {NULL, NULL} /* sentinel */ +static PyMethodDef NullImporter_methods[] = { + {"find_module", (PyCFunction)NullImporter_find_module, METH_VARARGS, + "Always return None" + }, + {NULL} /* Sentinel */ }; -static struct PyModuleDef impmodule = { - PyModuleDef_HEAD_INIT, - "_imp", - doc_imp, - 0, - imp_methods, - NULL, - NULL, - NULL, - NULL +PyTypeObject PyNullImporter_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "imp.NullImporter", /*tp_name*/ + sizeof(NullImporter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Null importer object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NullImporter_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)NullImporter_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ }; + PyMODINIT_FUNC -PyInit__imp(void) +initimp(void) { PyObject *m, *d; - m = PyModule_Create(&impmodule); - if (m == NULL) { + if (PyType_Ready(&PyNullImporter_Type) < 0) goto failure; - } - d = PyModule_GetDict(m); - if (d == NULL) { - goto failure; - } - const wchar_t *mode = _PyInterpreterState_Get()->config.check_hash_pycs_mode; - PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1); - if (pyc_mode == NULL) { + m = Py_InitModule4("imp", imp_methods, doc_imp, + NULL, PYTHON_API_VERSION); + if (m == NULL) goto failure; - } - if (PyDict_SetItemString(d, "check_hash_based_pycs", pyc_mode) < 0) { - Py_DECREF(pyc_mode); + d = PyModule_GetDict(m); + if (d == NULL) goto failure; - } - Py_DECREF(pyc_mode); - return m; + if (setint(d, "SEARCH_ERROR", SEARCH_ERROR) < 0) goto failure; + if (setint(d, "PY_SOURCE", PY_SOURCE) < 0) goto failure; + if (setint(d, "PY_COMPILED", PY_COMPILED) < 0) goto failure; + if (setint(d, "C_EXTENSION", C_EXTENSION) < 0) goto failure; + if (setint(d, "PY_RESOURCE", PY_RESOURCE) < 0) goto failure; + if (setint(d, "PKG_DIRECTORY", PKG_DIRECTORY) < 0) goto failure; + if (setint(d, "C_BUILTIN", C_BUILTIN) < 0) goto failure; + if (setint(d, "PY_FROZEN", PY_FROZEN) < 0) goto failure; + if (setint(d, "PY_CODERESOURCE", PY_CODERESOURCE) < 0) goto failure; + if (setint(d, "IMP_HOOK", IMP_HOOK) < 0) goto failure; + + Py_INCREF(&PyNullImporter_Type); + PyModule_AddObject(m, "NullImporter", (PyObject *)&PyNullImporter_Type); failure: - Py_XDECREF(m); - return NULL; + ; } @@ -2441,9 +3477,9 @@ PyInit__imp(void) int PyImport_ExtendInittab(struct _inittab *newtab) { + static struct _inittab *our_copy = NULL; struct _inittab *p; - size_t i, n; - int res = 0; + int i, n; /* Count the number of entries in both tables */ for (n = 0; newtab[n].name != NULL; n++) @@ -2453,45 +3489,31 @@ PyImport_ExtendInittab(struct _inittab *newtab) for (i = 0; PyImport_Inittab[i].name != NULL; i++) ; - /* Force default raw memory allocator to get a known allocator to be able - to release the memory in _PyImport_Fini2() */ - PyMemAllocatorEx old_alloc; - _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - /* Allocate new memory for the combined table */ - p = NULL; - if (i + n <= SIZE_MAX / sizeof(struct _inittab) - 1) { - size_t size = sizeof(struct _inittab) * (i + n + 1); - p = PyMem_RawRealloc(inittab_copy, size); - } - if (p == NULL) { - res = -1; - goto done; - } + p = our_copy; + PyMem_RESIZE(p, struct _inittab, i+n+1); + if (p == NULL) + return -1; - /* Copy the tables into the new memory at the first call - to PyImport_ExtendInittab(). */ - if (inittab_copy != PyImport_Inittab) { + /* Copy the tables into the new memory */ + if (our_copy != PyImport_Inittab) memcpy(p, PyImport_Inittab, (i+1) * sizeof(struct _inittab)); - } - memcpy(p + i, newtab, (n + 1) * sizeof(struct _inittab)); - PyImport_Inittab = inittab_copy = p; + PyImport_Inittab = our_copy = p; + memcpy(p+i, newtab, (n+1) * sizeof(struct _inittab)); -done: - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - return res; + return 0; } /* Shorthand to add a single entry given a name and a function */ int -PyImport_AppendInittab(const char *name, PyObject* (*initfunc)(void)) +PyImport_AppendInittab(const char *name, void (*initfunc)(void)) { struct _inittab newtab[2]; memset(newtab, '\0', sizeof newtab); - newtab[0].name = name; + newtab[0].name = (char *)name; newtab[0].initfunc = initfunc; return PyImport_ExtendInittab(newtab); |