Home | History | Annotate | Download | only in setuptools
      1 import os
      2 from distutils import log
      3 import itertools
      4 
      5 from setuptools.extern.six.moves import map
      6 
      7 
      8 flatten = itertools.chain.from_iterable
      9 
     10 
     11 class Installer:
     12 
     13     nspkg_ext = '-nspkg.pth'
     14 
     15     def install_namespaces(self):
     16         nsp = self._get_all_ns_packages()
     17         if not nsp:
     18             return
     19         filename, ext = os.path.splitext(self._get_target())
     20         filename += self.nspkg_ext
     21         self.outputs.append(filename)
     22         log.info("Installing %s", filename)
     23         lines = map(self._gen_nspkg_line, nsp)
     24 
     25         if self.dry_run:
     26             # always generate the lines, even in dry run
     27             list(lines)
     28             return
     29 
     30         with open(filename, 'wt') as f:
     31             f.writelines(lines)
     32 
     33     def uninstall_namespaces(self):
     34         filename, ext = os.path.splitext(self._get_target())
     35         filename += self.nspkg_ext
     36         if not os.path.exists(filename):
     37             return
     38         log.info("Removing %s", filename)
     39         os.remove(filename)
     40 
     41     def _get_target(self):
     42         return self.target
     43 
     44     _nspkg_tmpl = (
     45         "import sys, types, os",
     46         "has_mfs = sys.version_info > (3, 5)",
     47         "p = os.path.join(%(root)s, *%(pth)r)",
     48         "importlib = has_mfs and __import__('importlib.util')",
     49         "has_mfs and __import__('importlib.machinery')",
     50         "m = has_mfs and "
     51             "sys.modules.setdefault(%(pkg)r, "
     52                 "importlib.util.module_from_spec("
     53                     "importlib.machinery.PathFinder.find_spec(%(pkg)r, "
     54                         "[os.path.dirname(p)])))",
     55         "m = m or "
     56             "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
     57         "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
     58         "(p not in mp) and mp.append(p)",
     59     )
     60     "lines for the namespace installer"
     61 
     62     _nspkg_tmpl_multi = (
     63         'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
     64     )
     65     "additional line(s) when a parent package is indicated"
     66 
     67     def _get_root(self):
     68         return "sys._getframe(1).f_locals['sitedir']"
     69 
     70     def _gen_nspkg_line(self, pkg):
     71         # ensure pkg is not a unicode string under Python 2.7
     72         pkg = str(pkg)
     73         pth = tuple(pkg.split('.'))
     74         root = self._get_root()
     75         tmpl_lines = self._nspkg_tmpl
     76         parent, sep, child = pkg.rpartition('.')
     77         if parent:
     78             tmpl_lines += self._nspkg_tmpl_multi
     79         return ';'.join(tmpl_lines) % locals() + '\n'
     80 
     81     def _get_all_ns_packages(self):
     82         """Return sorted list of all package namespaces"""
     83         pkgs = self.distribution.namespace_packages or []
     84         return sorted(flatten(map(self._pkg_names, pkgs)))
     85 
     86     @staticmethod
     87     def _pkg_names(pkg):
     88         """
     89         Given a namespace package, yield the components of that
     90         package.
     91 
     92         >>> names = Installer._pkg_names('a.b.c')
     93         >>> set(names) == set(['a', 'a.b', 'a.b.c'])
     94         True
     95         """
     96         parts = pkg.split('.')
     97         while parts:
     98             yield '.'.join(parts)
     99             parts.pop()
    100 
    101 
    102 class DevelopInstaller(Installer):
    103     def _get_root(self):
    104         return repr(str(self.egg_path))
    105 
    106     def _get_target(self):
    107         return self.egg_link
    108