From a8480033ea7c71d6d7cc217738e0755318939455 Mon Sep 17 00:00:00 2001 From: Meenakshi Sistla <85261163+msistla96@users.noreply.github.com> Date: Wed, 28 Feb 2024 10:59:52 -0500 Subject: [PATCH] fix: Add changes to Feature View Pydantic model to support timestamps (#86) * Add changes to Pydantic model to support timestamps * Fix lint error * Fix lint errors --- .../pydantic_models/feature_view_model.py | 15 ++++++++++- sdk/python/tests/unit/test_pydantic_models.py | 25 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/sdk/python/feast/expediagroup/pydantic_models/feature_view_model.py b/sdk/python/feast/expediagroup/pydantic_models/feature_view_model.py index 12ae036075..88ce9add2e 100644 --- a/sdk/python/feast/expediagroup/pydantic_models/feature_view_model.py +++ b/sdk/python/feast/expediagroup/pydantic_models/feature_view_model.py @@ -70,6 +70,8 @@ class FeatureViewModel(BaseFeatureViewModel): tags: Optional[Dict[str, str]] owner: str materialization_intervals: List[Tuple[datetime, datetime]] = [] + created_timestamp: Optional[datetime] + last_updated_timestamp: Optional[datetime] def to_feature_view(self) -> FeatureView: """ @@ -107,6 +109,8 @@ def to_feature_view(self) -> FeatureView: owner=self.owner, ) feature_view.materialization_intervals = self.materialization_intervals + feature_view.created_timestamp = self.created_timestamp + feature_view.last_updated_timestamp = self.last_updated_timestamp return feature_view @@ -160,6 +164,8 @@ def from_feature_view( tags=feature_view.tags if feature_view.tags else None, owner=feature_view.owner, materialization_intervals=feature_view.materialization_intervals, + created_timestamp=feature_view.created_timestamp, + last_updated_timestamp=feature_view.last_updated_timestamp, ) @@ -214,6 +220,8 @@ class OnDemandFeatureViewModel(BaseFeatureViewModel): description: str tags: Dict[str, str] owner: str + created_timestamp: Optional[datetime] = None + last_updated_timestamp: Optional[datetime] = None def to_feature_view(self) -> OnDemandFeatureView: source_request_sources = dict() @@ -231,7 +239,7 @@ def to_feature_view(self) -> OnDemandFeatureView: key ] = feature_view_projection.to_feature_view_projection() - return OnDemandFeatureView( + odfv = OnDemandFeatureView( name=self.name, schema=[sch.to_field() for sch in self.features], sources=list(source_feature_view_projections.values()) @@ -242,6 +250,9 @@ def to_feature_view(self) -> OnDemandFeatureView: tags=self.tags, owner=self.owner, ) + odfv.created_timestamp = self.created_timestamp + odfv.last_updated_timestamp = self.last_updated_timestamp + return odfv @classmethod def from_feature_view( @@ -283,4 +294,6 @@ def from_feature_view( description=on_demand_feature_view.description, tags=on_demand_feature_view.tags, owner=on_demand_feature_view.owner, + created_timestamp=on_demand_feature_view.created_timestamp, + last_updated_timestamp=on_demand_feature_view.last_updated_timestamp, ) diff --git a/sdk/python/tests/unit/test_pydantic_models.py b/sdk/python/tests/unit/test_pydantic_models.py index 1ab11df385..f5018e86bb 100644 --- a/sdk/python/tests/unit/test_pydantic_models.py +++ b/sdk/python/tests/unit/test_pydantic_models.py @@ -314,6 +314,15 @@ def test_idempotent_featureview_conversion(): feature_view_model = FeatureViewModel.from_feature_view(feature_view) feature_view_b = feature_view_model.to_feature_view() assert feature_view == feature_view_b + assert feature_view_model.created_timestamp == feature_view.created_timestamp + assert ( + feature_view_model.last_updated_timestamp == feature_view.last_updated_timestamp + ) + assert feature_view_b.created_timestamp == feature_view_model.created_timestamp + assert ( + feature_view_b.last_updated_timestamp + == feature_view_model.last_updated_timestamp + ) spark_source = SparkSource( name="sparky_sparky_boom_man", @@ -386,6 +395,15 @@ def test_idempotent_featureview_with_streaming_source_conversion(): feature_view_model = FeatureViewModel.from_feature_view(feature_view) feature_view_b = feature_view_model.to_feature_view() assert feature_view == feature_view_b + assert feature_view_model.created_timestamp == feature_view.created_timestamp + assert ( + feature_view_model.last_updated_timestamp == feature_view.last_updated_timestamp + ) + assert feature_view_b.created_timestamp == feature_view_model.created_timestamp + assert ( + feature_view_b.last_updated_timestamp + == feature_view_model.last_updated_timestamp + ) spark_source = SparkSource( name="sparky_sparky_boom_man", @@ -595,6 +613,13 @@ def calculate_distance_demo_go(features_df: pd.DataFrame) -> pd.DataFrame: pydantic_obj = OnDemandFeatureViewModel.from_feature_view(python_obj) converted_python_obj = pydantic_obj.to_feature_view() assert python_obj == converted_python_obj + assert pydantic_obj.created_timestamp == python_obj.created_timestamp + assert pydantic_obj.last_updated_timestamp == python_obj.last_updated_timestamp + assert converted_python_obj.created_timestamp == pydantic_obj.created_timestamp + assert ( + converted_python_obj.last_updated_timestamp + == pydantic_obj.last_updated_timestamp + ) feast_proto = converted_python_obj.to_proto() python_obj_from_proto = OnDemandFeatureView.from_proto(feast_proto)