diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd350db8..ebe8887a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: isort args: [ "--profile", "black", "--filter-files" ] - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 22.10.0 hooks: - id: black language_version: python3.10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 12184bb1..7c7a85e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.6.2] — 2022-10-18 +### Added +- Added `get_attributes` API to the `CloudEvent` API. The method returns a read-only + view on the event attributes. ([#195]) + ## [1.6.1] — 2022-08-18 ### Fixed - Missing `to_json` import. ([#191]) @@ -146,6 +151,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.0.1] - 2018-11-19 ### Added - Initial release + +[1.6.2]: https://github.com/cloudevents/sdk-python/compare/1.6.1...1.6.2 [1.6.1]: https://github.com/cloudevents/sdk-python/compare/1.6.0...1.6.1 [1.6.0]: https://github.com/cloudevents/sdk-python/compare/1.5.0...1.6.0 [1.5.0]: https://github.com/cloudevents/sdk-python/compare/1.4.0...1.5.0 @@ -210,3 +217,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#186]: https://github.com/cloudevents/sdk-python/pull/186 [#188]: https://github.com/cloudevents/sdk-python/pull/188 [#191]: https://github.com/cloudevents/sdk-python/pull/191 +[#195]: https://github.com/cloudevents/sdk-python/pull/195 diff --git a/cloudevents/__init__.py b/cloudevents/__init__.py index c5503ec3..e74d8c07 100644 --- a/cloudevents/__init__.py +++ b/cloudevents/__init__.py @@ -12,4 +12,4 @@ # License for the specific language governing permissions and limitations # under the License. -__version__ = "1.6.1" +__version__ = "1.6.2" diff --git a/cloudevents/abstract/event.py b/cloudevents/abstract/event.py index 13e50397..19e1391b 100644 --- a/cloudevents/abstract/event.py +++ b/cloudevents/abstract/event.py @@ -14,6 +14,8 @@ import typing from abc import abstractmethod +from types import MappingProxyType +from typing import Mapping class CloudEvent: @@ -45,6 +47,14 @@ def create( """ raise NotImplementedError() + def get_attributes(self) -> Mapping[str, typing.Any]: + """ + Returns a read-only view on the attributes of the event. + + :returns: Read-only view on the attributes of the event. + """ + return MappingProxyType(self._get_attributes()) + @abstractmethod def _get_attributes(self) -> typing.Dict[str, typing.Any]: """ diff --git a/cloudevents/tests/test_http_events.py b/cloudevents/tests/test_http_events.py index 34f78089..b21c3729 100644 --- a/cloudevents/tests/test_http_events.py +++ b/cloudevents/tests/test_http_events.py @@ -15,6 +15,7 @@ import bz2 import io import json +import typing import pytest from sanic import Sanic, response @@ -83,7 +84,6 @@ async def echo(request): @pytest.mark.parametrize("body", invalid_cloudevent_request_body) def test_missing_required_fields_structured(body): with pytest.raises(cloud_exceptions.MissingRequiredFields): - _ = from_http( {"Content-Type": "application/cloudevents+json"}, json.dumps(body) ) @@ -188,7 +188,6 @@ def test_missing_ce_prefix_binary_event(specversion): "ce-specversion": specversion, } for key in headers: - # breaking prefix e.g. e-id instead of ce-id prefixed_headers[key[1:]] = headers[key] @@ -245,6 +244,25 @@ def test_structured_to_request(specversion): assert body["data"] == data, f"|{body_bytes}|| {body}" +@pytest.mark.parametrize("specversion", ["1.0", "0.3"]) +def test_attributes_view_accessor(specversion: str): + attributes: dict[str, typing.Any] = { + "specversion": specversion, + "type": "word.found.name", + "id": "96fb5f0b-001e-0108-6dfe-da6e2806f124", + "source": "pytest", + } + data = {"message": "Hello World!"} + + event: CloudEvent = CloudEvent(attributes, data) + event_attributes: typing.Mapping[str, typing.Any] = event.get_attributes() + assert event_attributes["specversion"] == attributes["specversion"] + assert event_attributes["type"] == attributes["type"] + assert event_attributes["id"] == attributes["id"] + assert event_attributes["source"] == attributes["source"] + assert event_attributes["time"] + + @pytest.mark.parametrize("specversion", ["1.0", "0.3"]) def test_binary_to_request(specversion): attributes = { diff --git a/cloudevents/tests/test_pydantic_events.py b/cloudevents/tests/test_pydantic_events.py index c0ed37c0..4195fdb6 100644 --- a/cloudevents/tests/test_pydantic_events.py +++ b/cloudevents/tests/test_pydantic_events.py @@ -15,6 +15,7 @@ import bz2 import io import json +import typing import pytest from sanic import Sanic, response @@ -242,6 +243,25 @@ def test_structured_to_request(specversion): assert body["data"] == data, f"|{body_bytes}|| {body}" +@pytest.mark.parametrize("specversion", ["1.0", "0.3"]) +def test_attributes_view_accessor(specversion: str): + attributes: dict[str, typing.Any] = { + "specversion": specversion, + "type": "word.found.name", + "id": "96fb5f0b-001e-0108-6dfe-da6e2806f124", + "source": "pytest", + } + data = {"message": "Hello World!"} + + event: CloudEvent = CloudEvent(attributes, data) + event_attributes: typing.Mapping[str, typing.Any] = event.get_attributes() + assert event_attributes["specversion"] == attributes["specversion"] + assert event_attributes["type"] == attributes["type"] + assert event_attributes["id"] == attributes["id"] + assert event_attributes["source"] == attributes["source"] + assert event_attributes["time"] + + @pytest.mark.parametrize("specversion", ["1.0", "0.3"]) def test_binary_to_request(specversion): attributes = {