annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/wheel.py @ 68:5028fdace37b

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