forked from p34709852/monkey
Merge pull request #2205 from guardicore/2179-create-ieventserializer
Event serializer
This commit is contained in:
commit
808bf5fee9
|
@ -0,0 +1,2 @@
|
|||
from .i_event_serialize import IEventSerializer
|
||||
from .event_serializer_registry import EventSerializerRegistry
|
|
@ -0,0 +1,41 @@
|
|||
from typing import Type, Union
|
||||
|
||||
from common.event_serializers import IEventSerializer
|
||||
from common.events import AbstractEvent
|
||||
|
||||
|
||||
class EventSerializerRegistry:
|
||||
"""
|
||||
Registry for event serializers using event class.
|
||||
|
||||
Example:
|
||||
event_serializer_registry = EventSerializerRegistry()
|
||||
event_serializer_registry[MyEvent] = MyEventSerializer()
|
||||
|
||||
my_event_dict = {"type": "MyEvent", "data": "123"}
|
||||
|
||||
serializer = event_serializer_registry[my_event_dict["type"]]
|
||||
my_event_object = serializer.deserialize(my_event_dict)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._registry = {}
|
||||
|
||||
def __setitem__(self, event_class: Type[AbstractEvent], event_serializer: IEventSerializer):
|
||||
if not issubclass(event_class, AbstractEvent):
|
||||
raise TypeError(f"Event class must be of type: {AbstractEvent.__name__}")
|
||||
|
||||
if not isinstance(event_serializer, IEventSerializer):
|
||||
raise TypeError(f"Event serializer must be of type: {IEventSerializer.__name__}")
|
||||
|
||||
self._registry[event_class] = event_serializer
|
||||
self._registry[event_class.__name__] = event_serializer
|
||||
|
||||
def __getitem__(self, event_class: Union[str, Type[AbstractEvent]]) -> IEventSerializer:
|
||||
if not (isinstance(event_class, str) or issubclass(event_class, AbstractEvent)):
|
||||
raise TypeError(
|
||||
f"Registry get key {event_class} must be of type: {AbstractEvent.__name__} or "
|
||||
f"{str.__name__}"
|
||||
)
|
||||
|
||||
return self._registry[event_class]
|
|
@ -0,0 +1,34 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, List, Union
|
||||
|
||||
from common.events import AbstractEvent
|
||||
|
||||
JSONSerializable = Union[
|
||||
Dict[str, "JSONSerializable"], List["JSONSerializable"], int, str, float, bool, None
|
||||
]
|
||||
|
||||
|
||||
class IEventSerializer(ABC):
|
||||
"""
|
||||
Manages serialization and deserialization of events
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def serialize(self, event: AbstractEvent) -> JSONSerializable:
|
||||
"""
|
||||
Serializes an event
|
||||
|
||||
:param event: Event to serialize
|
||||
:return: Serialized event
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def deserialize(self, serialized_event: JSONSerializable) -> AbstractEvent:
|
||||
"""
|
||||
Deserializes an event
|
||||
|
||||
:param serialized_event: Serialized event to deserialize
|
||||
:return: Deserialized event
|
||||
"""
|
||||
pass
|
|
@ -0,0 +1,71 @@
|
|||
from dataclasses import dataclass, field
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from common.event_serializers import EventSerializerRegistry, IEventSerializer
|
||||
from common.events import AbstractEvent
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SomeEvent(AbstractEvent):
|
||||
some_param: int = field(default=435)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OtherEvent(AbstractEvent):
|
||||
other_param: float = field(default=123.456)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NoneEvent(AbstractEvent):
|
||||
none_param: float = field(default=1.0)
|
||||
|
||||
|
||||
SOME_SERIALIZER = MagicMock(spec=IEventSerializer)
|
||||
OTHER_SERIALIZER = MagicMock(spec=IEventSerializer)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def event_serializer_registry():
|
||||
event_serializer_registry = EventSerializerRegistry()
|
||||
|
||||
event_serializer_registry[SomeEvent] = SOME_SERIALIZER
|
||||
event_serializer_registry[OtherEvent] = OTHER_SERIALIZER
|
||||
|
||||
return event_serializer_registry
|
||||
|
||||
|
||||
def test_event_serializer_registry_event(event_serializer_registry):
|
||||
assert event_serializer_registry[SomeEvent] == SOME_SERIALIZER
|
||||
assert event_serializer_registry[OtherEvent] == OTHER_SERIALIZER
|
||||
|
||||
|
||||
def test_event_serializer_registry_string(event_serializer_registry):
|
||||
assert event_serializer_registry[SomeEvent.__name__] == SOME_SERIALIZER
|
||||
assert event_serializer_registry[OtherEvent.__name__] == OTHER_SERIALIZER
|
||||
|
||||
|
||||
def test_event_serializer_registry_set_unsupported_type(event_serializer_registry):
|
||||
with pytest.raises(TypeError):
|
||||
event_serializer_registry[SomeEvent] = "SomethingBogusVogus"
|
||||
|
||||
|
||||
def test_event_serializer_registry_set_unsupported_type_key(event_serializer_registry):
|
||||
with pytest.raises(TypeError):
|
||||
event_serializer_registry["BogusKey"] = MagicMock(spec=IEventSerializer)
|
||||
|
||||
|
||||
def test_event_serializer_registry_get_unsuported_type(event_serializer_registry):
|
||||
with pytest.raises(TypeError):
|
||||
event_serializer_registry[1]
|
||||
|
||||
|
||||
def test_event_serializer_registry_get_unexisting_type(event_serializer_registry):
|
||||
with pytest.raises(KeyError):
|
||||
event_serializer_registry[NoneEvent]
|
||||
|
||||
|
||||
def test_event_serializer_registry_get_unexisting_string(event_serializer_registry):
|
||||
with pytest.raises(KeyError):
|
||||
event_serializer_registry[NoneEvent.__name__]
|
|
@ -266,3 +266,11 @@ subscribe_tag # common\event_queue\pypubsub_event_queue.py
|
|||
publish # common\event_queue\pypubsub_event_queue.py
|
||||
PyPubSubEventQueue # common\event_queue\pypubsub_event_queue.py
|
||||
subscribe_all_events # common\event_queue\pypubsub_event_queue.py
|
||||
|
||||
|
||||
# TODO: Remove once #2179 is closed
|
||||
EventSerializerRegistry
|
||||
serialize
|
||||
event
|
||||
deserialize
|
||||
serialized_event
|
||||
|
|
Loading…
Reference in New Issue