Fail-fast feature
Basic implementation here - #1321
Context: https://github.com/pydantic/pydantic-core/pull/1322#issuecomment-2166806100 https://github.com/pydantic/pydantic/pull/9708#issuecomment-2187337782
fail-fast feature might be extended and used not only for sequence types. It might be useful for other types like mappings or models.
I can see that it can be powerful feature when you can from python validator stop validation process by raising an exception. As was mentioned by @adriangb here - https://github.com/pydantic/pydantic-core/pull/1322#issuecomment-2166806100
I would like to work on both features if you don't mind.
Please let me know if you have some tips and ideas about implementation!
cc @sydney-runkle @adriangb
@uriyyo,
That sounds wonderful. Thanks for your amazing work here.
I like the idea of:
- A runtime flag
fail_fastthat is passed tomodel_validate - A
FailNowdata structure that can be used in custom validators - Generally, support for failing early / fast for lots of data types.
Let's confirm with @davidhewitt and @adriangb before moving forwards :).
Seems fine to me. I'm less sure about the FailNow structure; it might be better to instead pass fail_fast in the info and then let custom validators decide when to fail fast that way.
I would love to be able to use FailFast() on Literals. Currently I am having some performance troubles with a large number of different objects that can be passed to a list or Sequence. I am using a field called "name" to differentiate the different models. Do you think that FailFast() could help speed things up in this case or is it really an architectural issue?
Hmm, I don't think Fail-fast makes sense for literals. Could you give an example of your use case here? Guessing that discriminated unions might help here. Thanks!
I have a list like this:
[
{
"name": "Name1",
"arg1": 1.0
},
{
"name": "Name2",
"arg2": 3.0
}
]
The accompanying models are:
from typing import Literal
from pydantic.dataclasses import dataclass
class BaseClass:
name: str
@dataclass
class Name1(BaseClass):
name: Literal[”Name1”]
arg1: float
def do_something(self):
return 10 * self.arg1
@dataclass
class Name2(Base class):
name: Literal["Name2"]
arg2: float
def do_something(self):
return 10 * self.arg2
@dataclass
class Objects:
objects: list[Name1 | Name2]
# somewhere else in the code
def do_something_else(objects: Objects):
for item in objects.objects:
item.do_something()
pydantic will try to fit the items in the list for each Namex model. Effectively creating a running time of O(nm) with n the length of the list and m the number Namex models. I was hoping that checking for .name first might speed things up.
You can use a tagged union for this case :)
https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions
Thank you I believe this will work very well. Of course, I do have objects that are not parsed the same as my previous example (how can I forget?). They require 2 properties instead of 1, lets call them name1 and name2. name1 is not uniquely identifying the objects and neither is name2 but together they are. I searched the documentation for this case but I cant figure out what to do. I guess discriminated unions are not the way to go in that case?
Any updates on this, checking to see if this might be added to pydantic v2 in the near future? (or possibly for consideration into v3), especially looking for
- A runtime flag fail_fast that is passed to model_validate (and)
- Generally, support for failing early / fast for lots of data types.
Thanks