From 3814b038e790573ec4fc6be3a8f678d3ea34d405 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Tue, 6 Aug 2024 09:30:30 +0300 Subject: [PATCH 1/4] Add mediator.cached_call to other providers --- src/adaptix/_internal/datastructures.py | 4 ++ .../_internal/morphing/concrete_provider.py | 66 +++++++++++-------- .../constant_length_tuple_provider.py | 11 +++- .../_internal/morphing/dict_provider.py | 15 +++-- .../_internal/morphing/enum_provider.py | 20 +++--- .../_internal/morphing/generic_provider.py | 53 ++++++++++----- .../_internal/morphing/provider_template.py | 14 ++-- 7 files changed, 116 insertions(+), 67 deletions(-) diff --git a/src/adaptix/_internal/datastructures.py b/src/adaptix/_internal/datastructures.py index a4ea8ff5..054b100a 100644 --- a/src/adaptix/_internal/datastructures.py +++ b/src/adaptix/_internal/datastructures.py @@ -23,6 +23,7 @@ ) from .common import VarTuple +from .utils import MappingHashWrapper K = TypeVar("K", bound=Hashable) V = TypeVar("V") @@ -114,6 +115,9 @@ def __eq__(self, other): return self._mapping == other._mapping return NotImplemented + def __hash__(self): + return hash(MappingHashWrapper(self._mapping)) + # It's not a KeysView because __iter__ of KeysView must returns an Iterator[K_co] # but there is no inverse of Type[] diff --git a/src/adaptix/_internal/morphing/concrete_provider.py b/src/adaptix/_internal/morphing/concrete_provider.py index 2638b6cb..b16787cb 100644 --- a/src/adaptix/_internal/morphing/concrete_provider.py +++ b/src/adaptix/_internal/morphing/concrete_provider.py @@ -49,10 +49,10 @@ def isoformat_loader(data): except ValueError: raise ValueLoadError("Invalid isoformat string", data) - return isoformat_loader + return mediator.cached_call(lambda: isoformat_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return self._cls.isoformat + return mediator.cached_call(lambda: self._cls.isoformat) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING, format=self._CLS_TO_JSON_FORMAT[self._cls]) @@ -77,7 +77,7 @@ def datetime_format_loader(data): except TypeError: raise TypeLoadError(str, data) - return datetime_format_loader + return mediator.cached_call(lambda: datetime_format_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: fmt = self._fmt @@ -85,7 +85,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def datetime_format_dumper(data: datetime): return data.strftime(fmt) - return datetime_format_dumper + return mediator.cached_call(lambda: datetime_format_dumper) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING) @@ -112,13 +112,13 @@ def datetime_timestamp_loader(data): data, ) - return datetime_timestamp_loader + return mediator.cached_call(lambda: datetime_timestamp_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def datetime_timestamp_dumper(data: datetime): return data.timestamp() - return datetime_timestamp_dumper + return mediator.cached_call(lambda: datetime_timestamp_dumper) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NUMBER) @@ -168,7 +168,9 @@ def pydate_timestamp_loader(data): data, ) - return pydate_timestamp_loader if self._is_pydatetime() else date_timestamp_loader + return mediator.cached_call( + lambda: pydate_timestamp_loader if self._is_pydatetime() else date_timestamp_loader, + ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def date_timestamp_dumper(data: date): @@ -180,7 +182,7 @@ def date_timestamp_dumper(data: date): ) return dt.timestamp() - return date_timestamp_dumper + return mediator.cached_call(lambda: date_timestamp_dumper) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NUMBER) @@ -198,10 +200,10 @@ def timedelta_loader(data): raise TypeLoadError(Union[int, float, Decimal], data) return timedelta(seconds=int(data), microseconds=int(data % 1 * 10 ** 6)) - return timedelta_loader + return mediator.cached_call(lambda: timedelta_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return timedelta.total_seconds + return mediator.cached_call(lambda: timedelta.total_seconds) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NUMBER) @@ -216,10 +218,10 @@ def none_loader(data): @for_predicate(None) class NoneProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - return none_loader + return mediator.cached_call(lambda: none_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return as_is_stub + return mediator.cached_call(lambda: as_is_stub) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NULL) @@ -230,7 +232,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def bytes_base64_dumper(data): return b2a_base64(data, newline=False).decode("ascii") - return bytes_base64_dumper + return mediator.cached_call(lambda: bytes_base64_dumper) class _Base64JSONSchemaMixin(JSONSchemaProvider): @@ -258,7 +260,7 @@ def bytes_base64_loader(data): except binascii.Error as e: raise ValueLoadError(str(e), data) - return bytes_base64_loader + return mediator.cached_call(lambda: bytes_base64_loader) @for_predicate(BytesIO) @@ -271,13 +273,13 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: def bytes_io_base64_loader(data): return BytesIO(bytes_base64_loader(data)) - return bytes_io_base64_loader + return mediator.cached_call(lambda: bytes_io_base64_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def bytes_io_base64_dumper(data: BytesIO): return b2a_base64(data.getvalue(), newline=False).decode("ascii") - return bytes_io_base64_dumper + return mediator.cached_call(lambda: bytes_io_base64_dumper) @for_predicate(typing.IO[bytes]) @@ -289,7 +291,7 @@ def io_bytes_base64_dumper(data: typing.IO[bytes]): return b2a_base64(data.read(), newline=False).decode("ascii") - return io_bytes_base64_dumper + return mediator.cached_call(lambda: io_bytes_base64_dumper) @for_predicate(bytearray) @@ -305,7 +307,7 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: def bytearray_base64_loader(data): return bytearray(bytes_loader(data)) - return bytearray_base64_loader + return mediator.cached_call(lambda: bytearray_base64_loader) def _regex_dumper(data: re.Pattern): @@ -330,10 +332,10 @@ def regex_loader(data): except re.error as e: raise ValueLoadError(str(e), data) - return regex_loader + return mediator.cached_call(lambda: regex_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return _regex_dumper + return mediator.cached_call(lambda: _regex_dumper) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING, format=JSONSchemaBuiltinFormat.REGEX) @@ -360,10 +362,12 @@ def __init__( def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) - return self._strict_coercion_loader if strict_coercion else self._lax_coercion_loader + return mediator.cached_call( + lambda: self._strict_coercion_loader if strict_coercion else self._lax_coercion_loader, + ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return self._dumper + return mediator.cached_call(lambda: self._dumper) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return self._json_schema @@ -561,10 +565,18 @@ def _substituting_provide(self, mediator: Mediator, request: LocatedRequest): ) def provide_loader(self, mediator: Mediator[Loader], request: LoaderRequest) -> Loader: - return self._substituting_provide(mediator, request) + return mediator.cached_call( + self._substituting_provide, + mediator=mediator, + request=request, + ) def provide_dumper(self, mediator: Mediator[Dumper], request: DumperRequest) -> Dumper: - return self._substituting_provide(mediator, request) + return mediator.cached_call( + self._substituting_provide, + mediator=mediator, + request=request, + ) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return self._substituting_provide(mediator, request) @@ -574,10 +586,12 @@ def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) class LiteralStringProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) - return str_strict_coercion_loader if strict_coercion else str # type: ignore[return-value] + return mediator.cached_call( + lambda: str_strict_coercion_loader if strict_coercion else str, # type: ignore[return-value] + ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return as_is_stub + return mediator.cached_call(lambda: as_is_stub) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING) diff --git a/src/adaptix/_internal/morphing/constant_length_tuple_provider.py b/src/adaptix/_internal/morphing/constant_length_tuple_provider.py index 31b392ad..d8ea41e2 100644 --- a/src/adaptix/_internal/morphing/constant_length_tuple_provider.py +++ b/src/adaptix/_internal/morphing/constant_length_tuple_provider.py @@ -48,7 +48,12 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: ) strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) debug_trail = mediator.mandatory_provide(DebugTrailRequest(loc_stack=request.loc_stack)) - return self._make_loader(tuple(loaders), strict_coercion=strict_coercion, debug_trail=debug_trail) + return mediator.cached_call( + self._make_loader, + loaders=tuple(loaders), + strict_coercion=strict_coercion, + debug_trail=debug_trail, + ) def _make_loader(self, loaders: Collection[Loader], *, strict_coercion: bool, debug_trail: DebugTrail): if debug_trail == DebugTrail.DISABLE: @@ -225,7 +230,9 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: lambda: "Cannot create dumper for tuple. Dumpers for some elements cannot be created", ) debug_trail = mediator.mandatory_provide(DebugTrailRequest(loc_stack=request.loc_stack)) - return self._make_dumper(tuple(dumpers), debug_trail) + return mediator.cached_call(self._make_dumper, + dumpers=tuple(dumpers), + debug_trail=debug_trail) def _make_dumper(self, dumpers: Collection[Dumper], debug_trail: DebugTrail): if debug_trail == DebugTrail.DISABLE: diff --git a/src/adaptix/_internal/morphing/dict_provider.py b/src/adaptix/_internal/morphing/dict_provider.py index cc585c9c..06dd7522 100644 --- a/src/adaptix/_internal/morphing/dict_provider.py +++ b/src/adaptix/_internal/morphing/dict_provider.py @@ -44,7 +44,8 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: debug_trail = mediator.mandatory_provide( DebugTrailRequest(loc_stack=request.loc_stack), ) - return self._make_loader( + return mediator.cached_call( + self._make_loader, key_loader=key_loader, value_loader=value_loader, debug_trail=debug_trail, @@ -159,7 +160,8 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: debug_trail = mediator.mandatory_provide( DebugTrailRequest(loc_stack=request.loc_stack), ) - return self._make_dumper( + return mediator.cached_call( + self._make_dumper, key_dumper=key_dumper, value_dumper=value_dumper, debug_trail=debug_trail, @@ -266,13 +268,14 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: def defaultdict_loader(data): return defaultdict(default_factory, dict_loader(data)) - return defaultdict_loader + return mediator.cached_call(lambda: defaultdict_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: key, value = self._extract_key_value(request) dict_type_hint = Dict[key.source, value.source] # type: ignore[misc, name-defined] - return self._DICT_PROVIDER.provide_dumper( - mediator, - replace(request, loc_stack=request.loc_stack.replace_last_type(dict_type_hint)), + return mediator.cached_call( + self._DICT_PROVIDER.provide_dumper, + mediator=mediator, + request=replace(request, loc_stack=request.loc_stack.replace_last_type(dict_type_hint)), ) diff --git a/src/adaptix/_internal/morphing/enum_provider.py b/src/adaptix/_internal/morphing/enum_provider.py index 8d859b29..00d5a23e 100644 --- a/src/adaptix/_internal/morphing/enum_provider.py +++ b/src/adaptix/_internal/morphing/enum_provider.py @@ -120,7 +120,7 @@ def enum_loader(data): except TypeError: raise BadVariantLoadError(variants, data) - return enum_loader + return mediator.cached_call(lambda: enum_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: enum = request.last_loc.type @@ -129,7 +129,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def enum_dumper(data: Enum) -> str: return mapping[data] - return enum_dumper + return mediator.cached_call(lambda: enum_dumper) class EnumValueProvider(BaseEnumProvider): @@ -149,7 +149,7 @@ def enum_loader(data): except ValueError: raise MsgLoadError("Bad enum value", data) - return enum_loader + return mediator.cached_call(lambda: enum_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: value_dumper = mediator.mandatory_provide( @@ -159,7 +159,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def enum_dumper(data): return value_dumper(data.value) - return enum_dumper + return mediator.cached_call(lambda: enum_dumper) class EnumExactValueProvider(BaseEnumProvider): @@ -193,7 +193,7 @@ def enum_exact_loader_v2m(data): except TypeError: raise BadVariantLoadError(variants, data) - return enum_exact_loader_v2m + return mediator.cached_call(lambda: enum_exact_loader_v2m) def _get_exact_value_to_member(self, enum: Type[Enum]) -> Optional[Mapping[Any, Any]]: try: @@ -212,7 +212,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def enum_exact_value_dumper(data): return member_to_value[data] - return enum_exact_value_dumper + return mediator.cached_call(lambda: enum_exact_value_dumper) class FlagByExactValueProvider(BaseFlagProvider): @@ -246,13 +246,13 @@ def flag_loader(data): # so enum lookup cannot raise an error return enum(data) - return flag_loader + return mediator.cached_call(lambda: flag_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: def flag_exact_value_dumper(data): return data.value - return flag_exact_value_dumper + return mediator.cached_call(lambda: flag_exact_value_dumper) def _extract_non_compound_cases_from_flag(enum: Type[FlagT]) -> Sequence[FlagT]: @@ -326,7 +326,7 @@ def flag_loader(data) -> Flag: return result - return flag_loader + return mediator.cached_call(lambda: flag_loader) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: enum = request.last_loc.type @@ -349,4 +349,4 @@ def flag_dumper(value: Flag) -> Sequence[str]: result.append(mapping[case]) return list(reversed(result)) if need_to_reverse else result - return flag_dumper + return mediator.cached_call(lambda: flag_dumper) diff --git a/src/adaptix/_internal/morphing/generic_provider.py b/src/adaptix/_internal/morphing/generic_provider.py index d6206cc7..b8b42891 100644 --- a/src/adaptix/_internal/morphing/generic_provider.py +++ b/src/adaptix/_internal/morphing/generic_provider.py @@ -154,7 +154,7 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) enum_cases = [arg for arg in norm.args if isinstance(arg, Enum)] - enum_loaders = list(self._fetch_enum_loaders(mediator, request, self._get_enum_types(enum_cases))) + enum_loaders = tuple(self._fetch_enum_loaders(mediator, request, self._get_enum_types(enum_cases))) allowed_values_repr = self._get_allowed_values_repr(norm.args, mediator, request.loc_stack) if strict_coercion and any( @@ -182,7 +182,12 @@ def literal_loader(data): return data raise BadVariantLoadError(allowed_values_repr, data) - return self._get_literal_loader_with_enum(literal_loader, enum_loaders, allowed_values) + return mediator.cached_call( + self._get_literal_loader_with_enum, + basic_loader=literal_loader, + enum_loaders=enum_loaders, + allowed_values=allowed_values, + ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: norm = try_normalize_type(request.last_loc.type) @@ -208,7 +213,7 @@ def literal_dumper_with_enums(data): return enum_dumpers[type(data)](data) return data - return literal_dumper_with_enums + return mediator.cached_call(lambda: literal_dumper_with_enums) @for_predicate(Union) @@ -229,9 +234,16 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: lambda x: "Cannot create loader for union. Loaders for some union cases cannot be created", ) if debug_trail in (DebugTrail.ALL, DebugTrail.FIRST): - return self._single_optional_dt_loader(norm.source, not_none_loader) + return mediator.cached_call( + self._single_optional_dt_loader, + tp=norm.source, + loader=not_none_loader, + ) if debug_trail == DebugTrail.DISABLE: - return self._single_optional_dt_disable_loader(not_none_loader) + return mediator.cached_call( + self._single_optional_dt_disable_loader, + loader=not_none_loader, + ) raise ValueError loaders = mediator.mandatory_provide_by_iterable( @@ -247,11 +259,11 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: lambda: "Cannot create loader for union. Loaders for some union cases cannot be created", ) if debug_trail == DebugTrail.DISABLE: - return self._get_loader_dt_disable(tuple(loaders)) + return mediator.cached_call(self._get_loader_dt_disable, loader_iter=tuple(loaders)) if debug_trail == DebugTrail.FIRST: - return self._get_loader_dt_first(norm.source, tuple(loaders)) + return mediator.cached_call(self._get_loader_dt_first, tp=norm.source, loader_iter=tuple(loaders)) if debug_trail == DebugTrail.ALL: - return self._get_loader_dt_all(norm.source, tuple(loaders)) + return mediator.cached_call(self._get_loader_dt_all, tp=norm.source, loader_iter=tuple(loaders)) raise ValueError def _single_optional_dt_disable_loader(self, loader: Loader) -> Loader: @@ -341,8 +353,11 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: lambda x: "Cannot create dumper for union. Dumpers for some union cases cannot be created", ) if not_none_dumper == as_is_stub: - return as_is_stub - return self._get_single_optional_dumper(not_none_dumper) + return mediator.cached_call(lambda: as_is_stub) + return mediator.cached_call( + self._get_single_optional_dumper, + dumper=not_none_dumper, + ) forbidden_origins = [ case.source @@ -370,7 +385,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: lambda: "Cannot create dumper for union. Dumpers for some union cases cannot be created", ) if all(dumper == as_is_stub for dumper in dumpers): - return as_is_stub + return mediator.cached_call(lambda: as_is_stub) dumper_type_dispatcher = ClassDispatcher( {type(None) if case.origin is None else case.origin: dumper for case, dumper in zip(norm.args, dumpers)}, @@ -379,9 +394,12 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: literal_dumper = self._get_dumper_for_literal(norm, dumpers, dumper_type_dispatcher) if literal_dumper: - return literal_dumper + return mediator.cached_call(lambda: literal_dumper) - return self._produce_dumper(dumper_type_dispatcher) + return mediator.cached_call( + self._produce_dumper, + dumper_type_dispatcher=dumper_type_dispatcher, + ) def _produce_dumper(self, dumper_type_dispatcher: ClassDispatcher[Any, Dumper]) -> Dumper: def union_dumper(data): @@ -437,12 +455,13 @@ class PathLikeProvider(LoaderProvider, DumperProvider): _impl = Path def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - return mediator.mandatory_provide( - LoaderRequest( + return mediator.cached_call( + mediator.mandatory_provide, + request=LoaderRequest( loc_stack=request.loc_stack.replace_last_type(self._impl), ), - lambda x: f"Cannot create loader for {PathLike}. Loader for {Path} cannot be created", + error_describer=lambda x: f"Cannot create loader for {PathLike}. Loader for {Path} cannot be created", ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return path_like_dumper + return mediator.cached_call(lambda: path_like_dumper) diff --git a/src/adaptix/_internal/morphing/provider_template.py b/src/adaptix/_internal/morphing/provider_template.py index 28c39eb7..e345af2c 100644 --- a/src/adaptix/_internal/morphing/provider_template.py +++ b/src/adaptix/_internal/morphing/provider_template.py @@ -63,20 +63,22 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: if not self._for_loader: raise CannotProvide - return mediator.mandatory_provide( - LoaderRequest( + return mediator.cached_call( + mediator.mandatory_provide, + request=LoaderRequest( loc_stack=request.loc_stack.replace_last_type(self._impl), ), - lambda x: f"Cannot create loader for union. Loader for {self._impl} cannot be created", + error_describer=lambda x: f"Cannot create loader for union. Loader for {self._impl} cannot be created", ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: if not self._for_dumper: raise CannotProvide - return mediator.mandatory_provide( - DumperRequest( + return mediator.cached_call( + mediator.mandatory_provide, + request=DumperRequest( loc_stack=request.loc_stack.replace_last_type(self._impl), ), - lambda x: f"Cannot create dumper for union. Dumper for {self._impl} cannot be created", + error_describer=lambda x: f"Cannot create dumper for union. Dumper for {self._impl} cannot be created", ) From 033ecef3f6033c8813f9ebd8e87e2bb5ba2ca00a Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Wed, 7 Aug 2024 19:10:22 +0300 Subject: [PATCH 2/4] working... --- .../_internal/morphing/concrete_provider.py | 144 +++++++++++++----- .../_internal/morphing/dict_provider.py | 11 +- .../_internal/morphing/enum_provider.py | 8 +- 3 files changed, 121 insertions(+), 42 deletions(-) diff --git a/src/adaptix/_internal/morphing/concrete_provider.py b/src/adaptix/_internal/morphing/concrete_provider.py index b16787cb..04e1e3e9 100644 --- a/src/adaptix/_internal/morphing/concrete_provider.py +++ b/src/adaptix/_internal/morphing/concrete_provider.py @@ -39,6 +39,9 @@ def __repr__(self): return f"{type(self)}(cls={self._cls})" def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): raw_loader = self._cls.fromisoformat def isoformat_loader(data): @@ -48,11 +51,13 @@ def isoformat_loader(data): raise TypeLoadError(str, data) except ValueError: raise ValueLoadError("Invalid isoformat string", data) - - return mediator.cached_call(lambda: isoformat_loader) + return isoformat_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: self._cls.isoformat) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return self._cls.isoformat def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING, format=self._CLS_TO_JSON_FORMAT[self._cls]) @@ -67,6 +72,9 @@ def __repr__(self): return f"{type(self)}(fmt={self._fmt})" def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): fmt = self._fmt def datetime_format_loader(data): @@ -77,15 +85,18 @@ def datetime_format_loader(data): except TypeError: raise TypeLoadError(str, data) - return mediator.cached_call(lambda: datetime_format_loader) + return datetime_format_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): fmt = self._fmt def datetime_format_dumper(data: datetime): return data.strftime(fmt) - return mediator.cached_call(lambda: datetime_format_dumper) + return datetime_format_dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING) @@ -97,6 +108,9 @@ def __init__(self, tz: Optional[timezone]): self._tz = tz def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): tz = self._tz def datetime_timestamp_loader(data): @@ -112,13 +126,15 @@ def datetime_timestamp_loader(data): data, ) - return mediator.cached_call(lambda: datetime_timestamp_loader) + return datetime_timestamp_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): def datetime_timestamp_dumper(data: datetime): return data.timestamp() - - return mediator.cached_call(lambda: datetime_timestamp_dumper) + return datetime_timestamp_dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NUMBER) @@ -138,6 +154,9 @@ def _is_pydatetime(self) -> bool: return False def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): def date_timestamp_loader(data): try: # Pure-Python implementation and C-extension implementation @@ -168,11 +187,12 @@ def pydate_timestamp_loader(data): data, ) - return mediator.cached_call( - lambda: pydate_timestamp_loader if self._is_pydatetime() else date_timestamp_loader, - ) + return pydate_timestamp_loader if self._is_pydatetime() else date_timestamp_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): def date_timestamp_dumper(data: date): dt = datetime( year=data.year, @@ -181,8 +201,7 @@ def date_timestamp_dumper(data: date): tzinfo=timezone.utc, ) return dt.timestamp() - - return mediator.cached_call(lambda: date_timestamp_dumper) + return date_timestamp_dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NUMBER) @@ -193,6 +212,9 @@ class SecondsTimedeltaProvider(MorphingProvider): _OK_TYPES = (int, float, Decimal) def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): ok_types = self._OK_TYPES def timedelta_loader(data): @@ -200,10 +222,13 @@ def timedelta_loader(data): raise TypeLoadError(Union[int, float, Decimal], data) return timedelta(seconds=int(data), microseconds=int(data % 1 * 10 ** 6)) - return mediator.cached_call(lambda: timedelta_loader) + return timedelta_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: timedelta.total_seconds) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return timedelta.total_seconds def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NUMBER) @@ -218,10 +243,16 @@ def none_loader(data): @for_predicate(None) class NoneProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - return mediator.cached_call(lambda: none_loader) + return mediator.cached_call(self._make_loader) + + def _make_loader(self): + return none_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: as_is_stub) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return as_is_stub def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.NULL) @@ -229,11 +260,12 @@ def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) class _Base64DumperMixin(DumperProvider): def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): def bytes_base64_dumper(data): return b2a_base64(data, newline=False).decode("ascii") - - return mediator.cached_call(lambda: bytes_base64_dumper) - + return bytes_base64_dumper class _Base64JSONSchemaMixin(JSONSchemaProvider): def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: @@ -246,6 +278,9 @@ def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) @for_predicate(bytes) class BytesBase64Provider(_Base64DumperMixin, _Base64JSONSchemaMixin, MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): def bytes_base64_loader(data): try: encoded = data.encode("ascii") @@ -259,8 +294,7 @@ def bytes_base64_loader(data): return a2b_base64(encoded) except binascii.Error as e: raise ValueLoadError(str(e), data) - - return mediator.cached_call(lambda: bytes_base64_loader) + return bytes_base64_loader @for_predicate(BytesIO) @@ -268,30 +302,37 @@ class BytesIOBase64Provider(_Base64JSONSchemaMixin, MorphingProvider): _BYTES_PROVIDER = BytesBase64Provider() def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - bytes_base64_loader = self._BYTES_PROVIDER.provide_loader(mediator, request) + return mediator.cached_call( + self._make_loader, + loader=self._BYTES_PROVIDER.provide_loader(mediator, request), + ) + def _make_loader(self, loader: Loader): def bytes_io_base64_loader(data): - return BytesIO(bytes_base64_loader(data)) - - return mediator.cached_call(lambda: bytes_io_base64_loader) + return BytesIO(loader(data)) + return bytes_io_base64_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): def bytes_io_base64_dumper(data: BytesIO): return b2a_base64(data.getvalue(), newline=False).decode("ascii") - - return mediator.cached_call(lambda: bytes_io_base64_dumper) + return bytes_io_base64_dumper @for_predicate(typing.IO[bytes]) class IOBytesBase64Provider(BytesIOBase64Provider, _Base64JSONSchemaMixin, MorphingProvider): def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): def io_bytes_base64_dumper(data: typing.IO[bytes]): if data.seekable(): data.seek(0) return b2a_base64(data.read(), newline=False).decode("ascii") - - return mediator.cached_call(lambda: io_bytes_base64_dumper) + return io_bytes_base64_dumper @for_predicate(bytearray) @@ -304,10 +345,15 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: replace(request, loc_stack=request.loc_stack.replace_last_type(bytes)), ) - def bytearray_base64_loader(data): - return bytearray(bytes_loader(data)) + return mediator.cached_call( + self._make_loader, + loader=bytes_loader, + ) - return mediator.cached_call(lambda: bytearray_base64_loader) + def _make_loader(self, loader: Loader): + def bytearray_base64_loader(data): + return bytearray(loader(data)) + return bytearray_base64_loader def _regex_dumper(data: re.Pattern): @@ -320,6 +366,9 @@ def __init__(self, flags: re.RegexFlag = re.RegexFlag(0)): self.flags = flags def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: + return mediator.cached_call(self._make_loader) + + def _make_loader(self): flags = self.flags re_compile = re.compile @@ -332,10 +381,13 @@ def regex_loader(data): except re.error as e: raise ValueLoadError(str(e), data) - return mediator.cached_call(lambda: regex_loader) + return regex_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: _regex_dumper) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return _regex_dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING, format=JSONSchemaBuiltinFormat.REGEX) @@ -363,11 +415,18 @@ def __init__( def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) return mediator.cached_call( - lambda: self._strict_coercion_loader if strict_coercion else self._lax_coercion_loader, + self._make_loader, + strict_coercion=strict_coercion, ) + def _make_loader(self, strict_coercion: bool): + return self._strict_coercion_loader if strict_coercion else self._lax_coercion_loader + def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: self._dumper) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return self._dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return self._json_schema @@ -587,11 +646,18 @@ class LiteralStringProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) return mediator.cached_call( - lambda: str_strict_coercion_loader if strict_coercion else str, # type: ignore[return-value] + self._make_loader, # type: ignore[return-value] + strict_coercion=strict_coercion, ) + def _make_loader(self, strict_coercion: bool): + return str_strict_coercion_loader if strict_coercion else str + def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: as_is_stub) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return as_is_stub def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return JSONSchema(type=JSONSchemaType.STRING) diff --git a/src/adaptix/_internal/morphing/dict_provider.py b/src/adaptix/_internal/morphing/dict_provider.py index 06dd7522..79cb0ec6 100644 --- a/src/adaptix/_internal/morphing/dict_provider.py +++ b/src/adaptix/_internal/morphing/dict_provider.py @@ -263,12 +263,19 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: mediator, replace(request, loc_stack=request.loc_stack.replace_last_type(dict_type_hint)), ) + + return mediator.cached_call( + self._make_loader, + loader=dict_loader, + ) + + def _make_loader(self, loader: Loader): default_factory = self.default_factory def defaultdict_loader(data): - return defaultdict(default_factory, dict_loader(data)) + return defaultdict(default_factory, loader(data)) - return mediator.cached_call(lambda: defaultdict_loader) + return defaultdict_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: key, value = self._extract_key_value(request) diff --git a/src/adaptix/_internal/morphing/enum_provider.py b/src/adaptix/_internal/morphing/enum_provider.py index 00d5a23e..58b62192 100644 --- a/src/adaptix/_internal/morphing/enum_provider.py +++ b/src/adaptix/_internal/morphing/enum_provider.py @@ -110,6 +110,12 @@ def __init__(self, mapping_generator: BaseEnumMappingGenerator): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: enum = request.last_loc.type mapping = self._mapping_generator.generate_for_loading(enum.__members__.values()) + return mediator.cached_call( + self._make_loader, + mapping=mapping, + ) + + def _make_loader(self, mapping: Mapping): variants = list(mapping.keys()) def enum_loader(data): @@ -120,7 +126,7 @@ def enum_loader(data): except TypeError: raise BadVariantLoadError(variants, data) - return mediator.cached_call(lambda: enum_loader) + return enum_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: enum = request.last_loc.type From 5e9f9c4ca37c24a614a7260db95e5e90c5cafe16 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Wed, 7 Aug 2024 20:20:39 +0300 Subject: [PATCH 3/4] I hope this will be the last commit --- .../_internal/morphing/concrete_provider.py | 14 +-- .../_internal/morphing/enum_provider.py | 88 ++++++++++++++----- .../_internal/morphing/generic_provider.py | 57 ++++++++---- 3 files changed, 115 insertions(+), 44 deletions(-) diff --git a/src/adaptix/_internal/morphing/concrete_provider.py b/src/adaptix/_internal/morphing/concrete_provider.py index 04e1e3e9..025bd6ed 100644 --- a/src/adaptix/_internal/morphing/concrete_provider.py +++ b/src/adaptix/_internal/morphing/concrete_provider.py @@ -213,7 +213,7 @@ class SecondsTimedeltaProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: return mediator.cached_call(self._make_loader) - + def _make_loader(self): ok_types = self._OK_TYPES @@ -244,13 +244,13 @@ def none_loader(data): class NoneProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: return mediator.cached_call(self._make_loader) - + def _make_loader(self): return none_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: return mediator.cached_call(self._make_dumper) - + def _make_dumper(self): return as_is_stub @@ -279,7 +279,7 @@ def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) class BytesBase64Provider(_Base64DumperMixin, _Base64JSONSchemaMixin, MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: return mediator.cached_call(self._make_loader) - + def _make_loader(self): def bytes_base64_loader(data): try: @@ -419,7 +419,7 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion=strict_coercion, ) - def _make_loader(self, strict_coercion: bool): + def _make_loader(self, *, strict_coercion: bool): return self._strict_coercion_loader if strict_coercion else self._lax_coercion_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: @@ -646,11 +646,11 @@ class LiteralStringProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) return mediator.cached_call( - self._make_loader, # type: ignore[return-value] + self._make_loader, strict_coercion=strict_coercion, ) - def _make_loader(self, strict_coercion: bool): + def _make_loader(self, *, strict_coercion: bool): return str_strict_coercion_loader if strict_coercion else str def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: diff --git a/src/adaptix/_internal/morphing/enum_provider.py b/src/adaptix/_internal/morphing/enum_provider.py index 58b62192..b9afb421 100644 --- a/src/adaptix/_internal/morphing/enum_provider.py +++ b/src/adaptix/_internal/morphing/enum_provider.py @@ -108,14 +108,13 @@ def __init__(self, mapping_generator: BaseEnumMappingGenerator): self._mapping_generator = mapping_generator def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - enum = request.last_loc.type - mapping = self._mapping_generator.generate_for_loading(enum.__members__.values()) return mediator.cached_call( self._make_loader, - mapping=mapping, + enum=request.last_loc.type, ) - - def _make_loader(self, mapping: Mapping): + + def _make_loader(self, enum): + mapping = self._mapping_generator.generate_for_loading(enum.__members__.values()) variants = list(mapping.keys()) def enum_loader(data): @@ -130,12 +129,19 @@ def enum_loader(data): def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: enum = request.last_loc.type + + return mediator.cached_call( + self._make_dumper, + enum=enum, + ) + + def _make_dumper(self, enum): mapping = self._mapping_generator.generate_for_dumping(enum.__members__.values()) def enum_dumper(data: Enum) -> str: return mapping[data] - return mediator.cached_call(lambda: enum_dumper) + return enum_dumper class EnumValueProvider(BaseEnumProvider): @@ -148,6 +154,13 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: request.append_loc(TypeHintLoc(type=self._value_type)), ) + return mediator.cached_call( + self._make_loader, + enum=enum, + value_loader=value_loader, + ) + + def _make_loader(self, enum: Enum, value_loader: Loader): def enum_loader(data): loaded_value = value_loader(data) try: @@ -155,18 +168,23 @@ def enum_loader(data): except ValueError: raise MsgLoadError("Bad enum value", data) - return mediator.cached_call(lambda: enum_loader) + return enum_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: value_dumper = mediator.mandatory_provide( request.append_loc(TypeHintLoc(type=self._value_type)), ) + return mediator.cached_call( + self._make_dumper, + value_dumper=value_dumper, + ) + + def _make_dumper(self, value_dumper: Dumper): def enum_dumper(data): return value_dumper(data.value) - return mediator.cached_call(lambda: enum_dumper) - + return enum_dumper class EnumExactValueProvider(BaseEnumProvider): """This provider represents enum members to the outside world @@ -174,9 +192,13 @@ class EnumExactValueProvider(BaseEnumProvider): """ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - enum = request.last_loc.type - variants = [case.value for case in enum] + return mediator.cached_call( + self._make_loader, + enum=request.last_loc.type, + ) + def _make_loader(self, enum): + variants = [case.value for case in enum] value_to_member = self._get_exact_value_to_member(enum) if value_to_member is None: def enum_exact_loader(data): @@ -199,7 +221,8 @@ def enum_exact_loader_v2m(data): except TypeError: raise BadVariantLoadError(variants, data) - return mediator.cached_call(lambda: enum_exact_loader_v2m) + return enum_exact_loader_v2m + def _get_exact_value_to_member(self, enum: Type[Enum]) -> Optional[Mapping[Any, Any]]: try: @@ -213,17 +236,28 @@ def _get_exact_value_to_member(self, enum: Type[Enum]) -> Optional[Mapping[Any, return value_to_member def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - member_to_value = {member: member.value for member in request.last_loc.type} + return mediator.cached_call( + self._make_dumper, + enum=request.last_loc.type, + ) + + def _make_dumper(self, enum): + member_to_value = {member: member.value for member in enum} def enum_exact_value_dumper(data): return member_to_value[data] - return mediator.cached_call(lambda: enum_exact_value_dumper) + return enum_exact_value_dumper class FlagByExactValueProvider(BaseFlagProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - enum = request.last_loc.type + return mediator.cached_call( + self._make_loader, + enum=request.last_loc.type, + ) + + def _make_loader(self, enum): flag_mask = reduce(or_, enum.__members__.values()).value if flag_mask < 0: @@ -252,13 +286,16 @@ def flag_loader(data): # so enum lookup cannot raise an error return enum(data) - return mediator.cached_call(lambda: flag_loader) + return flag_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): def flag_exact_value_dumper(data): return data.value - return mediator.cached_call(lambda: flag_exact_value_dumper) + return flag_exact_value_dumper def _extract_non_compound_cases_from_flag(enum: Type[FlagT]) -> Sequence[FlagT]: @@ -288,6 +325,13 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: enum = request.last_loc.type strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) + return mediator.cached_call( + self._make_loader, + enum=enum, + strict_coercion=strict_coercion, + ) + + def _make_loader(self, enum, *, strict_coercion: bool): allow_single_value = self._allow_single_value allow_duplicates = self._allow_duplicates @@ -332,11 +376,15 @@ def flag_loader(data) -> Flag: return result - return mediator.cached_call(lambda: flag_loader) + return flag_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - enum = request.last_loc.type + return mediator.cached_call( + self._make_dumper, + enum=request.last_loc.type, + ) + def _make_dumper(self, enum): cases = self._get_cases(enum) need_to_reverse = self._allow_compound and cases != _extract_non_compound_cases_from_flag(enum) if need_to_reverse: @@ -355,4 +403,4 @@ def flag_dumper(value: Flag) -> Sequence[str]: result.append(mapping[case]) return list(reversed(result)) if need_to_reverse else result - return mediator.cached_call(lambda: flag_dumper) + return flag_dumper diff --git a/src/adaptix/_internal/morphing/generic_provider.py b/src/adaptix/_internal/morphing/generic_provider.py index b8b42891..df1b1dd1 100644 --- a/src/adaptix/_internal/morphing/generic_provider.py +++ b/src/adaptix/_internal/morphing/generic_provider.py @@ -191,6 +191,14 @@ def literal_loader(data): def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: norm = try_normalize_type(request.last_loc.type) + return mediator.cached_call( + self._make_dumper, + norm=norm, + mediator=mediator, + request=request, + ) + + def _make_dumper(self, norm: BaseNormType, mediator: Mediator, request: DumperRequest): enum_cases = [arg for arg in norm.args if isinstance(arg, Enum)] if not enum_cases: @@ -213,8 +221,7 @@ def literal_dumper_with_enums(data): return enum_dumpers[type(data)](data) return data - return mediator.cached_call(lambda: literal_dumper_with_enums) - + return literal_dumper_with_enums @for_predicate(Union) class UnionProvider(LoaderProvider, DumperProvider): @@ -222,6 +229,15 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: norm = try_normalize_type(request.last_loc.type) debug_trail = mediator.mandatory_provide(DebugTrailRequest(loc_stack=request.loc_stack)) + return mediator.cached_call( + self._make_loader, + norm=norm, + debug_trail=debug_trail, + mediator=mediator, + request=request, + ) + + def _make_loader(self, norm: BaseNormType, debug_trail: DebugTrail, mediator: Mediator, request: LoaderRequest): if self._is_single_optional(norm): not_none = next(case for case in norm.args if case.origin is not None) not_none_loader = mediator.mandatory_provide( @@ -234,14 +250,12 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: lambda x: "Cannot create loader for union. Loaders for some union cases cannot be created", ) if debug_trail in (DebugTrail.ALL, DebugTrail.FIRST): - return mediator.cached_call( - self._single_optional_dt_loader, + return self._single_optional_dt_loader( tp=norm.source, loader=not_none_loader, ) if debug_trail == DebugTrail.DISABLE: - return mediator.cached_call( - self._single_optional_dt_disable_loader, + return self._single_optional_dt_disable_loader( loader=not_none_loader, ) raise ValueError @@ -259,11 +273,11 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: lambda: "Cannot create loader for union. Loaders for some union cases cannot be created", ) if debug_trail == DebugTrail.DISABLE: - return mediator.cached_call(self._get_loader_dt_disable, loader_iter=tuple(loaders)) + return self._get_loader_dt_disable(loader_iter=tuple(loaders)) if debug_trail == DebugTrail.FIRST: - return mediator.cached_call(self._get_loader_dt_first, tp=norm.source, loader_iter=tuple(loaders)) + return self._get_loader_dt_first(tp=norm.source, loader_iter=tuple(loaders)) if debug_trail == DebugTrail.ALL: - return mediator.cached_call(self._get_loader_dt_all, tp=norm.source, loader_iter=tuple(loaders)) + return self._get_loader_dt_all(tp=norm.source, loader_iter=tuple(loaders)) raise ValueError def _single_optional_dt_disable_loader(self, loader: Loader) -> Loader: @@ -341,6 +355,14 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: request_type = request.last_loc.type norm = try_normalize_type(request_type) + return mediator.cached_call( + self._make_dumper, + norm=norm, + mediator=mediator, + request=request, + ) + + def _make_dumper(self, norm: BaseNormType, mediator: Mediator, request: DumperRequest): if self._is_single_optional(norm): not_none = next(case for case in norm.args if case.origin is not None) not_none_dumper = mediator.mandatory_provide( @@ -353,9 +375,8 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: lambda x: "Cannot create dumper for union. Dumpers for some union cases cannot be created", ) if not_none_dumper == as_is_stub: - return mediator.cached_call(lambda: as_is_stub) - return mediator.cached_call( - self._get_single_optional_dumper, + return as_is_stub + return self._get_single_optional_dumper( dumper=not_none_dumper, ) @@ -385,7 +406,7 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: lambda: "Cannot create dumper for union. Dumpers for some union cases cannot be created", ) if all(dumper == as_is_stub for dumper in dumpers): - return mediator.cached_call(lambda: as_is_stub) + return as_is_stub dumper_type_dispatcher = ClassDispatcher( {type(None) if case.origin is None else case.origin: dumper for case, dumper in zip(norm.args, dumpers)}, @@ -394,10 +415,9 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: literal_dumper = self._get_dumper_for_literal(norm, dumpers, dumper_type_dispatcher) if literal_dumper: - return mediator.cached_call(lambda: literal_dumper) + return literal_dumper - return mediator.cached_call( - self._produce_dumper, + return self._produce_dumper( dumper_type_dispatcher=dumper_type_dispatcher, ) @@ -464,4 +484,7 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(lambda: path_like_dumper) + return mediator.cached_call(self._make_dumper) + + def _make_dumper(self): + return path_like_dumper From 404937854c091b9e9c122236c13f2149886c00ee Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Thu, 8 Aug 2024 09:00:25 +0300 Subject: [PATCH 4/4] Address review --- .../_internal/morphing/concrete_provider.py | 35 ++----------------- .../_internal/morphing/enum_provider.py | 8 ++--- .../_internal/morphing/generic_provider.py | 10 ++---- .../_internal/morphing/provider_template.py | 14 ++++---- 4 files changed, 14 insertions(+), 53 deletions(-) diff --git a/src/adaptix/_internal/morphing/concrete_provider.py b/src/adaptix/_internal/morphing/concrete_provider.py index 025bd6ed..2f605c38 100644 --- a/src/adaptix/_internal/morphing/concrete_provider.py +++ b/src/adaptix/_internal/morphing/concrete_provider.py @@ -243,15 +243,9 @@ def none_loader(data): @for_predicate(None) class NoneProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - return mediator.cached_call(self._make_loader) - - def _make_loader(self): return none_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(self._make_dumper) - - def _make_dumper(self): return as_is_stub def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: @@ -384,9 +378,6 @@ def regex_loader(data): return regex_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(self._make_dumper) - - def _make_dumper(self): return _regex_dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: @@ -423,9 +414,6 @@ def _make_loader(self, *, strict_coercion: bool): return self._strict_coercion_loader if strict_coercion else self._lax_coercion_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(self._make_dumper) - - def _make_dumper(self): return self._dumper def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: @@ -624,18 +612,10 @@ def _substituting_provide(self, mediator: Mediator, request: LocatedRequest): ) def provide_loader(self, mediator: Mediator[Loader], request: LoaderRequest) -> Loader: - return mediator.cached_call( - self._substituting_provide, - mediator=mediator, - request=request, - ) + return self._substituting_provide(mediator, request) def provide_dumper(self, mediator: Mediator[Dumper], request: DumperRequest) -> Dumper: - return mediator.cached_call( - self._substituting_provide, - mediator=mediator, - request=request, - ) + return self._substituting_provide(mediator, request) def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: return self._substituting_provide(mediator, request) @@ -645,18 +625,9 @@ def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) class LiteralStringProvider(MorphingProvider): def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: strict_coercion = mediator.mandatory_provide(StrictCoercionRequest(loc_stack=request.loc_stack)) - return mediator.cached_call( - self._make_loader, - strict_coercion=strict_coercion, - ) - - def _make_loader(self, *, strict_coercion: bool): - return str_strict_coercion_loader if strict_coercion else str + return str_strict_coercion_loader if strict_coercion else str # type: ignore[return-value] def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(self._make_dumper) - - def _make_dumper(self): return as_is_stub def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema: diff --git a/src/adaptix/_internal/morphing/enum_provider.py b/src/adaptix/_internal/morphing/enum_provider.py index b9afb421..75f3460d 100644 --- a/src/adaptix/_internal/morphing/enum_provider.py +++ b/src/adaptix/_internal/morphing/enum_provider.py @@ -289,14 +289,10 @@ def flag_loader(data): return flag_loader def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(self._make_dumper) - - def _make_dumper(self): - def flag_exact_value_dumper(data): - return data.value - return flag_exact_value_dumper +def flag_exact_value_dumper(data): + return data.value def _extract_non_compound_cases_from_flag(enum: Type[FlagT]) -> Sequence[FlagT]: return [case for case in enum.__members__.values() if not math.log2(case.value) % 1] diff --git a/src/adaptix/_internal/morphing/generic_provider.py b/src/adaptix/_internal/morphing/generic_provider.py index df1b1dd1..76991149 100644 --- a/src/adaptix/_internal/morphing/generic_provider.py +++ b/src/adaptix/_internal/morphing/generic_provider.py @@ -475,16 +475,12 @@ class PathLikeProvider(LoaderProvider, DumperProvider): _impl = Path def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: - return mediator.cached_call( - mediator.mandatory_provide, - request=LoaderRequest( + return mediator.mandatory_provide( + LoaderRequest( loc_stack=request.loc_stack.replace_last_type(self._impl), ), - error_describer=lambda x: f"Cannot create loader for {PathLike}. Loader for {Path} cannot be created", + lambda x: f"Cannot create loader for {PathLike}. Loader for {Path} cannot be created", ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: - return mediator.cached_call(self._make_dumper) - - def _make_dumper(self): return path_like_dumper diff --git a/src/adaptix/_internal/morphing/provider_template.py b/src/adaptix/_internal/morphing/provider_template.py index e345af2c..28c39eb7 100644 --- a/src/adaptix/_internal/morphing/provider_template.py +++ b/src/adaptix/_internal/morphing/provider_template.py @@ -63,22 +63,20 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: if not self._for_loader: raise CannotProvide - return mediator.cached_call( - mediator.mandatory_provide, - request=LoaderRequest( + return mediator.mandatory_provide( + LoaderRequest( loc_stack=request.loc_stack.replace_last_type(self._impl), ), - error_describer=lambda x: f"Cannot create loader for union. Loader for {self._impl} cannot be created", + lambda x: f"Cannot create loader for union. Loader for {self._impl} cannot be created", ) def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper: if not self._for_dumper: raise CannotProvide - return mediator.cached_call( - mediator.mandatory_provide, - request=DumperRequest( + return mediator.mandatory_provide( + DumperRequest( loc_stack=request.loc_stack.replace_last_type(self._impl), ), - error_describer=lambda x: f"Cannot create dumper for union. Dumper for {self._impl} cannot be created", + lambda x: f"Cannot create dumper for union. Dumper for {self._impl} cannot be created", )