PrefectHQ / prefect

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

Order of Blocks' forms is not preserved #8177

Open fchareyr opened 1 year ago

fchareyr commented 1 year ago

First check

Bug summary

The order of fields in the Blocks' is not preserved between the code and the UI. As per pydantic documentation:

As of v1.0 all fields with annotations (whether annotation-only or with a default value) will precede all fields without an annotation. Within their respective groups, fields remain in the order they were defined.

Reproduction

  1. Create a CustomBlock class in custom.py:
    
    from typing import Optional

from prefect.blocks.core import Block from pydantic import Field

class CustomBlock(Block): a: Optional[int] = Field(default=None) b: str = Field(default="abc") c: Optional[str] = Field(default=None)

2. Register using `prefect block register -m mypackage.custom`
3. Modify the code such as we now have:
```python
from typing import Optional

from prefect.blocks.core import Block
from pydantic import Field

class CustomBlock(Block):
    b: str = Field(default="bca") # to ensure block was properly registered again
    c: Optional[str] = Field(default=None)
    a: Optional[int] = Field(default=None)

Error

After the first register, the order of the fields is correct. Capture1

After the second register, despite re-arranging the fields in the code, the initial order is preserved. image

Browsers

Prefect version

Version:             2.7.8
API version:         0.8.4
Python version:      3.10.5
Git commit:          75d2e146
Built:               Thu, Jan 12, 2023 1:41 PM
OS/Arch:             linux/x86_64
Profile:             default
Server type:         hosted

Additional context

No response

zanieb commented 1 year ago

Thanks for the issue; seems fixable. Similar to #8013 and https://github.com/PrefectHQ/prefect/issues/7508

znicholasbrown commented 1 year ago

Hi @fchareyr - thanks for the writeup

To clarify the problem here, these schemas are created by generating a JSON representation of your pydantic models which alone cannot guarantee ordering; JSON is inherently an unordered format and if you're using Postgres it will apply a key-length (!!) sort on your schema on load.

In https://github.com/PrefectHQ/prefect/pull/8013 @j-tr introduced a new position key to the schemas generated by the parameter schema callable which is used by deployments and flows. A similar position key on blocks would enable this same behavior; open to opinions / PRs on this though as there might be some block-specific considerations I'm not aware of

znicholasbrown commented 1 year ago

And to note: there shouldn't be any UI work involved here since schema form fields already respect the position key