CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
depends.py186 linesDownload Raw Back to setuptools
1from __future__ import annotations2 3import contextlib4import dis5import marshal6import sys7from types import CodeType8from typing import Any, Literal, TypeVar9 10from packaging.version import Version11 12from . import _imp13from ._imp import PY_COMPILED, PY_FROZEN, PY_SOURCE, find_module14 15_T = TypeVar("_T")16 17__all__ = ['Require', 'find_module']18 19 20class Require:21    """A prerequisite to building or installing a distribution"""22 23    def __init__(24        self,25        name,26        requested_version,27        module,28        homepage: str = '',29        attribute=None,30        format=None,31    ) -> None:32        if format is None and requested_version is not None:33            format = Version34 35        if format is not None:36            requested_version = format(requested_version)37            if attribute is None:38                attribute = '__version__'39 40        self.__dict__.update(locals())41        del self.self42 43    def full_name(self):44        """Return full package/distribution name, w/version"""45        if self.requested_version is not None:46            return f'{self.name}-{self.requested_version}'47        return self.name48 49    def version_ok(self, version):50        """Is 'version' sufficiently up-to-date?"""51        return (52            self.attribute is None53            or self.format is None54            or str(version) != "unknown"55            and self.format(version) >= self.requested_version56        )57 58    def get_version(59        self, paths=None, default: _T | Literal["unknown"] = "unknown"60    ) -> _T | Literal["unknown"] | None | Any:61        """Get version number of installed module, 'None', or 'default'62 63        Search 'paths' for module.  If not found, return 'None'.  If found,64        return the extracted version attribute, or 'default' if no version65        attribute was specified, or the value cannot be determined without66        importing the module.  The version is formatted according to the67        requirement's version format (if any), unless it is 'None' or the68        supplied 'default'.69        """70 71        if self.attribute is None:72            try:73                f, _p, _i = find_module(self.module, paths)74            except ImportError:75                return None76            if f:77                f.close()78            return default79 80        v = get_module_constant(self.module, self.attribute, default, paths)81 82        if v is not None and v is not default and self.format is not None:83            return self.format(v)84 85        return v86 87    def is_present(self, paths=None):88        """Return true if dependency is present on 'paths'"""89        return self.get_version(paths) is not None90 91    def is_current(self, paths=None):92        """Return true if dependency is present and up-to-date on 'paths'"""93        version = self.get_version(paths)94        if version is None:95            return False96        return self.version_ok(str(version))97 98 99def maybe_close(f):100    @contextlib.contextmanager101    def empty():102        yield103        return104 105    if not f:106        return empty()107 108    return contextlib.closing(f)109 110 111# Some objects are not available on some platforms.112# XXX it'd be better to test assertions about bytecode instead.113if not sys.platform.startswith('java') and sys.platform != 'cli':114 115    def get_module_constant(116        module, symbol, default: _T | int = -1, paths=None117    ) -> _T | int | None | Any:118        """Find 'module' by searching 'paths', and extract 'symbol'119 120        Return 'None' if 'module' does not exist on 'paths', or it does not define121        'symbol'.  If the module defines 'symbol' as a constant, return the122        constant.  Otherwise, return 'default'."""123 124        try:125            f, path, (_suffix, _mode, kind) = info = find_module(module, paths)126        except ImportError:127            # Module doesn't exist128            return None129 130        with maybe_close(f):131            if kind == PY_COMPILED:132                f.read(8)  # skip magic & date133                code = marshal.load(f)134            elif kind == PY_FROZEN:135                code = _imp.get_frozen_object(module, paths)136            elif kind == PY_SOURCE:137                code = compile(f.read(), path, 'exec')138            else:139                # Not something we can parse; we'll have to import it.  :(140                imported = _imp.get_module(module, paths, info)141                return getattr(imported, symbol, None)142 143        return extract_constant(code, symbol, default)144 145    def extract_constant(146        code: CodeType, symbol: str, default: _T | int = -1147    ) -> _T | int | None | Any:148        """Extract the constant value of 'symbol' from 'code'149 150        If the name 'symbol' is bound to a constant value by the Python code151        object 'code', return that value.  If 'symbol' is bound to an expression,152        return 'default'.  Otherwise, return 'None'.153 154        Return value is based on the first assignment to 'symbol'.  'symbol' must155        be a global, or at least a non-"fast" local in the code block.  That is,156        only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol'157        must be present in 'code.co_names'.158        """159        if symbol not in code.co_names:160            # name's not there, can't possibly be an assignment161            return None162 163        name_idx = list(code.co_names).index(symbol)164 165        STORE_NAME = dis.opmap['STORE_NAME']166        STORE_GLOBAL = dis.opmap['STORE_GLOBAL']167        LOAD_CONST = dis.opmap['LOAD_CONST']168 169        const = default170 171        for byte_code in dis.Bytecode(code):172            op = byte_code.opcode173            arg = byte_code.arg174 175            if op == LOAD_CONST:176                assert arg is not None177                const = code.co_consts[arg]178            elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):179                return const180            else:181                const = default182 183        return None184 185    __all__ += ['get_module_constant', 'extract_constant']186