Spaces:
Sleeping
Sleeping
import os | |
import sys | |
from itertools import product, starmap | |
import distutils.command.install_lib as orig | |
class install_lib(orig.install_lib): | |
"""Don't add compiled flags to filenames of non-Python files""" | |
def initialize_options(self): | |
orig.install_lib.initialize_options(self) | |
self.multiarch = None | |
self.install_layout = None | |
def finalize_options(self): | |
orig.install_lib.finalize_options(self) | |
self.set_undefined_options('install',('install_layout','install_layout')) | |
if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): | |
import sysconfig | |
self.multiarch = sysconfig.get_config_var('MULTIARCH') | |
def run(self): | |
self.build() | |
outfiles = self.install() | |
if outfiles is not None: | |
# always compile, in case we have any extension stubs to deal with | |
self.byte_compile(outfiles) | |
def get_exclusions(self): | |
""" | |
Return a collections.Sized collections.Container of paths to be | |
excluded for single_version_externally_managed installations. | |
""" | |
all_packages = ( | |
pkg | |
for ns_pkg in self._get_SVEM_NSPs() | |
for pkg in self._all_packages(ns_pkg) | |
) | |
excl_specs = product(all_packages, self._gen_exclusion_paths()) | |
return set(starmap(self._exclude_pkg_path, excl_specs)) | |
def _exclude_pkg_path(self, pkg, exclusion_path): | |
""" | |
Given a package name and exclusion path within that package, | |
compute the full exclusion path. | |
""" | |
parts = pkg.split('.') + [exclusion_path] | |
return os.path.join(self.install_dir, *parts) | |
def _all_packages(pkg_name): | |
""" | |
>>> list(install_lib._all_packages('foo.bar.baz')) | |
['foo.bar.baz', 'foo.bar', 'foo'] | |
""" | |
while pkg_name: | |
yield pkg_name | |
pkg_name, sep, child = pkg_name.rpartition('.') | |
def _get_SVEM_NSPs(self): | |
""" | |
Get namespace packages (list) but only for | |
single_version_externally_managed installations and empty otherwise. | |
""" | |
# TODO: is it necessary to short-circuit here? i.e. what's the cost | |
# if get_finalized_command is called even when namespace_packages is | |
# False? | |
if not self.distribution.namespace_packages: | |
return [] | |
install_cmd = self.get_finalized_command('install') | |
svem = install_cmd.single_version_externally_managed | |
return self.distribution.namespace_packages if svem else [] | |
def _gen_exclusion_paths(): | |
""" | |
Generate file paths to be excluded for namespace packages (bytecode | |
cache files). | |
""" | |
# always exclude the package module itself | |
yield '__init__.py' | |
yield '__init__.pyc' | |
yield '__init__.pyo' | |
if not hasattr(sys, 'implementation'): | |
return | |
base = os.path.join( | |
'__pycache__', '__init__.' + sys.implementation.cache_tag) | |
yield base + '.pyc' | |
yield base + '.pyo' | |
yield base + '.opt-1.pyc' | |
yield base + '.opt-2.pyc' | |
def copy_tree( | |
self, infile, outfile, | |
preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 | |
): | |
assert preserve_mode and preserve_times and not preserve_symlinks | |
exclude = self.get_exclusions() | |
if not exclude: | |
import distutils.dir_util | |
distutils.dir_util._multiarch = self.multiarch | |
return orig.install_lib.copy_tree(self, infile, outfile) | |
# Exclude namespace package __init__.py* files from the output | |
from setuptools.archive_util import unpack_directory | |
from distutils import log | |
outfiles = [] | |
if self.multiarch: | |
import sysconfig | |
ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') | |
if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): | |
new_suffix = None | |
else: | |
new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) | |
def pf(src, dst): | |
if dst in exclude: | |
log.warn("Skipping installation of %s (namespace package)", | |
dst) | |
return False | |
if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): | |
dst = dst.replace(ext_suffix, new_suffix) | |
log.info("renaming extension to %s", os.path.basename(dst)) | |
log.info("copying %s -> %s", src, os.path.dirname(dst)) | |
outfiles.append(dst) | |
return dst | |
unpack_directory(infile, outfile, pf) | |
return outfiles | |
def get_outputs(self): | |
outputs = orig.install_lib.get_outputs(self) | |
exclude = self.get_exclusions() | |
if exclude: | |
return [f for f in outputs if f not in exclude] | |
return outputs | |