mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Issue #13959: Re-implement imp.find_module() in Lib/imp.py.
Thanks to Eric Snow for taking an initial stab at the implementation.
This commit is contained in:
		
							parent
							
								
									b8c0206bd4
								
							
						
					
					
						commit
						e69f0df45b
					
				
					 2 changed files with 68 additions and 755 deletions
				
			
		
							
								
								
									
										72
									
								
								Lib/imp.py
									
										
									
									
									
								
							
							
						
						
									
										72
									
								
								Lib/imp.py
									
										
									
									
									
								
							|  | @ -15,16 +15,29 @@ | |||
| # Can (probably) move to importlib | ||||
| from _imp import get_suffixes | ||||
| # Should be re-implemented here (and mostly deprecated) | ||||
| from _imp import (find_module, NullImporter, | ||||
|                   SEARCH_ERROR, PY_SOURCE, PY_COMPILED, C_EXTENSION, | ||||
|                   PY_RESOURCE, PKG_DIRECTORY, C_BUILTIN, PY_FROZEN, | ||||
|                   PY_CODERESOURCE, IMP_HOOK) | ||||
| from _imp import NullImporter | ||||
| 
 | ||||
| from importlib._bootstrap import _new_module as new_module | ||||
| from importlib._bootstrap import _cache_from_source as cache_from_source | ||||
| 
 | ||||
| from importlib import _bootstrap | ||||
| import os | ||||
| import sys | ||||
| import tokenize | ||||
| 
 | ||||
| 
 | ||||
| # XXX "deprecate" once find_module(), load_module(), and get_suffixes() are | ||||
| #     deprecated. | ||||
| SEARCH_ERROR = 0 | ||||
| PY_SOURCE = 1 | ||||
| PY_COMPILED = 2 | ||||
| C_EXTENSION = 3 | ||||
| PY_RESOURCE = 4 | ||||
| PKG_DIRECTORY = 5 | ||||
| C_BUILTIN = 6 | ||||
| PY_FROZEN = 7 | ||||
| PY_CODERESOURCE = 8 | ||||
| IMP_HOOK = 9 | ||||
| 
 | ||||
| 
 | ||||
| def source_from_cache(path): | ||||
|  | @ -131,3 +144,54 @@ def load_module(name, file, filename, details): | |||
|     else: | ||||
|         msg =  "Don't know how to import {} (type code {}".format(name, type_) | ||||
|         raise ImportError(msg, name=name) | ||||
| 
 | ||||
| 
 | ||||
| def find_module(name, path=None): | ||||
|     """Search for a module. | ||||
| 
 | ||||
|     If path is omitted or None, search for a built-in, frozen or special | ||||
|     module and continue search in sys.path. The module name cannot | ||||
|     contain '.'; to search for a submodule of a package, pass the | ||||
|     submodule name and the package's __path__. | ||||
| 
 | ||||
|     """ | ||||
|     if not isinstance(name, str): | ||||
|         raise TypeError("'name' must be a str, not {}".format(type(name))) | ||||
|     elif not isinstance(path, (type(None), list)): | ||||
|         # Backwards-compatibility | ||||
|         raise RuntimeError("'list' must be None or a list, " | ||||
|                            "not {}".format(type(name))) | ||||
| 
 | ||||
|     if path is None: | ||||
|         if is_builtin(name): | ||||
|             return None, None, ('', '', C_BUILTIN) | ||||
|         elif is_frozen(name): | ||||
|             return None, None, ('', '', PY_FROZEN) | ||||
|         else: | ||||
|             path = sys.path | ||||
| 
 | ||||
