1
0

copymodules.py 1.9 KB

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