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 | # Can (probably) move to importlib | ||||||
| from _imp import get_suffixes | from _imp import get_suffixes | ||||||
| # Should be re-implemented here (and mostly deprecated) | # Should be re-implemented here (and mostly deprecated) | ||||||
| from _imp import (find_module, NullImporter, | from _imp import NullImporter | ||||||
|                   SEARCH_ERROR, PY_SOURCE, PY_COMPILED, C_EXTENSION, |  | ||||||
|                   PY_RESOURCE, PKG_DIRECTORY, C_BUILTIN, PY_FROZEN, |  | ||||||
|                   PY_CODERESOURCE, IMP_HOOK) |  | ||||||
| 
 | 
 | ||||||
| from importlib._bootstrap import _new_module as new_module | from importlib._bootstrap import _new_module as new_module | ||||||
| from importlib._bootstrap import _cache_from_source as cache_from_source | from importlib._bootstrap import _cache_from_source as cache_from_source | ||||||
| 
 | 
 | ||||||
| from importlib import _bootstrap | from importlib import _bootstrap | ||||||
| import os | 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): | def source_from_cache(path): | ||||||
|  | @ -131,3 +144,54 @@ def load_module(name, file, filename, details): | ||||||
|     else: |     else: | ||||||
|         msg =  "Don't know how to import {} (type code {}".format(name, type_) |         msg =  "Don't know how to import {} (type code {}".format(name, type_) | ||||||
|         raise ImportError(msg, name=name) |         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 */ | /* Forward */ | ||||||
| static struct filedescr *find_module(PyObject *, PyObject *, PyObject *, |  | ||||||
|                                      PyObject **, FILE **, PyObject **); |  | ||||||
| static struct _frozen * find_frozen(PyObject *); | static struct _frozen * find_frozen(PyObject *); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1220,678 +1218,12 @@ PyImport_GetImporter(PyObject *path) { | ||||||
|     return importer; |     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 | #ifdef MS_COREDLL | ||||||
| extern FILE *_PyWin_FindRegisteredModule(PyObject *, struct filedescr **, | extern FILE *_PyWin_FindRegisteredModule(PyObject *, struct filedescr **, | ||||||
|                                          PyObject **p_path); |                                          PyObject **p_path); | ||||||
| #endif | #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 */ | static int init_builtin(PyObject *); /* Forward */ | ||||||
| 
 | 
 | ||||||
|  | @ -2688,81 +2020,6 @@ imp_get_suffixes(PyObject *self, PyObject *noargs) | ||||||
|     return list; |     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 * | static PyObject * | ||||||
| imp_init_builtin(PyObject *self, PyObject *args) | 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, | PyDoc_STRVAR(doc_imp, | ||||||
| "(Extremely) low-level import machinery bits as used by importlib and 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, | PyDoc_STRVAR(doc_get_magic, | ||||||
| "get_magic() -> string\n\
 | "get_magic() -> string\n\
 | ||||||
| Return the magic number for .pyc or .pyo files."); | 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."); | On platforms without threads, this function does nothing."); | ||||||
| 
 | 
 | ||||||
| static PyMethodDef imp_methods[] = { | 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_magic",        imp_get_magic,    METH_NOARGS,  doc_get_magic}, | ||||||
|     {"get_tag",          imp_get_tag,      METH_NOARGS,  doc_get_tag}, |     {"get_tag",          imp_get_tag,      METH_NOARGS,  doc_get_tag}, | ||||||
|     {"get_suffixes", imp_get_suffixes, METH_NOARGS,  doc_get_suffixes}, |     {"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