3 from itertools
import product
, starmap
4 import distutils
.command
.install_lib
as orig
7 class install_lib(orig
.install_lib
):
8 """Don't add compiled flags to filenames of non-Python files"""
10 def initialize_options(self
):
11 orig
.install_lib
.initialize_options(self
)
13 self
.install_layout
= None
15 def finalize_options(self
):
16 orig
.install_lib
.finalize_options(self
)
17 self
.set_undefined_options('install',('install_layout','install_layout'))
18 if self
.install_layout
== 'deb' and sys
.version_info
[:2] >= (3, 3):
20 self
.multiarch
= sysconfig
.get_config_var('MULTIARCH')
24 outfiles
= self
.install()
25 if outfiles
is not None:
26 # always compile, in case we have any extension stubs to deal with
27 self
.byte_compile(outfiles
)
29 def get_exclusions(self
):
31 Return a collections.Sized collections.Container of paths to be
32 excluded for single_version_externally_managed installations.
36 for ns_pkg
in self
._get
_SVEM
_NSPs
()
37 for pkg
in self
._all
_packages
(ns_pkg
)
40 excl_specs
= product(all_packages
, self
._gen
_exclusion
_paths
())
41 return set(starmap(self
._exclude
_pkg
_path
, excl_specs
))
43 def _exclude_pkg_path(self
, pkg
, exclusion_path
):
45 Given a package name and exclusion path within that package,
46 compute the full exclusion path.
48 parts
= pkg
.split('.') + [exclusion_path
]
49 return os
.path
.join(self
.install_dir
, *parts
)
52 def _all_packages(pkg_name
):
54 >>> list(install_lib._all_packages('foo.bar.baz'))
55 ['foo.bar.baz', 'foo.bar', 'foo']
59 pkg_name
, sep
, child
= pkg_name
.rpartition('.')
61 def _get_SVEM_NSPs(self
):
63 Get namespace packages (list) but only for
64 single_version_externally_managed installations and empty otherwise.
66 # TODO: is it necessary to short-circuit here? i.e. what's the cost
67 # if get_finalized_command is called even when namespace_packages is
69 if not self
.distribution
.namespace_packages
:
72 install_cmd
= self
.get_finalized_command('install')
73 svem
= install_cmd
.single_version_externally_managed
75 return self
.distribution
.namespace_packages
if svem
else []
78 def _gen_exclusion_paths():
80 Generate file paths to be excluded for namespace packages (bytecode
83 # always exclude the package module itself
89 if not hasattr(sys
, 'implementation'):
93 '__pycache__', '__init__.' + sys
.implementation
.cache_tag
)
96 yield base
+ '.opt-1.pyc'
97 yield base
+ '.opt-2.pyc'
100 self
, infile
, outfile
,
101 preserve_mode
=1, preserve_times
=1, preserve_symlinks
=0, level
=1
103 assert preserve_mode
and preserve_times
and not preserve_symlinks
104 exclude
= self
.get_exclusions()
107 import distutils
.dir_util
108 distutils
.dir_util
._multiarch
= self
.multiarch
109 return orig
.install_lib
.copy_tree(self
, infile
, outfile
)
111 # Exclude namespace package __init__.py* files from the output
113 from setuptools
.archive_util
import unpack_directory
114 from distutils
import log
120 ext_suffix
= sysconfig
.get_config_var ('EXT_SUFFIX')
121 if ext_suffix
.endswith(self
.multiarch
+ ext_suffix
[-3:]):
124 new_suffix
= "%s-%s%s" % (ext_suffix
[:-3], self
.multiarch
, ext_suffix
[-3:])
128 log
.warn("Skipping installation of %s (namespace package)",
132 if self
.multiarch
and new_suffix
and dst
.endswith(ext_suffix
) and not dst
.endswith(new_suffix
):
133 dst
= dst
.replace(ext_suffix
, new_suffix
)
134 log
.info("renaming extension to %s", os
.path
.basename(dst
))
136 log
.info("copying %s -> %s", src
, os
.path
.dirname(dst
))
140 unpack_directory(infile
, outfile
, pf
)
143 def get_outputs(self
):
144 outputs
= orig
.install_lib
.get_outputs(self
)
145 exclude
= self
.get_exclusions()
147 return [f
for f
in outputs
if f
not in exclude
]