diff --git a/cloudevents/abstract/event.py b/cloudevents/abstract/event.py index de1e230..95d9a56 100644 --- a/cloudevents/abstract/event.py +++ b/cloudevents/abstract/event.py @@ -26,55 +26,27 @@ class CloudEvent: raise NotImplementedError() @property - def _attributes_read_model(self) -> typing.Dict[str, typing.Any]: + def attributes(self) -> typing.Dict[str, typing.Any]: """ :return: Attributes of this event. You MUST NOT mutate this dict. Implementation MAY assume the dict will not be mutated. - - The reason this is only a read model and not a write model is - because you MAY not have an easy write access to the data. - - For example - a database row or a cached value. - - We don't wont to restrict our future selves. - - When a write model will be needed, it will be implemented - - The we don't have an `attributes` property is to prevent API confusion - Examples of confusion: - * What is the difference between `event.get("myattr")` and - `event.attributes.get("myattr")` - * What SHOULD I use `event["myattr"]` or `event.attributes["myattr"]` ? """ raise NotImplementedError() @property - def _data_read_model(self) -> typing.Optional[typing.Any]: + def data(self) -> typing.Optional[typing.Any]: """ :return: Data value of the event. You MUST NOT mutate this dict. Implementation MAY assume the dict will not be mutated. - - The reason this is only a read model and not a write model is - because you MAY not have an easy write access to the data. - - For example - a database row or a cached value. - - We don't wont to restrict our future selves. - - When a write model will be needed, it will be implemented - """ raise NotImplementedError() def __eq__(self, other: typing.Any) -> bool: if isinstance(other, CloudEvent): - return ( - self._data_read_model == other._data_read_model - and self._attributes_read_model == other._attributes_read_model - ) + return self.data == other.data and self.attributes == other.attributes return False def __getitem__(self, key: str) -> typing.Any: @@ -84,7 +56,7 @@ class CloudEvent: :param key: The event attribute name. :return: The event attribute value. """ - return self._attributes_read_model[key] + return self.attributes[key] def get( self, key: str, default: typing.Optional[typing.Any] = None @@ -100,21 +72,19 @@ class CloudEvent: no attribute with the given key exists. :returns: The event attribute value if exists, default value otherwise. """ - return self._attributes_read_model.get(key, default) + return self.attributes.get(key, default) def __iter__(self) -> typing.Iterator[typing.Any]: - return iter(self._attributes_read_model) + return iter(self.attributes) def __len__(self) -> int: - return len(self._attributes_read_model) + return len(self.attributes) def __contains__(self, key: str) -> bool: - return key in self._attributes_read_model + return key in self.attributes def __repr__(self) -> str: - return str( - {"attributes": self._attributes_read_model, "data": self._data_read_model} - ) + return str({"attributes": self.attributes, "data": self.data}) AnyCloudEvent = TypeVar("AnyCloudEvent", bound=CloudEvent) diff --git a/cloudevents/http/event.py b/cloudevents/http/event.py index bc91002..e55375f 100644 --- a/cloudevents/http/event.py +++ b/cloudevents/http/event.py @@ -52,7 +52,7 @@ class CloudEvent(abstract.CloudEvent): :type data: typing.Any """ self._attributes = {k.lower(): v for k, v in attributes.items()} - self.data = data + self._data = data if "specversion" not in self._attributes: self._attributes["specversion"] = "1.0" if "id" not in self._attributes: @@ -75,12 +75,20 @@ class CloudEvent(abstract.CloudEvent): ) @property - def _attributes_read_model(self) -> typing.Dict[str, typing.Any]: + def attributes(self) -> typing.Dict[str, typing.Any]: return self._attributes @property - def _data_read_model(self) -> typing.Optional[typing.Any]: - return self.data + def data(self) -> typing.Optional[typing.Any]: + return self._data + + @data.setter + def data(self, value) -> None: + """ + Exists for backwards compatibility + :param value: new data vale + """ + self._data = value def __setitem__(self, key: str, value: typing.Any) -> None: self._attributes[key] = value diff --git a/cloudevents/tests/test_abstract_cloudevent.py b/cloudevents/tests/test_abstract_cloudevent.py index 148222f..bd5bdb2 100644 --- a/cloudevents/tests/test_abstract_cloudevent.py +++ b/cloudevents/tests/test_abstract_cloudevent.py @@ -27,17 +27,17 @@ def test_create_is_abstract(): assert CloudEvent.create({}, None) is None -def test_data_read_is_abstract(): +def test_data_is_abstract(): """ exists mainly for coverage reasons """ with pytest.raises(NotImplementedError): - CloudEvent()._data_read_model + CloudEvent().data -def test_attributes_read_model_is_abstract(): +def test_attributes_is_abstract(): """ exists mainly for coverage reasons """ with pytest.raises(NotImplementedError): - CloudEvent()._attributes_read_model + CloudEvent().attributes