annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/wheel.py @ 69:33d812a61356

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