From 1a93f6b9f5d3793308724e1ba7d4c2dadc1e0810 Mon Sep 17 00:00:00 2001 From: Shizoqua Date: Wed, 31 Dec 2025 00:59:37 +0100 Subject: [PATCH 1/4] feat: pass ODFVs to provider for historical retrieval Signed-off-by: Shizoqua --- sdk/python/tests/foo_provider.py | 3 + ..._feature_store_passes_odfvs_to_provider.py | 62 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py diff --git a/sdk/python/tests/foo_provider.py b/sdk/python/tests/foo_provider.py index a04ff3cc456..28d0a2f62df 100644 --- a/sdk/python/tests/foo_provider.py +++ b/sdk/python/tests/foo_provider.py @@ -22,6 +22,7 @@ from feast.infra.offline_stores.offline_store import RetrievalJob from feast.infra.provider import Provider from feast.infra.registry.base_registry import BaseRegistry +from feast.on_demand_feature_view import OnDemandFeatureView from feast.infra.supported_async_methods import ( ProviderAsyncMethods, SupportedAsyncMethods, @@ -98,12 +99,14 @@ def get_historical_features( self, config: RepoConfig, feature_views: List[FeatureView], + on_demand_feature_views: List[OnDemandFeatureView], feature_refs: List[str], entity_df: Union[pandas.DataFrame, str], registry: BaseRegistry, project: str, full_feature_names: bool = False, ) -> RetrievalJob: + del on_demand_feature_views return RetrievalJob() def online_read( diff --git a/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py b/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py new file mode 100644 index 00000000000..e55729a81d4 --- /dev/null +++ b/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py @@ -0,0 +1,62 @@ +from types import SimpleNamespace + +import pytest + +from feast.feature_store import FeatureStore +from feast.infra.offline_stores.offline_store import RetrievalJob + + +class _CapturingProvider: + def __init__(self): + self.captured_on_demand_feature_views = None + + def get_historical_features( + self, + config, + feature_views, + on_demand_feature_views, + feature_refs, + entity_df, + registry, + project, + full_feature_names, + **kwargs, + ): + self.captured_on_demand_feature_views = on_demand_feature_views + return RetrievalJob() + + +def test_feature_store_passes_on_demand_feature_views_to_provider(monkeypatch): + provider = _CapturingProvider() + + store = FeatureStore.__new__(FeatureStore) + store.config = SimpleNamespace(project="test_project", coerce_tz_aware=False) + store._registry = object() + store._get_provider = lambda: provider + + fv = object() + odfv = object() + + monkeypatch.setattr( + "feast.utils._get_features", + lambda registry, project, features, allow_cache=False: ["odfv:feat"], + ) + monkeypatch.setattr( + "feast.utils._get_feature_views_to_use", + lambda registry, project, features, allow_cache=False, hide_dummy_entity=True: ( + [fv], + [odfv], + ), + ) + monkeypatch.setattr( + "feast.utils._group_feature_refs", + lambda feature_refs, feature_views, on_demand_feature_views: ( + [(fv, [])], + [(odfv, [])], + ), + ) + monkeypatch.setattr("feast.utils._validate_feature_refs", lambda *args, **kwargs: None) + + store.get_historical_features(entity_df="SELECT 1", features=["odfv:feat"]) + + assert provider.captured_on_demand_feature_views == [odfv] From 01a83206ffc17b0136dfdf804f0b919902a145c3 Mon Sep 17 00:00:00 2001 From: Shizoqua Date: Wed, 31 Dec 2025 01:10:58 +0100 Subject: [PATCH 2/4] feat: pass requested ODFVs into provider.get_historical_features Signed-off-by: Shizoqua --- sdk/python/feast/feature_store.py | 1 + sdk/python/feast/infra/passthrough_provider.py | 2 ++ sdk/python/feast/infra/provider.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/sdk/python/feast/feature_store.py b/sdk/python/feast/feature_store.py index fce051f950d..fe5501d7f3b 100644 --- a/sdk/python/feast/feature_store.py +++ b/sdk/python/feast/feature_store.py @@ -1218,6 +1218,7 @@ def get_historical_features( job = provider.get_historical_features( self.config, feature_views, + on_demand_feature_views, _feature_refs, entity_df, self._registry, diff --git a/sdk/python/feast/infra/passthrough_provider.py b/sdk/python/feast/infra/passthrough_provider.py index 2f960a02822..5e0fc413cdd 100644 --- a/sdk/python/feast/infra/passthrough_provider.py +++ b/sdk/python/feast/infra/passthrough_provider.py @@ -459,6 +459,7 @@ def get_historical_features( self, config: RepoConfig, feature_views: List[Union[FeatureView, OnDemandFeatureView]], + on_demand_feature_views: List[OnDemandFeatureView], feature_refs: List[str], entity_df: Optional[Union[pd.DataFrame, str]], registry: BaseRegistry, @@ -466,6 +467,7 @@ def get_historical_features( full_feature_names: bool, **kwargs, ) -> RetrievalJob: + del on_demand_feature_views job = self.offline_store.get_historical_features( config=config, feature_views=feature_views, diff --git a/sdk/python/feast/infra/provider.py b/sdk/python/feast/infra/provider.py index c2879c1e2db..58d44ccaebb 100644 --- a/sdk/python/feast/infra/provider.py +++ b/sdk/python/feast/infra/provider.py @@ -250,6 +250,7 @@ def get_historical_features( self, config: RepoConfig, feature_views: List[Union[FeatureView, OnDemandFeatureView]], + on_demand_feature_views: List[OnDemandFeatureView], feature_refs: List[str], entity_df: Optional[Union[pd.DataFrame, str]], registry: BaseRegistry, @@ -263,6 +264,7 @@ def get_historical_features( Args: config: The config for the current feature store. feature_views: A list containing all feature views that are referenced in the entity rows. + on_demand_feature_views: The on demand feature views requested as part of the retrieval. feature_refs: The features to be retrieved. entity_df: A collection of rows containing all entity columns on which features need to be joined, as well as the timestamp column used for point-in-time joins. Either a pandas dataframe can be From c52cee36cb1a677640cd744eb5b8da961328d51b Mon Sep 17 00:00:00 2001 From: Shizoqua Date: Thu, 1 Jan 2026 14:38:08 +0100 Subject: [PATCH 3/4] chore: fix ruff lint in ODFV provider tests Signed-off-by: Shizoqua --- sdk/python/tests/foo_provider.py | 2 +- .../tests/unit/test_feature_store_passes_odfvs_to_provider.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sdk/python/tests/foo_provider.py b/sdk/python/tests/foo_provider.py index 28d0a2f62df..a528013056e 100644 --- a/sdk/python/tests/foo_provider.py +++ b/sdk/python/tests/foo_provider.py @@ -22,11 +22,11 @@ from feast.infra.offline_stores.offline_store import RetrievalJob from feast.infra.provider import Provider from feast.infra.registry.base_registry import BaseRegistry -from feast.on_demand_feature_view import OnDemandFeatureView from feast.infra.supported_async_methods import ( ProviderAsyncMethods, SupportedAsyncMethods, ) +from feast.on_demand_feature_view import OnDemandFeatureView from feast.online_response import OnlineResponse from feast.protos.feast.types.EntityKey_pb2 import EntityKey as EntityKeyProto from feast.protos.feast.types.Value_pb2 import RepeatedValue diff --git a/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py b/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py index e55729a81d4..6f1999b5bf7 100644 --- a/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py +++ b/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py @@ -1,7 +1,5 @@ from types import SimpleNamespace -import pytest - from feast.feature_store import FeatureStore from feast.infra.offline_stores.offline_store import RetrievalJob From 1501fd46fcd4a12a668c441d947bc9072b7c6f9a Mon Sep 17 00:00:00 2001 From: Shizoqua Date: Mon, 12 Jan 2026 20:21:16 +0100 Subject: [PATCH 4/4] style: format ODFV provider test Signed-off-by: Shizoqua --- .../unit/test_feature_store_passes_odfvs_to_provider.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py b/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py index 6f1999b5bf7..bdcf404c5b3 100644 --- a/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py +++ b/sdk/python/tests/unit/test_feature_store_passes_odfvs_to_provider.py @@ -53,7 +53,10 @@ def test_feature_store_passes_on_demand_feature_views_to_provider(monkeypatch): [(odfv, [])], ), ) - monkeypatch.setattr("feast.utils._validate_feature_refs", lambda *args, **kwargs: None) + monkeypatch.setattr( + "feast.utils._validate_feature_refs", + lambda *args, **kwargs: None, + ) store.get_historical_features(entity_df="SELECT 1", features=["odfv:feat"])