add
This commit is contained in:
1047
ccxt/static_dependencies/marshmallow_dataclass/__init__.py
Normal file
1047
ccxt/static_dependencies/marshmallow_dataclass/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
import typing
|
||||
|
||||
import marshmallow
|
||||
|
||||
|
||||
class Sequence(marshmallow.fields.List):
|
||||
"""
|
||||
A sequence field, basically an immutable version of the list field.
|
||||
"""
|
||||
|
||||
def _deserialize( # type: ignore[override]
|
||||
self,
|
||||
value: typing.Any,
|
||||
attr: typing.Any,
|
||||
data: typing.Any,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Optional[typing.Sequence[typing.Any]]:
|
||||
optional_list = super()._deserialize(value, attr, data, **kwargs)
|
||||
return None if optional_list is None else tuple(optional_list)
|
||||
|
||||
|
||||
class Set(marshmallow.fields.List):
|
||||
"""
|
||||
A set field. A set is an unordered/mutable collection of unique elements, same for frozenset
|
||||
except it's immutable.
|
||||
|
||||
Notes:
|
||||
Beware the a Set guarantees uniqueness in the resulting list but in return the item's order
|
||||
will be random. So if the order matters, use a List or Sequence !
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
cls_or_instance: typing.Union[marshmallow.fields.Field, type],
|
||||
frozen: bool = False,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(cls_or_instance, **kwargs)
|
||||
self.set_type: typing.Type[typing.Union[frozenset, set]] = (
|
||||
frozenset if frozen else set
|
||||
)
|
||||
|
||||
def _deserialize( # type: ignore[override]
|
||||
self,
|
||||
value: typing.Any,
|
||||
attr: typing.Any,
|
||||
data: typing.Any,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Union[typing.Set[typing.Any], typing.FrozenSet[typing.Any], None]:
|
||||
optional_list = super()._deserialize(value, attr, data, **kwargs)
|
||||
return None if optional_list is None else self.set_type(optional_list)
|
||||
@@ -0,0 +1,45 @@
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
|
||||
__all__ = ("lazy_class_attribute",)
|
||||
|
||||
|
||||
class LazyClassAttribute:
|
||||
"""Descriptor decorator implementing a class-level, read-only
|
||||
property, which caches its results on the class(es) on which it
|
||||
operates.
|
||||
"""
|
||||
|
||||
__slots__ = ("func", "name", "called", "forward_value")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
func: Callable[..., Any],
|
||||
name: Optional[str] = None,
|
||||
forward_value: Any = None,
|
||||
):
|
||||
self.func = func
|
||||
self.name = name
|
||||
self.called = False
|
||||
self.forward_value = forward_value
|
||||
|
||||
def __get__(self, instance, cls=None):
|
||||
if not cls:
|
||||
cls = type(instance)
|
||||
|
||||
# avoid recursion
|
||||
if self.called:
|
||||
return self.forward_value
|
||||
|
||||
self.called = True
|
||||
|
||||
setattr(cls, self.name, self.func())
|
||||
|
||||
# "getattr" is used to handle bounded methods
|
||||
return getattr(cls, self.name)
|
||||
|
||||
def __set_name__(self, owner, name):
|
||||
self.name = self.name or name
|
||||
|
||||
|
||||
lazy_class_attribute = LazyClassAttribute
|
||||
71
ccxt/static_dependencies/marshmallow_dataclass/mypy.py
Normal file
71
ccxt/static_dependencies/marshmallow_dataclass/mypy.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import inspect
|
||||
from typing import Callable, Optional, Type
|
||||
|
||||
from mypy import nodes
|
||||
from mypy.plugin import DynamicClassDefContext, Plugin
|
||||
from mypy.plugins import dataclasses
|
||||
|
||||
import marshmallow_dataclass
|
||||
|
||||
_NEW_TYPE_SIG = inspect.signature(marshmallow_dataclass.NewType)
|
||||
|
||||
|
||||
def plugin(version: str) -> Type[Plugin]:
|
||||
return MarshmallowDataclassPlugin
|
||||
|
||||
|
||||
class MarshmallowDataclassPlugin(Plugin):
|
||||
def get_dynamic_class_hook(
|
||||
self, fullname: str
|
||||
) -> Optional[Callable[[DynamicClassDefContext], None]]:
|
||||
if fullname == "marshmallow_dataclass.NewType":
|
||||
return new_type_hook
|
||||
return None
|
||||
|
||||
def get_class_decorator_hook(self, fullname: str):
|
||||
if fullname == "marshmallow_dataclass.dataclass":
|
||||
return dataclasses.dataclass_class_maker_callback
|
||||
return None
|
||||
|
||||
|
||||
def new_type_hook(ctx: DynamicClassDefContext) -> None:
|
||||
"""
|
||||
Dynamic class hook for :func:`marshmallow_dataclass.NewType`.
|
||||
|
||||
Uses the type of the ``typ`` argument.
|
||||
"""
|
||||
typ = _get_arg_by_name(ctx.call, "typ", _NEW_TYPE_SIG)
|
||||
if not isinstance(typ, nodes.RefExpr):
|
||||
return
|
||||
info = typ.node
|
||||
if not isinstance(info, nodes.TypeInfo):
|
||||
return
|
||||
ctx.api.add_symbol_table_node(ctx.name, nodes.SymbolTableNode(nodes.GDEF, info))
|
||||
|
||||
|
||||
def _get_arg_by_name(
|
||||
call: nodes.CallExpr, name: str, sig: inspect.Signature
|
||||
) -> Optional[nodes.Expression]:
|
||||
"""
|
||||
Get value of argument from a call.
|
||||
|
||||
:return: The argument value, or ``None`` if it cannot be found.
|
||||
|
||||
.. warning::
|
||||
This probably doesn't yet work for calls with ``*args`` and/or ``*kwargs``.
|
||||
"""
|
||||
args = []
|
||||
kwargs = {}
|
||||
for arg_name, arg_value in zip(call.arg_names, call.args):
|
||||
if arg_name is None:
|
||||
args.append(arg_value)
|
||||
else:
|
||||
kwargs[arg_name] = arg_value
|
||||
try:
|
||||
bound_args = sig.bind(*args, **kwargs)
|
||||
except TypeError:
|
||||
return None
|
||||
try:
|
||||
return bound_args.arguments[name]
|
||||
except KeyError:
|
||||
return None
|
||||
14
ccxt/static_dependencies/marshmallow_dataclass/typing.py
Normal file
14
ccxt/static_dependencies/marshmallow_dataclass/typing.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import sys
|
||||
|
||||
import marshmallow.fields
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated
|
||||
else:
|
||||
from typing_extensions import Annotated
|
||||
|
||||
Url = Annotated[str, marshmallow.fields.Url]
|
||||
Email = Annotated[str, marshmallow.fields.Email]
|
||||
|
||||
# Aliases
|
||||
URL = Url
|
||||
@@ -0,0 +1,82 @@
|
||||
import copy
|
||||
import inspect
|
||||
from typing import List, Tuple, Any, Optional
|
||||
|
||||
import typeguard
|
||||
from marshmallow import fields, Schema, ValidationError
|
||||
|
||||
try:
|
||||
from typeguard import TypeCheckError # type: ignore[attr-defined]
|
||||
except ImportError:
|
||||
# typeguard < 3
|
||||
TypeCheckError = TypeError # type: ignore[misc, assignment]
|
||||
|
||||
if "argname" not in inspect.signature(typeguard.check_type).parameters:
|
||||
|
||||
def _check_type(value, expected_type, argname: str):
|
||||
return typeguard.check_type(value=value, expected_type=expected_type)
|
||||
|
||||
else:
|
||||
# typeguard < 3.0.0rc2
|
||||
def _check_type(value, expected_type, argname: str):
|
||||
return typeguard.check_type( # type: ignore[call-overload]
|
||||
value=value, expected_type=expected_type, argname=argname
|
||||
)
|
||||
|
||||
|
||||
class Union(fields.Field):
|
||||
"""A union field, composed other `Field` classes or instances.
|
||||
This field serializes elements based on their type, with one of its child fields.
|
||||
|
||||
Example: ::
|
||||
|
||||
number_or_string = UnionField([
|
||||
(float, fields.Float()),
|
||||
(str, fields.Str())
|
||||
])
|
||||
|
||||
:param union_fields: A list of types and their associated field instance.
|
||||
:param kwargs: The same keyword arguments that :class:`Field` receives.
|
||||
"""
|
||||
|
||||
def __init__(self, union_fields: List[Tuple[type, fields.Field]], **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.union_fields = union_fields
|
||||
|
||||
def _bind_to_schema(self, field_name: str, schema: Schema) -> None:
|
||||
super()._bind_to_schema(field_name, schema)
|
||||
new_union_fields = []
|
||||
for typ, field in self.union_fields:
|
||||
field = copy.deepcopy(field)
|
||||
field._bind_to_schema(field_name, self)
|
||||
new_union_fields.append((typ, field))
|
||||
|
||||
self.union_fields = new_union_fields
|
||||
|
||||
def _serialize(self, value: Any, attr: Optional[str], obj, **kwargs) -> Any:
|
||||
errors = []
|
||||
if value is None:
|
||||
return value
|
||||
for typ, field in self.union_fields:
|
||||
try:
|
||||
_check_type(value=value, expected_type=typ, argname=attr or "anonymous")
|
||||
return field._serialize(value, attr, obj, **kwargs)
|
||||
except TypeCheckError as e:
|
||||
errors.append(e)
|
||||
raise TypeError(
|
||||
f"Unable to serialize value with any of the fields in the union: {errors}"
|
||||
)
|
||||
|
||||
def _deserialize(self, value: Any, attr: Optional[str], data, **kwargs) -> Any:
|
||||
errors = []
|
||||
for typ, field in self.union_fields:
|
||||
try:
|
||||
result = field.deserialize(value, **kwargs)
|
||||
_check_type(
|
||||
value=result, expected_type=typ, argname=attr or "anonymous"
|
||||
)
|
||||
return result
|
||||
except (TypeCheckError, ValidationError) as e:
|
||||
errors.append(e)
|
||||
|
||||
raise ValidationError(errors)
|
||||
Reference in New Issue
Block a user