Replies: 11 comments
-
It is a pydantic question imho
Take a look at pydantic/pydantic#360
Or 284
Le mer. 21 août 2019 à 4:00 PM, Vadim Suharnikov <notifications@github.com>
a écrit :
… Integer fields convert bool and float values to integer (1.5, true -> 1,
0) without error raising.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#453>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAINSPSZIRQ7SWXCBO77UDDQFVDA3ANCNFSM4IOHLQEQ>
.
|
Beta Was this translation helpful? Give feedback.
-
@Deterok Look at the pydantic docs on It's not clear whether you want to check if the input is of type int, or if it is allowed to be a float as long as when rounded to an int it is equal to itself. Either way, it can be done inside a validator, just raise a ValueError or TypeError if you want to fail validation, and return the original value (or the int-casted version of it) if you want it to pass. |
Beta Was this translation helpful? Give feedback.
-
Pydantic already has class StrictInt(int):
@classmethod
def __get_validators__(cls) -> Generator[Callable[[Any], int], None, None]:
# yield int_validator
yield cls.validate
@classmethod
def validate(cls, v: Any) -> int:
if not isinstance(v, int):
raise IntegerError()
return v @samuelcolvin - wouldn't it be nice to have |
Beta Was this translation helpful? Give feedback.
-
@haizaar to that point, I think it probably makes sense to just have a generic way to achieve T = TypeVar("T")
def strict_type(type_: Type[T]) -> Type[T]:
class StrictType(type_):
def __get_validators__(cls) -> Generator[Callable[[Any], int], None, None]:
# yield int_validator
yield cls.validate
@classmethod
def validate(cls, v: Any) -> int:
if not isinstance(v, type_):
raise TypeError(f"{v} was not a {type_}")
return v
return StrictType
StrictInt = strict_type(int) This probably needs a little more massaging to get it to play nice with mypy, etc; maybe it should be a generic type (though this might be more awkward for consumers): T = TypeVar("T")
class StrictType(Generic[T]):
type_: ClassVar[Type[T]]
def __get_validators__(cls) -> Generator[Callable[[Any], int], None, None]:
# yield int_validator
yield cls.validate
@classmethod
def validate(cls, v: Any) -> int:
if not isinstance(v, cls.type_):
raise TypeError(f"Received {type(v)}; required {cls.type_}")
return v
class StrictInt(StrictType[int]):
type_ = int But a generic approach might be better than a proliferation of StrictX classes. |
Beta Was this translation helpful? Give feedback.
-
@dmontagu I think your idea is brilliant. I prefer creator function approach - anyone can create classes for strict instance checking to their liking. I took your example one step forward. Still mypy complains :( Any mypy gurus here to help? Here is the complete code: from typing import Any, Callable, Generator, Type, TypeVar
from pydantic import BaseModel
T = TypeVar("T")
def strict_type(type_: Type[T]) -> Type[T]:
class StrictType(type_):
@classmethod
def __get_validators__(cls) -> Generator[Callable[[Any], T], None, None]:
yield cls.validate
@classmethod
def validate(cls, v: Any) -> T:
if not isinstance(v, type_):
raise TypeError(f"Expected instance of {type_}, got {type(v)} instead")
return v
return StrictType
StrictInt = strict_type(int)
class MyModel(BaseModel):
foo: StrictInt
print(MyModel(foo=10).json(indent=2)) Any mypy complains about:
|
Beta Was this translation helpful? Give feedback.
-
Yeah, I don’t think mypy lets you do this — it really doesn’t like dynamically generated types (for good reason, I suppose). They can be handled via mypy plugin, but that’s also kind of awkward. That’s why I proposed the generic class approach, which does play nice with mypy, but definitely feels more awkward to use (since you have to declare a class each time). Maybe there’s a version of this that uses a custom root... At any rate, this discussion probably should be moved to a pydantic issue. |
Beta Was this translation helpful? Give feedback.
-
Let's create an issue on pydantic to discuss. I agree a general implementation would be the best solution, we might then create However note the following: Pydantic is not a validation library, it's parsing library. It makes guarantees about the form of data you get out, rather than making a guarantee about the form of the data you put in. That's how pydantic started, it's decision I'm happy with and it is not going to change. If you use pydantic hoping it will do strict validation you will be disappointed. Please see pydantic/pydantic#578. |
Beta Was this translation helpful? Give feedback.
-
Created pydantic/pydantic#780 @samuelcolvin The difference between validation vs parsing library never occurred to me until now. All I tried is to define a union of str, bool, and int that manages to keep the original data type coming from JSON. (I don't want to start validation vs parsing argument, just would like to understand your opinion and approach on this specific matter.) |
Beta Was this translation helpful? Give feedback.
-
@Deterok yeah, that's how standard Python works. And Pydantic is quite Pythonic, so it uses the same behavior, it tries first to make it work before complaining. You can still use Pydantic's strict versions if you need them. But for example, have in mind that if you declare something like a path parameter That automatic conversion is what allows declaring more specific data types for Path, Query, Header, and Cookie parameters, that otherwise would be just strings. |
Beta Was this translation helpful? Give feedback.
-
I've done |
Beta Was this translation helpful? Give feedback.
-
Another option might be dacite, if there's a good way to plug it into FastAPI. |
Beta Was this translation helpful? Give feedback.
-
Integer fields convert bool and float values to integer (1.5, true -> 1, 0) without error raising.
Beta Was this translation helpful? Give feedback.
All reactions