pydantic / pydantic-core

Core validation logic for pydantic written in rust
MIT License
1.4k stars 232 forks source link

Numerically constrainted fields don't generate proper error on non-Number fields #1338

Open AnthonyVH opened 3 months ago

AnthonyVH commented 3 months ago

It's possible to create for example a GreaterThan constraint on a field which is not number, but still has the required comparison operators. This works fine, except that when the constraint is violated, a TypeError exception is thrown during the generation of the PydanticKnownError.

The cause of this is the call to field_from_context when the constraint isn't met. This requires the object to compare against to be a Number (well, for GreaterThan it does). When that isn't the case, it triggers line 56 in src/errors/types.rs, causing the TypeError.

I'm running into this for a model I've made that validates astropy.units.Quantity fields. In this case, the object to constrain against could be for example 5 * astropy.units.meter.

It's not clear to me why pydantic-core requires this object to be a Number. It seems that it having the required comparison operator (to do the check) and being able to be converted into a string (to generate an exception message) should be enough. Both are the case for a astropy.units.Quantity object.

Edit: I can't trigger this when the annotated field is a string (Annonated[str, Field(gt="b")]) so maybe I'm misunderstanding the exact reason the TypeError is raised.

davidhewitt commented 2 months ago

You're absolutely correct in identifying Number as the root cause and IMO that's an unnecessary constraint (especially as this is an error message). Probably the whole Number enum can be removed and we should just use PyObject there to allow any Python object. A PR to relax this would be welcome 👍

AnthonyVH commented 1 month ago

I've had a look at the code, but I'm afraid my Rust is not up to snuff to put together a proper PR :sweat_smile:.