84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198 | @app.command()
+async def init(
+ 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 = fields or []
+ recipe_paths = prefect.__module_path__ / "deployments" / "recipes"
+
+ for field in fields:
+ key, value = field.split("=")
+ inputs[key] = value
+
+ if not recipe and is_interactive():
+ recipe_paths = prefect.__module_path__ / "deployments" / "recipes"
+ recipes = []
+
+ for r in recipe_paths.iterdir():
+ if r.is_dir() and (r / "prefect.yaml").exists():
+ with open(r / "prefect.yaml") as f:
+ recipe_data = yaml.safe_load(f)
+ recipe_name = r.name
+ recipe_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={},
+ )
+ if selected_recipe != {}:
+ recipe = selected_recipe["name"]
+
+ if recipe and (recipe_paths / recipe / "prefect.yaml").exists():
+ with open(recipe_paths / recipe / "prefect.yaml") as f:
+ recipe_inputs = yaml.safe_load(f).get("required_inputs") or {}
+
+ if recipe_inputs:
+ if set(recipe_inputs.keys()) < set(inputs.keys()):
+ # message to user about extra fields
+ app.console.print(
+ (
+ f"Warning: extra fields provided for {recipe!r} recipe:"
+ f" '{', '.join(set(inputs.keys()) - set(recipe_inputs.keys()))}'"
+ ),
+ style="red",
+ )
+ elif set(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
+ )
+ for field, description in recipe_inputs.items():
+ if field not in inputs:
+ table.add_row(field, description)
+
+ app.console.print(table)
+
+ for key, description in recipe_inputs.items():
+ if key not in inputs:
+ inputs[key] = typer.prompt(key)
+
+ app.console.print("-" * 15)
+
+ try:
+ files = [
+ f"[green]{fname}[/green]"
+ for fname in initialize_project(name=name, recipe=recipe, inputs=inputs)
+ ]
+ except ValueError as exc:
+ if "Unknown recipe" in str(exc):
+ exit_with_error(
+ f"Unknown recipe {recipe!r} provided - run [yellow]`prefect init"
+ "`[/yellow] to see all available recipes."
+ )
+ else:
+ raise
+
+ files = "\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_msg if files else empty_msg)
+
|