PrefectHQ / prefect

Prefect is a workflow orchestration framework for building resilient data pipelines in Python.
https://prefect.io
Apache License 2.0
17.41k stars 1.64k forks source link

Prefect 3 upgrade - read_flow_runs crushes KeyError: "No class found for dispatch key 'unpersisted' in registry for type 'BaseResult'." #15585

Open ori-scala opened 1 month ago

ori-scala commented 1 month ago

Bug summary

We're in the midst of upgrading our code to Prefect v3.0.4 The following code snippet

from prefect.client.orchestration import get_client
client = get_client()
res = await client.read_flow_runs(limit=1)

It works well on Prefect v2.20.4, now crushes and spits out the following error:

Traceback (most recent call last):
  File "/opt/homebrew/anaconda3/envs/env/lib/python3.12/site-packages/prefect/results.py", line 1156, in __new__
    subcls = lookup_type(cls, dispatch_key=kwargs["type"])
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/anaconda3/envs/env/lib/python3.12/site-packages/prefect/utilities/dispatch.py", line 199, in lookup_type
    raise KeyError(
KeyError: "No class found for dispatch key 'unpersisted' in registry for type 'BaseResult'."
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/opt/homebrew/anaconda3/envs/env/lib/python3.12/site-packages/IPython/core/interactiveshell.py", line 3575, in run_code
    await eval(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-10-61b2f1ad092c>", line 1, in <module>
    res = await client.read_flow_runs(limit=1)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/anaconda3/envs/env/lib/python3.12/site-packages/prefect/client/orchestration.py", line 2120, in read_flow_runs
  File "/opt/homebrew/anaconda3/envs/lenv/lib/python3.12/site-packages/pydantic/type_adapter.py", line 135, in wrapped
    return func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/anaconda3/envs/env/lib/python3.12/site-packages/pydantic/type_adapter.py", line 366, in validate_python
    return self.validator.validate_python(object, strict=strict, from_attributes=from_attributes, context=context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/anaconda3/envs/env/lib/python3.12/site-packages/prefect/results.py", line 1158, in __new__
    raise ValidationError(errors=[exc], model=cls)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: No constructor defined

When running the following, it works perfectly:

res = await client.read_flow_runs(limit=1, flow_run_filter=FlowRunFilter(),  sort=FlowRunSort.START_TIME_DESC)

Please advise

Version info (prefect version output)

Version:             3.0.4
API version:         0.8.4
Python version:      3.12.3
Git commit:          c068d7e2
Built:               Tue, Oct 1, 2024 11:54 AM
OS/Arch:             darwin/x86_64
Profile:             default
Server type:         cloud
Pydantic version:    2.9.2

Additional context

No response

zzstoatzz commented 1 month ago

hi @ori-scala - thanks for the issue!

I cannot reproduce just using that snippet, I think the error likely corresponds to something else going on elsewhere in your code. Are you using the UnpersistedResult class anywhere directly?

I don't think this is related to the root of the problem, but we also appear to be misusing the ValidationError here, which is why we get TypeError: No constructor defined - PR incoming for that

ori-scala commented 1 month ago

@zzstoatzz I'm not using UnpersistedResult anywhere in our code base... It does feel a bit inconsistent so I'd be happy to try again after you release a fix for the other issue. Also, i can send the json response that fails to translate into the list[FlowRun] object