Skip to content

Commit 883dc2d

Browse files
test: cover ODFV source isolation for an aliased source
Add a regression test that sources a pandas ODFV from an aliased feature view (with_name) and asserts the declared feature still reaches the UDF while an unrelated feature view stays hidden. The isolation filter keys columns by projection.name, which is what the retrieval path emits regardless of the alias; the test fails if that is switched to name_to_use(). Signed-off-by: Vedant Agarwal <[email protected]>
1 parent 7b368eb commit 883dc2d

1 file changed

Lines changed: 47 additions & 0 deletions

File tree

sdk/python/tests/unit/test_on_demand_pandas_transformation.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,50 @@ def odfv_b(inputs: pd.DataFrame) -> pd.DataFrame:
550550
# odfv_a shouldn't see fv2's column; odfv_b still uses it fine
551551
assert response["a_saw_fv2"] == [False]
552552
assert response["b_out"] is not None
553+
554+
555+
def test_odfv_udf_receives_aliased_declared_source_columns():
556+
"""A declared source referenced under an alias (``with_name``) must still reach
557+
the UDF. The isolation filter keys columns by ``projection.name``, which is what
558+
the retrieval path emits regardless of the alias, so the aliased source's feature
559+
is retained (not dropped) while an unrelated feature view stays hidden (#6158)."""
560+
with tempfile.TemporaryDirectory() as data_dir:
561+
store, driver, src, fv1, fv2, driver_df = _two_fv_store(data_dir)
562+
563+
# ODFV declares fv1 *under an alias*; fv2 is requested but undeclared.
564+
aliased_source = fv1.with_name("aliased_fv1")
565+
assert aliased_source.projection.name == "fv1"
566+
assert aliased_source.projection.name_to_use() == "aliased_fv1"
567+
568+
@on_demand_feature_view(
569+
sources=[aliased_source],
570+
schema=[
571+
Field(name="saw_declared", dtype=Bool),
572+
Field(name="saw_undeclared", dtype=Bool),
573+
],
574+
mode="pandas",
575+
)
576+
def aliased_guard(inputs: pd.DataFrame) -> pd.DataFrame:
577+
out = pd.DataFrame()
578+
n = range(len(inputs))
579+
out["saw_declared"] = ["conv_rate" in inputs.columns for _ in n]
580+
out["saw_undeclared"] = ["avg_daily_trips" in inputs.columns for _ in n]
581+
return out
582+
583+
store.apply([driver, src, fv1, fv2, aliased_guard])
584+
store.write_to_online_store(feature_view_name="fv1", df=driver_df)
585+
store.write_to_online_store(feature_view_name="fv2", df=driver_df)
586+
587+
response = store.get_online_features(
588+
entity_rows=[{"driver_id": 1001}],
589+
features=[
590+
"fv1:conv_rate",
591+
"fv2:avg_daily_trips",
592+
"aliased_guard:saw_declared",
593+
"aliased_guard:saw_undeclared",
594+
],
595+
).to_dict()
596+
597+
# the aliased-but-declared source must survive; the unrelated FV stays hidden
598+
assert response["saw_declared"] == [True]
599+
assert response["saw_undeclared"] == [False]

0 commit comments

Comments
 (0)