Skip to content

Commit

Permalink
refactor!: move AbstractProvider to openfeature.provider
Browse files Browse the repository at this point in the history
  • Loading branch information
federicobond committed Apr 10, 2024
1 parent 34ac91c commit 9c62d29
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 105 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
4 changes: 2 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,7 @@ 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()):
if ProviderStatus.from_provider_event(event) == 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
99 changes: 98 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 All @@ -17,6 +21,20 @@ class ProviderStatus(Enum):
STALE = "STALE"
FATAL = "FATAL"

__events__: typing.ClassVar[typing.Dict[ProviderEvent, str]] = {
ProviderEvent.PROVIDER_READY: READY,
ProviderEvent.PROVIDER_ERROR: ERROR,
ProviderEvent.PROVIDER_ERROR: FATAL,
ProviderEvent.PROVIDER_STALE: STALE,
}

@classmethod
def from_provider_event(
cls, event: ProviderEvent
) -> typing.Optional[ProviderStatus]:
value = ProviderStatus.__events__.get(event)
return ProviderStatus[value] if value else None


class FeatureProvider(typing.Protocol): # pragma: no cover
def initialize(self, evaluation_context: EvaluationContext) -> None: ...
Expand Down Expand Up @@ -61,3 +79,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)
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 9c62d29

Please sign in to comment.