From 25d077d1a47ffe4a487183eace9569de5817cf43 Mon Sep 17 00:00:00 2001 From: Linda Oraegbunam Date: Thu, 11 Jun 2026 20:32:28 +0100 Subject: [PATCH] docs: add end-to-end registry deletion lifecycle snippet (#5360) The existing registry deletion docs cover the CLI and individual Python SDK delete methods, but lack a single copy-pasteable example showing the full create -> verify -> delete -> confirm flow. - Add an 'End-to-end example' snippet to registry.md that lists a feature view, deletes it with delete_feature_view(), and lists again to confirm. - Add a unit test for FeatureView deletion via apply(objects_to_delete=..., partial=False) to guard the programmatic deletion path. Signed-off-by: Linda Oraegbunam --- docs/getting-started/components/registry.md | 24 ++++++++ .../test_local_feature_store.py | 60 ++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/components/registry.md b/docs/getting-started/components/registry.md index 9723e6cfe63..34beae25084 100644 --- a/docs/getting-started/components/registry.md +++ b/docs/getting-started/components/registry.md @@ -69,6 +69,30 @@ store._registry.delete_validation_reference("my_validation_reference", project=s When using `feast apply` via the CLI, you can also use the `objects_to_delete` parameter with `partial=False` to delete objects as part of the apply operation. However, this is less common and typically used in automated deployment scenarios. {% endhint %} +### End-to-end example + +The following snippet shows the full lifecycle of deleting a feature view from the registry: + +```python +from feast import FeatureStore + +store = FeatureStore(repo_path=".") + +# 1. Verify the object exists before deletion +print(store.list_batch_feature_views()) # shows my_feature_view + +# 2. Delete the feature view +store.delete_feature_view("my_feature_view") + +# 3. Confirm it's gone +print(store.list_batch_feature_views()) # my_feature_view no longer listed + +# Trying to fetch it now raises FeatureViewNotFoundException +# store.get_feature_view("my_feature_view") +``` + +The same pattern works for other registry objects: list/verify the object, call the corresponding `delete_*` method, then list again to confirm the deletion. + ## Accessing the registry from clients Users can specify the registry through a `feature_store.yaml` config file, or programmatically. We often see teams diff --git a/sdk/python/tests/unit/local_feast_tests/test_local_feature_store.py b/sdk/python/tests/unit/local_feast_tests/test_local_feature_store.py index 9b7660bf692..9b981585594 100644 --- a/sdk/python/tests/unit/local_feast_tests/test_local_feature_store.py +++ b/sdk/python/tests/unit/local_feast_tests/test_local_feature_store.py @@ -11,7 +11,7 @@ from feast.data_format import AvroFormat, ParquetFormat from feast.data_source import KafkaSource from feast.entity import Entity -from feast.errors import ConflictingFeatureViewNames +from feast.errors import ConflictingFeatureViewNames, FeatureViewNotFoundException from feast.feast_object import ALL_RESOURCE_TYPES from feast.feature_store import FeatureStore from feast.feature_view import DUMMY_ENTITY_ID, DUMMY_ENTITY_NAME, FeatureView @@ -441,6 +441,64 @@ def test_apply_permissions(test_feature_store): test_feature_store.teardown() +@pytest.mark.parametrize( + "test_feature_store", + [lazy_fixture("feature_store_with_local_registry")], +) +def test_apply_delete_feature_view(test_feature_store): + """Test that a feature view can be deleted using objects_to_delete with partial=False.""" + assert isinstance(test_feature_store, FeatureStore) + + now = pd.Timestamp.utcnow().round("ms") + dataframe_source = pd.DataFrame( + { + "test_key": [1, 2, 1, 3, 3], + "feature_value": [0.1, 0.2, 0.3, 4.0, 5.0], + "ts_1": [ + now, + now - pd.Timedelta(hours=4), + now - pd.Timedelta(hours=3), + now - pd.Timedelta(hours=2), + now - pd.Timedelta(hours=1), + ], + } + ) + + with prep_file_source(df=dataframe_source, timestamp_field="ts_1") as file_source: + entity = Entity( + name="driver_entity", join_keys=["test_key"], value_type=ValueType.INT64 + ) + driver_fv = FeatureView( + name="driver_fv_to_delete", + entities=[entity], + schema=[Field(name="test_key", dtype=Int64)], + source=file_source, + ) + + # Register entity and feature view + test_feature_store.apply([entity, driver_fv]) + + # Verify feature view exists + fvs = test_feature_store.list_batch_feature_views() + assert len(fvs) == 1 + assert fvs[0].name == driver_fv.name + + # Delete the feature view using objects_to_delete + test_feature_store.apply( + objects=[], objects_to_delete=[driver_fv], partial=False + ) + + # Verify feature view is deleted + fvs = test_feature_store.list_batch_feature_views() + assert len(fvs) == 0 + + # Verify get_feature_view raises FeatureViewNotFoundException + with pytest.raises(FeatureViewNotFoundException): + test_feature_store.get_feature_view(driver_fv.name) + + test_feature_store.teardown() + + @pytest.mark.parametrize( "test_feature_store", [lazy_fixture("feature_store_with_local_registry")],