From dd5c9af8e2d5fff5f36cfaa28cd89483965f80ee Mon Sep 17 00:00:00 2001 From: antznette1 Date: Sat, 24 Jan 2026 11:59:17 +0100 Subject: [PATCH] refactor: centralize feature view object lookup Signed-off-by: antznette1 --- sdk/python/feast/feature_logging.py | 30 ++++++-------- sdk/python/feast/feature_server.py | 27 ++++--------- sdk/python/feast/feature_view_utils.py | 56 ++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 37 deletions(-) diff --git a/sdk/python/feast/feature_logging.py b/sdk/python/feast/feature_logging.py index 9bd5d8a91c0..5596aae3ae9 100644 --- a/sdk/python/feast/feature_logging.py +++ b/sdk/python/feast/feature_logging.py @@ -8,10 +8,9 @@ from feast.embedded_go.type_map import FEAST_TYPE_TO_ARROW_TYPE, PA_TIMESTAMP_TYPE from feast.errors import ( FeastObjectNotFoundException, - FeatureViewNotFoundException, - OnDemandFeatureViewNotFoundException, ) from feast.feature_view import DUMMY_ENTITY_ID +from feast.feature_view_utils import get_feast_object_from_registry from feast.protos.feast.core.FeatureService_pb2 import ( LoggingConfig as LoggingConfigProto, ) @@ -58,25 +57,22 @@ def get_schema(self, registry: "BaseRegistry") -> pa.Schema: # Go code can be found here: # https://github.com/feast-dev/feast/blob/master/go/internal/feast/server/logging/memorybuffer.go#L51 try: - feature_view = registry.get_feature_view(projection.name, self._project) - except FeatureViewNotFoundException: - try: - on_demand_feature_view = registry.get_on_demand_feature_view( - projection.name, self._project - ) - except OnDemandFeatureViewNotFoundException: - raise FeastObjectNotFoundException( - f"Can't recognize feature view with a name {projection.name}" - ) + feast_object = get_feast_object_from_registry( + registry, + projection.name, + self._project, + ) + except FeastObjectNotFoundException: + raise FeastObjectNotFoundException( + f"Can't recognize feature view with a name {projection.name}" + ) - for ( - request_source - ) in on_demand_feature_view.source_request_sources.values(): + if hasattr(feast_object, "source_request_sources"): + for request_source in feast_object.source_request_sources.values(): for field in request_source.schema: fields[field.name] = FEAST_TYPE_TO_ARROW_TYPE[field.dtype] - else: - for entity_column in feature_view.entity_columns: + for entity_column in feast_object.entity_columns: if entity_column.name == DUMMY_ENTITY_ID: continue diff --git a/sdk/python/feast/feature_server.py b/sdk/python/feast/feature_server.py index 6f0d192b65c..f1c4eb25246 100644 --- a/sdk/python/feast/feature_server.py +++ b/sdk/python/feast/feature_server.py @@ -51,9 +51,9 @@ from feast.data_source import PushMode from feast.errors import ( FeastError, - FeatureViewNotFoundException, ) from feast.feast_object import FeastObject +from feast.feature_view_utils import get_feast_object_from_feature_store from feast.permissions.action import WRITE, AuthzedAction from feast.permissions.security_manager import assert_permissions from feast.permissions.server.rest import inject_user_details @@ -493,25 +493,12 @@ async def _get_feast_object( ) -> FeastObject: # FIXME: this logic repeated at least 3 times in the codebase - should be centralized # in logging, in server and in feature_store (Python SDK) - try: - return await run_in_threadpool( - store.get_feature_view, - feature_view_name, - allow_registry_cache=allow_registry_cache, - ) - except FeatureViewNotFoundException: - try: - return await run_in_threadpool( - store.get_on_demand_feature_view, - feature_view_name, - allow_registry_cache=allow_registry_cache, - ) - except FeatureViewNotFoundException: - return await run_in_threadpool( - store.get_stream_feature_view, - feature_view_name, - allow_registry_cache=allow_registry_cache, - ) + return await run_in_threadpool( + get_feast_object_from_feature_store, + store, + feature_view_name, + allow_registry_cache, + ) @app.post("/write-to-online-store", dependencies=[Depends(inject_user_details)]) async def write_to_online_store(request: WriteToFeatureStoreRequest) -> None: diff --git a/sdk/python/feast/feature_view_utils.py b/sdk/python/feast/feature_view_utils.py index daf28e09dec..c86096311c6 100644 --- a/sdk/python/feast/feature_view_utils.py +++ b/sdk/python/feast/feature_view_utils.py @@ -7,9 +7,18 @@ from dataclasses import dataclass from typing import Callable, Optional +from feast.errors import ( + FeastObjectNotFoundException, + FeatureViewNotFoundException, + OnDemandFeatureViewNotFoundException, +) + if typing.TYPE_CHECKING: from feast.data_source import DataSource + from feast.feature_store import FeatureStore from feast.feature_view import FeatureView + from feast.feast_object import FeastObject + from feast.infra.registry.base_registry import BaseRegistry from feast.repo_config import RepoConfig logger = logging.getLogger(__name__) @@ -227,3 +236,50 @@ def resolve_feature_view_source_with_fallback( raise ValueError( f"Unable to resolve any data source for feature view {feature_view.name}" ) + + +def get_feast_object_from_feature_store( + store: "FeatureStore", + name: str, + allow_registry_cache: bool = False, + ) -> "FeastObject": + try: + return store.get_feature_view(name, allow_registry_cache=allow_registry_cache) + except FeatureViewNotFoundException: + try: + return store.get_on_demand_feature_view( + name, allow_registry_cache=allow_registry_cache + ) + except (FeatureViewNotFoundException, OnDemandFeatureViewNotFoundException): + try: + return store.get_stream_feature_view( + name, allow_registry_cache=allow_registry_cache + ) + except FeatureViewNotFoundException as e: + raise FeastObjectNotFoundException( + f"Can't recognize feast object with a name {name}" + ) from e + + +def get_feast_object_from_registry( + registry: "BaseRegistry", + name: str, + project: str, + allow_cache: bool = False, + ) -> "FeastObject": + try: + return registry.get_feature_view(name, project, allow_cache=allow_cache) + except FeatureViewNotFoundException: + try: + return registry.get_on_demand_feature_view( + name, project, allow_cache=allow_cache + ) + except (FeatureViewNotFoundException, OnDemandFeatureViewNotFoundException): + try: + return registry.get_stream_feature_view( + name, project, allow_cache=allow_cache + ) + except FeatureViewNotFoundException as e: + raise FeastObjectNotFoundException( + f"Can't recognize feast object with a name {name}" + ) from e