@app.command()asyncdefdeploy(entrypoint:str=typer.Argument(None,help=("The path to a flow entrypoint within a project, in the form of"" `./path/to/file.py:flow_func_name`"),),names:List[str]=typer.Option(None,"--name","-n",help=("The name to give the deployment. Can be a pattern. Examples:"" 'my-deployment', 'my-flow/my-deployment', 'my-deployment-*',"" '*-flow-name/deployment*'"),),description:str=typer.Option(None,"--description","-d",help=("The description to give the deployment. If not provided, the description"" will be populated from the flow's description."),),version:str=typer.Option(None,"--version",help="A version to give the deployment."),tags:List[str]=typer.Option(None,"-t","--tag",help=("One or more optional tags to apply to the deployment. Note: tags are used"" only for organizational purposes. For delegating work to agents, use the"" --work-queue flag."),),work_pool_name:str=SettingsOption(PREFECT_DEFAULT_WORK_POOL_NAME,"-p","--pool",help="The work pool that will handle this deployment's runs.",),work_queue_name:str=typer.Option(None,"-q","--work-queue",help=("The work queue that will handle this deployment's runs. ""It will be created if it doesn't already exist. Defaults to `None`."),),variables:List[str]=typer.Option(None,"-v","--variable",help=("DEPRECATED: Please use --jv/--job-variable for similar functionality "),),job_variables:List[str]=typer.Option(None,"-jv","--job-variable",help=("One or more job variable overrides for the work pool provided in the"" format of key=value string or a JSON object"),),cron:List[str]=typer.Option(None,"--cron",help="A cron string that will be used to set a CronSchedule on the deployment.",),interval:List[int]=typer.Option(None,"--interval",help=("An integer specifying an interval (in seconds) that will be used to set an"" IntervalSchedule on the deployment."),),interval_anchor:Optional[str]=typer.Option(None,"--anchor-date",help="The anchor date for all interval schedules"),rrule:List[str]=typer.Option(None,"--rrule",help="An RRule that will be used to set an RRuleSchedule on the deployment.",),timezone:str=typer.Option(None,"--timezone",help="Deployment schedule timezone string e.g. 'America/New_York'",),trigger:List[str]=typer.Option(None,"--trigger",help=("Specifies a trigger for the deployment. The value can be a"" json string or path to `.yaml`/`.json` file. This flag can be used"" multiple times."),),param:List[str]=typer.Option(None,"--param",help=("An optional parameter override, values are parsed as JSON strings e.g."" --param question=ultimate --param answer=42"),),params:str=typer.Option(None,"--params",help=("An optional parameter override in a JSON string format e.g."' --params=\'{"question": "ultimate", "answer": 42}\''),),enforce_parameter_schema:bool=typer.Option(False,"--enforce-parameter-schema",help=("Whether to enforce the parameter schema on this deployment. If set to"" True, any parameters passed to this deployment must match the signature"" of the flow."),),deploy_all:bool=typer.Option(False,"--all",help=("Deploy all flows in the project. If a flow name or entrypoint is also"" provided, this flag will be ignored."),),prefect_file:Path=typer.Option(Path("prefect.yaml"),"--prefect-file",help="Specify a custom path to a prefect.yaml file",),):""" Deploy a flow from this project by creating a deployment. Should be run from a project root directory. """ifvariablesisnotNone:app.console.print(generate_deprecation_message(name="The `--variable` flag",start_date="Mar 2024",help=("Please use the `--job-variable foo=bar` argument instead: `prefect"" deploy --job-variable`."),),style="yellow",)ifvariablesisNone:variables=list()ifjob_variablesisNone:job_variables=list()job_variables.extend(variables)options={"entrypoint":entrypoint,"description":description,"version":version,"tags":tags,"work_pool_name":work_pool_name,"work_queue_name":work_queue_name,"variables":job_variables,"cron":cron,"interval":interval,"anchor_date":interval_anchor,"rrule":rrule,"timezone":timezone,"triggers":trigger,"param":param,"params":params,"enforce_parameter_schema":enforce_parameter_schema,}try:deploy_configs,actions=_load_deploy_configs_and_actions(prefect_file=prefect_file,)parsed_names=[]fornameinnamesor[]:if"*"inname:parsed_names.extend(_parse_name_from_pattern(deploy_configs,name))else:parsed_names.append(name)deploy_configs=_pick_deploy_configs(deploy_configs,parsed_names,deploy_all,)iflen(deploy_configs)>1:ifany(options.values()):app.console.print(("You have passed options to the deploy command, but you are"" creating or updating multiple deployments. These options"" will be ignored."),style="yellow",)await_run_multi_deploy(deploy_configs=deploy_configs,actions=actions,deploy_all=deploy_all,prefect_file=prefect_file,)else:# Accommodate passing in -n flow-name/deployment-name as well as -n deployment-nameoptions["names"]=[name.split("/",1)[-1]if"/"innameelsenamefornameinparsed_names]await_run_single_deploy(deploy_config=deploy_configs[0]ifdeploy_configselse{},actions=actions,options=options,prefect_file=prefect_file,)exceptValueErrorasexc:exit_with_error(str(exc))
@app.command()asyncdefinit(name:str=None,recipe:str=None,fields:List[str]=typer.Option(None,"-f","--field",help=("One or more fields to pass to the recipe (e.g., image_name) in the format"" of key=value."),),):""" Initialize a new deployment configuration recipe. """inputs={}fields=fieldsor[]recipe_paths=prefect.__module_path__/"deployments"/"recipes"forfieldinfields:key,value=field.split("=")inputs[key]=valueifnotrecipeandis_interactive():recipe_paths=prefect.__module_path__/"deployments"/"recipes"recipes=[]forrinrecipe_paths.iterdir():ifr.is_dir()and(r/"prefect.yaml").exists():withopen(r/"prefect.yaml")asf:recipe_data=yaml.safe_load(f)recipe_name=r.namerecipe_description=recipe_data.get("description","(no description available)")recipe_dict={"name":recipe_name,"description":recipe_description,}recipes.append(recipe_dict)selected_recipe=prompt_select_from_table(app.console,"Would you like to initialize your deployment configuration with a recipe?",columns=[{"header":"Name","key":"name"},{"header":"Description","key":"description"},],data=recipes,opt_out_message="No, I'll use the default deployment configuration.",opt_out_response={},)ifselected_recipe!={}:recipe=selected_recipe["name"]ifrecipeand(recipe_paths/recipe/"prefect.yaml").exists():withopen(recipe_paths/recipe/"prefect.yaml")asf:recipe_inputs=yaml.safe_load(f).get("required_inputs")or{}ifrecipe_inputs:ifset(recipe_inputs.keys())<set(inputs.keys()):# message to user about extra fieldsapp.console.print((f"Warning: extra fields provided for {recipe!r} recipe:"f" '{', '.join(set(inputs.keys())-set(recipe_inputs.keys()))}'"),style="red",)elifset(recipe_inputs.keys())>set(inputs.keys()):table=Table(title=f"[red]Required inputs for {recipe!r} recipe[/red]",)table.add_column("Field Name",style="green",no_wrap=True)table.add_column("Description",justify="left",style="white",no_wrap=False)forfield,descriptioninrecipe_inputs.items():iffieldnotininputs:table.add_row(field,description)app.console.print(table)forkey,descriptioninrecipe_inputs.items():ifkeynotininputs:inputs[key]=typer.prompt(key)app.console.print("-"*15)try:files=[f"[green]{fname}[/green]"forfnameininitialize_project(name=name,recipe=recipe,inputs=inputs)]exceptValueErrorasexc:if"Unknown recipe"instr(exc):exit_with_error(f"Unknown recipe {recipe!r} provided - run [yellow]`prefect init""`[/yellow] to see all available recipes.")else:raisefiles="\n".join(files)empty_msg=(f"Created project in [green]{Path('.').resolve()}[/green]; no new files"" created.")file_msg=(f"Created project in [green]{Path('.').resolve()}[/green] with the following"f" new files:\n{files}")app.console.print(file_msgiffileselseempty_msg)