Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/ld omitted #356

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/adaptix/_internal/morphing/concrete_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,25 @@
from io import BytesIO
from typing import Generic, Optional, TypeVar, Union

from adaptix._internal.utils import Omittable, Omitted

from ... import DebugTrail
from ..common import Dumper, Loader
from ..feature_requirement import HAS_PY_311, HAS_SELF_TYPE
from ..provider.essential import CannotProvide, Mediator
from ..provider.loc_stack_filtering import P, create_loc_stack_checker
from ..provider.loc_stack_tools import find_owner_with_field
from ..provider.located_request import LocatedRequest, for_predicate
from ..provider.location import GenericParamLoc
from ..special_cases_optimization import as_is_stub
from .dump_error import SentinelDumpError
from .json_schema.definitions import JSONSchema
from .json_schema.request_cls import JSONSchemaRequest
from .json_schema.schema_model import JSONSchemaBuiltinFormat, JSONSchemaType
from .load_error import FormatMismatchLoadError, TypeLoadError, ValueLoadError
from .load_error import FormatMismatchLoadError, LoadError, TypeLoadError, UnionLoadError, ValueLoadError
from .provider_template import DumperProvider, JSONSchemaProvider, MorphingProvider
from .request_cls import DumperRequest, LoaderRequest, StrictCoercionRequest
from .request_cls import DebugTrailRequest, DumperRequest, LoaderRequest, StrictCoercionRequest
from .utils import try_normalize_type


class IsoFormatProvider(MorphingProvider):
Expand Down Expand Up @@ -633,3 +639,27 @@ def provide_dumper(self, mediator: Mediator, request: DumperRequest) -> Dumper:

def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema:
return JSONSchema(type=JSONSchemaType.STRING)


def make_sentinel_dumper(sentinel_type: typing.Type):
def sentinel_dumper(data):
if type(data) is sentinel_type:
raise SentinelDumpError(sentinel_type)
return sentinel_dumper


def sentinel_loader(data):
raise ValueLoadError("Field value required", data)


@for_predicate(Omitted)
class OmittedProvider(MorphingProvider):
def _generate_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> JSONSchema:
raise CannotProvide

def provide_dumper(self, mediator: Mediator[Dumper], request: DumperRequest) -> Dumper:
return make_sentinel_dumper(Omitted)


def provide_loader(self, mediator: Mediator[Loader], request: LoaderRequest) -> Loader:
return sentinel_loader
12 changes: 12 additions & 0 deletions src/adaptix/_internal/morphing/dump_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import dataclasses

from adaptix._internal.utils import fix_dataclass_from_builtin


@dataclasses.dataclass(eq=False)
@fix_dataclass_from_builtin
class SentinelDumpError(Exception):
sentinel: type

def __str__(self):
return f"Cannot dump {self.sentinel!r}"
2 changes: 2 additions & 0 deletions src/adaptix/_internal/morphing/facade/retort.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
IsoFormatProvider,
LiteralStringProvider,
NoneProvider,
OmittedProvider,
RegexPatternProvider,
SecondsTimedeltaProvider,
SelfTypeProvider,
Expand Down Expand Up @@ -136,6 +137,7 @@ class FilledRetort(OperatingRetort, ABC):
RegexPatternProvider(),
SelfTypeProvider(),
LiteralStringProvider(),
OmittedProvider(),

ABCProxy(Mapping, dict),
ABCProxy(MutableMapping, dict),
Expand Down
4 changes: 3 additions & 1 deletion src/adaptix/_internal/morphing/model/basic_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ def get_skipped_fields(shape: BaseShape, name_layout: BaseNameLayout) -> Set[str
extra_targets = name_layout.extra_move.fields if isinstance(name_layout.extra_move, ExtraTargets) else ()
return {
field.id for field in shape.fields
if field.id not in used_direct_fields and field.id not in extra_targets
if field.id not in used_direct_fields
and field.id not in extra_targets

}


Expand Down
43 changes: 42 additions & 1 deletion tests/unit/morphing/test_concrete_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@

import pytest
from tests_helpers import cond_list, raises_exc
from unit.integrations.sqlalchemy.test_orm import retort

from adaptix import Retort
from adaptix import DebugTrail, Omittable, Omitted, Retort
from adaptix._internal.feature_requirement import HAS_PY_311, IS_PYPY
from adaptix._internal.morphing.concrete_provider import (
DatetimeFormatProvider,
DateTimestampProvider,
DatetimeTimestampProvider,
)
from adaptix._internal.morphing.dump_error import SentinelDumpError
from adaptix._internal.morphing.load_error import LoadError, UnionLoadError
from adaptix.load_error import FormatMismatchLoadError, TypeLoadError, ValueLoadError

INVALID_INPUT_ISO_FORMAT = (
Expand Down Expand Up @@ -514,3 +517,41 @@ def test_complex_loader_provider(strict_coercion, debug_trail):
raises_exc(ValueLoadError("Bad string format", "foo"), lambda: loader("foo"))
raises_exc(TypeLoadError(Union[str, complex], None), lambda: loader(None))
raises_exc(TypeLoadError(Union[str, complex], []), lambda: loader([]))


def test_omittable_provider(strict_coercion, debug_trail):
retort = Retort(
strict_coercion=strict_coercion,
debug_trail=debug_trail,
)

dumper = retort.get_dumper(Omittable[int])
raises_exc(
SentinelDumpError(Omitted),
lambda: dumper(Omitted()),
)
loader = retort.get_loader(Omittable[int])
assert loader(1) == 1

if debug_trail == DebugTrail.DISABLE:
raises_exc(
LoadError(),
lambda: loader(Omitted()),
)
raises_exc(
LoadError(),
lambda: loader([]),
)
elif debug_trail in (DebugTrail.FIRST, DebugTrail.ALL):
if not strict_coercion:
return
raises_exc(
UnionLoadError(
f"while loading {Union[int, Omitted]}",
[
ValueLoadError("Field value required", "100"),
TypeLoadError(int, "100"),
],
),
lambda: loader("100"),
)