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
72
Lib/imp.py
72
Lib/imp.py
|
@ -15,16 +15,29 @@ from _imp import get_magic, get_tag
|
|||
# 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 @@ unchanged:
|
|||
}
|
||||
|
||||
/* 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…
Reference in New Issue