Team Ai
Datasetpublic

codekingpro/portable-devtools

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