Import python venv for stability

This commit is contained in:
2026-02-15 21:24:16 -08:00
parent 1343e93a59
commit 7d784705c9
4997 changed files with 1628270 additions and 0 deletions
@@ -0,0 +1,61 @@
r"""
Provides frozendict, a simple immutable dictionary.
"""
try: # pragma: no cover
from ._frozendict import *
c_ext = True
# noinspection PyUnresolvedReferences
del _frozendict
except ImportError:
from ._frozendict_py import *
c_ext = False
from . import cool
from . import monkeypatch
from .cool import *
from .version import version as __version__
def _getFrozendictJsonEncoder(BaseJsonEncoder = None):
if BaseJsonEncoder is None: # pragma: no cover
from json.encoder import JSONEncoder
BaseJsonEncoder = JSONEncoder
class FrozendictJsonEncoderInternal(BaseJsonEncoder):
def default(self, obj):
if isinstance(obj, frozendict): # pragma: no cover
# TODO create a C serializer
return dict(obj)
return BaseJsonEncoder.default(
self,
obj
) # pragma: no cover
return FrozendictJsonEncoderInternal
FrozendictJsonEncoder = _getFrozendictJsonEncoder()
monkeypatch.patchOrUnpatchAll(patch = True, warn = False)
from collections.abc import Mapping
# noinspection PyUnresolvedReferences
Mapping.register(frozendict)
del Mapping
if c_ext: # pragma: no cover
__all__ = (frozendict.__name__, )
else:
__all__ = _frozendict_py.__all__
del _frozendict_py
# TODO deprecated, to remove in future versions
FrozenOrderedDict = frozendict
__all__ += cool.__all__
__all__ += (FrozendictJsonEncoder.__name__, "FrozenOrderedDict")
@@ -0,0 +1,123 @@
from __future__ import annotations
from typing import (
TypeVar,
overload,
Optional,
Union,
Any,
Dict,
Callable,
)
from collections.abc import Hashable
try:
from typing import Mapping, Iterable, Iterator, Tuple, Type
except ImportError:
from collections.abc import Mapping, Iterable, Iterator
Tuple = tuple
Type = type
K = TypeVar("K")
V = TypeVar("V", covariant=True)
K2 = TypeVar("K2")
V2 = TypeVar("V2", covariant=True)
SelfT = TypeVar("SelfT", bound=frozendict[K, V])
# noinspection PyPep8Naming
class frozendict(Mapping[K, V]):
@overload
def __new__(cls: Type[SelfT]) -> SelfT: ...
@overload
def __new__(cls: Type[SelfT], **kwargs: V) -> frozendict[str, V]: ...
@overload
def __new__(cls: Type[SelfT], mapping: Mapping[K, V]) -> SelfT: ...
@overload
def __new__(cls: Type[SelfT], iterable: Iterable[Tuple[K, V]]) -> SelfT: ...
def __getitem__(self: SelfT, key: K) -> V: ...
def __len__(self: SelfT) -> int: ...
def __iter__(self: SelfT) -> Iterator[K]: ...
def __hash__(self: SelfT) -> int: ...
def __reversed__(self: SelfT) -> Iterator[K]: ...
def copy(self: SelfT) -> SelfT: ...
def __copy__(self: SelfT) -> SelfT: ...
def __deepcopy__(self: SelfT) -> SelfT: ...
def delete(self: SelfT, key: K) -> SelfT: ...
@overload
def key(self: SelfT, index: int) -> K: ...
@overload
def key(self: SelfT) -> K: ...
@overload
def value(self: SelfT, index: int) -> V: ...
@overload
def value(self: SelfT) -> V: ...
@overload
def item(self: SelfT, index: int) -> Tuple[K, V]: ...
@overload
def item(self: SelfT) -> Tuple[K, V]: ...
@overload
def __or__(self: SelfT, other: Mapping[K, V]) -> SelfT: ...
@overload
def __or__(self: SelfT, other: Mapping[K2, V]) -> frozendict[Union[K, K2], V]: ...
@overload
def __or__(self: SelfT, other: Mapping[K, V2]) -> frozendict[K, Union[V, V2]]: ...
@overload
def __or__(self: SelfT, other: Mapping[K2, V2]) -> frozendict[Union[K, K2], Union[V, V2]]: ...
@overload
def set(self: SelfT, key: K, value: V) -> SelfT: ...
@overload
def set(self: SelfT, key: K2, value: V) -> frozendict[Union[K, K2], V]: ...
@overload
def set(self: SelfT, key: K, value: V2) -> frozendict[K, Union[V, V2]]: ...
@overload
def set(self: SelfT, key: K2, value: V2) -> frozendict[Union[K, K2], Union[V, V2]]: ...
@overload
def setdefault(self: SelfT, key: K) -> SelfT: ...
@overload
def setdefault(self: SelfT, key: K2) -> SelfT: ...
@overload
def setdefault(self: SelfT, key: K, default: V) -> SelfT: ...
@overload
def setdefault(self: SelfT, key: K2, default: V) -> frozendict[Union[K, K2], V]: ...
@overload
def setdefault(self: SelfT, key: K, default: V2) -> frozendict[K, Union[V, V2]]: ...
@overload
def setdefault(self: SelfT, key: K2, default: V2) -> frozendict[Union[K, K2], Union[V, V2]]: ...
@classmethod
def fromkeys(
cls: Type[SelfT],
seq: Iterable[K],
value: Optional[V] = None
) -> SelfT: ...
FrozenOrderedDict = frozendict
c_ext: bool
class FreezeError(Exception): pass
class FreezeWarning(UserWarning): pass
# PyCharm complains about returning Hashable, because
# it's not subscriptable
def deepfreeze(
o: Any,
custom_converters: Optional[Dict[Any, Callable[[Any], Hashable]]] = None,
custom_inverse_converters: Optional[Dict[Any, Callable[[Any], Any]]] = None
) -> Any: ...
def register(
to_convert: Any,
converter: Callable[[Any], Any],
*,
inverse: bool = False
) -> None: ...
def unregister(
type: Any,
inverse: bool = False
) -> None: ...
@@ -0,0 +1,254 @@
from copy import deepcopy
def immutable(self, *_args, **_kwargs):
r"""
Function for not implemented method since the object is immutable
"""
raise AttributeError(
f"'{self.__class__.__name__}' object is read-only"
)
_empty_frozendict = None
_module_name = "frozendict"
# noinspection PyPep8Naming
class frozendict(dict):
r"""
A simple immutable dictionary.
The API is the same as `dict`, without methods that can change the
immutability. In addition, it supports __hash__().
"""
__slots__ = (
"_hash",
)
@classmethod
def fromkeys(cls, *args, **kwargs):
r"""
Identical to dict.fromkeys().
"""
return cls(dict.fromkeys(*args, **kwargs))
# noinspection PyMethodParameters
def __new__(e4b37cdf_d78a_4632_bade_6f0579d8efac, *args, **kwargs):
cls = e4b37cdf_d78a_4632_bade_6f0579d8efac
has_kwargs = bool(kwargs)
continue_creation = True
self = None
# check if there's only an argument and it's of the same class
if len(args) == 1 and not has_kwargs:
it = args[0]
# no isinstance, to avoid subclassing problems
if it.__class__ == frozendict and cls == frozendict:
self = it
continue_creation = False
if continue_creation:
self = dict.__new__(cls, *args, **kwargs)
dict.__init__(self, *args, **kwargs)
# empty singleton - start
if self.__class__ == frozendict and not len(self):
global _empty_frozendict
if _empty_frozendict is None:
_empty_frozendict = self
else:
self = _empty_frozendict
continue_creation = False
# empty singleton - end
if continue_creation:
object.__setattr__(self, "_hash", -1)
return self
# noinspection PyMissingConstructor
def __init__(self, *args, **kwargs):
pass
def __hash__(self, *args, **kwargs):
r"""
Calculates the hash if all values are hashable, otherwise
raises a TypeError.
"""
if self._hash != -1:
_hash = self._hash
else:
fs = frozenset(self.items())
_hash = hash(fs)
object.__setattr__(self, "_hash", _hash)
return _hash
def __repr__(self, *args, **kwargs):
r"""
Identical to dict.__repr__().
"""
body = super().__repr__(*args, **kwargs)
klass = self.__class__
if klass == frozendict:
name = f"{_module_name}.{klass.__name__}"
else:
name = klass.__name__
return f"{name}({body})"
def copy(self):
r"""
Return the object itself, as it's an immutable.
"""
klass = self.__class__
if klass == frozendict:
return self
return klass(self)
def __copy__(self, *args, **kwargs):
r"""
See copy().
"""
return self.copy()
def __deepcopy__(self, memo, *args, **kwargs):
r"""
As for tuples, if hashable, see copy(); otherwise, it returns a
deepcopy.
"""
klass = self.__class__
return_copy = klass == frozendict
if return_copy:
try:
hash(self)
except TypeError:
return_copy = False
if return_copy:
return self.copy()
tmp = deepcopy(dict(self))
return klass(tmp)
def __reduce__(self, *args, **kwargs):
r"""
Support for `pickle`.
"""
return (self.__class__, (dict(self),))
def set(self, key, val):
new_self = dict(self)
new_self[key] = val
return self.__class__(new_self)
def setdefault(self, key, default=None):
if key in self:
return self
new_self = dict(self)
new_self[key] = default
return self.__class__(new_self)
def delete(self, key):
new_self = dict(self)
del new_self[key]
if new_self:
return self.__class__(new_self)
return self.__class__()
def _get_by_index(self, collection, index):
try:
return collection[index]
except IndexError:
maxindex = len(collection) - 1
name = self.__class__.__name__
raise IndexError(
f"{name} index {index} out of range {maxindex}"
) from None
def key(self, index=0):
collection = tuple(self.keys())
return self._get_by_index(collection, index)
def value(self, index=0):
collection = tuple(self.values())
return self._get_by_index(collection, index)
def item(self, index=0):
collection = tuple(self.items())
return self._get_by_index(collection, index)
def __setitem__(self, key, val, *args, **kwargs):
raise TypeError(
f"'{self.__class__.__name__}' object doesn't support item "
"assignment"
)
def __delitem__(self, key, *args, **kwargs):
raise TypeError(
f"'{self.__class__.__name__}' object doesn't support item "
"deletion"
)
def frozendict_or(self, other, *_args, **_kwargs):
res = {}
res.update(self)
res.update(other)
return self.__class__(res)
frozendict.__or__ = frozendict_or
frozendict.__ior__ = frozendict_or
try:
# noinspection PyStatementEffect
frozendict.__reversed__
except AttributeError: # pragma: no cover
def frozendict_reversed(self, *_args, **_kwargs):
return reversed(tuple(self))
frozendict.__reversed__ = frozendict_reversed
frozendict.clear = immutable
frozendict.pop = immutable
frozendict.popitem = immutable
frozendict.update = immutable
frozendict.__delattr__ = immutable
frozendict.__setattr__ = immutable
frozendict.__module__ = _module_name
__all__ = (frozendict.__name__,)
@@ -0,0 +1,328 @@
from collections.abc import MutableMapping, MutableSequence, MutableSet
from enum import Enum
from types import MappingProxyType
from array import array
from frozendict import frozendict
# fix for python 3.9-
# coverage does not work here!
if not issubclass(array, MutableSequence): # pragma: no cover
# noinspection PyUnresolvedReferences
MutableSequence.register(array)
def isIterableNotString(o):
from collections import abc
return (
isinstance(o, abc.Iterable) and
not isinstance(o, memoryview) and
not hasattr(o, "isalpha")
)
def getItems(o):
from collections import abc
if not isinstance(o, abc.Iterable):
raise TypeError("object must be an iterable")
if isinstance(o, abc.Mapping):
return dict.items
return enumerate
def nil(x):
return x
_freeze_conversion_map = frozendict({
MutableMapping: frozendict,
bytearray: bytes,
MutableSequence: tuple,
MutableSet: frozenset,
Enum: nil,
})
_freeze_conversion_map_custom = {}
class FreezeError(Exception):
pass
class FreezeWarning(UserWarning):
pass
def register(to_convert, converter, *, inverse = False):
r"""
Adds a `converter` for a type `to_convert`. `converter`
must be callable. The new converter will be used by `deepfreeze()`
and has precedence over any previous converter.
If `to_covert` has already a converter, a FreezeWarning is raised.
If `inverse` is True, the conversion is considered from an immutable
type to a mutable one. This make it possible to convert mutable
objects nested in the registered immutable one.
"""
if not issubclass(type(to_convert), type):
raise ValueError(
f"`to_convert` parameter must be a type, {to_convert} found"
)
try:
converter.__call__
except AttributeError:
raise ValueError(
f"`converter` parameter must be a callable, {converter}" +
"found"
)
if inverse:
freeze_conversion_map = getFreezeConversionInverseMap()
else:
freeze_conversion_map = getFreezeConversionMap()
if to_convert in freeze_conversion_map:
import warnings
warnings.warn(
f"{to_convert.__name__} is already in the conversion map",
FreezeWarning
)
if inverse:
freeze_conversion_map = _freeze_conversion_inverse_map_custom
else:
freeze_conversion_map = _freeze_conversion_map_custom
freeze_conversion_map[to_convert] = converter
def unregister(type, inverse = False):
r"""
Unregister a type from custom conversion. If `inverse` is `True`,
the unregistered conversion is an inverse conversion
(see `register()`).
"""
if inverse:
freeze_conversion_map = _freeze_conversion_inverse_map_custom
else:
freeze_conversion_map = _freeze_conversion_map_custom
try:
del freeze_conversion_map[type]
except KeyError:
raise FreezeError(f"{type.__name__} is not registered")
def getFreezeConversionMap():
return _freeze_conversion_map | _freeze_conversion_map_custom
_freeze_conversion_inverse_map = frozendict({
frozendict: dict,
MappingProxyType: dict,
tuple: list,
})
_freeze_conversion_inverse_map_custom = {}
def getFreezeConversionInverseMap():
return (
_freeze_conversion_inverse_map |
_freeze_conversion_inverse_map_custom
)
_freeze_types = (
[x for x in _freeze_conversion_map] +
[x for x in _freeze_conversion_inverse_map]
)
def getFreezeTypes():
return (tuple(
_freeze_types +
[x for x in _freeze_conversion_map_custom] +
[x for x in _freeze_conversion_inverse_map_custom]
))
_freeze_types_plain = (MutableSet, bytearray, array)
def deepfreeze(
o,
custom_converters = None,
custom_inverse_converters = None
):
r"""
Converts the object and all the objects nested in it in its
immutable counterparts.
The conversion map is in getFreezeConversionMap().
You can register a new conversion using `register()` You can also
pass a map of custom converters with `custom_converters` and a map
of custom inverse converters with `custom_inverse_converters`,
without using `register()`.
By default, if the type is not registered and has a `__dict__`
attribute, it's converted to the `frozendict` of that `__dict__`.
This function assumes that hashable == immutable (that is not
always true).
This function uses recursion, with all the limits of recursions in
Python.
Where is a good old tail call when you need it?
"""
from frozendict import frozendict
if custom_converters is None:
custom_converters = frozendict()
if custom_inverse_converters is None:
custom_inverse_converters = frozendict()
for type_i, converter in custom_converters.items():
if not issubclass(type(type_i), type):
raise ValueError(
f"{type_i} in `custom_converters` parameter is not a " +
"type"
)
try:
converter.__call__
except AttributeError:
raise ValueError(
f"converter for {type_i} in `custom_converters` " +
"parameter is not a callable"
)
for type_i, converter in custom_inverse_converters.items():
if not issubclass(type(type_i), type):
raise ValueError(
f"{type_i} in `custom_inverse_converters` parameter " +
"is not a type"
)
try:
converter.__call__
except AttributeError:
raise ValueError(
f"converter for {type_i} in " +
"`custom_inverse_converters`parameter is not a callable"
)
type_o = type(o)
freeze_types = tuple(custom_converters.keys()) + getFreezeTypes()
base_type_o = None
for freeze_type in freeze_types:
if isinstance(o, freeze_type):
base_type_o = freeze_type
break
if base_type_o is None:
# this is before hash check because all object in Python are
# hashable by default, if not explicitly suppressed
try:
o.__dict__
except AttributeError:
pass
else:
return frozendict(o.__dict__)
try:
hash(o)
except TypeError:
pass
else:
# without a converter, we can only hope that
# hashable == immutable
return o
supported_types = ", ".join((x.__name__ for x in freeze_types))
err = (
f"type {type_o} is not hashable or is not equal or a " +
f"subclass of the supported types: {supported_types}"
)
raise TypeError(err)
freeze_conversion_map = getFreezeConversionMap()
freeze_conversion_map = freeze_conversion_map | custom_converters
if base_type_o in _freeze_types_plain:
return freeze_conversion_map[base_type_o](o)
if not isIterableNotString(o):
return freeze_conversion_map[base_type_o](o)
freeze_conversion_inverse_map = getFreezeConversionInverseMap()
freeze_conversion_inverse_map = (
freeze_conversion_inverse_map |
custom_inverse_converters
)
frozen_type = base_type_o in freeze_conversion_inverse_map
if frozen_type:
o = freeze_conversion_inverse_map[base_type_o](o)
from copy import copy
o_copy = copy(o)
for k, v in getItems(o_copy)(o_copy):
o_copy[k] = deepfreeze(
v,
custom_converters = custom_converters,
custom_inverse_converters = custom_inverse_converters
)
try:
freeze = freeze_conversion_map[base_type_o]
except KeyError:
if frozen_type:
freeze = type_o
else: # pragma: no cover
raise
return freeze(o_copy)
__all__ = (
deepfreeze.__name__,
register.__name__,
unregister.__name__,
getFreezeConversionMap.__name__,
getFreezeConversionInverseMap.__name__,
FreezeError.__name__,
FreezeWarning.__name__,
)
del MappingProxyType
del array
del frozendict
del MutableMapping
del MutableSequence
del MutableSet
del Enum
@@ -0,0 +1,6 @@
# this provides compatibility for older pickles
# created on a python-only implementation that
# specifically mention frozendict.core.frozendict
# noinspection PyUnresolvedReferences
from frozendict import frozendict
@@ -0,0 +1,208 @@
_OldJsonEncoder = None
_oldOrjsonDumps = None
_oldMutableMappingSubclasshook = None
class MonkeypatchWarning(UserWarning):
pass
def checkCExtension(*, warn, warn_c = False):
import frozendict as cool
res = cool.c_ext
if warn and res == warn_c:
if warn_c: # pragma: no cover
msg = "C Extension version, monkeypatch will be not applied"
else:
msg = "Pure Python version, monkeypatch will be not applied"
import warnings
warnings.warn(msg, MonkeypatchWarning)
return res
def patchOrUnpatchJson(*, patch, warn = True): # pragma: no cover
if not checkCExtension(warn = warn):
return
from importlib import import_module
self = import_module(__name__)
import frozendict as cool
import json
OldJsonEncoder = self._OldJsonEncoder
# noinspection PyUnresolvedReferences, PyProtectedMember
FrozendictJsonEncoder = cool._getFrozendictJsonEncoder(
OldJsonEncoder
)
if patch:
DefaultJsonEncoder = FrozendictJsonEncoder
else:
DefaultJsonEncoder = OldJsonEncoder
if DefaultJsonEncoder is None:
default_json_encoder = None
else:
default_json_encoder = DefaultJsonEncoder(
skipkeys = False,
ensure_ascii = True,
check_circular = True,
allow_nan = True,
indent = None,
separators = None,
default = None,
)
if patch:
if OldJsonEncoder is None:
self._OldJsonEncoder = json.encoder.JSONEncoder
else:
if OldJsonEncoder is None:
raise ValueError(
"Old json encoder is None " +
"(maybe you already unpatched json?)"
)
self._OldJsonEncoder = None
cool.FrozendictJsonEncoder = FrozendictJsonEncoder
json.JSONEncoder = DefaultJsonEncoder
json.encoder.JSONEncoder = DefaultJsonEncoder
json._default_encoder = default_json_encoder
def patchOrUnpatchOrjson(*, patch, warn = True): # pragma: no cover
if not checkCExtension(warn = warn):
return
from importlib import import_module
self = import_module(__name__)
# noinspection PyUnresolvedReferences
import orjson
if self._oldOrjsonDumps is None:
if not patch:
raise ValueError(
"Old orjson encoder is None " +
"(maybe you already unpatched orjson?)"
)
oldOrjsonDumps = orjson.dumps
else:
oldOrjsonDumps = self._oldOrjsonDumps
if patch:
from frozendict import frozendict
def frozendictOrjsonDumps(obj, *args, **kwargs):
if isinstance(obj, frozendict):
obj = dict(obj)
return oldOrjsonDumps(obj, *args, **kwargs)
defaultOrjsonDumps = frozendictOrjsonDumps
newOldOrjsonDumps = oldOrjsonDumps
else:
defaultOrjsonDumps = oldOrjsonDumps
newOldOrjsonDumps = None
self._oldOrjsonDumps = newOldOrjsonDumps
orjson.dumps = defaultOrjsonDumps
orjson.orjson.dumps = defaultOrjsonDumps
def patchOrUnpatchMutableMappingSubclasshook(
*,
patch,
warn = True
): # pragma: no cover
warn_c = True
if checkCExtension(warn = warn, warn_c = warn_c):
return
from importlib import import_module
self = import_module(__name__)
from collections.abc import MutableMapping
from frozendict import frozendict
if self._oldMutableMappingSubclasshook is None:
if not patch:
raise ValueError(
"Old MutableMapping subclasshook is None " +
"(maybe you already unpatched MutableMapping?)"
)
oldMutableMappingHook = MutableMapping.__subclasshook__
else:
oldMutableMappingHook = self._oldMutableMappingSubclasshook
if patch:
# noinspection PyDecorator
@classmethod
def frozendictMutableMappingSubclasshook(
klass,
subclass,
*args,
**kwargs
):
if klass == MutableMapping:
if issubclass(subclass, frozendict):
return False
# noinspection PyArgumentList
return oldMutableMappingHook(
subclass,
*args,
**kwargs
)
return NotImplemented
defaultMutableMappingHook = frozendictMutableMappingSubclasshook
newOldMutableMappingHook = oldMutableMappingHook
else:
defaultMutableMappingHook = oldMutableMappingHook
newOldMutableMappingHook = None
self._oldMutableMappingSubclasshook = newOldMutableMappingHook
MutableMapping.__subclasshook__ = defaultMutableMappingHook
try:
# noinspection PyUnresolvedReferences, PyProtectedMember
MutableMapping._abc_caches_clear()
except AttributeError:
# noinspection PyUnresolvedReferences, PyProtectedMember
MutableMapping._abc_cache.discard(frozendict)
# noinspection PyUnresolvedReferences, PyProtectedMember
MutableMapping._abc_negative_cache.discard(frozendict)
def patchOrUnpatchAll(*, patch, warn = True, raise_orjson = False):
patchOrUnpatchJson(patch = patch, warn = warn)
try:
import orjson
except ImportError: # pragma: no cover
if raise_orjson:
raise
else: # pragma: no cover
patchOrUnpatchOrjson(patch = patch, warn = warn)
patchOrUnpatchMutableMappingSubclasshook(patch = patch, warn = warn)
__all__ = (
patchOrUnpatchJson.__name__,
patchOrUnpatchOrjson.__name__,
patchOrUnpatchMutableMappingSubclasshook.__name__,
patchOrUnpatchAll.__name__,
MonkeypatchWarning.__name__,
)
@@ -0,0 +1 @@
version = "2.4.7"