Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/setuptools/command/build_py.py
811 views
1
from glob import glob
2
from distutils.util import convert_path
3
import distutils.command.build_py as orig
4
import os
5
import fnmatch
6
import textwrap
7
import io
8
import distutils.errors
9
import itertools
10
import stat
11
12
from setuptools.extern import six
13
from setuptools.extern.six.moves import map, filter, filterfalse
14
15
try:
16
from setuptools.lib2to3_ex import Mixin2to3
17
except ImportError:
18
19
class Mixin2to3:
20
def run_2to3(self, files, doctests=True):
21
"do nothing"
22
23
24
def make_writable(target):
25
os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE)
26
27
28
class build_py(orig.build_py, Mixin2to3):
29
"""Enhanced 'build_py' command that includes data files with packages
30
31
The data files are specified via a 'package_data' argument to 'setup()'.
32
See 'setuptools.dist.Distribution' for more details.
33
34
Also, this version of the 'build_py' command allows you to specify both
35
'py_modules' and 'packages' in the same setup operation.
36
"""
37
38
def finalize_options(self):
39
orig.build_py.finalize_options(self)
40
self.package_data = self.distribution.package_data
41
self.exclude_package_data = (self.distribution.exclude_package_data or
42
{})
43
if 'data_files' in self.__dict__:
44
del self.__dict__['data_files']
45
self.__updated_files = []
46
self.__doctests_2to3 = []
47
48
def run(self):
49
"""Build modules, packages, and copy data files to build directory"""
50
if not self.py_modules and not self.packages:
51
return
52
53
if self.py_modules:
54
self.build_modules()
55
56
if self.packages:
57
self.build_packages()
58
self.build_package_data()
59
60
self.run_2to3(self.__updated_files, False)
61
self.run_2to3(self.__updated_files, True)
62
self.run_2to3(self.__doctests_2to3, True)
63
64
# Only compile actual .py files, using our base class' idea of what our
65
# output files are.
66
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
67
68
def __getattr__(self, attr):
69
"lazily compute data files"
70
if attr == 'data_files':
71
self.data_files = self._get_data_files()
72
return self.data_files
73
return orig.build_py.__getattr__(self, attr)
74
75
def build_module(self, module, module_file, package):
76
if six.PY2 and isinstance(package, six.string_types):
77
# avoid errors on Python 2 when unicode is passed (#190)
78
package = package.split('.')
79
outfile, copied = orig.build_py.build_module(self, module, module_file,
80
package)
81
if copied:
82
self.__updated_files.append(outfile)
83
return outfile, copied
84
85
def _get_data_files(self):
86
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
87
self.analyze_manifest()
88
return list(map(self._get_pkg_data_files, self.packages or ()))
89
90
def _get_pkg_data_files(self, package):
91
# Locate package source directory
92
src_dir = self.get_package_dir(package)
93
94
# Compute package build directory
95
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
96
97
# Strip directory from globbed filenames
98
filenames = [
99
os.path.relpath(file, src_dir)
100
for file in self.find_data_files(package, src_dir)
101
]
102
return package, src_dir, build_dir, filenames
103
104
def find_data_files(self, package, src_dir):
105
"""Return filenames for package's data files in 'src_dir'"""
106
patterns = self._get_platform_patterns(
107
self.package_data,
108
package,
109
src_dir,
110
)
111
globs_expanded = map(glob, patterns)
112
# flatten the expanded globs into an iterable of matches
113
globs_matches = itertools.chain.from_iterable(globs_expanded)
114
glob_files = filter(os.path.isfile, globs_matches)
115
files = itertools.chain(
116
self.manifest_files.get(package, []),
117
glob_files,
118
)
119
return self.exclude_data_files(package, src_dir, files)
120
121
def build_package_data(self):
122
"""Copy data files into build directory"""
123
for package, src_dir, build_dir, filenames in self.data_files:
124
for filename in filenames:
125
target = os.path.join(build_dir, filename)
126
self.mkpath(os.path.dirname(target))
127
srcfile = os.path.join(src_dir, filename)
128
outf, copied = self.copy_file(srcfile, target)
129
make_writable(target)
130
srcfile = os.path.abspath(srcfile)
131
if (copied and
132
srcfile in self.distribution.convert_2to3_doctests):
133
self.__doctests_2to3.append(outf)
134
135
def analyze_manifest(self):
136
self.manifest_files = mf = {}
137
if not self.distribution.include_package_data:
138
return
139
src_dirs = {}
140
for package in self.packages or ():
141
# Locate package source directory
142
src_dirs[assert_relative(self.get_package_dir(package))] = package
143
144
self.run_command('egg_info')
145
ei_cmd = self.get_finalized_command('egg_info')
146
for path in ei_cmd.filelist.files:
147
d, f = os.path.split(assert_relative(path))
148
prev = None
149
oldf = f
150
while d and d != prev and d not in src_dirs:
151
prev = d
152
d, df = os.path.split(d)
153
f = os.path.join(df, f)
154
if d in src_dirs:
155
if path.endswith('.py') and f == oldf:
156
continue # it's a module, not data
157
mf.setdefault(src_dirs[d], []).append(path)
158
159
def get_data_files(self):
160
pass # Lazily compute data files in _get_data_files() function.
161
162
def check_package(self, package, package_dir):
163
"""Check namespace packages' __init__ for declare_namespace"""
164
try:
165
return self.packages_checked[package]
166
except KeyError:
167
pass
168
169
init_py = orig.build_py.check_package(self, package, package_dir)
170
self.packages_checked[package] = init_py
171
172
if not init_py or not self.distribution.namespace_packages:
173
return init_py
174
175
for pkg in self.distribution.namespace_packages:
176
if pkg == package or pkg.startswith(package + '.'):
177
break
178
else:
179
return init_py
180
181
with io.open(init_py, 'rb') as f:
182
contents = f.read()
183
if b'declare_namespace' not in contents:
184
raise distutils.errors.DistutilsError(
185
"Namespace package problem: %s is a namespace package, but "
186
"its\n__init__.py does not call declare_namespace()! Please "
187
'fix it.\n(See the setuptools manual under '
188
'"Namespace Packages" for details.)\n"' % (package,)
189
)
190
return init_py
191
192
def initialize_options(self):
193
self.packages_checked = {}
194
orig.build_py.initialize_options(self)
195
196
def get_package_dir(self, package):
197
res = orig.build_py.get_package_dir(self, package)
198
if self.distribution.src_root is not None:
199
return os.path.join(self.distribution.src_root, res)
200
return res
201
202
def exclude_data_files(self, package, src_dir, files):
203
"""Filter filenames for package's data files in 'src_dir'"""
204
files = list(files)
205
patterns = self._get_platform_patterns(
206
self.exclude_package_data,
207
package,
208
src_dir,
209
)
210
match_groups = (
211
fnmatch.filter(files, pattern)
212
for pattern in patterns
213
)
214
# flatten the groups of matches into an iterable of matches
215
matches = itertools.chain.from_iterable(match_groups)
216
bad = set(matches)
217
keepers = (
218
fn
219
for fn in files
220
if fn not in bad
221
)
222
# ditch dupes
223
return list(_unique_everseen(keepers))
224
225
@staticmethod
226
def _get_platform_patterns(spec, package, src_dir):
227
"""
228
yield platform-specific path patterns (suitable for glob
229
or fn_match) from a glob-based spec (such as
230
self.package_data or self.exclude_package_data)
231
matching package in src_dir.
232
"""
233
raw_patterns = itertools.chain(
234
spec.get('', []),
235
spec.get(package, []),
236
)
237
return (
238
# Each pattern has to be converted to a platform-specific path
239
os.path.join(src_dir, convert_path(pattern))
240
for pattern in raw_patterns
241
)
242
243
244
# from Python docs
245
def _unique_everseen(iterable, key=None):
246
"List unique elements, preserving order. Remember all elements ever seen."
247
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
248
# unique_everseen('ABBCcAD', str.lower) --> A B C D
249
seen = set()
250
seen_add = seen.add
251
if key is None:
252
for element in filterfalse(seen.__contains__, iterable):
253
seen_add(element)
254
yield element
255
else:
256
for element in iterable:
257
k = key(element)
258
if k not in seen:
259
seen_add(k)
260
yield element
261
262
263
def assert_relative(path):
264
if not os.path.isabs(path):
265
return path
266
from distutils.errors import DistutilsSetupError
267
268
msg = textwrap.dedent("""
269
Error: setup script specifies an absolute path:
270
271
%s
272
273
setup() arguments must *always* be /-separated paths relative to the
274
setup.py directory, *never* absolute paths.
275
""").lstrip() % path
276
raise DistutilsSetupError(msg)
277
278