|
@@ -1,57 +1,107 @@
|
|
-import importlib, importlib.abc, importlib.machinery
|
|
|
|
import os
|
|
import os
|
|
import shutil
|
|
import shutil
|
|
import sys
|
|
import sys
|
|
import zipfile, zipimport
|
|
import zipfile, zipimport
|
|
|
|
|
|
-class ModuleCopier:
|
|
|
|
- """Finds and copies importable Python modules and packages.
|
|
|
|
-
|
|
|
|
- This uses importlib to locate modules.
|
|
|
|
- """
|
|
|
|
- def __init__(self, path=None):
|
|
|
|
- self.path = path if (path is not None) else ([''] + sys.path)
|
|
|
|
-
|
|
|
|
- def copy(self, modname, target):
|
|
|
|
- """Copy the importable module 'modname' to the directory 'target'.
|
|
|
|
-
|
|
|
|
- modname should be a top-level import, i.e. without any dots. Packages
|
|
|
|
- are always copied whole.
|
|
|
|
-
|
|
|
|
- This can currently copy regular filesystem files and directories, and
|
|
|
|
- extract modules and packages from appropriately structured zip files.
|
|
|
|
|
|
+PY2 = sys.version_info[0] == 2
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def copy_zipmodule(loader, modname, target):
|
|
|
|
+ file = loader.get_filename(modname)
|
|
|
|
+ prefix = loader.archive + '/' + loader.prefix
|
|
|
|
+ assert file.startswith(prefix)
|
|
|
|
+ path_in_zip = file[len(prefix):]
|
|
|
|
+ zf = zipfile.ZipFile(loader.archive)
|
|
|
|
+ if loader.is_package(modname):
|
|
|
|
+ pkgdir, basename = path_in_zip.rsplit('/', 1)
|
|
|
|
+ assert basename.startswith('__init__')
|
|
|
|
+ pkgfiles = [f for f in zf.namelist() if f.startswith(pkgdir)]
|
|
|
|
+ zf.extractall(target, pkgfiles)
|
|
|
|
+ else:
|
|
|
|
+ zf.extract(path_in_zip, target)
|
|
|
|
+
|
|
|
|
+if not PY2:
|
|
|
|
+ import importlib
|
|
|
|
+ import importlib.abc
|
|
|
|
+ import importlib.machinery
|
|
|
|
+
|
|
|
|
+ class ModuleCopier:
|
|
|
|
+ """Finds and copies importable Python modules and packages.
|
|
|
|
+
|
|
|
|
+ This uses importlib to locate modules.
|
|
|
|
+ """
|
|
|
|
+ def __init__(self, path=None):
|
|
|
|
+ self.path = path if (path is not None) else ([''] + sys.path)
|
|
|
|
+
|
|
|
|
+ def copy(self, modname, target):
|
|
|
|
+ """Copy the importable module 'modname' to the directory 'target'.
|
|
|
|
+
|
|
|
|
+ modname should be a top-level import, i.e. without any dots.
|
|
|
|
+ Packages are always copied whole.
|
|
|
|
+
|
|
|
|
+ This can currently copy regular filesystem files and directories,
|
|
|
|
+ and extract modules and packages from appropriately structured zip
|
|
|
|
+ files.
|
|
|
|
+ """
|
|
|
|
+ loader = importlib.find_loader(modname, self.path)
|
|
|
|
+ if loader is None:
|
|
|
|
+ raise ImportError('Could not find %s' % modname)
|
|
|
|
+ pkg = loader.is_package(modname)
|
|
|
|
+
|
|
|
|
+ if isinstance(loader, importlib.machinery.ExtensionFileLoader):
|
|
|
|
+ shutil.copy2(loader.path, target)
|
|
|
|
+
|
|
|
|
+ elif isinstance(loader, importlib.abc.FileLoader):
|
|
|
|
+ file = loader.get_filename(modname)
|
|
|
|
+ if pkg:
|
|
|
|
+ pkgdir, basename = os.path.split(file)
|
|
|
|
+ assert basename.startswith('__init__')
|
|
|
|
+ dest = os.path.join(target, modname)
|
|
|
|
+ shutil.copytree(pkgdir, dest,
|
|
|
|
+ ignore=shutil.ignore_patterns('*.pyc'))
|
|
|
|
+ else:
|
|
|
|
+ shutil.copy2(file, target)
|
|
|
|
+
|
|
|
|
+ elif isinstance(loader, zipimport.zipimporter):
|
|
|
|
+ copy_zipmodule(loader, modname, target)
|
|
|
|
+else:
|
|
|
|
+ import imp
|
|
|
|
+
|
|
|
|
+ class ModuleCopier:
|
|
|
|
+ """Finds and copies importable Python modules and packages.
|
|
|
|
+
|
|
|
|
+ This uses importlib to locate modules.
|
|
"""
|
|
"""
|
|
- loader = importlib.find_loader(modname, self.path)
|
|
|
|
- if loader is None:
|
|
|
|
- raise ImportError('Could not find %s' % modname)
|
|
|
|
- pkg = loader.is_package(modname)
|
|
|
|
-
|
|
|
|
- if isinstance(loader, importlib.machinery.ExtensionFileLoader):
|
|
|
|
- shutil.copy2(loader.path, target)
|
|
|
|
-
|
|
|
|
- elif isinstance(loader, importlib.abc.FileLoader):
|
|
|
|
- file = loader.get_filename(modname)
|
|
|
|
- if pkg:
|
|
|
|
- pkgdir, basename = os.path.split(file)
|
|
|
|
- assert basename.startswith('__init__')
|
|
|
|
|
|
+ def __init__(self, path=None):
|
|
|
|
+ self.path = path if (path is not None) else ([''] + sys.path)
|
|
|
|
+
|
|
|
|
+ def copy(self, modname, target):
|
|
|
|
+ """Copy the importable module 'modname' to the directory 'target'.
|
|
|
|
+
|
|
|
|
+ modname should be a top-level import, i.e. without any dots.
|
|
|
|
+ Packages are always copied whole.
|
|
|
|
+
|
|
|
|
+ This can currently copy regular filesystem files and directories,
|
|
|
|
+ and extract modules and packages from appropriately structured zip
|
|
|
|
+ files.
|
|
|
|
+ """
|
|
|
|
+ modinfo = imp.find_module(modname, self.path)
|
|
|
|
+
|
|
|
|
+ if modinfo[2][2] in (imp.PY_SOURCE, imp.C_EXTENSION):
|
|
|
|
+ shutil.copy2(modinfo[1], target)
|
|
|
|
+
|
|
|
|
+ elif modinfo[2][2] == imp.PKG_DIRECTORY:
|
|
dest = os.path.join(target, modname)
|
|
dest = os.path.join(target, modname)
|
|
- shutil.copytree(pkgdir, dest, ignore=shutil.ignore_patterns('*.pyc'))
|
|
|
|
- else:
|
|
|
|
- shutil.copy2(file, target)
|
|
|
|
-
|
|
|
|
- elif isinstance(loader, zipimport.zipimporter):
|
|
|
|
- file = loader.get_filename(modname)
|
|
|
|
- prefix = loader.archive + '/' + loader.prefix
|
|
|
|
- assert file.startswith(prefix)
|
|
|
|
- path_in_zip = file[len(prefix):]
|
|
|
|
- zf = zipfile.ZipFile(loader.archive)
|
|
|
|
- if pkg:
|
|
|
|
- pkgdir, basename = path_in_zip.rsplit('/', 1)
|
|
|
|
- assert basename.startswith('__init__')
|
|
|
|
- pkgfiles = [f for f in zf.namelist() if f.startswith(pkgdir)]
|
|
|
|
- zf.extractall(target, pkgfiles)
|
|
|
|
- else:
|
|
|
|
- zf.extract(path_in_zip, target)
|
|
|
|
|
|
+ shutil.copytree(modinfo[1], dest,
|
|
|
|
+ ignore=shutil.ignore_patterns('*.pyc'))
|
|
|
|
+
|
|
|
|
+ elif any(p.endswith('.zip') for p in self.path):
|
|
|
|
+ for fpath in (p for p in self.path if p.endswith('.zip')):
|
|
|
|
+ loader = zipimport.zipimporter(fpath)
|
|
|
|
+ if loader.find_module(modname) is None:
|
|
|
|
+ continue
|
|
|
|
+ copy_zipmodule(loader, modname, target)
|
|
|
|
+
|
|
|
|
|
|
def copy_modules(modnames, target, path=None):
|
|
def copy_modules(modnames, target, path=None):
|
|
"""Copy the specified importable modules to the target directory.
|
|
"""Copy the specified importable modules to the target directory.
|