From 686a55c314719c34411305a69816579a6a83dc44 Mon Sep 17 00:00:00 2001 From: Venkateswarlu Boggavarapu Date: Wed, 22 Apr 2026 13:23:58 -0400 Subject: [PATCH 1/2] feat(cli): add 'feast projects delete' command (issue #5095) Exposes project deletion via the CLI. The new `feast projects delete ` command calls `store._registry.delete_project()` which is already implemented in all concrete registries. Adds an interactive confirmation prompt that can be bypassed with --yes/-y for scripted workflows. - Adds type guard (`assert store._registry is not None`) for mypy. - Catches both FeastObjectNotFoundException and ProjectNotFoundException so the CLI exits cleanly (exit code 1) for either variant raised by concrete registry implementations. Squashed history: this commit consolidates the previous unsigned commits on the branch into a single DCO-signed commit, per DCO requirements. Signed-off-by: Venkateswarlu Boggavarapu --- sdk/python/feast/cli/projects.py | 51 +++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/sdk/python/feast/cli/projects.py b/sdk/python/feast/cli/projects.py index ea8d5b573a6..02ddbc020db 100644 --- a/sdk/python/feast/cli/projects.py +++ b/sdk/python/feast/cli/projects.py @@ -3,16 +3,15 @@ from feast import utils from feast.cli.cli_options import tagsOption -from feast.errors import FeastObjectNotFoundException +from feast.errors import FeastObjectNotFoundException, ProjectNotFoundException from feast.repo_operations import create_feature_store @click.group(name="projects") def projects_cmd(): """ - Access projects + Access and manage projects """ - pass @projects_cmd.command("describe") @@ -27,8 +26,8 @@ def project_describe(ctx: click.Context, name: str): try: project = store.get_project(name) except FeastObjectNotFoundException as e: - print(e) - exit(1) + print(str(e)) + raise SystemExit(1) print( yaml.dump( @@ -58,7 +57,7 @@ def project_current(ctx: click.Context): ) -@projects_cmd.command(name="list") +@projects_cmd.command("list") @tagsOption @click.pass_context def project_list(ctx: click.Context, tags: list[str]): @@ -75,6 +74,44 @@ def project_list(ctx: click.Context, tags: list[str]): print( tabulate( - table, headers=["NAME", "DESCRIPTION", "TAGS", "OWNER"], tablefmt="plain" + table, + headers=["NAME", "DESCRIPTION", "TAGS", "OWNER"], + tablefmt="plain", ) ) + + +@projects_cmd.command("delete") +@click.argument("name", type=click.STRING) +@click.option( + "--yes", + "-y", + is_flag=True, + help="Skip confirmation prompt and delete immediately.", +) +@click.pass_context +def project_delete(ctx: click.Context, name: str, yes: bool): + """ + Delete a project and all its resources from the registry. + + This removes the project entry from the registry. Individual objects + (feature views, entities, data sources) that belong to the project + are also purged when commit=True (the default). + """ + store = create_feature_store(ctx) + + if not yes: + click.confirm( + f"Are you sure you want to delete project '{name}'? " + "This will remove all associated resources from the registry.", + abort=True, + ) + + try: + assert store._registry is not None + store._registry.delete_project(name, commit=True) + except (FeastObjectNotFoundException, ProjectNotFoundException) as e: + print(str(e)) + raise SystemExit(1) + + print(f"Project '{name}' deleted successfully.") From a8315f4ceccdc12e35d147909c010001e4285c95 Mon Sep 17 00:00:00 2001 From: mailtoboggavarapu-coder Date: Wed, 22 Apr 2026 13:53:42 -0400 Subject: [PATCH 2/2] fix: use store.registry property instead of store._registry in project_delete store._registry is always None until accessed via the lazy-init registry property. Using store._registry directly caused project_delete to always crash with an AssertionError. Fixes: Devin Review finding in feast-dev/feast#6302 Signed-off-by: Venkateswarlu Boggavarapu --- sdk/python/feast/cli/projects.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk/python/feast/cli/projects.py b/sdk/python/feast/cli/projects.py index 02ddbc020db..a4ae3216cb8 100644 --- a/sdk/python/feast/cli/projects.py +++ b/sdk/python/feast/cli/projects.py @@ -108,8 +108,7 @@ def project_delete(ctx: click.Context, name: str, yes: bool): ) try: - assert store._registry is not None - store._registry.delete_project(name, commit=True) + store.registry.delete_project(name, commit=True) except (FeastObjectNotFoundException, ProjectNotFoundException) as e: print(str(e)) raise SystemExit(1)