|     for entry in path: | ||||
|         package_directory = os.path.join(entry, name) | ||||
|         for suffix in ['.py', _bootstrap.BYTECODE_SUFFIX]: | ||||
|             package_file_name = '__init__' + suffix | ||||
|             file_path = os.path.join(package_directory, package_file_name) | ||||
|             if os.path.isfile(file_path): | ||||
|                 return None, package_directory, ('', '', PKG_DIRECTORY) | ||||
|         for suffix, mode, type_ in get_suffixes(): | ||||
|             file_name = name + suffix | ||||
|             file_path = os.path.join(entry, file_name) | ||||
|             if os.path.isfile(file_path): | ||||
|                 break | ||||
|         else: | ||||
|             continue | ||||
|         break  # Break out of outer loop when breaking out of inner loop. | ||||
|     else: | ||||
|         raise ImportError('No module name {!r}'.format(name), name=name) | ||||
| 
 | ||||
|     encoding = None | ||||
|     if mode == 'U': | ||||
|         with open(file_path, 'rb') as file: | ||||
|             encoding = tokenize.detect_encoding(file.readline)[0] | ||||
|     file = open(file_path, mode, encoding=encoding) | ||||
|     return file, file_path, (suffix, mode, type_) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										751
									
								
								Python/import.c
									
										
									
									
									
								
							
							
						
						
									
										751
									
								
								Python/import.c
									
										
									
									
									
								
							|  | @ -1118,8 +1118,6 @@ get_sourcefile(PyObject *filename) | |||
| } | ||||
| 
 | ||||
| /* Forward */ | ||||
| static struct filedescr *find_module(PyObject *, PyObject *, PyObject *, | ||||
|                                      PyObject **, FILE **, PyObject **); | ||||
| static struct _frozen * find_frozen(PyObject *); | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1220,678 +1218,12 @@ PyImport_GetImporter(PyObject *path) { | |||
|     return importer; | ||||
| } | ||||
| 
 | ||||
| /* 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. */ | ||||
| 
 | ||||
| #ifdef MS_COREDLL | ||||
| extern FILE *_PyWin_FindRegisteredModule(PyObject *, struct filedescr **, | ||||
|                                          PyObject **p_path); | ||||
| #endif | ||||
| 
 | ||||
| /* Forward */ | ||||
| static int case_ok(PyObject *, Py_ssize_t, PyObject *); | ||||
| static int find_init_module(PyObject *); | ||||
| static struct filedescr importhookdescr = {"", "", IMP_HOOK}; | ||||
| 
 | ||||
| /* Get the path of a module: get its importer and call importer.find_module()
 | ||||
|    hook, or check if the module if a package (if path/__init__.py exists). | ||||
| 
 | ||||
|     -1: error: a Python error occurred | ||||
|      0: ignore: an error occurred because of invalid data, but the error is not | ||||
|         important enough to be reported. | ||||
|      1: get path: module not found, but *buf contains its path | ||||
|      2: found: *p_fd is the file descriptor (IMP_HOOK or PKG_DIRECTORY) | ||||
|         and *buf is the path */ | ||||
| 
 | ||||
