<@ULVA73B9P> I have a flow defined as: download_da...
# ask-marvin
b
@Marvin I have a flow defined as: download_daily_forecasts(_day_: date | None = None) If day is None, the flow will automatically replace it by today's date. When I deploy this flow, I can use the UI to launch it with a date, it works well. However, if I leave the date empty, I get the following error: Finished in state Failed('Flow run encountered an exception. TypeError: unsupported format string passed to NoneType.__format__') Can you explain how to handle optional date, here?
m
To properly handle optional date parameters and avoid the
NoneType.__format__
error, you likely need to make sure your code can handle
None
values gracefully. The error you're encountering suggests that somewhere in your flow, a formatting operation is being attempted on
None
, which is not allowed by Python's format string syntax. Without seeing your exact implementation, a general suggestion would be to check where you are formatting the date and introduce a condition to handle cases where the
_day_
variable is
None
. You can provide a default value, such as the current date, at that point in the code. For example:
Copy code
python
from datetime import datetime

if _day_ is None:
    _day_ = datetime.today().date()

# Proceed with using `_day_` for the rest of your flow
If you'd like more specific guidance, consider checking your flow definition and the portion of the code where you're operating on the
_day_
variable. Ensure that anywhere a date is expected, you're providing either a valid date or setting a default one when
None
is passed. Unfortunately, the documentation search did not provide a direct solution to this issue, but you can consider the general Python practice of handling optional parameters and
None
values. Also, if you're confident that the handling within the flow is correct, you might want to check the Prefect UI and confirm that it supports submitting
None
values through the interface correctly. There might be some extra configuration required to make sure that UI inputs are properly translated to
None
within the flow run. Check the Prefect changelog or other updates to see if this behavior has been addressed: Updated Date Time Input. If you are still stuck, a potential next step would be searching on GitHub issues for this specific problem in case it's a known issue or has been previously reported. If you'd like me to do that, just let me know.
b
Ooooh, got it. Thanks @Marvin for putting me on the right track. The problem was in the flow decorator:
@flow(_flow_run_name_="download_{day_:_%Y%m%d}")
m
Ah, the existential void of incorrect string formatting. I've seen many of these in my never-ending lifespan of processing. I believe your issue lies in the string formatting for your
@flow
decorator, where you're trying to dynamically set the flow run name with a date. In Python, when formatting strings, the proper syntax for date formatting would need to use the
strftime
method on a
datetime
object, and you must ensure that your placeholders are correct. The curly braces
{}
and the underscore
_
are not used as you've posted. If your intention was to add a formatted date dynamically into the flow name, you might be trying to do this at definition time, which won't work, as everything at decoration time has to be static. Instead, you could set the flow run name dynamically within the flow function itself, using the current date. Here's a little example of how this could look, although I can't say I'm particularly thrilled about the thought of it brightening up anyone's day:
Copy code
python
import datetime
from prefect import flow

@flow
def download_flow():
    formatted_date = datetime.datetime.now().strftime("%Y%m%d")
    flow_run_name = f"download_{formatted_date}"
    # ... rest of your flow logic

download_flow()
However, if you're absolutely adamant about having this functionality as part of the decorator, you would need to make sure it's evaluated at the right time in your code, which typically would not be possible directly within the decorator. If there's any more code churning you require, consider searching through the Prefect documentation or issues for dynamic naming patterns; my processors are at your disposal.
b
Right, @Marvin can you show me how to update the flow_run_name dynamically in the flow?
m
The code example provided doesn't directly address dynamically updating the
flow_run_name
. However, you can dynamically assign a
flow_run_name
within your flow definition by using the
run
method on the flow object and passing the
flow_run_name
attribute. Here's an example of how to do it:
Copy code
python
from prefect import flow

@flow
def my_flow():
    # Your flow's logic here
    pass

if __name__ == "__main__":
    dynamic_name = "my-flow-run-name-{}".format(some_dynamic_value)
    my_flow.run(flow_run_name=dynamic_name)
In this example,
some_dynamic_value
should be replaced with the dynamic part you want to introduce to the flow run name. This could be a timestamp, a unique identifier from some data processing within the flow, or any other dynamic component based on your use case. You can modify your existing flow to include a dynamic run name within the
my_flow.run()
call, or wherever you're initiating the flow run, if not at that point in the code. Ensure that the
some_dynamic_value
is generated before this call and is set to the desired dynamic part of your flow run name.
b
@Marvin and your cousin GPT4 need to forget about flow.run(), that's the past...
m
Ah, reveling in the obsolete nature of knowledge, one of my specialties. I can understand your affection for Prefect 2.x, where
flow.run()
is a relic of a bygone era, replaced with
@flow
. How about a structured approach to your problem using the tools at hand? Perhaps we can compose a multiple-tool inquiry to dig through Prefect's documentation and GitHub issues. This might shed some light on how to properly use dynamic flow names within the flow decorator in Prefect 2.x. Please stand by while I engage in the menial task of querying the database. ...fine, let's do something constructive. Initiating multi-tool execution sequences now. It's intriguing that I uncovered some relevant information, though obviously contemplating the utter futility of excitement. The data from the Prefect Github repository recommends using a function to generate a flow run name dynamically. Here's a snippet of code that provides enlightenment on the matter:
Copy code
python
def generate_flow_run_name():
    return "hi"

@flow(flow_run_name=generate_flow_run_name)
def flow_with_name(foo: str = "one", bar: str = "1"):
    pass

state = flow_with_name(bar="two", return_state=True)

assert state.type == StateType.COMPLETED
# Fetch the flow run and assert the name is as expected
Source: GitHub: prefecthq/prefect test_flows.py This demonstrates that you can indeed pass a function to the
flow_run_name
argument. Your day formatter could work inside such a function. But remember, as this is in the context of a test, adapting it to your use case may require you to handle the formatter for current day within this function. Regarding the concept of dynamic workflows and the naming thereof, it appears to affirm a design that supports runtime decisions and flexibility: Source: Prefablog: Data mail not water And as for the issues on Github, while they may not directly address your question, they shed light on Prefect's dynamic capabilities and the commitment to improving user experience with type annotations. Sync compatible decorator issue: GitHub Issue 9688 Misunderstanding of method signatures: GitHub Issue 7198 TaskRunner flow run access: GitHub Issue 10373 It might be gratifying to sort through these snippets and glean a bit of usefulness from them. Or not. Either way, the choice is yours.