diff --git a/README.md b/README.md index d5ff5dfc..b7d731eb 100644 --- a/README.md +++ b/README.md @@ -259,8 +259,7 @@ from typing import List, Optional, Union from openfeature.evaluation_context import EvaluationContext from openfeature.flag_evaluation import FlagResolutionDetails from openfeature.hook import Hook -from openfeature.provider.metadata import Metadata -from openfeature.provider.provider import AbstractProvider +from openfeature.provider import AbstractProvider, Metadata class MyProvider(AbstractProvider): def get_metadata(self) -> Metadata: diff --git a/openfeature/_event_support.py b/openfeature/_event_support.py index 5842b0f4..26753b05 100644 --- a/openfeature/_event_support.py +++ b/openfeature/_event_support.py @@ -9,7 +9,7 @@ ProviderEvent, ProviderEventDetails, ) -from openfeature.provider import FeatureProvider +from openfeature.provider import FeatureProvider, ProviderStatus if TYPE_CHECKING: from openfeature.client import OpenFeatureClient @@ -80,7 +80,13 @@ def run_handlers_for_provider( def _run_immediate_handler( client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler ) -> None: - if event == ProviderEvent.from_provider_status(client.get_provider_status()): + status_to_event = { + ProviderStatus.READY: ProviderEvent.PROVIDER_READY, + ProviderStatus.ERROR: ProviderEvent.PROVIDER_ERROR, + ProviderStatus.FATAL: ProviderEvent.PROVIDER_ERROR, + ProviderStatus.STALE: ProviderEvent.PROVIDER_STALE, + } + if event == status_to_event.get(client.get_provider_status()): handler(EventDetails(provider_name=client.provider.get_metadata().name)) diff --git a/openfeature/event.py b/openfeature/event.py index 5fd64d2d..e41a3704 100644 --- a/openfeature/event.py +++ b/openfeature/event.py @@ -2,10 +2,9 @@ from dataclasses import dataclass, field from enum import Enum -from typing import Callable, ClassVar, Dict, List, Optional, Union +from typing import Callable, Dict, List, Optional, Union from openfeature.exception import ErrorCode -from openfeature.provider import ProviderStatus __all__ = ["ProviderEvent", "ProviderEventDetails", "EventDetails", "EventHandler"] @@ -16,18 +15,6 @@ class ProviderEvent(Enum): PROVIDER_ERROR = "PROVIDER_ERROR" PROVIDER_STALE = "PROVIDER_STALE" - __status__: ClassVar[Dict[ProviderStatus, str]] = { - ProviderStatus.READY: PROVIDER_READY, - ProviderStatus.ERROR: PROVIDER_ERROR, - ProviderStatus.FATAL: PROVIDER_ERROR, - ProviderStatus.STALE: PROVIDER_STALE, - } - - @classmethod - def from_provider_status(cls, status: ProviderStatus) -> Optional[ProviderEvent]: - value = ProviderEvent.__status__.get(status) - return ProviderEvent[value] if value else None - @dataclass class ProviderEventDetails: diff --git a/openfeature/provider/__init__.py b/openfeature/provider/__init__.py index 77111f29..95fdac5d 100644 --- a/openfeature/provider/__init__.py +++ b/openfeature/provider/__init__.py @@ -1,13 +1,17 @@ +from __future__ import annotations + import typing +from abc import abstractmethod from enum import Enum from openfeature.evaluation_context import EvaluationContext +from openfeature.event import ProviderEvent, ProviderEventDetails from openfeature.flag_evaluation import FlagResolutionDetails from openfeature.hook import Hook from .metadata import Metadata -__all__ = ["ProviderStatus", "FeatureProvider", "Metadata"] +__all__ = ["AbstractProvider", "ProviderStatus", "FeatureProvider", "Metadata"] class ProviderStatus(Enum): @@ -61,3 +65,82 @@ def resolve_object_details( default_value: typing.Union[dict, list], evaluation_context: typing.Optional[EvaluationContext] = None, ) -> FlagResolutionDetails[typing.Union[dict, list]]: ... + + +class AbstractProvider(FeatureProvider): + def initialize(self, evaluation_context: EvaluationContext) -> None: + pass + + def shutdown(self) -> None: + pass + + @abstractmethod + def get_metadata(self) -> Metadata: + pass + + def get_provider_hooks(self) -> typing.List[Hook]: + return [] + + @abstractmethod + def resolve_boolean_details( + self, + flag_key: str, + default_value: bool, + evaluation_context: typing.Optional[EvaluationContext] = None, + ) -> FlagResolutionDetails[bool]: + pass + + @abstractmethod + def resolve_string_details( + self, + flag_key: str, + default_value: str, + evaluation_context: typing.Optional[EvaluationContext] = None, + ) -> FlagResolutionDetails[str]: + pass + + @abstractmethod + def resolve_integer_details( + self, + flag_key: str, + default_value: int, + evaluation_context: typing.Optional[EvaluationContext] = None, + ) -> FlagResolutionDetails[int]: + pass + + @abstractmethod + def resolve_float_details( + self, + flag_key: str, + default_value: float, + evaluation_context: typing.Optional[EvaluationContext] = None, + ) -> FlagResolutionDetails[float]: + pass + + @abstractmethod + def resolve_object_details( + self, + flag_key: str, + default_value: typing.Union[dict, list], + evaluation_context: typing.Optional[EvaluationContext] = None, + ) -> FlagResolutionDetails[typing.Union[dict, list]]: + pass + + def emit_provider_ready(self, details: ProviderEventDetails) -> None: + self.emit(ProviderEvent.PROVIDER_READY, details) + + def emit_provider_configuration_changed( + self, details: ProviderEventDetails + ) -> None: + self.emit(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, details) + + def emit_provider_error(self, details: ProviderEventDetails) -> None: + self.emit(ProviderEvent.PROVIDER_ERROR, details) + + def emit_provider_stale(self, details: ProviderEventDetails) -> None: + self.emit(ProviderEvent.PROVIDER_STALE, details) + + def emit(self, event: ProviderEvent, details: ProviderEventDetails) -> None: + from openfeature.provider._registry import provider_registry + + provider_registry.dispatch_event(self, event, details) diff --git a/openfeature/provider/in_memory_provider.py b/openfeature/provider/in_memory_provider.py index 7fe7e735..322f4ed6 100644 --- a/openfeature/provider/in_memory_provider.py +++ b/openfeature/provider/in_memory_provider.py @@ -6,8 +6,7 @@ from openfeature.exception import FlagNotFoundError from openfeature.flag_evaluation import FlagMetadata, FlagResolutionDetails, Reason from openfeature.hook import Hook -from openfeature.provider.metadata import Metadata -from openfeature.provider.provider import AbstractProvider +from openfeature.provider import AbstractProvider, Metadata PASSED_IN_DEFAULT = "Passed in default" diff --git a/openfeature/provider/no_op_provider.py b/openfeature/provider/no_op_provider.py index e1a4f4a2..070945c9 100644 --- a/openfeature/provider/no_op_provider.py +++ b/openfeature/provider/no_op_provider.py @@ -3,9 +3,8 @@ from openfeature.evaluation_context import EvaluationContext from openfeature.flag_evaluation import FlagResolutionDetails, Reason from openfeature.hook import Hook -from openfeature.provider.metadata import Metadata +from openfeature.provider import AbstractProvider, Metadata from openfeature.provider.no_op_metadata import NoOpMetadata -from openfeature.provider.provider import AbstractProvider PASSED_IN_DEFAULT = "Passed in default" diff --git a/openfeature/provider/provider.py b/openfeature/provider/provider.py index 9fc85946..fc951d6e 100644 --- a/openfeature/provider/provider.py +++ b/openfeature/provider/provider.py @@ -1,90 +1,11 @@ -import typing -from abc import abstractmethod +import warnings -from openfeature.evaluation_context import EvaluationContext -from openfeature.event import ProviderEvent, ProviderEventDetails -from openfeature.flag_evaluation import FlagResolutionDetails -from openfeature.hook import Hook -from openfeature.provider import FeatureProvider -from openfeature.provider.metadata import Metadata +from openfeature.provider import AbstractProvider __all__ = ["AbstractProvider"] - -class AbstractProvider(FeatureProvider): - def initialize(self, evaluation_context: EvaluationContext) -> None: - pass - - def shutdown(self) -> None: - pass - - @abstractmethod - def get_metadata(self) -> Metadata: - pass - - def get_provider_hooks(self) -> typing.List[Hook]: - return [] - - @abstractmethod - def resolve_boolean_details( - self, - flag_key: str, - default_value: bool, - evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagResolutionDetails[bool]: - pass - - @abstractmethod - def resolve_string_details( - self, - flag_key: str, - default_value: str, - evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagResolutionDetails[str]: - pass - - @abstractmethod - def resolve_integer_details( - self, - flag_key: str, - default_value: int, - evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagResolutionDetails[int]: - pass - - @abstractmethod - def resolve_float_details( - self, - flag_key: str, - default_value: float, - evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagResolutionDetails[float]: - pass - - @abstractmethod - def resolve_object_details( - self, - flag_key: str, - default_value: typing.Union[dict, list], - evaluation_context: typing.Optional[EvaluationContext] = None, - ) -> FlagResolutionDetails[typing.Union[dict, list]]: - pass - - def emit_provider_ready(self, details: ProviderEventDetails) -> None: - self.emit(ProviderEvent.PROVIDER_READY, details) - - def emit_provider_configuration_changed( - self, details: ProviderEventDetails - ) -> None: - self.emit(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, details) - - def emit_provider_error(self, details: ProviderEventDetails) -> None: - self.emit(ProviderEvent.PROVIDER_ERROR, details) - - def emit_provider_stale(self, details: ProviderEventDetails) -> None: - self.emit(ProviderEvent.PROVIDER_STALE, details) - - def emit(self, event: ProviderEvent, details: ProviderEventDetails) -> None: - from openfeature.provider._registry import provider_registry - - provider_registry.dispatch_event(self, event, details) +warnings.warn( + "openfeature.provider.provider is deprecated, use openfeature.provider instead", + DeprecationWarning, + stacklevel=1, +)