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"])