I don’t know if I’m the only one experiencing this...
# prefect-ui
a
I don’t know if I’m the only one experiencing this. I have some flows that accept *args, **kwargs and if I custom run a deployment that uses these flows it keeps saying that these are required. However, if I trigger it via JSON I don’t get that error. Anyway to mark those as Optional by default?
j
Hi! 👋 As with Python functions, if you assign a default, then your arguments should be optional.
a
*args and **kwargs are generally not assigned defaults
m
This looks like a broader UI bug to me. I face this with nested optional Pydantic models too:
Copy code
from typing import Optional

from prefect import flow
from prefect.deployments import Deployment
from pydantic import BaseModel

class MySubModel(BaseModel):
    a: int

class MyModel(BaseModel):
    sub_model: Optional[MySubModel] = None

@flow
def my_flow(my_model: MyModel):
    return

Deployment.build_from_flow(
    flow=my_flow,
    parameters={
        "my_model": MyModel()
    },
    name="test",
).apply()
results in ⬇️ on 2.14.6
thank you 1
1
a
Thanks for confirming the bug that I’m seeing @Michał Augoff. Can you try it via the JSON tab? It should be able to submit it
m
yes, it works via json
j
Thanks for the extra detail. I'm not a pydantic expert but if it helps the following works for me and allows optional inputs:
Copy code
from typing import Optional

from prefect import flow
from pydantic import BaseModel, Field

class PydanticFieldsDefault(BaseModel): 
    str_field_default: Optional[str] = Field(
        title="Title str_field_default", description="Description str_field_default"
    )

@flow(log_prints=True)
def optional(pydantic_fields_default: PydanticFieldsDefault = PydanticFieldsDefault()):
    print(pydantic_fields_default)
    return pydantic_fields_default

if __name__ == "__main__":
    optional.serve(name="print")
And glad to hear that the json input works for you too.
Be aware that they get set to null in case that is unexpected behavior
m
hey Jenny, thanks for the follow up! in my case, the problem is specifically with non-optional parameters inside an optional submodel. Your example only uses a main BaseModel with an optional str property (vs a main BaseModel with an optional BaseModel)
it looks like the UI incorrectly translates those optional fields as required because of how they appear in the original class (but if that class is used as an optional property, they should not be required(
Maybe this example is clearer. Sending a postcard with an optional sender field:
Copy code
from typing import Optional

from prefect import flow
from prefect.deployments import Deployment
from pydantic import BaseModel

class Person(BaseModel):
    first_name: str
    last_name: str

class Postcard(BaseModel):
    sender: Optional[Person]
    recipient: Person
    text: str

@flow(log_prints=True)
def send_postcard(postcard: Postcard):
    print(f"Sending {postcard.text} to {postcard.recipient} (sender: {postcard.sender})")

my_postcard = Postcard(
    recipient=Person(first_name="My", last_name="Friend"),
    text="Greetings from Prefect"
)

send_postcard(my_postcard)

Deployment.build_from_flow(
    flow=send_postcard,
    parameters={"postcard": my_postcard},
    name="test",
).apply()
calling the flow directly with
my_postcard
gives the expected result
Copy code
10:54:41.429 | INFO    | Flow run 'unique-bobcat' - Sending Greetings from Prefect to first_name='My' last_name='Friend' (sender: None)
But when I go to the UI of the deployment, I see, even though
sender
should be optional:
j
Ah ok I get you. As a little context, mapping the schemas here in the UI can get complex so it's hard to cover every pydantic model. I think it's possible that we will revisit the way we map to inputs in the future so if you'd like to open an issue in the prefect repo we can include this in areas we'd consider. In the meantime, we added the json input option as a workaround for more complex models.
m
👍 I’ll open an issue and see maybe I can contribute if this is handled by the client/server and not the UI 🙂
🙌 2
j
Fab! gratitude thank you
m
Actually, this bug prevents me from triggering deployments from the UI. I was able to use
run_deployment
to successfully trigger a run. Continuing with the postcard example above, when I run the flow locally, the optional sender parameter is correctly reported as
null
(screen 1). When I register the same exact flow as a deployment with default parameters matching the local run, the optional parameter gets translated to
{}
(screen 2). Even if I manually overwrite it to
null
inside
Quick run
to match parameters from the local run, it’s still gets passed to the triggered run as
{}
and fails parameter validation (screen 3), so it’s impossible to run this deployment unless I provide the sender parameter as a valid
Person
object which essentially makes that parameter required
🤯 1
j
Would you mind copying this into an issue for us @Michał Augoff? I can reproduce your issue but we'll need to think carefully about the way we resolve it.