Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
_static.py189 linesDownload Raw Back to setuptools
1from functools import wraps2from typing import TypeVar3 4import packaging.specifiers5 6from .warnings import SetuptoolsDeprecationWarning7 8 9class Static:10    """11    Wrapper for built-in object types that are allow setuptools to identify12    static core metadata (in opposition to ``Dynamic``, as defined :pep:`643`).13 14    The trick is to mark values with :class:`Static` when they come from15    ``pyproject.toml`` or ``setup.cfg``, so if any plugin overwrite the value16    with a built-in, setuptools will be able to recognise the change.17 18    We inherit from built-in classes, so that we don't need to change the existing19    code base to deal with the new types.20    We also should strive for immutability objects to avoid changes after the21    initial parsing.22    """23 24    _mutated_: bool = False  # TODO: Remove after deprecation warning is solved25 26 27def _prevent_modification(target: type, method: str, copying: str) -> None:28    """29    Because setuptools is very flexible we cannot fully prevent30    plugins and user customizations from modifying static values that were31    parsed from config files.32    But we can attempt to block "in-place" mutations and identify when they33    were done.34    """35    fn = getattr(target, method, None)36    if fn is None:37        return38 39    @wraps(fn)40    def _replacement(self: Static, *args, **kwargs):41        # TODO: After deprecation period raise NotImplementedError instead of warning42        #       which obviated the existence and checks of the `_mutated_` attribute.43        self._mutated_ = True44        SetuptoolsDeprecationWarning.emit(45            "Direct modification of value will be disallowed",46            f"""47            In an effort to implement PEP 643, direct/in-place changes of static values48            that come from configuration files are deprecated.49            If you need to modify this value, please first create a copy with {copying}50            and make sure conform to all relevant standards when overriding setuptools51            functionality (https://packaging.python.org/en/latest/specifications/).52            """,53            due_date=(2025, 10, 10),  # Initially introduced in 2024-09-0654        )55        return fn(self, *args, **kwargs)56 57    _replacement.__doc__ = ""  # otherwise doctest may fail.58    setattr(target, method, _replacement)59 60 61class Str(str, Static):62    pass63 64 65class Tuple(tuple, Static):66    pass67 68 69class List(list, Static):70    """71    :meta private:72    >>> x = List([1, 2, 3])73    >>> is_static(x)74    True75    >>> x += [0]  # doctest: +IGNORE_EXCEPTION_DETAIL76    Traceback (most recent call last):77    SetuptoolsDeprecationWarning: Direct modification ...78    >>> is_static(x)  # no longer static after modification79    False80    >>> y = list(x)81    >>> y.clear()82    >>> y83    []84    >>> y == x85    False86    >>> is_static(List(y))87    True88    """89 90 91# Make `List` immutable-ish92# (certain places of setuptools/distutils issue a warn if we use tuple instead of list)93for _method in (94    '__delitem__',95    '__iadd__',96    '__setitem__',97    'append',98    'clear',99    'extend',100    'insert',101    'remove',102    'reverse',103    'pop',104):105    _prevent_modification(List, _method, "`list(value)`")106 107 108class Dict(dict, Static):109    """110    :meta private:111    >>> x = Dict({'a': 1, 'b': 2})112    >>> is_static(x)113    True114    >>> x['c'] = 0  # doctest: +IGNORE_EXCEPTION_DETAIL115    Traceback (most recent call last):116    SetuptoolsDeprecationWarning: Direct modification ...117    >>> x._mutated_118    True119    >>> is_static(x)  # no longer static after modification120    False121    >>> y = dict(x)122    >>> y.popitem()123    ('b', 2)124    >>> y == x125    False126    >>> is_static(Dict(y))127    True128    """129 130 131# Make `Dict` immutable-ish (we cannot inherit from types.MappingProxyType):132for _method in (133    '__delitem__',134    '__ior__',135    '__setitem__',136    'clear',137    'pop',138    'popitem',139    'setdefault',140    'update',141):142    _prevent_modification(Dict, _method, "`dict(value)`")143 144 145class SpecifierSet(packaging.specifiers.SpecifierSet, Static):146    """Not exactly a built-in type but useful for ``requires-python``"""147 148 149T = TypeVar("T")150 151 152def noop(value: T) -> T:153    """154    >>> noop(42)155    42156    """157    return value158 159 160_CONVERSIONS = {str: Str, tuple: Tuple, list: List, dict: Dict}161 162 163def attempt_conversion(value: T) -> T:164    """165    >>> is_static(attempt_conversion("hello"))166    True167    >>> is_static(object())168    False169    """170    return _CONVERSIONS.get(type(value), noop)(value)  # type: ignore[call-overload]171 172 173def is_static(value: object) -> bool:174    """175    >>> is_static(a := Dict({'a': 1}))176    True177    >>> is_static(dict(a))178    False179    >>> is_static(b := List([1, 2, 3]))180    True181    >>> is_static(list(b))182    False183    """184    return isinstance(value, Static) and not value._mutated_185 186 187EMPTY_LIST = List()188EMPTY_DICT = Dict()189 
codekingpro/portable-devtools · Team Ai