copymodules.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import importlib, importlib.abc
  2. import os
  3. import shutil
  4. import sys
  5. import zipfile, zipimport
  6. class ModuleCopier:
  7. def __init__(self, path=None):
  8. self.path = path if (path is not None) else ([''] + sys.path)
  9. def copy(self, modname, target):
  10. loader = importlib.find_loader(modname, self.path)
  11. if loader is None:
  12. raise ImportError('Could not find %s' % modname)
  13. pkg = loader.is_package(modname)
  14. file = loader.get_filename(modname)
  15. if isinstance(loader, importlib.abc.FileLoader):
  16. if pkg:
  17. pkgdir, basename = os.path.split(file)
  18. assert basename.startswith('__init__')
  19. dest = os.path.join(target, modname)
  20. shutil.copytree(pkgdir, dest, ignore=shutil.ignore_patterns('*.pyc'))
  21. else:
  22. shutil.copy2(file, target)
  23. elif isinstance(loader, zipimport.zipimporter):
  24. prefix = loader.archive + '/' + loader.prefix
  25. assert file.startswith(prefix)
  26. path_in_zip = file[len(prefix):]
  27. zf = zipfile.ZipFile(loader.archive)
  28. if pkg:
  29. pkgdir, basename = path_in_zip.rsplit('/', 1)
  30. assert basename.startswith('__init__')
  31. pkgfiles = [f for f in zf.namelist() if f.startswith(pkgdir)]
  32. zf.extractall(target, pkgfiles)
  33. else:
  34. zf.extract(path_in_zip, target)
  35. def copy_modules(modnames, target, path=None):
  36. """Copy the specified importable modules to the target directory.
  37. By default, it finds modules in sys.path - this can be overridden by passing
  38. the path parameter.
  39. """
  40. mc = ModuleCopier(path)
  41. files_in_target_noext = [os.path.splitext(f)[0] for f in os.listdir(target)]
  42. for modname in modnames:
  43. if modname in files_in_target_noext:
  44. # Already there, no need to copy it.
  45. continue
  46. mc.copy(modname, target)