comparison lib/python3.8/site-packages/setuptools/wheel.py @ 0:9e54283cc701 draft

"planemo upload commit d12c32a45bcd441307e632fca6d9af7d60289d44"
author guerler
date Mon, 27 Jul 2020 03:47:31 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:9e54283cc701
1 """Wheels support."""
2
3 from distutils.util import get_platform
4 from distutils import log
5 import email
6 import itertools
7 import os
8 import posixpath
9 import re
10 import zipfile
11
12 import pkg_resources
13 import setuptools
14 from pkg_resources import parse_version
15 from setuptools.extern.packaging.tags import sys_tags
16 from setuptools.extern.packaging.utils import canonicalize_name
17 from setuptools.extern.six import PY3
18 from setuptools.command.egg_info import write_requirements
19
20
21 __metaclass__ = type
22
23
24 WHEEL_NAME = re.compile(
25 r"""^(?P<project_name>.+?)-(?P<version>\d.*?)
26 ((-(?P<build>\d.*?))?-(?P<py_version>.+?)-(?P<abi>.+?)-(?P<platform>.+?)
27 )\.whl$""",
28 re.VERBOSE).match
29
30 NAMESPACE_PACKAGE_INIT = '''\
31 try:
32 __import__('pkg_resources').declare_namespace(__name__)
33 except ImportError:
34 __path__ = __import__('pkgutil').extend_path(__path__, __name__)
35 '''
36
37
38 def unpack(src_dir, dst_dir):
39 '''Move everything under `src_dir` to `dst_dir`, and delete the former.'''
40 for dirpath, dirnames, filenames in os.walk(src_dir):
41 subdir = os.path.relpath(dirpath, src_dir)
42 for f in filenames:
43 src = os.path.join(dirpath, f)
44 dst = os.path.join(dst_dir, subdir, f)
45 os.renames(src, dst)
46 for n, d in reversed(list(enumerate(dirnames))):
47 src = os.path.join(dirpath, d)
48 dst = os.path.join(dst_dir, subdir, d)
49 if not os.path.exists(dst):
50 # Directory does not exist in destination,
51 # rename it and prune it from os.walk list.
52 os.renames(src, dst)
53 del dirnames[n]
54 # Cleanup.
55 for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True):
56 assert not filenames
57 os.rmdir(dirpath)
58
59
60 class Wheel:
61
62 def __init__(self, filename):
63 match = WHEEL_NAME(os.path.basename(filename))
64 if match is None:
65 raise ValueError('invalid wheel name: %r' % filename)
66 self.filename = filename
67 for k, v in match.groupdict().items():
68 setattr(self, k, v)
69
70 def tags(self):
71 '''List tags (py_version, abi, platform) supported by this wheel.'''
72 return itertools.product(
73 self.py_version.split('.'),
74 self.abi.split('.'),
75 self.platform.split('.'),
76 )
77
78 def is_compatible(self):
79 '''Is the wheel is compatible with the current platform?'''
80 supported_tags = set(
81 (t.interpreter, t.abi, t.platform) for t in sys_tags())
82 return next((True for t in self.tags() if t in supported_tags), False)
83
84 def egg_name(self):
85 return pkg_resources.Distribution(
86 project_name=self.project_name, version=self.version,
87 platform=(None if self.platform == 'any' else get_platform()),
88 ).egg_name() + '.egg'
89
90 def get_dist_info(self, zf):
91 # find the correct name of the .dist-info dir in the wheel file
92 for member in zf.namelist():
93 dirname = posixpath.dirname(member)
94 if (dirname.endswith('.dist-info') and
95 canonicalize_name(dirname).startswith(
96 canonicalize_name(self.project_name))):
97 return dirname
98 raise ValueError("unsupported wheel format. .dist-info not found")
99
100 def install_as_egg(self, destination_eggdir):
101 '''Install wheel as an egg directory.'''
102 with zipfile.ZipFile(self.filename) as zf:
103 self._install_as_egg(destination_eggdir, zf)
104
105 def _install_as_egg(self, destination_eggdir, zf):
106 dist_basename = '%s-%s' % (self.project_name, self.version)
107 dist_info = self.get_dist_info(zf)
108 dist_data = '%s.data' % dist_basename
109 egg_info = os.path.join(destination_eggdir, 'EGG-INFO')
110
111 self._convert_metadata(zf, destination_eggdir, dist_info, egg_info)
112 self._move_data_entries(destination_eggdir, dist_data)
113 self._fix_namespace_packages(egg_info, destination_eggdir)
114
115 @staticmethod
116 def _convert_metadata(zf, destination_eggdir, dist_info, egg_info):
117 def get_metadata(name):
118 with zf.open(posixpath.join(dist_info, name)) as fp:
119 value = fp.read().decode('utf-8') if PY3 else fp.read()
120 return email.parser.Parser().parsestr(value)
121
122 wheel_metadata = get_metadata('WHEEL')
123 # Check wheel format version is supported.
124 wheel_version = parse_version(wheel_metadata.get('Wheel-Version'))
125 wheel_v1 = (
126 parse_version('1.0') <= wheel_version < parse_version('2.0dev0')
127 )
128 if not wheel_v1:
129 raise ValueError(
130 'unsupported wheel format version: %s' % wheel_version)
131 # Extract to target directory.
132 os.mkdir(destination_eggdir)
133 zf.extractall(destination_eggdir)
134 # Convert metadata.
135 dist_info = os.path.join(destination_eggdir, dist_info)
136 dist = pkg_resources.Distribution.from_location(
137 destination_eggdir, dist_info,
138 metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info),
139 )
140
141 # Note: Evaluate and strip markers now,
142 # as it's difficult to convert back from the syntax:
143 # foobar; "linux" in sys_platform and extra == 'test'
144 def raw_req(req):
145 req.marker = None
146 return str(req)
147 install_requires = list(sorted(map(raw_req, dist.requires())))
148 extras_require = {
149 extra: sorted(
150 req
151 for req in map(raw_req, dist.requires((extra,)))
152 if req not in install_requires
153 )
154 for extra in dist.extras
155 }
156 os.rename(dist_info, egg_info)
157 os.rename(
158 os.path.join(egg_info, 'METADATA'),
159 os.path.join(egg_info, 'PKG-INFO'),
160 )
161 setup_dist = setuptools.Distribution(
162 attrs=dict(
163 install_requires=install_requires,
164 extras_require=extras_require,
165 ),
166 )
167 # Temporarily disable info traces.
168 log_threshold = log._global_log.threshold
169 log.set_threshold(log.WARN)
170 try:
171 write_requirements(
172 setup_dist.get_command_obj('egg_info'),
173 None,
174 os.path.join(egg_info, 'requires.txt'),
175 )
176 finally:
177 log.set_threshold(log_threshold)
178
179 @staticmethod
180 def _move_data_entries(destination_eggdir, dist_data):
181 """Move data entries to their correct location."""
182 dist_data = os.path.join(destination_eggdir, dist_data)
183 dist_data_scripts = os.path.join(dist_data, 'scripts')
184 if os.path.exists(dist_data_scripts):
185 egg_info_scripts = os.path.join(
186 destination_eggdir, 'EGG-INFO', 'scripts')
187 os.mkdir(egg_info_scripts)
188 for entry in os.listdir(dist_data_scripts):
189 # Remove bytecode, as it's not properly handled
190 # during easy_install scripts install phase.
191 if entry.endswith('.pyc'):
192 os.unlink(os.path.join(dist_data_scripts, entry))
193 else:
194 os.rename(
195 os.path.join(dist_data_scripts, entry),
196 os.path.join(egg_info_scripts, entry),
197 )
198 os.rmdir(dist_data_scripts)
199 for subdir in filter(os.path.exists, (
200 os.path.join(dist_data, d)
201 for d in ('data', 'headers', 'purelib', 'platlib')
202 )):
203 unpack(subdir, destination_eggdir)
204 if os.path.exists(dist_data):
205 os.rmdir(dist_data)
206
207 @staticmethod
208 def _fix_namespace_packages(egg_info, destination_eggdir):
209 namespace_packages = os.path.join(
210 egg_info, 'namespace_packages.txt')
211 if os.path.exists(namespace_packages):
212 with open(namespace_packages) as fp:
213 namespace_packages = fp.read().split()
214 for mod in namespace_packages:
215 mod_dir = os.path.join(destination_eggdir, *mod.split('.'))
216 mod_init = os.path.join(mod_dir, '__init__.py')
217 if not os.path.exists(mod_dir):
218 os.mkdir(mod_dir)
219 if not os.path.exists(mod_init):
220 with open(mod_init, 'w') as fp:
221 fp.write(NAMESPACE_PACKAGE_INIT)