Hi, is there any insights on prefect having old fl...
# ask-community
a
Hi, is there any insights on prefect having old flow runs using pydantic V1 data models still retrievable via client with prefect 2.18+ with pydantic v2 in place?
a
Hey Duy! Can you say more here — are you encountering an error?
a
Yes. I’m trying to upgrade data models in my project to pydantic 2.7. After the upgrade, I’m seeing that I’d need to upgrade prefect to at least 2.18 as pydantic 2 is supported there. Then, I tried to run prefect client with 2.18 and pydantic 2.7 to fetch historical data and could not get it due to
Copy code
no validator found for <class 'this.is.my.DataClass'>, see `arbitrary_types_allowed` in Config
Is there a way after the upgrade, we could still fetch historical data without issues?
Copy code
prefect_client = get_client()
flow_run = await prefect_client.read_flow_run(UUID(flow_run_id))
result: DataClass = await flow_run.state.result(fetch=True)
This is how I’m fetching flow run results.
a
Gotcha. This isn’t quite enough for me to reproduce — if you wanted to share more code (like what the
DataClass
model is and how you’re using it to postprocess results (?)) typically I see that
no validator
error when I try to use a v1 basemodel as a type on a v2 basemodel.
upvote 1
a
I think you already point to the issue. So, if we have
DataClass
was defined with v1 yesterday and the flow run result of type
DataClass
was persisted to S3 with prefect server v2.16. Then, today, we upgrade prefect server to v2.18 and having prefect client v2.18 and we pull the flow run data with the script I mentioned above. The error will be thrown with
no validator.
.
So, after the upgrade to prefect (server and client) v2.18 or 2.19, can we still fetch old flow run result with pydantic v1 BaseModel?
a
I believe so - yep!
a
@Alexander Azzam Here’s my traceback
Copy code
Traceback (most recent call last):
  File "src/app/flow/get_flow_run.py", line 61, in get_flow_run
    await flow_run.state.result(fetch=True)  # type: ignore[call-overload]
  File ".venv/lib/python3.10/site-packages/prefect/states.py", line 98, in _get_state_result
    result = await state.data.get()
  File ".venv/lib/python3.10/site-packages/prefect/client/utilities.py", line 100, in with_injected_client
    return await fn(*args, **kwargs)
  File ".venv/lib/python3.10/site-packages/prefect/results.py", line 605, in get
    obj = blob.serializer.loads(blob.data)
  File ".venv/lib/python3.10/site-packages/prefect/serializers.py", line 220, in loads
    return json.loads(blob.decode(), **kwargs)
  File "/.pyenv/versions/3.10.11/lib/python3.10/json/__init__.py", line 359, in loads
    return cls(**kw).decode(s)
  File "/.pyenv/versions/3.10.11/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/.pyenv/versions/3.10.11/lib/python3.10/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
  File ".venv/lib/python3.10/site-packages/prefect/serializers.py", line 84, in prefect_json_object_decoder
    return parse_obj_as(from_qualified_name(result["__class__"]), result["data"])
  File ".venv/lib/python3.10/site-packages/pydantic/v1/tools.py", line 37, in parse_obj_as
    model_type = _get_parsing_type(type_, type_name=type_name)  # type: ignore[arg-type]
  File ".venv/lib/python3.10/site-packages/pydantic/v1/tools.py", line 30, in _get_parsing_type
    return create_model(type_name, __root__=(type_, ...))
  File ".venv/lib/python3.10/site-packages/pydantic/v1/main.py", line 1024, in create_model
    return meta(__model_name, resolved_bases, namespace, **kwds)
  File ".venv/lib/python3.10/site-packages/pydantic/v1/main.py", line 197, in __new__
    fields[ann_name] = ModelField.infer(
  File ".venv/lib/python3.10/site-packages/pydantic/v1/fields.py", line 504, in infer
    return cls(
  File ".venv/lib/python3.10/site-packages/pydantic/v1/fields.py", line 434, in __init__
    self.prepare()
  File ".venv/lib/python3.10/site-packages/pydantic/v1/fields.py", line 555, in prepare
    self.populate_validators()
  File ".venv/lib/python3.10/site-packages/pydantic/v1/fields.py", line 829, in populate_validators
    *(get_validators() if get_validators else list(find_validators(self.type_, self.model_config))),
  File ".venv/lib/python3.10/site-packages/pydantic/v1/validators.py", line 765, in find_validators
    raise RuntimeError(f'no validator found for {type_}, see `arbitrary_types_allowed` in Config')
RuntimeError: no validator found for <class 'app.flow.flow_response_model.FlowResult'>, see `arbitrary_types_allowed` in Config
I’m not sure why it’s using
parse_obj_as
from pydantic v1 to load FlowResult data class which is a v2 BaseModel.
a
Can I see the FlowResult class with its imports?
a
Copy code
class FlowResult(BaseModel):
    """
    Pydantic model for the result of the app flow.

    Args:
        task_1 (Optional[Task1Result]): The result task_1 produced.
        task_2 (Optional[Task2Result]): The result task_2 produced.
    """

    task_1: Optional[Task1Result] = Field(default=None)
    task_2: Optional[Task1Result] = Field(default=None)
Here’s the content of it.
All FlowResult, Task1Result and Task2Result are using V2 BaseModel.
a
Thanks!
a
@Alexander Azzam were you able to reproduce? I think I got the point of failure in
prefect/serializers.py
As
Serializer
there is still using V1 BaseModel and
FlowResult
is using V2 BaseModel. It’s not possible to use
parse_obj_as
of
pydantic.v1
but should use
parse_obj_as
in
pydantic
and everything will works.
So, the line
Copy code
return parse_obj_as(from_qualified_name(result["__class__"]), result["data"])
Should use
parse_obj_as
dynamically based on
from_qualified_name(result["__class__"])
using V1 or V2 BaseModel.
But, I think if it’s having pydantic V2 in the running system, it would be just simply change the imports Before:
Copy code
if HAS_PYDANTIC_V2:
    from pydantic.v1 import (
        BaseModel,
        Field,
        ValidationError,
        parse_obj_as,
        root_validator,
        validator,
    )
After:
Copy code
if HAS_PYDANTIC_V2:
    from pydantic.v1 import (
        BaseModel,
        Field,
        ValidationError,
        root_validator,
        validator,
    )
    from pydantic import parse_obj_as
I’ll open a PR for this 👍
Oh, I could see in latest main branch, it’s not the same as in 2.19.2.
So, it should be working fine.
@Alexander Azzam Is there possibility to install nightly build of prefect in main branch?
@Nate @Alexander Azzam I opened a PR to fix this issue on
2.x
branch. Please check it out when you have time.
@Nate I replied to your comment on my PR here, please take a look when you have time.