From b07243f76cfc9c55a9badb70a72b1fd8a9a6141c Mon Sep 17 00:00:00 2001 From: Joseph Perez Date: Thu, 2 Dec 2021 23:39:24 +0100 Subject: [PATCH] Cherry pick #255 --- apischema/serialization/__init__.py | 19 ++++++++++++++----- docs/de_serialization.md | 2 +- docs/performance_and_benchmark.md | 7 +++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/apischema/serialization/__init__.py b/apischema/serialization/__init__.py index 15fdc960..1ef180a1 100644 --- a/apischema/serialization/__init__.py +++ b/apischema/serialization/__init__.py @@ -125,11 +125,14 @@ class PassThroughOptions: any: bool = False collections: bool = False enums: bool = False + tuple: bool = False types: CollectionOrPredicate[AnyType] = () def __post_init__(self): if isinstance(self.types, Collection) and not isinstance(self.types, tuple): object.__setattr__(self, "types", tuple(self.types)) + if self.collections and not self.tuple: + object.__setattr__(self, "tuple", True) @dataclass @@ -213,10 +216,14 @@ def collection( method: SerializationMethod if value_method is not IDENTITY_METHOD: - return CollectionMethod(value_method) - elif issubclass(cls, (list, tuple)) or ( - self.pass_through_options.collections - and not issubclass(cls, collections.abc.Set) + method = CollectionMethod(value_method) + elif ( + issubclass(cls, list) + or (self.pass_through_options.tuple and issubclass(cls, tuple)) + or ( + self.pass_through_options.collections + and not issubclass(cls, collections.abc.Set) + ) ): method = IDENTITY_METHOD else: @@ -341,7 +348,9 @@ def subprimitive(self, cls: Type, superclass: Type) -> SerializationMethod: def tuple(self, types: Sequence[AnyType]) -> SerializationMethod: elt_methods = tuple(map(self.visit, types)) method: SerializationMethod - if all(method is IDENTITY_METHOD for method in elt_methods): + if self.pass_through_options.tuple and all( + method is IDENTITY_METHOD for method in elt_methods + ): method = IDENTITY_METHOD else: method = TupleMethod(elt_methods) diff --git a/docs/de_serialization.md b/docs/de_serialization.md index 87016d05..6094bdc6 100644 --- a/docs/de_serialization.md +++ b/docs/de_serialization.md @@ -19,7 +19,7 @@ Deserialization performs a validation of data, based on typing annotations and o ### Allowed types -In some case, e.g. a MessagePack load with raw bytes inside, some data will have other type than +In some case, e.g. MessagePack loading with raw bytes inside, some data will have other type than JSON primitive ones. These types can be allowed using `allowed_types` parameter; it must be collection of classes, or a predicate. Only non JSON primitive classes can be allowed, because *apischema* relies on a type check with `isinstance` to skip deserialization. That exclude `NewType` but also `TypeDict`. diff --git a/docs/performance_and_benchmark.md b/docs/performance_and_benchmark.md index 75602bb4..3e2af2ea 100644 --- a/docs/performance_and_benchmark.md +++ b/docs/performance_and_benchmark.md @@ -68,6 +68,13 @@ But, most of the time, collections runtime types are `list`/`dict`, so others ca #### `enums` — pass through enums +#### `tuple` — pass through `tuple` + +Even if `tuple` is often supported by JSON serializers, if this options is not enabled, tuples will be serialized as lists. It also allows easier test writing for example. + +!!! note + `collections=True` implies `tuple=True`; + #### `types` — pass through arbitrary types Either a collection of types, or a predicate to determine if type has to be passed through.