Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 1 addition & 21 deletions sdk/python/feast/infra/registry/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ def apply_feature_view(
self._prepare_registry_for_changes(project)
assert self.cached_registry_proto

self._check_conflicting_feature_view_names(feature_view)
self._ensure_feature_view_name_is_unique(feature_view, project, allow_cache=True)
existing_feature_views_of_same_type: RepeatedCompositeFieldContainer
if isinstance(feature_view, StreamFeatureView):
existing_feature_views_of_same_type = (
Expand Down Expand Up @@ -1351,26 +1351,6 @@ def _get_registry_proto(

return registry_proto

def _check_conflicting_feature_view_names(self, feature_view: BaseFeatureView):
name_to_fv_protos = self._existing_feature_view_names_to_fvs()
if feature_view.name in name_to_fv_protos:
if not isinstance(
name_to_fv_protos.get(feature_view.name), feature_view.proto_class
):
raise ConflictingFeatureViewNames(feature_view.name)

def _existing_feature_view_names_to_fvs(self) -> Dict[str, Message]:
assert self.cached_registry_proto
odfvs = {
fv.spec.name: fv
for fv in self.cached_registry_proto.on_demand_feature_views
}
fvs = {fv.spec.name: fv for fv in self.cached_registry_proto.feature_views}
sfv = {
fv.spec.name: fv for fv in self.cached_registry_proto.stream_feature_views
}
return {**odfvs, **fvs, **sfv}

def get_permission(
self, name: str, project: str, allow_cache: bool = False
) -> Permission:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2192,3 +2192,58 @@ def shared_odfv_name(inputs: pd.DataFrame) -> pd.DataFrame:
# Cleanup
test_registry.delete_feature_view("shared_odfv_name", project)
test_registry.teardown()


@pytest.mark.parametrize(
"test_registry",
all_fixtures,
)
Comment on lines +2197 to +2200
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 New test missing @pytest.mark.integration marker, breaking test categorization

The new test_cross_project_feature_view_name_allowed test is missing the @pytest.mark.integration marker that every other parametrized test using all_fixtures in this file has (e.g., test_cross_type_feature_view_name_conflict at line 2081, test_cross_type_feature_view_odfv_conflict at line 2150, and all ~20 other tests). Without this marker, the test won't be selected when running integration tests via make test-python-integration (which filters by pytest.mark.integration), so the regression test for issue #6209 will never actually run in CI.

Suggested change
@pytest.mark.parametrize(
"test_registry",
all_fixtures,
)
@pytest.mark.integration
@pytest.mark.parametrize(
"test_registry",
all_fixtures,
)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

def test_cross_project_feature_view_name_allowed(test_registry: BaseRegistry):
"""
Test that different projects can use the same feature view names.
This is a regression test for issue #6209.
"""
project_a = "project_a"
project_b = "project_b"

# Create a FeatureView in project A
feature_view_a = FeatureView(
name="shared_name",
entities=[],
schema=[Field(name="feature1", dtype=Float32)],
source=FileSource(path="data.parquet"),
)

# Create a StreamFeatureView with the same name in project B
stream_feature_view_b = StreamFeatureView(
name="shared_name",
entities=[],
schema=[Field(name="feature2", dtype=Float32)],
source=KafkaSource(
name="kafka_source",
kafka_bootstrap_servers="localhost:9092",
topic="test_topic",
timestamp_field="event_timestamp",
batch_source=FileSource(path="stream_data.parquet"),
),
aggregations=[],
)

# Both should apply successfully without ConflictingFeatureViewNames error
test_registry.apply_feature_view(feature_view_a, project_a)
test_registry.apply_feature_view(stream_feature_view_b, project_b)

# Verify both exist in their respective projects
retrieved_fv_a = test_registry.get_feature_view("shared_name", project_a)
assert retrieved_fv_a.name == "shared_name"
assert isinstance(retrieved_fv_a, FeatureView)
assert not isinstance(retrieved_fv_a, StreamFeatureView)

retrieved_sfv_b = test_registry.get_stream_feature_view("shared_name", project_b)
assert retrieved_sfv_b.name == "shared_name"
assert isinstance(retrieved_sfv_b, StreamFeatureView)

# Cleanup
test_registry.delete_feature_view("shared_name", project_a)
test_registry.delete_feature_view("shared_name", project_b)
test_registry.teardown()