From the docs:
https://adaptix.readthedocs.io/en/latest/loading-and-dumping/extended-usage.html
| TypeVar |
Derived implicit parameter |
| T = TypeVar('T') |
Any |
| B = TypeVar('B', bound=Book) |
Book |
| C = TypeVar('C', str, bytes) |
Union[str, bytes] |
The behaviour for the third case is wrong: Union[str, bytes] is not a valid value for C.
A constrained type variable can only be resolved to one of the options, so Thing[int] is valid, Thing[str] is valid, but Thing[str | int], Thing[Literal[0]], Thing[str | Literal[0]], and Thing[bool] are all invalid. (see the specification on TypeVars)
In other words, TypeVar("S", str, int) is not the same as TypeVar("S", bound=str | int).
Example code:
from dataclasses import dataclass
from typing import Generic, TypeVar
import adaptix
S = TypeVar("S", str, int)
@dataclass
class Thing(Generic[S]):
first: S
second: S
def should_always_be_true(self) -> bool:
return (
isinstance(self.first, str) and isinstance(self.second, str)
or
isinstance(self.first, int) and isinstance(self.second, int)
)
thing = adaptix.load({"first": "hmm", "second": 42}, Thing)
print(thing) # Thing(first='hmm', second=42)
print(thing.should_always_be_true()) # False
Possible solutions:
- ban unqualified constrained typevars (i.e.
Thing[str] is legal as the second argument to load, Thing is not)
- change
Thing with no parameter to mean Thing[str] | Thing[int]
From the docs:
The behaviour for the third case is wrong:
Union[str, bytes]is not a valid value forC.A constrained type variable can only be resolved to one of the options, so
Thing[int]is valid,Thing[str]is valid, butThing[str | int],Thing[Literal[0]],Thing[str | Literal[0]], andThing[bool]are all invalid. (see the specification on TypeVars)In other words,
TypeVar("S", str, int)is not the same asTypeVar("S", bound=str | int).Example code:
Possible solutions:
Thing[str]is legal as the second argument toload,Thingis not)Thingwith no parameter to meanThing[str] | Thing[int]