Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/setuptools/command/build_py.py
4799 views
1
from functools import partial
2
from glob import glob
3
from distutils.util import convert_path
4
import distutils.command.build_py as orig
5
import os
6
import fnmatch
7
import textwrap
8
import io
9
import distutils.errors
10
import itertools
11
import stat
12
import warnings
13
from pathlib import Path
14
from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
15
from setuptools.extern.more_itertools import unique_everseen
16
17
18
def make_writable(target):
19
os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE)
20
21
22
class build_py(orig.build_py):
23
"""Enhanced 'build_py' command that includes data files with packages
24
25
The data files are specified via a 'package_data' argument to 'setup()'.
26
See 'setuptools.dist.Distribution' for more details.
27
28
Also, this version of the 'build_py' command allows you to specify both
29
'py_modules' and 'packages' in the same setup operation.
30
"""
31
32
def finalize_options(self):
33
orig.build_py.finalize_options(self)
34
self.package_data = self.distribution.package_data
35
self.exclude_package_data = self.distribution.exclude_package_data or {}
36
if 'data_files' in self.__dict__:
37
del self.__dict__['data_files']
38
self.__updated_files = []
39
40
def run(self):
41
"""Build modules, packages, and copy data files to build directory"""
42
if not self.py_modules and not self.packages:
43
return
44
45
if self.py_modules:
46
self.build_modules()
47
48
if self.packages:
49
self.build_packages()
50
self.build_package_data()
51
52
# Only compile actual .py files, using our base class' idea of what our
53
# output files are.
54
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
55
56
def __getattr__(self, attr):
57
"lazily compute data files"
58
if attr == 'data_files':
59
self.data_files = self._get_data_files()
60
return self.data_files
61
return orig.build_py.__getattr__(self, attr)
62
63
def build_module(self, module, module_file, package):
64
outfile, copied = orig.build_py.build_module(self, module, module_file, package)
65
if copied:
66
self.__updated_files.append(outfile)
67
return outfile, copied
68
69
def _get_data_files(self):
70
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
71
self.analyze_manifest()
72
return list(map(self._get_pkg_data_files, self.packages or ()))
73
74
def get_data_files_without_manifest(self):
75
"""
76
Generate list of ``(package,src_dir,build_dir,filenames)`` tuples,
77
but without triggering any attempt to analyze or build the manifest.
78
"""
79
# Prevent eventual errors from unset `manifest_files`
80
# (that would otherwise be set by `analyze_manifest`)
81
self.__dict__.setdefault('manifest_files', {})
82
return list(map(self._get_pkg_data_files, self.packages or ()))
83
84
def _get_pkg_data_files(self, package):
85
# Locate package source directory
86
src_dir = self.get_package_dir(package)
87
88
# Compute package build directory
89
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
90
91
# Strip directory from globbed filenames
92
filenames = [
93
os.path.relpath(file, src_dir)
94
for file in self.find_data_files(package, src_dir)
95
]
96
return package, src_dir, build_dir, filenames
97
98
def find_data_files(self, package, src_dir):
99
"""Return filenames for package's data files in 'src_dir'"""
100
patterns = self._get_platform_patterns(
101
self.package_data,
102
package,
103
src_dir,
104
)
105
globs_expanded = map(partial(glob, recursive=True), patterns)
106
# flatten the expanded globs into an iterable of matches
107
globs_matches = itertools.chain.from_iterable(globs_expanded)
108
glob_files = filter(os.path.isfile, globs_matches)
109
files = itertools.chain(
110
self.manifest_files.get(package, []),
111
glob_files,
112
)
113
return self.exclude_data_files(package, src_dir, files)
114
115
def build_package_data(self):
116
"""Copy data files into build directory"""
117
for package, src_dir, build_dir, filenames in self.data_files:
118
for filename in filenames:
119
target = os.path.join(build_dir, filename)
120
self.mkpath(os.path.dirname(target))
121
srcfile = os.path.join(src_dir, filename)
122
outf, copied = self.copy_file(srcfile, target)
123
make_writable(target)
124
srcfile = os.path.abspath(srcfile)
125
126
def analyze_manifest(self):
127
self.manifest_files = mf = {}
128
if not self.distribution.include_package_data:
129
return
130
src_dirs = {}
131
for package in self.packages or ():
132
# Locate package source directory
133
src_dirs[assert_relative(self.get_package_dir(package))] = package
134
135
self.run_command('egg_info')
136
check = _IncludePackageDataAbuse()
137
ei_cmd = self.get_finalized_command('egg_info')
138
for path in ei_cmd.filelist.files:
139
d, f = os.path.split(assert_relative(path))
140
prev = None
141
oldf = f
142
while d and d != prev and d not in src_dirs:
143
prev = d
144
d, df = os.path.split(d)
145
f = os.path.join(df, f)
146
if d in src_dirs:
147
if f == oldf:
148
if check.is_module(f):
149
continue # it's a module, not data
150
else:
151
importable = check.importable_subpackage(src_dirs[d], f)
152
if importable:
153
check.warn(importable)
154
mf.setdefault(src_dirs[d], []).append(path)
155
156
def get_data_files(self):
157
pass # Lazily compute data files in _get_data_files() function.
158
159
def check_package(self, package, package_dir):
160
"""Check namespace packages' __init__ for declare_namespace"""
161
try:
162
return self.packages_checked[package]
163
except KeyError:
164
pass
165
166
init_py = orig.build_py.check_package(self, package, package_dir)
167
self.packages_checked[package] = init_py
168
169
if not init_py or not self.distribution.namespace_packages:
170
return init_py
171
172
for pkg in self.distribution.namespace_packages:
173
if pkg == package or pkg.startswith(package + '.'):
174
break
175
else:
176
return init_py
177
178
with io.open(init_py, 'rb') as f:
179
contents = f.read()
180
if b'declare_namespace' not in contents:
181
raise distutils.errors.DistutilsError(
182
"Namespace package problem: %s is a namespace package, but "
183
"its\n__init__.py does not call declare_namespace()! Please "
184
'fix it.\n(See the setuptools manual under '
185
'"Namespace Packages" for details.)\n"' % (package,)
186
)
187
return init_py
188
189
def initialize_options(self):
190
self.packages_checked = {}
191
orig.build_py.initialize_options(self)
192
193
def get_package_dir(self, package):
194
res = orig.build_py.get_package_dir(self, package)
195
if self.distribution.src_root is not None:
196
return os.path.join(self.distribution.src_root, res)
197
return res
198
199
def exclude_data_files(self, package, src_dir, files):
200
"""Filter filenames for package's data files in 'src_dir'"""
201
files = list(files)
202
patterns = self._get_platform_patterns(
203
self.exclude_package_data,
204
package,
205
src_dir,
206
)
207
match_groups = (fnmatch.filter(files, pattern) for pattern in patterns)
208
# flatten the groups of matches into an iterable of matches
209
matches = itertools.chain.from_iterable(match_groups)
210
bad = set(matches)
211
keepers = (fn for fn in files if fn not in bad)
212
# ditch dupes
213
return list(unique_everseen(keepers))
214
215
@staticmethod
216
def _get_platform_patterns(spec, package, src_dir):
217
"""
218
yield platform-specific path patterns (suitable for glob
219
or fn_match) from a glob-based spec (such as
220
self.package_data or self.exclude_package_data)
221
matching package in src_dir.
222
"""
223
raw_patterns = itertools.chain(
224
spec.get('', []),
225
spec.get(package, []),
226
)
227
return (
228
# Each pattern has to be converted to a platform-specific path
229
os.path.join(src_dir, convert_path(pattern))
230
for pattern in raw_patterns
231
)
232
233
234
def assert_relative(path):
235
if not os.path.isabs(path):
236
return path
237
from distutils.errors import DistutilsSetupError
238
239
msg = (
240
textwrap.dedent(
241
"""
242
Error: setup script specifies an absolute path:
243
244
%s
245
246
setup() arguments must *always* be /-separated paths relative to the
247
setup.py directory, *never* absolute paths.
248
"""
249
).lstrip()
250
% path
251
)
252
raise DistutilsSetupError(msg)
253
254
255
class _IncludePackageDataAbuse:
256
"""Inform users that package or module is included as 'data file'"""
257
258
MESSAGE = """\
259
Installing {importable!r} as data is deprecated, please list it in `packages`.
260
!!\n\n
261
############################
262
# Package would be ignored #
263
############################
264
Python recognizes {importable!r} as an importable package, however it is
265
included in the distribution as "data".
266
This behavior is likely to change in future versions of setuptools (and
267
therefore is considered deprecated).
268
269
Please make sure that {importable!r} is included as a package by using
270
setuptools' `packages` configuration field or the proper discovery methods
271
(for example by using `find_namespace_packages(...)`/`find_namespace:`
272
instead of `find_packages(...)`/`find:`).
273
274
You can read more about "package discovery" and "data files" on setuptools
275
documentation page.
276
\n\n!!
277
"""
278
279
def __init__(self):
280
self._already_warned = set()
281
282
def is_module(self, file):
283
return file.endswith(".py") and file[:-len(".py")].isidentifier()
284
285
def importable_subpackage(self, parent, file):
286
pkg = Path(file).parent
287
parts = list(itertools.takewhile(str.isidentifier, pkg.parts))
288
if parts:
289
return ".".join([parent, *parts])
290
return None
291
292
def warn(self, importable):
293
if importable not in self._already_warned:
294
msg = textwrap.dedent(self.MESSAGE).format(importable=importable)
295
warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2)
296
self._already_warned.add(importable)
297
298