Skip to content

Commit

Permalink
refactor: replace EventSupport class with module-level functions
Browse files Browse the repository at this point in the history
Signed-off-by: Federico Bond <federicobond@gmail.com>
  • Loading branch information
federicobond committed Mar 13, 2024
1 parent f43ed00 commit 425629c
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 102 deletions.
141 changes: 72 additions & 69 deletions openfeature/_event_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,72 +15,75 @@
from openfeature.client import OpenFeatureClient

Check warning on line 15 in openfeature/_event_support.py

View check run for this annotation

Codecov / codecov/patch

openfeature/_event_support.py#L15

Added line #L15 was not covered by tests


class EventSupport:
_global_handlers: Dict[ProviderEvent, List[EventHandler]]
_client_handlers: Dict[OpenFeatureClient, Dict[ProviderEvent, List[EventHandler]]]

def __init__(self) -> None:
self._global_handlers = defaultdict(list)
self._client_handlers = defaultdict(lambda: defaultdict(list))

def run_client_handlers(
self, client: OpenFeatureClient, event: ProviderEvent, details: EventDetails
) -> None:
for handler in self._client_handlers[client][event]:
handler(details)

def run_global_handlers(self, event: ProviderEvent, details: EventDetails) -> None:
for handler in self._global_handlers[event]:
handler(details)

def add_client_handler(
self, client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler
) -> None:
handlers = self._client_handlers[client][event]
handlers.append(handler)

self._run_immediate_handler(client, event, handler)

def remove_client_handler(
self, client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler
) -> None:
handlers = self._client_handlers[client][event]
handlers.remove(handler)

def add_global_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
self._global_handlers[event].append(handler)

from openfeature.api import get_client

self._run_immediate_handler(get_client(), event, handler)

def remove_global_handler(
self, event: ProviderEvent, handler: EventHandler
) -> None:
self._global_handlers[event].remove(handler)

def run_handlers_for_provider(
self,
provider: FeatureProvider,
event: ProviderEvent,
provider_details: ProviderEventDetails,
) -> None:
details = EventDetails.from_provider_event_details(
provider.get_metadata().name, provider_details
)
# run the global handlers
self.run_global_handlers(event, details)
# run the handlers for clients associated to this provider
for client in self._client_handlers:
if client.provider == provider:
self.run_client_handlers(client, event, details)

def _run_immediate_handler(
self, 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(self) -> None:
self._global_handlers.clear()
self._client_handlers.clear()
_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()
25 changes: 1 addition & 24 deletions openfeature/api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import typing

from openfeature._event_support import EventSupport
from openfeature import _event_support
from openfeature.client import OpenFeatureClient
from openfeature.evaluation_context import EvaluationContext
from openfeature.event import (
EventHandler,
ProviderEvent,
ProviderEventDetails,
)
from openfeature.exception import GeneralError
from openfeature.hook import Hook
Expand All @@ -20,8 +19,6 @@

_provider_registry: ProviderRegistry = ProviderRegistry()

_event_support: EventSupport = EventSupport()


def get_client(
domain: typing.Optional[str] = None, version: typing.Optional[str] = None
Expand Down Expand Up @@ -84,23 +81,3 @@ def add_handler(event: ProviderEvent, handler: EventHandler) -> None:

def remove_handler(event: ProviderEvent, handler: EventHandler) -> None:
_event_support.remove_global_handler(event, handler)


def _add_client_handler(
client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler
) -> None:
_event_support.add_client_handler(client, event, handler)


def _remove_client_handler(
client: OpenFeatureClient, event: ProviderEvent, handler: EventHandler
) -> None:
_event_support.remove_client_handler(client, event, handler)


def _run_handlers_for_provider(
provider: FeatureProvider,
event: ProviderEvent,
provider_details: ProviderEventDetails,
) -> None:
_event_support.run_handlers_for_provider(provider, event, provider_details)
6 changes: 3 additions & 3 deletions openfeature/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import typing
from dataclasses import dataclass

from openfeature import api
from openfeature import _event_support, api
from openfeature.evaluation_context import EvaluationContext
from openfeature.event import EventHandler, ProviderEvent
from openfeature.exception import (
Expand Down Expand Up @@ -441,10 +441,10 @@ def _create_provider_evaluation(
)

def add_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
api._add_client_handler(self, event, handler)
_event_support.add_client_handler(self, event, handler)

def remove_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
api._remove_client_handler(self, event, handler)
_event_support.remove_client_handler(self, event, handler)


def _typecheck_flag_value(value: typing.Any, flag_type: FlagType) -> None:
Expand Down
5 changes: 2 additions & 3 deletions openfeature/provider/provider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import typing
from abc import abstractmethod

from openfeature._event_support import run_handlers_for_provider
from openfeature.evaluation_context import EvaluationContext
from openfeature.event import ProviderEvent, ProviderEventDetails
from openfeature.flag_evaluation import FlagResolutionDetails
Expand Down Expand Up @@ -83,6 +84,4 @@ def emit_provider_stale(self, details: ProviderEventDetails) -> None:
self.emit(ProviderEvent.PROVIDER_STALE, details)

def emit(self, event: ProviderEvent, details: ProviderEventDetails) -> None:
from openfeature.api import _run_handlers_for_provider

_run_handlers_for_provider(self, event, details)
run_handlers_for_provider(self, event, details)
5 changes: 2 additions & 3 deletions openfeature/provider/registry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import typing

from openfeature._event_support import run_handlers_for_provider
from openfeature.evaluation_context import EvaluationContext
from openfeature.event import (
ProviderEvent,
Expand Down Expand Up @@ -100,6 +101,4 @@ def _set_provider_status(
self._provider_status[provider] = status

if event := ProviderEvent.from_provider_status(status):
from openfeature.api import _run_handlers_for_provider

_run_handlers_for_provider(provider, event, ProviderEventDetails())
run_handlers_for_provider(provider, event, ProviderEventDetails())

0 comments on commit 425629c

Please sign in to comment.