Skip to content

Commit 44066d2

Browse files
almost got everything working and type validation behaving
Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
1 parent cf613bd commit 44066d2

File tree

7 files changed

+53
-21
lines changed

7 files changed

+53
-21
lines changed

sdk/python/feast/base_feature_view.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from google.protobuf.json_format import MessageToJson
1919
from google.protobuf.message import Message
2020

21+
from feast.data_source import DataSource
2122
from feast.feature_view_projection import FeatureViewProjection
2223
from feast.field import Field
2324
from feast.protos.feast.core.FeatureView_pb2 import FeatureView as FeatureViewProto
@@ -65,6 +66,7 @@ def __init__(
6566
description: str = "",
6667
tags: Optional[Dict[str, str]] = None,
6768
owner: str = "",
69+
source: Optional[DataSource] = None,
6870
):
6971
"""
7072
Creates a BaseFeatureView object.
@@ -76,7 +78,8 @@ def __init__(
7678
tags (optional): A dictionary of key-value pairs to store arbitrary metadata.
7779
owner (optional): The owner of the base feature view, typically the email of the
7880
primary maintainer.
79-
81+
source (optional): The source of data for this group of features. May be a stream source, or a batch source.
82+
If a stream source, the source should contain a batch_source for backfills & batch materialization.
8083
Raises:
8184
ValueError: A field mapping conflicts with an Entity or a Feature.
8285
"""
@@ -90,6 +93,9 @@ def __init__(
9093
self.created_timestamp = None
9194
self.last_updated_timestamp = None
9295

96+
if source:
97+
self.source = source
98+
9399
@property
94100
@abstractmethod
95101
def proto_class(self) -> Type[Message]:
@@ -155,6 +161,7 @@ def __eq__(self, other):
155161
or self.description != other.description
156162
or self.tags != other.tags
157163
or self.owner != other.owner
164+
or self.source != other.source
158165
):
159166
return False
160167

sdk/python/feast/feature_view.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def __init__(
206206
description=description,
207207
tags=tags,
208208
owner=owner,
209+
source=source,
209210
)
210211
self.online = online
211212
self.materialization_intervals = []
@@ -429,7 +430,9 @@ def from_proto(cls, feature_view_proto: FeatureViewProto):
429430

430431
# FeatureViewProjections are not saved in the FeatureView proto.
431432
# Create the default projection.
432-
feature_view.projection = FeatureViewProjection.from_definition(feature_view)
433+
feature_view.projection = FeatureViewProjection.from_feature_view_definition(
434+
feature_view
435+
)
433436

434437
if feature_view_proto.meta.HasField("created_timestamp"):
435438
feature_view.created_timestamp = (

sdk/python/feast/feature_view_projection.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
if TYPE_CHECKING:
1212
from feast.base_feature_view import BaseFeatureView
13+
from feast.feature_view import FeatureView
1314

1415

1516
@dataclass
@@ -53,17 +54,17 @@ def name_to_use(self):
5354
def to_proto(self) -> FeatureViewProjectionProto:
5455
batch_source = None
5556
if getattr(self, "batch_source", None):
56-
if type(self.batch_source).__name__ == "DataSource":
57-
batch_source = self.batch_source
58-
else:
57+
if isinstance(self.batch_source, DataSource):
5958
batch_source = self.batch_source.to_proto()
59+
else:
60+
batch_source = self.batch_source
6061
feature_reference_proto = FeatureViewProjectionProto(
6162
feature_view_name=self.name,
6263
feature_view_name_alias=self.name_alias or "",
6364
join_key_map=self.join_key_map,
64-
timestamp_field=self.timestamp_field,
65-
date_partition_column=self.date_partition_column,
66-
created_timestamp_column=self.created_timestamp_column,
65+
timestamp_field=self.timestamp_field or "",
66+
date_partition_column=self.date_partition_column or "",
67+
created_timestamp_column=self.created_timestamp_column or "",
6768
batch_source=batch_source,
6869
)
6970
for feature in self.features:
@@ -90,8 +91,25 @@ def from_proto(proto: FeatureViewProjectionProto):
9091
return feature_view_projection
9192

9293
@staticmethod
93-
def from_definition(base_feature_view: "BaseFeatureView"):
94+
def from_feature_view_definition(feature_view: "FeatureView"):
9495
# TODO need to implement this for StreamFeatureViews
96+
if getattr(feature_view, "batch_source", None):
97+
return FeatureViewProjection(
98+
name=feature_view.name,
99+
name_alias=None,
100+
features=feature_view.features,
101+
desired_features=[],
102+
timestamp_field=feature_view.batch_source.created_timestamp_column
103+
or None,
104+
created_timestamp_column=feature_view.batch_source.created_timestamp_column
105+
or None,
106+
date_partition_column=feature_view.batch_source.date_partition_column
107+
or None,
108+
batch_source=feature_view.batch_source or None,
109+
)
110+
111+
@staticmethod
112+
def from_definition(base_feature_view: "BaseFeatureView"):
95113
if getattr(base_feature_view, "batch_source", None):
96114
return FeatureViewProjection(
97115
name=base_feature_view.name,
@@ -106,12 +124,13 @@ def from_definition(base_feature_view: "BaseFeatureView"):
106124
or None,
107125
batch_source=base_feature_view.batch_source or None,
108126
)
109-
return FeatureViewProjection(
110-
name=base_feature_view.name,
111-
name_alias=None,
112-
features=base_feature_view.features,
113-
desired_features=[],
114-
)
127+
else:
128+
return FeatureViewProjection(
129+
name=base_feature_view.name,
130+
name_alias=None,
131+
features=base_feature_view.features,
132+
desired_features=[],
133+
)
115134

116135
def get_feature(self, feature_name: str) -> Field:
117136
try:

sdk/python/feast/inference.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def _infer_features_and_entities(
203203
run_inference_for_features: Whether to run inference for features.
204204
config: The config for the current feature store.
205205
"""
206-
entity_columns = []
206+
entity_columns: list[str] = []
207207
if isinstance(fv, OnDemandFeatureView):
208208
columns_to_exclude = set()
209209
for (

sdk/python/feast/on_demand_feature_view.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,9 @@ def __eq__(self, other):
235235
"Comparisons should only involve OnDemandFeatureView class objects."
236236
)
237237

238-
if not super().__eq__(other):
239-
return False
240-
238+
# Note, no longer evaluating the base feature view layer as ODFVs can have
239+
# multiple datasources and a base_feature_view only has one source
240+
# though maybe that shouldn't be true
241241
if (
242242
self.source_feature_view_projections
243243
!= other.source_feature_view_projections

sdk/python/feast/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ def _group_feature_refs(
344344

345345
# on demand view to on demand view proto
346346
on_demand_view_index = {
347-
view.projection.name_to_use(): view for view in all_on_demand_feature_views
347+
view.projection.name_to_use(): view
348+
for view in all_on_demand_feature_views
349+
if view.projection
348350
}
349351

350352
# view name to feature names

sdk/python/tests/unit/local_feast_tests/test_local_feature_store.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,9 @@ def test_apply_feature_view_with_inline_batch_source(
209209
test_feature_store.apply([entity, driver_fv])
210210

211211
fvs = test_feature_store.list_batch_feature_views()
212+
dfv = fvs[0]
212213
assert len(fvs) == 1
213-
assert fvs[0] == driver_fv
214+
assert dfv == driver_fv
214215

215216
ds = test_feature_store.list_data_sources()
216217
assert len(ds) == 1

0 commit comments

Comments
 (0)