Skip to content

Commit

Permalink
refactor!: move AbstractProvider to openfeature.provider (#314)
Browse files Browse the repository at this point in the history
Signed-off-by: Federico Bond <federicobond@gmail.com>
  • Loading branch information
federicobond authored Apr 12, 2024
1 parent cd605c4 commit 96ba793
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 109 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 8 additions & 2 deletions openfeature/_event_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))


Expand Down
15 changes: 1 addition & 14 deletions openfeature/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand All @@ -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:
Expand Down
85 changes: 84 additions & 1 deletion openfeature/provider/__init__.py
Original file line number Diff line number Diff line change
@@ -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):
Expand Down Expand Up @@ -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)
3 changes: 1 addition & 2 deletions openfeature/provider/in_memory_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
3 changes: 1 addition & 2 deletions openfeature/provider/no_op_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
93 changes: 7 additions & 86 deletions openfeature/provider/provider.py
Original file line number Diff line number Diff line change
@@ -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,
)

0 comments on commit 96ba793

Please sign in to comment.