-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement provider events (#278)
* feat: implement provider events Signed-off-by: Federico Bond <[email protected]> * feat: add error_code field to EventDetails and ProviderEventDetails Signed-off-by: Federico Bond <[email protected]> * fix: replace strings with postponed evaluation of annotations Signed-off-by: Federico Bond <[email protected]> * feat: run handlers immediately if provider already in associated state Signed-off-by: Federico Bond <[email protected]> * feat: remove unused _provider from openfeature.api Signed-off-by: Federico Bond <[email protected]> * test: add some comments to test cases Signed-off-by: Federico Bond <[email protected]> * test: add provider event late binding test cases Signed-off-by: Federico Bond <[email protected]> * fix: fix status handlers running immediately if provider already in associated state Signed-off-by: Federico Bond <[email protected]> * refactor: reuse provider property in OpenFeatureClient Signed-off-by: Federico Bond <[email protected]> * refactor: move _provider_status_to_event to ProviderEvent.from_provider_status Signed-off-by: Federico Bond <[email protected]> * refactor: move EventSupport class to an internal module Signed-off-by: Federico Bond <[email protected]> * refactor: replace EventSupport class with module-level functions Signed-off-by: Federico Bond <[email protected]> * style: fix code style --------- Signed-off-by: Federico Bond <[email protected]>
- Loading branch information
1 parent
04b4009
commit 679409f
Showing
10 changed files
with
412 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
from __future__ import annotations | ||
|
||
from collections import defaultdict | ||
from typing import TYPE_CHECKING, Dict, List | ||
|
||
from openfeature.event import ( | ||
EventDetails, | ||
EventHandler, | ||
ProviderEvent, | ||
ProviderEventDetails, | ||
) | ||
from openfeature.provider import FeatureProvider | ||
|
||
if TYPE_CHECKING: | ||
from openfeature.client import OpenFeatureClient | ||
|
||
|
||
_global_handlers: Dict[ProviderEvent, List[EventHandler]] = defaultdict(list) | ||
_client_handlers: Dict[OpenFeatureClient, Dict[ProviderEvent, List[EventHandler]]] = ( | ||
defaultdict(lambda: defaultdict(list)) | ||
) | ||
|
||
|
||
def run_client_handlers( | ||
client: OpenFeatureClient, event: ProviderEvent, details: EventDetails | ||
) -> None: | ||
for handler in _client_handlers[client][event]: | ||
handler(details) | ||
|
||
|
||
def run_global_handlers(event: ProviderEvent, details: EventDetails) -> None: | ||
for handler in _global_handlers[event]: | ||
handler(details) | ||
|
||
|
||
def add_client_handler( | ||
client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler | ||
) -> None: | ||
handlers = _client_handlers[client][event] | ||
handlers.append(handler) | ||
|
||
_run_immediate_handler(client, event, handler) | ||
|
||
|
||
def remove_client_handler( | ||
client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler | ||
) -> None: | ||
handlers = _client_handlers[client][event] | ||
handlers.remove(handler) | ||
|
||
|
||
def add_global_handler(event: ProviderEvent, handler: EventHandler) -> None: | ||
_global_handlers[event].append(handler) | ||
|
||
from openfeature.api import get_client | ||
|
||
_run_immediate_handler(get_client(), event, handler) | ||
|
||
|
||
def remove_global_handler(event: ProviderEvent, handler: EventHandler) -> None: | ||
_global_handlers[event].remove(handler) | ||
|
||
|
||
def run_handlers_for_provider( | ||
provider: FeatureProvider, | ||
event: ProviderEvent, | ||
provider_details: ProviderEventDetails, | ||
) -> None: | ||
details = EventDetails.from_provider_event_details( | ||
provider.get_metadata().name, provider_details | ||
) | ||
# run the global handlers | ||
run_global_handlers(event, details) | ||
# run the handlers for clients associated to this provider | ||
for client in _client_handlers: | ||
if client.provider == provider: | ||
run_client_handlers(client, event, details) | ||
|
||
|
||
def _run_immediate_handler( | ||
client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler | ||
) -> None: | ||
if event == ProviderEvent.from_provider_status(client.get_provider_status()): | ||
handler(EventDetails(provider_name=client.provider.get_metadata().name)) | ||
|
||
|
||
def clear() -> None: | ||
_global_handlers.clear() | ||
_client_handlers.clear() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass, field | ||
from enum import Enum | ||
from typing import Callable, ClassVar, Dict, List, Optional, Union | ||
|
||
from openfeature.exception import ErrorCode | ||
from openfeature.provider import ProviderStatus | ||
|
||
|
||
class ProviderEvent(Enum): | ||
PROVIDER_READY = "PROVIDER_READY" | ||
PROVIDER_CONFIGURATION_CHANGED = "PROVIDER_CONFIGURATION_CHANGED" | ||
PROVIDER_ERROR = "PROVIDER_ERROR" | ||
PROVIDER_FATAL = "PROVIDER_FATAL" | ||
PROVIDER_STALE = "PROVIDER_STALE" | ||
|
||
__status__: ClassVar[Dict[ProviderStatus, str]] = { | ||
ProviderStatus.READY: PROVIDER_READY, | ||
ProviderStatus.ERROR: PROVIDER_ERROR, | ||
ProviderStatus.FATAL: PROVIDER_FATAL, | ||
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: | ||
flags_changed: Optional[List[str]] = None | ||
message: Optional[str] = None | ||
error_code: Optional[ErrorCode] = None | ||
metadata: Dict[str, Union[bool, str, int, float]] = field(default_factory=dict) | ||
|
||
|
||
@dataclass | ||
class EventDetails(ProviderEventDetails): | ||
provider_name: str = "" | ||
flags_changed: Optional[List[str]] = None | ||
message: Optional[str] = None | ||
error_code: Optional[ErrorCode] = None | ||
metadata: Dict[str, Union[bool, str, int, float]] = field(default_factory=dict) | ||
|
||
@classmethod | ||
def from_provider_event_details( | ||
cls, provider_name: str, details: ProviderEventDetails | ||
) -> EventDetails: | ||
return cls( | ||
provider_name=provider_name, | ||
flags_changed=details.flags_changed, | ||
message=details.message, | ||
error_code=details.error_code, | ||
metadata=details.metadata, | ||
) | ||
|
||
|
||
EventHandler = Callable[[EventDetails], None] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.