From e8dfad47216909e709304173477c43651f040a21 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Fri, 17 Jun 2016 17:22:51 -0700 Subject: [PATCH] Heading toward a final draft of the Py-2 instances. --- README.rst | 36 ++++++++++---------- polyloader/__init__.py | 6 ++-- polyloader/{_python27.py => _python2.py} | 43 ++++++++++++++---------- 3 files changed, 46 insertions(+), 39 deletions(-) rename polyloader/{_python27.py => _python2.py} (73%) diff --git a/README.rst b/README.rst index 055cc31..10265b5 100644 --- a/README.rst +++ b/README.rst @@ -7,28 +7,28 @@ critical to the functioning of other programming languages that use the Python AST and Python VM, languages such as Hy, Doge, and Mochi. Problem Statement - ----------------- +----------------- The Python module loader system is hard-coded to prevent the discovery of heterogenous source code packages. From Python 2.6 through the -current (as of this writing) Python 3.5, the import mechanism allowed -for the creation of file finders and importers that would transform -Python's import syntax into a *path,* assert whether or not that path -could be made to correspond to a *syntax object*, and then attempt to -*load* that syntax object as a Python module. Python *packages*, -however, are assumed to be uniformly made up of Python syntax objects, -be they **.py** source files, **.pyc/.pyo** bytecode, or **.so/.dll** -files with an exposed Python-to-C API. In Python 2 these suffixes are -hard-coded into the source in the **imp** builtin module; in Python 3 -these suffixes are constants defined in a private section of -**importlib**; in either case, they are unavailable for modification. -This lack of access to the extensions list prevents the *discovery* of -heterogenous source code packages. +current (as of this writing) Python 3.5, the import mechanism allows for +the creation of file finders and importers that would transform Python's +import syntax into a *path,* assert whether or not that path could be +made to correspond to a *syntax object*, and then attempt to *load* that +syntax object as a Python module. Python *packages*, however, are +assumed to be uniformly made up of Python syntax objects, be they +**.py** source files, **.pyc/.pyo** bytecode, or **.so/.dll** files with +an exposed Python-to-C API. In Python 2 these suffixes are hard-coded +into the source in the **imp** builtin module; in Python 3 these +suffixes are constants defined in a private section of **importlib**; in +either case, they are unavailable for modification. This lack of access +to the extensions list prevents the *discovery* of heterogenous source +code packages. -The discovery mechanism is outlined in Python's pkgutil module; features -such as **pkgutil.iter_modules** do not work with heterogenous source -code, which in turn means that one cannot write, for one important -example, Django management commands in an alternative syntax. +The discovery mechanism is outlined in Python's **pkgutil** module; +features such as **pkgutil.iter_modules** do not work with heterogenous +source code, which in turn means that one cannot write, for one +important example, Django management commands in an alternative syntax. **polyloader** is a python module that intercepts calls to the default finder, loader, and package module iterator, and if the path resolves to diff --git a/polyloader/__init__.py b/polyloader/__init__.py index f51afe8..405e87c 100644 --- a/polyloader/__init__.py +++ b/polyloader/__init__.py @@ -5,10 +5,10 @@ __author__ = 'Kenneth M. "Elf" Sternberg' __email__ = 'elf.sternberg@gmail.com' __version__ = '0.1.0' -if sys.version[0:2] == (2, 7): - from ._python27 import install +if sys.version_info[0:2] >= (2, 6): + from ._python2 import install -if sys.version[0] >= 3: +if sys.version_info[0] >= 3: from ._python3 import install __all__ = ['install'] diff --git a/polyloader/_python27.py b/polyloader/_python2.py similarity index 73% rename from polyloader/_python27.py rename to polyloader/_python2.py index c866ce5..6f34d0a 100644 --- a/polyloader/_python27.py +++ b/polyloader/_python2.py @@ -64,34 +64,41 @@ class PolyLoader(pkgutil.ImpLoader): # the iter_modules; or we provide our own finder and ensure it gets # found before the native one. -We actually want to have multiple -# SourceFileFinders, each of which either recognizes the file to be - +# Why the heck python 2.6 insists on calling finders "importers" is +# beyond me. At least in calls loaders "loaders". + class PolyFinder(object): def __init__(self, path = None): self.path = path - def find_on_path(self, fullname): + def _pl_find_on_path(self, fullname, path=None): + subname = fullname.split(".")[-1] + if subname != fullname and self.path is None: + return None + # As in the original, we ignore the 'path' argument + path = None + if self.path is not None: + path = [os.path.realpath(self.path)] + fls = ["%s/__init__.%s", "%s.%s"] - dirpath = "/".join(fullname.split(".")) - - for pth in sys.path: - pth = os.path.abspath(pth) - for fp in fls: - for (compiler, suffix) in PolyLoader._loader_handlers: - composed_path = fp % ("%s/%s" % (pth, dirpath), suffix) - if os.path.exists(composed_path): - return composed_path - + for fp in fls: + for (compiler, suffix) in PolyLoader._loader_handlers: + composed_path = fp % ("%s/%s" % (pth, dirpath), suffix) + if os.path.exists(composed_path): + return PolyLoader(composed_path) + try: + file, filename, etc = imp.find_module(subname, path) + except ImportError: + return None + return ImpLoader(fullname, file, filename, etc) + def find_module(self, fullname, path=None): - path = self.find_on_path(fullname) + path = self._pl_find_on_path(fullname) if path: return PolyLoader(path) - + return None def _install(compiler, suffixes): - - sys.meta_path.insert(0, MetaImporter()) iter_importer_modules.register(MetaImporter, meta_iterate_modules)