Visitar URL original
feat: Add optional 'org' in feature view (#6288) by nquinn408 · Pull Request #6301 · feast-dev/feast · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
feat: Add optional 'org' in feature view (#6288)
Signed-off-by: Nick Quinn <nicholas_quinn@apple.com>
  • Loading branch information
nickquinn408 committed Apr 25, 2026
commit 481f3aa038448764cfcf1ece65b3b7edeabbfd77
5 changes: 4 additions & 1 deletion protos/feast/core/FeatureView.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ message FeatureView {
FeatureViewMeta meta = 2;
}

// Next available id: 19
// Next available id: 20
// TODO(adchia): refactor common fields from this and ODFV into separate metadata proto
message FeatureViewSpec {
// Name of the feature view. Must be unique. Not updated.
Expand Down Expand Up @@ -97,6 +97,9 @@ message FeatureViewSpec {

// User-specified version pin (e.g. "latest", "v2", "version2")
string version = 18;

// Organizational unit that owns this feature view (e.g. "ads", "search").
string org = 19;
}

message FeatureViewMeta {
Expand Down
2 changes: 2 additions & 0 deletions sdk/python/feast/batch_feature_view.py
Comment thread
nquinn408 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def __init__(
offline: bool = False,
description: str = "",
owner: str = "",
org: str = "",
schema: Optional[List[Field]] = None,
udf: Optional[Callable[[Any], Any]] = None,
udf_string: Optional[str] = "",
Expand Down Expand Up @@ -151,6 +152,7 @@ def __init__(
offline=offline,
description=description,
owner=owner,
org=org,
schema=schema,
source=source, # type: ignore[arg-type]
sink_source=sink_source,
Expand Down
10 changes: 10 additions & 0 deletions sdk/python/feast/feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class FeatureView(BaseFeatureView):
description: str
tags: Dict[str, str]
owner: str
org: str
materialization_intervals: List[Tuple[datetime, datetime]]
mode: Optional[Union["TransformationMode", str]]
enable_validation: bool
Expand All @@ -125,6 +126,7 @@ def __init__(
description: str = "",
tags: Optional[Dict[str, str]] = None,
owner: str = "",
org: str = "",
mode: Optional[Union["TransformationMode", str]] = None,
enable_validation: bool = False,
version: str = "latest",
Expand Down Expand Up @@ -152,6 +154,8 @@ def __init__(
tags (optional): A dictionary of key-value pairs to store arbitrary metadata.
owner (optional): The owner of the feature view, typically the email of the
primary maintainer.
org (optional): The organizational unit that owns this feature view
(e.g. "ads", "search").
mode (optional): The transformation mode for feature transformations. Only meaningful
when transformations are applied. Choose from TransformationMode enum values.
enable_validation (optional): If True, enables schema validation during materialization
Expand Down Expand Up @@ -278,6 +282,7 @@ def __init__(
owner=owner,
source=self.batch_source,
)
self.org = org
self.online = online
self.offline = offline
self.mode = mode
Expand All @@ -302,6 +307,7 @@ def __copy__(self):
version=self.version,
description=self.description,
owner=self.owner,
org=self.org,
)

# This is deliberately set outside of the FV initialization as we do not have the Entity objects.
Expand Down Expand Up @@ -355,6 +361,7 @@ def __eq__(self, other):
or self.enable_validation != other.enable_validation
or normalize_version_string(self.version)
!= normalize_version_string(other.version)
or self.org != other.org
):
return False

Expand Down Expand Up @@ -485,6 +492,7 @@ def to_proto_spec(
description=self.description,
tags=self.tags,
owner=self.owner,
org=self.org,
ttl=(ttl_duration if ttl_duration is not None else None),
online=self.online,
offline=self.offline,
Expand Down Expand Up @@ -615,6 +623,7 @@ def _from_proto_internal(
description=feature_view_proto.spec.description,
tags=dict(feature_view_proto.spec.tags),
owner=feature_view_proto.spec.owner,
org=feature_view_proto.spec.org,
online=feature_view_proto.spec.online,
offline=feature_view_proto.spec.offline,
ttl=(
Expand All @@ -637,6 +646,7 @@ def _from_proto_internal(
description=feature_view_proto.spec.description,
tags=dict(feature_view_proto.spec.tags),
owner=feature_view_proto.spec.owner,
org=feature_view_proto.spec.org,
online=feature_view_proto.spec.online,
offline=feature_view_proto.spec.offline,
ttl=(
Expand Down
55 changes: 55 additions & 0 deletions sdk/python/tests/unit/test_feature_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,3 +542,58 @@ def simple_udf(df: pd.DataFrame) -> pd.DataFrame:
assert deserialized.feature_transformation is not None, (
"Expected transformation to be present"
)


def test_feature_view_org_field():
"""Test that the optional `org` field is stored, serialized, and round-trips correctly."""
file_source = FileSource(name="my-file-source", path="test.parquet")

# org is optional — defaults to empty string
fv_no_org = FeatureView(
name="fv-no-org",
entities=[],
schema=[Field(name="feature1", dtype=Float32)],
source=file_source,
)
assert fv_no_org.org == ""

# org can be set explicitly
fv_with_org = FeatureView(
name="fv-with-org",
entities=[],
schema=[Field(name="feature1", dtype=Float32)],
source=file_source,
org="ads",
)
assert fv_with_org.org == "ads"

# org is serialized to proto
proto = fv_with_org.to_proto()
assert proto.spec.org == "ads"

# org survives a proto round-trip
roundtripped = FeatureView.from_proto(proto)
assert roundtripped.org == "ads"

# a view without org round-trips to empty string
proto_no_org = fv_no_org.to_proto()
assert proto_no_org.spec.org == ""
roundtripped_no_org = FeatureView.from_proto(proto_no_org)
assert roundtripped_no_org.org == ""

# equality respects org
fv_org_a = FeatureView(
name="fv-eq",
entities=[],
schema=[Field(name="feature1", dtype=Float32)],
source=file_source,
org="ads",
)
fv_org_b = FeatureView(
name="fv-eq",
entities=[],
schema=[Field(name="feature1", dtype=Float32)],
source=file_source,
org="search",
)
assert fv_org_a != fv_org_b