| static int | ||||
| find_module_path(PyObject *fullname, PyObject *name, PyObject *path, | ||||
|                  PyObject *path_hooks, PyObject *path_importer_cache, | ||||
|                  PyObject **p_path, PyObject **p_loader, struct filedescr **p_fd) | ||||
| { | ||||
|     PyObject *path_unicode, *filename = NULL; | ||||
|     Py_ssize_t len, pos; | ||||
|     struct stat statbuf; | ||||
|     static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; | ||||
|     int err, result, addsep; | ||||
| 
 | ||||
|     if (PyUnicode_Check(path)) { | ||||
|         Py_INCREF(path); | ||||
|         path_unicode = path; | ||||
|     } | ||||
|     else if (PyBytes_Check(path)) { | ||||
|         path_unicode = PyUnicode_DecodeFSDefaultAndSize( | ||||
|             PyBytes_AS_STRING(path), PyBytes_GET_SIZE(path)); | ||||
|         if (path_unicode == NULL) | ||||
|             return -1; | ||||
|     } | ||||
|     else | ||||
|         return 0; | ||||
| 
 | ||||
|     if (PyUnicode_READY(path_unicode)) | ||||
|         return -1; | ||||
| 
 | ||||
|     len = PyUnicode_GET_LENGTH(path_unicode); | ||||
|     if (PyUnicode_FindChar(path_unicode, 0, 0, len, 1) != -1) { | ||||
|         result = 0; | ||||
|         goto out;  /* path contains '\0' */ | ||||
|     } | ||||
| 
 | ||||
|     /* sys.path_hooks import hook */ | ||||
|     if (p_loader != NULL) { | ||||
|         _Py_IDENTIFIER(find_module); | ||||
|         PyObject *importer; | ||||
| 
 | ||||
|         importer = get_path_importer(path_importer_cache, | ||||
|                                      path_hooks, path); | ||||
|         if (importer == NULL) { | ||||
|             result = -1; | ||||
|             goto out; | ||||
|         } | ||||
|         /* Note: importer is a borrowed reference */ | ||||
|         if (importer != Py_None) { | ||||
|             PyObject *loader; | ||||
|             loader = _PyObject_CallMethodId(importer, | ||||
|                                             &PyId_find_module, "O", fullname); | ||||
|             if (loader == NULL) { | ||||
|                 result = -1; /* error */ | ||||
|                 goto out; | ||||
|             } | ||||
|             if (loader != Py_None) { | ||||
|                 /* a loader was found */ | ||||
|                 *p_loader = loader; | ||||
|                 *p_fd = &importhookdescr; | ||||
|                 result = 2; | ||||
|                 goto out; | ||||
|             } | ||||
|             Py_DECREF(loader); | ||||
|             result = 0; | ||||
|             goto out; | ||||
|         } | ||||
|     } | ||||
|     /* no hook was found, use builtin import */ | ||||
| 
 | ||||
|     addsep = 0; | ||||
|     if (len > 0 && PyUnicode_READ_CHAR(path_unicode, len-1) != SEP | ||||
| #ifdef ALTSEP | ||||
|         && PyUnicode_READ_CHAR(path_unicode, len-1) != ALTSEP | ||||
| #endif | ||||
|         ) | ||||
|         addsep = 1; | ||||
|     filename = PyUnicode_New(len + PyUnicode_GET_LENGTH(name) + addsep, | ||||
|                              Py_MAX(PyUnicode_MAX_CHAR_VALUE(path_unicode), | ||||
|                                     PyUnicode_MAX_CHAR_VALUE(name))); | ||||
|     if (filename == NULL) { | ||||
|         result = -1; | ||||
|         goto out; | ||||
|     } | ||||
|     PyUnicode_CopyCharacters(filename, 0, path_unicode, 0, len); | ||||
|     pos = len; | ||||
|     if (addsep) | ||||
|         PyUnicode_WRITE(PyUnicode_KIND(filename), | ||||
|                         PyUnicode_DATA(filename), | ||||
|                         pos++, SEP); | ||||
|     PyUnicode_CopyCharacters(filename, pos, name, 0, | ||||
|                              PyUnicode_GET_LENGTH(name)); | ||||
| 
 | ||||
|     /* Check for package import (buf holds a directory name,
 | ||||
|        and there's an __init__ module in that directory */ | ||||
| #ifdef HAVE_STAT | ||||
|     err = _Py_stat(filename, &statbuf); | ||||
|     if (err == -2) { | ||||
|         result = -1; | ||||
|         goto out; | ||||
|     } | ||||
|     if (err == 0 &&         /* it exists */ | ||||
|         S_ISDIR(statbuf.st_mode))           /* it's a directory */ | ||||
|     { | ||||
|         int match; | ||||
| 
 | ||||
|         match = case_ok(filename, 0, name); | ||||
|         if (match < 0) { | ||||
|             result = -1; | ||||
|             goto out; | ||||
|         } | ||||
|         if (match) { /* case matches */ | ||||
|             if (find_init_module(filename)) { /* and has __init__.py */ | ||||
|                 *p_path = filename; | ||||
|                 filename = NULL; | ||||
|                 *p_fd = &fd_package; | ||||
|                 result = 2; | ||||
|                 goto out; | ||||
|             } | ||||
|             else { | ||||
|                 int err; | ||||
|                 err = PyErr_WarnFormat(PyExc_ImportWarning, 1, | ||||
|                     "Not importing directory %R: missing __init__.py", | ||||
|                     filename); | ||||
|                 if (err) { | ||||
|                     result = -1; | ||||
|                     goto out; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|     *p_path = filename; | ||||
|     filename = NULL; | ||||
|     result = 1; | ||||
|   out: | ||||
|     Py_DECREF(path_unicode); | ||||
|     Py_XDECREF(filename); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| /* Find a module in search_path_list. For each path, try
 | ||||
|    find_module_path() or try each _PyImport_Filetab suffix. | ||||
| 
 | ||||
|    If the module is found, return a file descriptor, write the path in | ||||
|    *p_filename, write the pointer to the file object into *p_fp, and (if | ||||
|    p_loader is not NULL) the loader into *p_loader. | ||||
| 
 | ||||
|    Otherwise, raise an exception and return NULL. */ | ||||
| 
 | ||||
| static struct filedescr* | ||||
| find_module_path_list(PyObject *fullname, PyObject *name, | ||||
|                       PyObject *search_path_list, PyObject *path_hooks, | ||||
|                       PyObject *path_importer_cache, | ||||
|                       PyObject **p_path, FILE **p_fp, PyObject **p_loader) | ||||
| { | ||||
|     Py_ssize_t i, npath; | ||||
|     struct filedescr *fdp = NULL; | ||||
|     char *filemode; | ||||
|     FILE *fp = NULL; | ||||
|     PyObject *prefix, *filename; | ||||
|     int match; | ||||
|     int err; | ||||
| 
 | ||||
|     npath = PyList_Size(search_path_list); | ||||
|     for (i = 0; i < npath; i++) { | ||||
|         PyObject *path; | ||||
|         int ok; | ||||
| 
 | ||||
|         path = PyList_GetItem(search_path_list, i); | ||||
|         if (path == NULL) | ||||
|             return NULL; | ||||
| 
 | ||||
|         prefix = NULL; | ||||
|         ok = find_module_path(fullname, name, path, | ||||
|                               path_hooks, path_importer_cache, | ||||
|                               &prefix, p_loader, &fdp); | ||||
|         if (ok < 0) | ||||
|             return NULL; | ||||
|         if (ok == 0) | ||||
|             continue; | ||||
|         if (ok == 2) { | ||||
|             *p_path = prefix; | ||||
|             return fdp; | ||||
|         } | ||||
| 
 | ||||
|         for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { | ||||
|             struct stat statbuf; | ||||
| 
 | ||||
|             filemode = fdp->mode; | ||||
|             if (filemode[0] == 'U') | ||||
|                 filemode = "r" PY_STDIOTEXTMODE; | ||||
| 
 | ||||
|             filename = PyUnicode_FromFormat("%U%s", prefix, fdp->suffix); | ||||
|             if (filename == NULL) { | ||||
|                 Py_DECREF(prefix); | ||||
|                 return NULL; | ||||
|             } | ||||
| 
 | ||||
|             if (Py_VerboseFlag > 1) | ||||
|                 PySys_FormatStderr("# trying %R\n", filename); | ||||
| 
 | ||||
|             err = _Py_stat(filename, &statbuf); | ||||
|             if (err == -2) { | ||||
|                 Py_DECREF(prefix); | ||||
|                 Py_DECREF(filename); | ||||
|                 return NULL; | ||||
|             } | ||||
|             if (err != 0 || S_ISDIR(statbuf.st_mode)) { | ||||
|                 /* it doesn't exist, or it's a directory */ | ||||
|                 Py_DECREF(filename); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             fp = _Py_fopen(filename, filemode); | ||||
|             if (fp == NULL) { | ||||
|                 Py_DECREF(filename); | ||||
|                 if (PyErr_Occurred()) { | ||||
|                     Py_DECREF(prefix); | ||||
|                     return NULL; | ||||
|                 } | ||||
|                 continue; | ||||
|             } | ||||
|             match = case_ok(filename, -(Py_ssize_t)strlen(fdp->suffix), name); | ||||
|             if (match < 0) { | ||||
|                 Py_DECREF(prefix); | ||||
|                 Py_DECREF(filename); | ||||
|                 return NULL; | ||||
|             } | ||||
|             if (match) { | ||||
|                 Py_DECREF(prefix); | ||||
|                 *p_path = filename; | ||||
|                 *p_fp = fp; | ||||
|                 return fdp; | ||||
|             } | ||||
|             Py_DECREF(filename); | ||||
| 
 | ||||
|             fclose(fp); | ||||
|             fp = NULL; | ||||
|         } | ||||
|         Py_DECREF(prefix); | ||||
|     } | ||||
|     PyErr_Format(PyExc_ImportError, | ||||
|                  "No module named %R", name); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /* Find a module:
 | ||||
| 
 | ||||
|    - try find_module() of each sys.meta_path hook | ||||
|    - try find_frozen() | ||||
|    - try is_builtin() | ||||
|    - try _PyWin_FindRegisteredModule() (Windows only) | ||||
|    - otherwise, call find_module_path_list() with search_path_list (if not | ||||
|      NULL) or sys.path | ||||
| 
 | ||||
|    fullname can be NULL, but only if p_loader is NULL. | ||||
| 
 | ||||
|    Return: | ||||
| 
 | ||||
|    - &fd_builtin (C_BUILTIN) if it is a builtin | ||||
|    - &fd_frozen (PY_FROZEN) if it is frozen | ||||
|    - &fd_package (PKG_DIRECTORY) and write the filename into *p_path | ||||
|      if it is a package | ||||
|    - &importhookdescr (IMP_HOOK) and write the loader into *p_loader if a | ||||
|      importer loader was found | ||||
|    - a file descriptor (PY_SOURCE, PY_COMPILED, C_EXTENSION, PY_RESOURCE or | ||||
|      PY_CODERESOURCE: see _PyImport_Filetab), write the filename into | ||||
|      *p_path and the pointer to the open file into *p_fp | ||||
|    - NULL on error | ||||
| 
 | ||||
|    By default, *p_path, *p_fp and *p_loader (if set) are set to NULL. | ||||
|    Eg. *p_path is set to NULL for a builtin package. | ||||
| */ | ||||
| 
 | ||||
| static struct filedescr * | ||||
| find_module(PyObject *fullname, PyObject *name, PyObject *search_path_list, | ||||
|             PyObject **p_path, FILE **p_fp, PyObject **p_loader) | ||||
| { | ||||
|     Py_ssize_t i, npath; | ||||
|     static struct filedescr fd_frozen = {"", "", PY_FROZEN}; | ||||
|     static struct filedescr fd_builtin = {"", "", C_BUILTIN}; | ||||
|     PyObject *path_hooks, *path_importer_cache; | ||||
| 
 | ||||
|     *p_path = NULL; | ||||
|     *p_fp = NULL; | ||||
|     if (p_loader != NULL) | ||||
|         *p_loader = NULL; | ||||
| 
 | ||||
|     /* sys.meta_path import hook */ | ||||
|     if (p_loader != NULL) { | ||||
|         _Py_IDENTIFIER(find_module); | ||||
|         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"); | ||||
|             return NULL; | ||||
|         } | ||||
|         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_CallMethodId(hook, &PyId_find_module, | ||||
|                                          "OO", fullname, | ||||
|                                          search_path_list != NULL ? | ||||
|                                          search_path_list : Py_None); | ||||
|             if (loader == NULL) { | ||||
|                 Py_DECREF(meta_path); | ||||
|                 return NULL;  /* true error */ | ||||
|             } | ||||
|             if (loader != Py_None) { | ||||
|                 /* a loader was found */ | ||||
|                 *p_loader = loader; | ||||
|                 Py_DECREF(meta_path); | ||||
|                 return &importhookdescr; | ||||
|             } | ||||
|             Py_DECREF(loader); | ||||
|         } | ||||
|         Py_DECREF(meta_path); | ||||
|     } | ||||
| 
 | ||||
|     if (find_frozen(fullname) != NULL) | ||||
|         return &fd_frozen; | ||||
| 
 | ||||
|     if (search_path_list == NULL) { | ||||
| #ifdef MS_COREDLL | ||||
|         FILE *fp; | ||||
|         struct filedescr *fdp; | ||||
| #endif | ||||
|         if (is_builtin(name)) | ||||
|             return &fd_builtin; | ||||
| #ifdef MS_COREDLL | ||||
|         fp = _PyWin_FindRegisteredModule(name, &fdp, p_path); | ||||
|         if (fp != NULL) { | ||||
|             *p_fp = fp; | ||||
|             return fdp; | ||||
|         } | ||||
|         else if (PyErr_Occurred()) | ||||
|             return NULL; | ||||
| #endif | ||||
|         search_path_list = PySys_GetObject("path"); | ||||
|     } | ||||
| 
 | ||||
|     if (search_path_list == NULL || !PyList_Check(search_path_list)) { | ||||
|         PyErr_SetString(PyExc_RuntimeError, | ||||
|                         "sys.path must be a list of directory names"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     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"); | ||||
|         return NULL; | ||||
|     } | ||||
|     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"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return find_module_path_list(fullname, name, | ||||
|                                  search_path_list, path_hooks, | ||||
|                                  path_importer_cache, | ||||
|                                  p_path, p_fp, p_loader); | ||||
| } | ||||
| 
 | ||||
| /* case_bytes(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_bytes() is to return 1 if there's a case-sensitive match for | ||||
|  * name, else 0.  case_bytes() is also to return 1 if envar PYTHONCASEOK | ||||
|  * exists. | ||||
|  * | ||||
|  * case_bytes() 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_bytes(). | ||||
|  */ | ||||
| #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> | ||||
| #endif | ||||
| 
 | ||||
| #if defined(DJGPP) \ | ||||
|     || ((defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) \ | ||||
|         && defined(HAVE_DIRENT_H)) \ | ||||
|     || defined(PYOS_OS2) | ||||
| #  define USE_CASE_OK_BYTES | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #ifdef USE_CASE_OK_BYTES | ||||
| static int | ||||
| case_bytes(char *buf, Py_ssize_t len, Py_ssize_t namelen, const char *name) | ||||
| { | ||||
| /* Pick a platform-specific implementation; the sequence of #if's here should
 | ||||
|  * match the sequence just above. | ||||
|  */ | ||||
| 
 | ||||
| /* DJGPP */ | ||||
| #if 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 -1; | ||||
|     } | ||||
|     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 */ | ||||
| 
 | ||||
| /* 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 | ||||
| #   error "USE_CASE_OK_BYTES is not correctly defined" | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Check if a filename case matchs the name case. 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, 0 if it | ||||
|  * the filename doesn't match, or -1 on error.  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. | ||||
|  */ | ||||
| 
 | ||||
| static int | ||||
| case_ok(PyObject *filename, Py_ssize_t prefix_delta, PyObject *name) | ||||
| { | ||||
| #ifdef MS_WINDOWS | ||||
|     WIN32_FIND_DATAW data; | ||||
|     HANDLE h; | ||||
|     int cmp; | ||||
|     wchar_t *wfilename, *wname; | ||||
|     Py_ssize_t wname_len; | ||||
| 
 | ||||
|     if (Py_GETENV("PYTHONCASEOK") != NULL) | ||||
|         return 1; | ||||
| 
 | ||||
|     wfilename = PyUnicode_AsUnicode(filename); | ||||
|     if (wfilename == NULL) | ||||
|         return -1; | ||||
| 
 | ||||
|     h = FindFirstFileW(wfilename, &data); | ||||
|     if (h == INVALID_HANDLE_VALUE) { | ||||
|         PyErr_Format(PyExc_NameError, | ||||
|           "Can't find file for module %R\n(filename %R)", | ||||
|           name, filename); | ||||
|         return -1; | ||||
|     } | ||||
|     FindClose(h); | ||||
| 
 | ||||
|     wname = PyUnicode_AsUnicodeAndSize(name, &wname_len); | ||||
|     if (wname == NULL) | ||||
|         return -1; | ||||
| 
 | ||||
|     cmp = wcsncmp(data.cFileName, wname, wname_len); | ||||
|     return cmp == 0; | ||||
| #elif defined(USE_CASE_OK_BYTES) | ||||
|     int match; | ||||
|     PyObject *filebytes, *namebytes; | ||||
|     filebytes = PyUnicode_EncodeFSDefault(filename); | ||||
|     if (filebytes == NULL) | ||||
|         return -1; | ||||
|     namebytes = PyUnicode_EncodeFSDefault(name); | ||||
|     if (namebytes == NULL) { | ||||
|         Py_DECREF(filebytes); | ||||
|         return -1; | ||||
|     } | ||||
|     match = case_bytes( | ||||
|         PyBytes_AS_STRING(filebytes), | ||||
|         PyBytes_GET_SIZE(filebytes) + prefix_delta, | ||||
|         PyBytes_GET_SIZE(namebytes), | ||||
|         PyBytes_AS_STRING(namebytes)); | ||||
|     Py_DECREF(filebytes); | ||||
|     Py_DECREF(namebytes); | ||||
|     return match; | ||||
| #else | ||||
|     /* assuming it's a case-sensitive filesystem, so there's nothing to do! */ | ||||
|     return 1; | ||||
| 
 | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #ifdef HAVE_STAT | ||||
| 
 | ||||
| /* Helper to look for __init__.py or __init__.py[co] in potential package.
 | ||||
|    Return 1 if __init__ was found, 0 if not, or -1 on error. */ | ||||
| static int | ||||
| find_init_module(PyObject *directory) | ||||
| { | ||||
|     struct stat statbuf; | ||||
|     PyObject *filename; | ||||
|     int match; | ||||
|     int err; | ||||
| 
 | ||||
|     filename = PyUnicode_FromFormat("%U%c__init__.py", directory, SEP); | ||||
|     if (filename == NULL) | ||||
|         return -1; | ||||
|     err = _Py_stat(filename, &statbuf); | ||||
|     if (err == -2) | ||||
|         return -1; | ||||
|     if (err == 0) { | ||||
|         /* 3=len(".py") */ | ||||
|         match = case_ok(filename, -3, initstr); | ||||
|         if (match < 0) { | ||||
|             Py_DECREF(filename); | ||||
|             return -1; | ||||
|         } | ||||
|         if (match) { | ||||
|             Py_DECREF(filename); | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|     Py_DECREF(filename); | ||||
| 
 | ||||
|     filename = PyUnicode_FromFormat("%U%c__init__.py%c", | ||||
|         directory, SEP, Py_OptimizeFlag ? 'o' : 'c'); | ||||
|     if (filename == NULL) | ||||
|         return -1; | ||||
|     err = _Py_stat(filename, &statbuf); | ||||
|     if (err == -2) { | ||||
|         Py_DECREF(filename); | ||||
|         return -1; | ||||
|     } | ||||
|     if (err == 0) { | ||||
|         /* 4=len(".pyc") */ | ||||
|         match = case_ok(filename, -4, initstr); | ||||
|         if (match < 0) { | ||||
|             Py_DECREF(filename); | ||||
|             return -1; | ||||
|         } | ||||
|         if (match) { | ||||
|             Py_DECREF(filename); | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|     Py_DECREF(filename); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #endif /* HAVE_STAT */ | ||||
| 
 | ||||
| 
 | ||||
| static int init_builtin(PyObject *); /* Forward */ | ||||
| 
 | ||||
|  | @ -2688,81 +2020,6 @@ imp_get_suffixes(PyObject *self, PyObject *noargs) | |||
|     return list; | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| call_find_module(PyObject *name, PyObject *path_list) | ||||
| { | ||||
|     extern int fclose(FILE *); | ||||
|     PyObject *fob, *ret; | ||||
|     PyObject *pathobj; | ||||
|     struct filedescr *fdp; | ||||
|     FILE *fp; | ||||
|     int fd = -1; | ||||
|     char *found_encoding = NULL; | ||||
|     char *encoding = NULL; | ||||
| 
 | ||||
|     if (path_list == Py_None) | ||||
|         path_list = NULL; | ||||
|     fdp = find_module(NULL, name, path_list, | ||||
|                       &pathobj, &fp, NULL); | ||||
|     if (fdp == NULL) | ||||
|         return NULL; | ||||
|     if (fp != NULL) { | ||||
|         fd = fileno(fp); | ||||
|         if (fd != -1) | ||||
|             fd = dup(fd); | ||||
|         fclose(fp); | ||||
|         fp = NULL; | ||||
|         if (fd == -1) | ||||
|             return PyErr_SetFromErrno(PyExc_OSError); | ||||
|     } | ||||
|     if (fd != -1) { | ||||
|         if (strchr(fdp->mode, 'b') == NULL) { | ||||
|             /* PyTokenizer_FindEncodingFilename() returns PyMem_MALLOC'ed
 | ||||
|                memory. */ | ||||
|             found_encoding = PyTokenizer_FindEncodingFilename(fd, pathobj); | ||||
|             lseek(fd, 0, 0); /* Reset position */ | ||||
|             if (found_encoding == NULL && PyErr_Occurred()) { | ||||
|                 Py_XDECREF(pathobj); | ||||
|                 close(fd); | ||||
|                 return NULL; | ||||
|             } | ||||
|             encoding = (found_encoding != NULL) ? found_encoding : | ||||
|                    (char*)PyUnicode_GetDefaultEncoding(); | ||||
|         } | ||||
|         fob = PyFile_FromFd(fd, NULL, fdp->mode, -1, | ||||
|                             (char*)encoding, NULL, NULL, 1); | ||||
|         if (fob == NULL) { | ||||
|             Py_XDECREF(pathobj); | ||||
|             close(fd); | ||||
|             PyMem_FREE(found_encoding); | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
|     else { | ||||
|         fob = Py_None; | ||||
|         Py_INCREF(fob); | ||||
|     } | ||||
|     if (pathobj == NULL) { | ||||
|         Py_INCREF(Py_None); | ||||
|         pathobj = Py_None; | ||||
|     } | ||||
|     ret = Py_BuildValue("NN(ssi)", | ||||
|                   fob, pathobj, fdp->suffix, fdp->mode, fdp->type); | ||||
|     PyMem_FREE(found_encoding); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| imp_find_module(PyObject *self, PyObject *args) | ||||
| { | ||||
|     PyObject *name, *path_list = NULL; | ||||
|     if (!PyArg_ParseTuple(args, "U|O:find_module", | ||||
|                           &name, &path_list)) | ||||
|         return NULL; | ||||
|     return call_find_module(name, path_list); | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| imp_init_builtin(PyObject *self, PyObject *args) | ||||
| { | ||||
|  | @ -2931,13 +2188,6 @@ Reload the module.  The module must have been successfully imported before."); | |||
| PyDoc_STRVAR(doc_imp, | ||||
| "(Extremely) low-level import machinery bits as used by importlib and imp."); | ||||
| 
 | ||||
| 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_get_magic, | ||||
| "get_magic() -> string\n\
 | ||||
| Return the magic number for .pyc or .pyo files."); | ||||
|  | @ -2969,7 +2219,6 @@ Release the interpreter's import lock.\n\ | |||
| On platforms without threads, this function does nothing."); | ||||
| 
 | ||||
| static PyMethodDef imp_methods[] = { | ||||
|     {"find_module",      imp_find_module,  METH_VARARGS, doc_find_module}, | ||||
|     {"get_magic",        imp_get_magic,    METH_NOARGS,  doc_get_magic}, | ||||
|     {"get_tag",          imp_get_tag,      METH_NOARGS,  doc_get_tag}, | ||||
|     {"get_suffixes", imp_get_suffixes, METH_NOARGS,  doc_get_suffixes}, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brett Cannon
						Brett Cannon