automated terminal push
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable, TypeVar
|
||||
|
||||
if sys.version_info[:2] < (3, 10):
|
||||
from typing_extensions import ParamSpec
|
||||
else:
|
||||
from typing import ParamSpec
|
||||
|
||||
|
||||
def validate_datetime(v, _):
|
||||
if not isinstance(v, datetime):
|
||||
raise Exception(f"Expected datetime, got {v}")
|
||||
return v
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
P = ParamSpec("P")
|
||||
|
||||
|
||||
def wrap(_: Callable[P, Any]) -> Callable[[Callable[..., T]], Callable[P, T]]:
|
||||
"""Wrap a `Converter` `__init__` in a type-safe way."""
|
||||
|
||||
def impl(x: Callable[..., T]) -> Callable[P, T]:
|
||||
return x
|
||||
|
||||
return impl
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
106
cdk-env/lib/python3.12/site-packages/cattrs/preconf/bson.py
Normal file
106
cdk-env/lib/python3.12/site-packages/cattrs/preconf/bson.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""Preconfigured converters for bson."""
|
||||
|
||||
from base64 import b85decode, b85encode
|
||||
from datetime import date, datetime
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from bson import DEFAULT_CODEC_OPTIONS, CodecOptions, Int64, ObjectId, decode, encode
|
||||
|
||||
from cattrs._compat import AbstractSet, is_mapping
|
||||
from cattrs.gen import make_mapping_structure_fn
|
||||
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..dispatch import StructureHook
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import validate_datetime, wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class Base85Bytes(bytes):
|
||||
"""A subclass to help with binary key encoding/decoding."""
|
||||
|
||||
|
||||
class BsonConverter(Converter):
|
||||
def dumps(
|
||||
self,
|
||||
obj: Any,
|
||||
unstructure_as: Any = None,
|
||||
check_keys: bool = False,
|
||||
codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS,
|
||||
) -> bytes:
|
||||
return encode(
|
||||
self.unstructure(obj, unstructure_as=unstructure_as),
|
||||
check_keys=check_keys,
|
||||
codec_options=codec_options,
|
||||
)
|
||||
|
||||
def loads(
|
||||
self,
|
||||
data: bytes,
|
||||
cl: Type[T],
|
||||
codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS,
|
||||
) -> T:
|
||||
return self.structure(decode(data, codec_options=codec_options), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the bson library.
|
||||
|
||||
* sets are serialized as lists
|
||||
* byte mapping keys are base85-encoded into strings when unstructuring, and reverse
|
||||
* non-string, non-byte mapping keys are coerced into strings when unstructuring
|
||||
* a deserialization hook is registered for bson.ObjectId by default
|
||||
"""
|
||||
|
||||
def gen_unstructure_mapping(cl: Any, unstructure_to=None):
|
||||
key_handler = str
|
||||
args = getattr(cl, "__args__", None)
|
||||
if args:
|
||||
if issubclass(args[0], str):
|
||||
key_handler = None
|
||||
elif issubclass(args[0], bytes):
|
||||
|
||||
def key_handler(k):
|
||||
return b85encode(k).decode("utf8")
|
||||
|
||||
return converter.gen_unstructure_mapping(
|
||||
cl, unstructure_to=unstructure_to, key_handler=key_handler
|
||||
)
|
||||
|
||||
def gen_structure_mapping(cl: Any) -> StructureHook:
|
||||
args = getattr(cl, "__args__", None)
|
||||
if args and issubclass(args[0], bytes):
|
||||
h = make_mapping_structure_fn(cl, converter, key_type=Base85Bytes)
|
||||
else:
|
||||
h = make_mapping_structure_fn(cl, converter)
|
||||
return h
|
||||
|
||||
converter.register_structure_hook(Base85Bytes, lambda v, _: b85decode(v))
|
||||
converter.register_unstructure_hook_factory(is_mapping, gen_unstructure_mapping)
|
||||
converter.register_structure_hook_factory(is_mapping, gen_structure_mapping)
|
||||
|
||||
converter.register_structure_hook(ObjectId, lambda v, _: ObjectId(v))
|
||||
configure_union_passthrough(
|
||||
Union[str, bool, int, float, None, bytes, datetime, ObjectId, Int64], converter
|
||||
)
|
||||
|
||||
# datetime inherits from date, so identity unstructure hook used
|
||||
# here to prevent the date unstructure hook running.
|
||||
converter.register_unstructure_hook(datetime, lambda v: v)
|
||||
converter.register_structure_hook(datetime, validate_datetime)
|
||||
converter.register_unstructure_hook(date, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
|
||||
|
||||
@wrap(BsonConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> BsonConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = BsonConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
50
cdk-env/lib/python3.12/site-packages/cattrs/preconf/cbor2.py
Normal file
50
cdk-env/lib/python3.12/site-packages/cattrs/preconf/cbor2.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""Preconfigured converters for cbor2."""
|
||||
|
||||
from datetime import date, datetime, timezone
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from cbor2 import dumps, loads
|
||||
|
||||
from cattrs._compat import AbstractSet
|
||||
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class Cbor2Converter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
|
||||
return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: bytes, cl: Type[T], **kwargs: Any) -> T:
|
||||
return self.structure(loads(data, **kwargs), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the cbor2 library.
|
||||
|
||||
* datetimes are serialized as timestamp floats
|
||||
* sets are serialized as lists
|
||||
"""
|
||||
converter.register_unstructure_hook(datetime, lambda v: v.timestamp())
|
||||
converter.register_structure_hook(
|
||||
datetime, lambda v, _: datetime.fromtimestamp(v, timezone.utc)
|
||||
)
|
||||
converter.register_unstructure_hook(date, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
configure_union_passthrough(Union[str, bool, int, float, None, bytes], converter)
|
||||
|
||||
|
||||
@wrap(Cbor2Converter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> Cbor2Converter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = Cbor2Converter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
56
cdk-env/lib/python3.12/site-packages/cattrs/preconf/json.py
Normal file
56
cdk-env/lib/python3.12/site-packages/cattrs/preconf/json.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""Preconfigured converters for the stdlib json."""
|
||||
|
||||
from base64 import b85decode, b85encode
|
||||
from datetime import date, datetime
|
||||
from json import dumps, loads
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from .._compat import AbstractSet, Counter
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class JsonConverter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
|
||||
return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: Union[bytes, str], cl: Type[T], **kwargs: Any) -> T:
|
||||
return self.structure(loads(data, **kwargs), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the stdlib json module.
|
||||
|
||||
* bytes are serialized as base85 strings
|
||||
* datetimes are serialized as ISO 8601
|
||||
* counters are serialized as dicts
|
||||
* sets are serialized as lists
|
||||
* union passthrough is configured for unions of strings, bools, ints,
|
||||
floats and None
|
||||
"""
|
||||
converter.register_unstructure_hook(
|
||||
bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
|
||||
)
|
||||
converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
|
||||
converter.register_unstructure_hook(datetime, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v))
|
||||
converter.register_unstructure_hook(date, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
configure_union_passthrough(Union[str, bool, int, float, None], converter)
|
||||
|
||||
|
||||
@wrap(JsonConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> JsonConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
Counter: dict,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = JsonConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
@@ -0,0 +1,54 @@
|
||||
"""Preconfigured converters for msgpack."""
|
||||
|
||||
from datetime import date, datetime, time, timezone
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from msgpack import dumps, loads
|
||||
|
||||
from cattrs._compat import AbstractSet
|
||||
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class MsgpackConverter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
|
||||
return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: bytes, cl: Type[T], **kwargs: Any) -> T:
|
||||
return self.structure(loads(data, **kwargs), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the msgpack library.
|
||||
|
||||
* datetimes are serialized as timestamp floats
|
||||
* sets are serialized as lists
|
||||
"""
|
||||
converter.register_unstructure_hook(datetime, lambda v: v.timestamp())
|
||||
converter.register_structure_hook(
|
||||
datetime, lambda v, _: datetime.fromtimestamp(v, timezone.utc)
|
||||
)
|
||||
converter.register_unstructure_hook(
|
||||
date, lambda v: datetime.combine(v, time(tzinfo=timezone.utc)).timestamp()
|
||||
)
|
||||
converter.register_structure_hook(
|
||||
date, lambda v, _: datetime.fromtimestamp(v, timezone.utc).date()
|
||||
)
|
||||
configure_union_passthrough(Union[str, bool, int, float, None, bytes], converter)
|
||||
|
||||
|
||||
@wrap(MsgpackConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> MsgpackConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = MsgpackConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
185
cdk-env/lib/python3.12/site-packages/cattrs/preconf/msgspec.py
Normal file
185
cdk-env/lib/python3.12/site-packages/cattrs/preconf/msgspec.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""Preconfigured converters for msgspec."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from base64 import b64decode
|
||||
from datetime import date, datetime
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from typing import Any, Callable, TypeVar, Union, get_type_hints
|
||||
|
||||
from attrs import has as attrs_has
|
||||
from attrs import resolve_types
|
||||
from msgspec import Struct, convert, to_builtins
|
||||
from msgspec.json import Encoder, decode
|
||||
|
||||
from .._compat import (
|
||||
fields,
|
||||
get_args,
|
||||
get_origin,
|
||||
has,
|
||||
is_bare,
|
||||
is_mapping,
|
||||
is_sequence,
|
||||
)
|
||||
from ..cols import is_namedtuple
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..dispatch import UnstructureHook
|
||||
from ..fns import identity
|
||||
from ..gen import make_hetero_tuple_unstructure_fn
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
__all__ = ["MsgspecJsonConverter", "configure_converter", "make_converter"]
|
||||
|
||||
|
||||
class MsgspecJsonConverter(Converter):
|
||||
"""A converter specialized for the _msgspec_ library."""
|
||||
|
||||
#: The msgspec encoder for dumping.
|
||||
encoder: Encoder = Encoder()
|
||||
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
|
||||
"""Unstructure and encode `obj` into JSON bytes."""
|
||||
return self.encoder.encode(
|
||||
self.unstructure(obj, unstructure_as=unstructure_as), **kwargs
|
||||
)
|
||||
|
||||
def get_dumps_hook(
|
||||
self, unstructure_as: Any, **kwargs: Any
|
||||
) -> Callable[[Any], bytes]:
|
||||
"""Produce a `dumps` hook for the given type."""
|
||||
unstruct_hook = self.get_unstructure_hook(unstructure_as)
|
||||
if unstruct_hook in (identity, to_builtins):
|
||||
return self.encoder.encode
|
||||
return self.dumps
|
||||
|
||||
def loads(self, data: bytes, cl: type[T], **kwargs: Any) -> T:
|
||||
"""Decode and structure `cl` from the provided JSON bytes."""
|
||||
return self.structure(decode(data, **kwargs), cl)
|
||||
|
||||
def get_loads_hook(self, cl: type[T]) -> Callable[[bytes], T]:
|
||||
"""Produce a `loads` hook for the given type."""
|
||||
return partial(self.loads, cl=cl)
|
||||
|
||||
|
||||
def configure_converter(converter: Converter) -> None:
|
||||
"""Configure the converter for the msgspec library.
|
||||
|
||||
* bytes are serialized as base64 strings, directly by msgspec
|
||||
* datetimes and dates are passed through to be serialized as RFC 3339 directly
|
||||
* enums are passed through to msgspec directly
|
||||
* union passthrough configured for str, bool, int, float and None
|
||||
"""
|
||||
configure_passthroughs(converter)
|
||||
|
||||
converter.register_unstructure_hook(Struct, to_builtins)
|
||||
converter.register_unstructure_hook(Enum, to_builtins)
|
||||
|
||||
converter.register_structure_hook(Struct, convert)
|
||||
converter.register_structure_hook(bytes, lambda v, _: b64decode(v))
|
||||
converter.register_structure_hook(datetime, lambda v, _: convert(v, datetime))
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
configure_union_passthrough(Union[str, bool, int, float, None], converter)
|
||||
|
||||
|
||||
@wrap(MsgspecJsonConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> MsgspecJsonConverter:
|
||||
res = MsgspecJsonConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
return res
|
||||
|
||||
|
||||
def configure_passthroughs(converter: Converter) -> None:
|
||||
"""Configure optimizing passthroughs.
|
||||
|
||||
A passthrough is when we let msgspec handle something automatically.
|
||||
"""
|
||||
converter.register_unstructure_hook(bytes, to_builtins)
|
||||
converter.register_unstructure_hook_factory(is_mapping, mapping_unstructure_factory)
|
||||
converter.register_unstructure_hook_factory(is_sequence, seq_unstructure_factory)
|
||||
converter.register_unstructure_hook_factory(has, attrs_unstructure_factory)
|
||||
converter.register_unstructure_hook_factory(
|
||||
is_namedtuple, namedtuple_unstructure_factory
|
||||
)
|
||||
|
||||
|
||||
def seq_unstructure_factory(type, converter: Converter) -> UnstructureHook:
|
||||
"""The msgspec unstructure hook factory for sequences."""
|
||||
if is_bare(type):
|
||||
type_arg = Any
|
||||
else:
|
||||
args = get_args(type)
|
||||
type_arg = args[0]
|
||||
handler = converter.get_unstructure_hook(type_arg, cache_result=False)
|
||||
|
||||
if handler in (identity, to_builtins):
|
||||
return handler
|
||||
return converter.gen_unstructure_iterable(type)
|
||||
|
||||
|
||||
def mapping_unstructure_factory(type, converter: BaseConverter) -> UnstructureHook:
|
||||
"""The msgspec unstructure hook factory for mappings."""
|
||||
if is_bare(type):
|
||||
key_arg = Any
|
||||
val_arg = Any
|
||||
key_handler = converter.get_unstructure_hook(key_arg, cache_result=False)
|
||||
value_handler = converter.get_unstructure_hook(val_arg, cache_result=False)
|
||||
else:
|
||||
args = get_args(type)
|
||||
if len(args) == 2:
|
||||
key_arg, val_arg = args
|
||||
else:
|
||||
# Probably a Counter
|
||||
key_arg, val_arg = args, Any
|
||||
key_handler = converter.get_unstructure_hook(key_arg, cache_result=False)
|
||||
value_handler = converter.get_unstructure_hook(val_arg, cache_result=False)
|
||||
|
||||
if key_handler in (identity, to_builtins) and value_handler in (
|
||||
identity,
|
||||
to_builtins,
|
||||
):
|
||||
return to_builtins
|
||||
return converter.gen_unstructure_mapping(type)
|
||||
|
||||
|
||||
def attrs_unstructure_factory(type: Any, converter: Converter) -> UnstructureHook:
|
||||
"""Choose whether to use msgspec handling or our own."""
|
||||
origin = get_origin(type)
|
||||
attribs = fields(origin or type)
|
||||
if attrs_has(type) and any(isinstance(a.type, str) for a in attribs):
|
||||
resolve_types(type)
|
||||
attribs = fields(origin or type)
|
||||
|
||||
if any(
|
||||
attr.name.startswith("_")
|
||||
or (
|
||||
converter.get_unstructure_hook(attr.type, cache_result=False)
|
||||
not in (identity, to_builtins)
|
||||
)
|
||||
for attr in attribs
|
||||
):
|
||||
return converter.gen_unstructure_attrs_fromdict(type)
|
||||
|
||||
return to_builtins
|
||||
|
||||
|
||||
def namedtuple_unstructure_factory(
|
||||
type: type[tuple], converter: BaseConverter
|
||||
) -> UnstructureHook:
|
||||
"""A hook factory for unstructuring namedtuples, modified for msgspec."""
|
||||
|
||||
if all(
|
||||
converter.get_unstructure_hook(t) in (identity, to_builtins)
|
||||
for t in get_type_hints(type).values()
|
||||
):
|
||||
return identity
|
||||
|
||||
return make_hetero_tuple_unstructure_fn(
|
||||
type,
|
||||
converter,
|
||||
unstructure_to=tuple,
|
||||
type_args=tuple(get_type_hints(type).values()),
|
||||
)
|
@@ -0,0 +1,95 @@
|
||||
"""Preconfigured converters for orjson."""
|
||||
|
||||
from base64 import b85decode, b85encode
|
||||
from datetime import date, datetime
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from orjson import dumps, loads
|
||||
|
||||
from .._compat import AbstractSet, is_mapping
|
||||
from ..cols import is_namedtuple, namedtuple_unstructure_factory
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..fns import identity
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class OrjsonConverter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
|
||||
return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: Union[bytes, bytearray, memoryview, str], cl: Type[T]) -> T:
|
||||
return self.structure(loads(data), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the orjson library.
|
||||
|
||||
* bytes are serialized as base85 strings
|
||||
* datetimes and dates are passed through to be serialized as RFC 3339 by orjson
|
||||
* typed namedtuples are serialized as lists
|
||||
* sets are serialized as lists
|
||||
* string enum mapping keys have special handling
|
||||
* mapping keys are coerced into strings when unstructuring
|
||||
|
||||
.. versionchanged: 24.1.0
|
||||
Add support for typed namedtuples.
|
||||
"""
|
||||
converter.register_unstructure_hook(
|
||||
bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
|
||||
)
|
||||
converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
|
||||
|
||||
converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v))
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
|
||||
def gen_unstructure_mapping(cl: Any, unstructure_to=None):
|
||||
key_handler = str
|
||||
args = getattr(cl, "__args__", None)
|
||||
if args:
|
||||
if issubclass(args[0], str) and issubclass(args[0], Enum):
|
||||
|
||||
def key_handler(v):
|
||||
return v.value
|
||||
|
||||
else:
|
||||
# It's possible the handler for the key type has been overridden.
|
||||
# (For example base85 encoding for bytes.)
|
||||
# In that case, we want to use the override.
|
||||
|
||||
kh = converter.get_unstructure_hook(args[0])
|
||||
if kh != identity:
|
||||
key_handler = kh
|
||||
|
||||
return converter.gen_unstructure_mapping(
|
||||
cl, unstructure_to=unstructure_to, key_handler=key_handler
|
||||
)
|
||||
|
||||
converter._unstructure_func.register_func_list(
|
||||
[
|
||||
(is_mapping, gen_unstructure_mapping, True),
|
||||
(
|
||||
is_namedtuple,
|
||||
partial(namedtuple_unstructure_factory, unstructure_to=tuple),
|
||||
"extended",
|
||||
),
|
||||
]
|
||||
)
|
||||
configure_union_passthrough(Union[str, bool, int, float, None], converter)
|
||||
|
||||
|
||||
@wrap(OrjsonConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> OrjsonConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = OrjsonConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
@@ -0,0 +1,72 @@
|
||||
"""Preconfigured converters for pyyaml."""
|
||||
|
||||
from datetime import date, datetime
|
||||
from functools import partial
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from yaml import safe_dump, safe_load
|
||||
|
||||
from .._compat import FrozenSetSubscriptable
|
||||
from ..cols import is_namedtuple, namedtuple_unstructure_factory
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import validate_datetime, wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def validate_date(v, _):
|
||||
if not isinstance(v, date):
|
||||
raise ValueError(f"Expected date, got {v}")
|
||||
return v
|
||||
|
||||
|
||||
class PyyamlConverter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
|
||||
return safe_dump(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: str, cl: Type[T]) -> T:
|
||||
return self.structure(safe_load(data), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the pyyaml library.
|
||||
|
||||
* frozensets are serialized as lists
|
||||
* string enums are converted into strings explicitly
|
||||
* datetimes and dates are validated
|
||||
* typed namedtuples are serialized as lists
|
||||
|
||||
.. versionchanged: 24.1.0
|
||||
Add support for typed namedtuples.
|
||||
"""
|
||||
converter.register_unstructure_hook(
|
||||
str, lambda v: v if v.__class__ is str else v.value
|
||||
)
|
||||
|
||||
# datetime inherits from date, so identity unstructure hook used
|
||||
# here to prevent the date unstructure hook running.
|
||||
converter.register_unstructure_hook(datetime, lambda v: v)
|
||||
converter.register_structure_hook(datetime, validate_datetime)
|
||||
converter.register_structure_hook(date, validate_date)
|
||||
|
||||
converter.register_unstructure_hook_factory(is_namedtuple)(
|
||||
partial(namedtuple_unstructure_factory, unstructure_to=tuple)
|
||||
)
|
||||
|
||||
configure_union_passthrough(
|
||||
Union[str, bool, int, float, None, bytes, datetime, date], converter
|
||||
)
|
||||
|
||||
|
||||
@wrap(PyyamlConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> PyyamlConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
FrozenSetSubscriptable: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = PyyamlConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
@@ -0,0 +1,87 @@
|
||||
"""Preconfigured converters for tomlkit."""
|
||||
|
||||
from base64 import b85decode, b85encode
|
||||
from datetime import date, datetime
|
||||
from enum import Enum
|
||||
from operator import attrgetter
|
||||
from typing import Any, Type, TypeVar, Union
|
||||
|
||||
from tomlkit import dumps, loads
|
||||
from tomlkit.items import Float, Integer, String
|
||||
|
||||
from cattrs._compat import AbstractSet, is_mapping
|
||||
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import validate_datetime, wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
_enum_value_getter = attrgetter("_value_")
|
||||
|
||||
|
||||
class TomlkitConverter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
|
||||
return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: str, cl: Type[T]) -> T:
|
||||
return self.structure(loads(data), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the tomlkit library.
|
||||
|
||||
* bytes are serialized as base85 strings
|
||||
* sets are serialized as lists
|
||||
* tuples are serializas as lists
|
||||
* mapping keys are coerced into strings when unstructuring
|
||||
"""
|
||||
converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
|
||||
converter.register_unstructure_hook(
|
||||
bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
|
||||
)
|
||||
|
||||
def gen_unstructure_mapping(cl: Any, unstructure_to=None):
|
||||
key_handler = str
|
||||
args = getattr(cl, "__args__", None)
|
||||
if args:
|
||||
# Currently, tomlkit has inconsistent behavior on 3.11
|
||||
# so we paper over it here.
|
||||
# https://github.com/sdispater/tomlkit/issues/237
|
||||
if issubclass(args[0], str):
|
||||
key_handler = _enum_value_getter if issubclass(args[0], Enum) else None
|
||||
elif issubclass(args[0], bytes):
|
||||
|
||||
def key_handler(k: bytes):
|
||||
return b85encode(k).decode("utf8")
|
||||
|
||||
return converter.gen_unstructure_mapping(
|
||||
cl, unstructure_to=unstructure_to, key_handler=key_handler
|
||||
)
|
||||
|
||||
converter._unstructure_func.register_func_list(
|
||||
[(is_mapping, gen_unstructure_mapping, True)]
|
||||
)
|
||||
|
||||
# datetime inherits from date, so identity unstructure hook used
|
||||
# here to prevent the date unstructure hook running.
|
||||
converter.register_unstructure_hook(datetime, lambda v: v)
|
||||
converter.register_structure_hook(datetime, validate_datetime)
|
||||
converter.register_unstructure_hook(date, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
configure_union_passthrough(
|
||||
Union[str, String, bool, int, Integer, float, Float], converter
|
||||
)
|
||||
|
||||
|
||||
@wrap(TomlkitConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> TomlkitConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
tuple: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = TomlkitConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
55
cdk-env/lib/python3.12/site-packages/cattrs/preconf/ujson.py
Normal file
55
cdk-env/lib/python3.12/site-packages/cattrs/preconf/ujson.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Preconfigured converters for ujson."""
|
||||
|
||||
from base64 import b85decode, b85encode
|
||||
from datetime import date, datetime
|
||||
from typing import Any, AnyStr, Type, TypeVar, Union
|
||||
|
||||
from ujson import dumps, loads
|
||||
|
||||
from cattrs._compat import AbstractSet
|
||||
|
||||
from ..converters import BaseConverter, Converter
|
||||
from ..strategies import configure_union_passthrough
|
||||
from . import wrap
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class UjsonConverter(Converter):
|
||||
def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
|
||||
return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
|
||||
|
||||
def loads(self, data: AnyStr, cl: Type[T], **kwargs: Any) -> T:
|
||||
return self.structure(loads(data, **kwargs), cl)
|
||||
|
||||
|
||||
def configure_converter(converter: BaseConverter):
|
||||
"""
|
||||
Configure the converter for use with the ujson library.
|
||||
|
||||
* bytes are serialized as base64 strings
|
||||
* datetimes are serialized as ISO 8601
|
||||
* sets are serialized as lists
|
||||
"""
|
||||
converter.register_unstructure_hook(
|
||||
bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
|
||||
)
|
||||
converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
|
||||
|
||||
converter.register_unstructure_hook(datetime, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v))
|
||||
converter.register_unstructure_hook(date, lambda v: v.isoformat())
|
||||
converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
|
||||
configure_union_passthrough(Union[str, bool, int, float, None], converter)
|
||||
|
||||
|
||||
@wrap(UjsonConverter)
|
||||
def make_converter(*args: Any, **kwargs: Any) -> UjsonConverter:
|
||||
kwargs["unstruct_collection_overrides"] = {
|
||||
AbstractSet: list,
|
||||
**kwargs.get("unstruct_collection_overrides", {}),
|
||||
}
|
||||
res = UjsonConverter(*args, **kwargs)
|
||||
configure_converter(res)
|
||||
|
||||
return res
|
Reference in New Issue
Block a user