From 61cb627fdf8307be13468b50b64fbdaac0e9209a Mon Sep 17 00:00:00 2001 From: Grant Timmerman Date: Thu, 13 Aug 2020 10:54:35 -0500 Subject: [PATCH 1/5] docs: rename receiving cloudevents (#91) Signed-off-by: Grant Timmerman --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96d3bfe2..967b9a0e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ requests.post("", data=body, headers=headers) You can find a complete example of turning a CloudEvent into a HTTP request [in the samples directory](samples/http-json-cloudevents/client.py). -#### Request to CloudEvent +## Receiving CloudEvents The code below shows how to consume a cloudevent using the popular python web framework [flask](https://flask.palletsprojects.com/en/1.1.x/quickstart/): From 72b10bbc7f402bbd57c412b68b6f6e4e4cf87622 Mon Sep 17 00:00:00 2001 From: Doug Davis Date: Thu, 13 Aug 2020 11:56:31 -0400 Subject: [PATCH 2/5] add coc ref (#90) Signed-off-by: Doug Davis Co-authored-by: Curtis Mason <31265687+cumason123@users.noreply.github.com> --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 967b9a0e..22539ac1 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,17 @@ the same API. It will use semantic versioning with following rules: - Email: https://lists.cncf.io/g/cncf-cloudevents-sdk - Contact for additional information: Denis Makogon (`@denysmakogon` on slack). +Each SDK may have its own unique processes, tooling and guidelines, common +governance related material can be found in the +[CloudEvents `community`](https://github.com/cloudevents/spec/tree/master/community) +directory. In particular, in there you will find information concerning +how SDK projects are +[managed](https://github.com/cloudevents/spec/blob/master/community/SDK-GOVERNANCE.md), +[guidelines](https://github.com/cloudevents/spec/blob/master/community/SDK-maintainer-guidelines.md) +for how PR reviews and approval, and our +[Code of Conduct](https://github.com/cloudevents/spec/blob/master/community/GOVERNANCE.md#additional-information) +information. + ## Maintenance We use black and isort for autoformatting. We setup a tox environment to reformat From b5448b7657c16ca90ba6da8cd8c5d3a94110af31 Mon Sep 17 00:00:00 2001 From: Curtis Mason <31265687+cumason123@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:01:04 -0400 Subject: [PATCH 3/5] CloudEvents equality override (#98) * added tests to cloudevent eq Signed-off-by: Curtis Mason * lint fix Signed-off-by: Curtis Mason * modified changelog Signed-off-by: Curtis Mason * version bump Signed-off-by: Curtis Mason --- CHANGELOG.md | 5 ++ cloudevents/__init__.py | 2 +- cloudevents/http/event.py | 3 + .../tests/test_http_cloudevent_overrides.py | 71 +++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 cloudevents/tests/test_http_cloudevent_overrides.py diff --git a/CHANGELOG.md b/CHANGELOG.md index aa8f3a11..8a66cf3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.1] +### Added +- CloudEvent equality override ([#98]) + ## [1.0.0] ### Added - Added a user friendly CloudEvent class with data validation ([#36]) @@ -77,3 +81,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#36]: https://github.com/cloudevents/sdk-python/pull/36 [#43]: https://github.com/cloudevents/sdk-python/pull/43 [#47]: https://github.com/cloudevents/sdk-python/pull/47 +[#98]: https://github.com/cloudevents/sdk-python/pull/98 \ No newline at end of file diff --git a/cloudevents/__init__.py b/cloudevents/__init__.py index 5becc17c..5c4105cd 100644 --- a/cloudevents/__init__.py +++ b/cloudevents/__init__.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "1.0.1" diff --git a/cloudevents/http/event.py b/cloudevents/http/event.py index a31b894b..9cb4400e 100644 --- a/cloudevents/http/event.py +++ b/cloudevents/http/event.py @@ -68,6 +68,9 @@ def __init__( f"Missing required keys: {required_set - attributes.keys()}" ) + def __eq__(self, other): + return self.data == other.data and self._attributes == other._attributes + # Data access is handled via `.data` member # Attribute access is managed via Mapping type def __getitem__(self, key): diff --git a/cloudevents/tests/test_http_cloudevent_overrides.py b/cloudevents/tests/test_http_cloudevent_overrides.py new file mode 100644 index 00000000..1babbe21 --- /dev/null +++ b/cloudevents/tests/test_http_cloudevent_overrides.py @@ -0,0 +1,71 @@ +import pytest + +from cloudevents.http import CloudEvent + + +@pytest.mark.parametrize("specversion", ["0.3", "1.0"]) +def test_http_cloudevent_equality(specversion): + attributes = { + "source": "", + "specversion": specversion, + "id": "my-id", + "time": "tomorrow", + "type": "tests.cloudevents.override", + "datacontenttype": "application/json", + "subject": "my-subject", + } + data = '{"name":"john"}' + event1 = CloudEvent(attributes, data) + event2 = CloudEvent(attributes, data) + assert event1 == event2 + # Test different attributes + for key in attributes: + if key == "specversion": + continue + else: + attributes[key] = f"noise-{key}" + event3 = CloudEvent(attributes, data) + event2 = CloudEvent(attributes, data) + assert event2 == event3 + assert event1 != event2 and event3 != event1 + + # Test different data + data = '{"name":"paul"}' + event3 = CloudEvent(attributes, data) + event2 = CloudEvent(attributes, data) + assert event2 == event3 + assert event1 != event2 and event3 != event1 + + +@pytest.mark.parametrize("specversion", ["0.3", "1.0"]) +def test_http_cloudevent_mutates_equality(specversion): + attributes = { + "source": "", + "specversion": specversion, + "id": "my-id", + "time": "tomorrow", + "type": "tests.cloudevents.override", + "datacontenttype": "application/json", + "subject": "my-subject", + } + data = '{"name":"john"}' + event1 = CloudEvent(attributes, data) + event2 = CloudEvent(attributes, data) + event3 = CloudEvent(attributes, data) + + assert event1 == event2 + # Test different attributes + for key in attributes: + if key == "specversion": + continue + else: + event2[key] = f"noise-{key}" + event3[key] = f"noise-{key}" + assert event2 == event3 + assert event1 != event2 and event3 != event1 + + # Test different data + event2.data = '{"name":"paul"}' + event3.data = '{"name":"paul"}' + assert event2 == event3 + assert event1 != event2 and event3 != event1 From e1d043c3437d0f70e3a4e8ae10d3cd3753a48401 Mon Sep 17 00:00:00 2001 From: Curtis Mason <31265687+cumason123@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:43:28 -0400 Subject: [PATCH 4/5] cloudevent fields type checking adjustments (#97) * added exceptions and more indepth can_read Signed-off-by: Curtis Mason * moved is_binary, is_structured into http module Signed-off-by: Curtis Mason * changelog and version bump Signed-off-by: Curtis Mason * removed unused import and spacing Signed-off-by: Curtis Mason * lint fix Signed-off-by: Curtis Mason * reverted auto format change Signed-off-by: Curtis Mason * reverted changelog and auto format changes Signed-off-by: Curtis Mason --- cloudevents/exceptions.py | 19 +++++++++++ cloudevents/http/__init__.py | 1 + cloudevents/http/event.py | 5 +-- cloudevents/http/event_type.py | 29 ++++++++++++++++ cloudevents/http/http_methods.py | 14 +++++--- cloudevents/sdk/converters/__init__.py | 29 ---------------- cloudevents/sdk/converters/binary.py | 10 +++--- cloudevents/sdk/converters/structured.py | 9 ++--- cloudevents/sdk/converters/util.py | 10 ++++++ cloudevents/sdk/event/base.py | 26 +++++++++++---- cloudevents/tests/test_http_events.py | 42 ++++++++---------------- 11 files changed, 114 insertions(+), 80 deletions(-) create mode 100644 cloudevents/exceptions.py create mode 100644 cloudevents/http/event_type.py create mode 100644 cloudevents/sdk/converters/util.py diff --git a/cloudevents/exceptions.py b/cloudevents/exceptions.py new file mode 100644 index 00000000..5d2e191e --- /dev/null +++ b/cloudevents/exceptions.py @@ -0,0 +1,19 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +class CloudEventMissingRequiredFields(Exception): + pass + + +class CloudEventTypeErrorRequiredFields(Exception): + pass diff --git a/cloudevents/http/__init__.py b/cloudevents/http/__init__.py index 80fc5a74..d7c62ec4 100644 --- a/cloudevents/http/__init__.py +++ b/cloudevents/http/__init__.py @@ -15,6 +15,7 @@ import typing from cloudevents.http.event import CloudEvent +from cloudevents.http.event_type import is_binary, is_structured from cloudevents.http.http_methods import ( from_http, to_binary_http, diff --git a/cloudevents/http/event.py b/cloudevents/http/event.py index 9cb4400e..7354ae32 100644 --- a/cloudevents/http/event.py +++ b/cloudevents/http/event.py @@ -16,6 +16,7 @@ import typing import uuid +import cloudevents.exceptions as cloud_exceptions from cloudevents.http.mappings import _required_by_version @@ -57,14 +58,14 @@ def __init__( ).isoformat() if self._attributes["specversion"] not in _required_by_version: - raise ValueError( + raise cloud_exceptions.CloudEventMissingRequiredFields( f"Invalid specversion: {self._attributes['specversion']}" ) # There is no good way to default 'source' and 'type', so this # checks for those (or any new required attributes). required_set = _required_by_version[self._attributes["specversion"]] if not required_set <= self._attributes.keys(): - raise ValueError( + raise cloud_exceptions.CloudEventMissingRequiredFields( f"Missing required keys: {required_set - attributes.keys()}" ) diff --git a/cloudevents/http/event_type.py b/cloudevents/http/event_type.py new file mode 100644 index 00000000..fe6c0268 --- /dev/null +++ b/cloudevents/http/event_type.py @@ -0,0 +1,29 @@ +import typing + +from cloudevents.sdk.converters import binary, structured + + +def is_binary(headers: typing.Dict[str, str]) -> bool: + """Uses internal marshallers to determine whether this event is binary + :param headers: the HTTP headers + :type headers: typing.Dict[str, str] + :returns bool: returns a bool indicating whether the headers indicate a binary event type + """ + headers = {key.lower(): value for key, value in headers.items()} + content_type = headers.get("content-type", "") + binary_parser = binary.BinaryHTTPCloudEventConverter() + return binary_parser.can_read(content_type=content_type, headers=headers) + + +def is_structured(headers: typing.Dict[str, str]) -> bool: + """Uses internal marshallers to determine whether this event is structured + :param headers: the HTTP headers + :type headers: typing.Dict[str, str] + :returns bool: returns a bool indicating whether the headers indicate a structured event type + """ + headers = {key.lower(): value for key, value in headers.items()} + content_type = headers.get("content-type", "") + structured_parser = structured.JSONHTTPCloudEventConverter() + return structured_parser.can_read( + content_type=content_type, headers=headers + ) diff --git a/cloudevents/http/http_methods.py b/cloudevents/http/http_methods.py index 113e1969..6f7b68d9 100644 --- a/cloudevents/http/http_methods.py +++ b/cloudevents/http/http_methods.py @@ -1,7 +1,9 @@ import json import typing +import cloudevents.exceptions as cloud_exceptions from cloudevents.http.event import CloudEvent +from cloudevents.http.event_type import is_binary, is_structured from cloudevents.http.mappings import _marshaller_by_format, _obj_by_version from cloudevents.http.util import _json_or_string from cloudevents.sdk import converters, marshaller, types @@ -27,19 +29,23 @@ def from_http( marshall = marshaller.NewDefaultHTTPMarshaller() - if converters.is_binary(headers): + if is_binary(headers): specversion = headers.get("ce-specversion", None) else: raw_ce = json.loads(data) specversion = raw_ce.get("specversion", None) if specversion is None: - raise ValueError("could not find specversion in HTTP request") + raise cloud_exceptions.CloudEventMissingRequiredFields( + "could not find specversion in HTTP request" + ) event_handler = _obj_by_version.get(specversion, None) if event_handler is None: - raise ValueError(f"found invalid specversion {specversion}") + raise cloud_exceptions.CloudEventTypeErrorRequiredFields( + f"found invalid specversion {specversion}" + ) event = marshall.FromRequest( event_handler(), headers, data, data_unmarshaller=data_unmarshaller @@ -71,7 +77,7 @@ def _to_http( data_marshaller = _marshaller_by_format[format] if event._attributes["specversion"] not in _obj_by_version: - raise ValueError( + raise cloud_exceptions.CloudEventTypeErrorRequiredFields( f"Unsupported specversion: {event._attributes['specversion']}" ) diff --git a/cloudevents/sdk/converters/__init__.py b/cloudevents/sdk/converters/__init__.py index 289cfab4..936e8084 100644 --- a/cloudevents/sdk/converters/__init__.py +++ b/cloudevents/sdk/converters/__init__.py @@ -11,36 +11,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. - -import typing - from cloudevents.sdk.converters import binary, structured TypeBinary = binary.BinaryHTTPCloudEventConverter.TYPE TypeStructured = structured.JSONHTTPCloudEventConverter.TYPE - - -def is_binary(headers: typing.Dict[str, str]) -> bool: - """Uses internal marshallers to determine whether this event is binary - :param headers: the HTTP headers - :type headers: typing.Dict[str, str] - :returns bool: returns a bool indicating whether the headers indicate a binary event type - """ - headers = {key.lower(): value for key, value in headers.items()} - content_type = headers.get("content-type", "") - binary_parser = binary.BinaryHTTPCloudEventConverter() - return binary_parser.can_read(content_type=content_type, headers=headers) - - -def is_structured(headers: typing.Dict[str, str]) -> bool: - """Uses internal marshallers to determine whether this event is structured - :param headers: the HTTP headers - :type headers: typing.Dict[str, str] - :returns bool: returns a bool indicating whether the headers indicate a structured event type - """ - headers = {key.lower(): value for key, value in headers.items()} - content_type = headers.get("content-type", "") - structured_parser = structured.JSONHTTPCloudEventConverter() - return structured_parser.can_read( - content_type=content_type, headers=headers - ) diff --git a/cloudevents/sdk/converters/binary.py b/cloudevents/sdk/converters/binary.py index 46277727..e45b9471 100644 --- a/cloudevents/sdk/converters/binary.py +++ b/cloudevents/sdk/converters/binary.py @@ -16,7 +16,7 @@ from cloudevents.sdk import exceptions, types from cloudevents.sdk.converters import base -from cloudevents.sdk.converters.structured import JSONHTTPCloudEventConverter +from cloudevents.sdk.converters.util import has_binary_headers from cloudevents.sdk.event import base as event_base from cloudevents.sdk.event import v1, v03 @@ -28,13 +28,11 @@ class BinaryHTTPCloudEventConverter(base.Converter): def can_read( self, - content_type: str, + content_type: str = None, headers: typing.Dict[str, str] = {"ce-specversion": None}, ) -> bool: - return ("ce-specversion" in headers) and not ( - isinstance(content_type, str) - and content_type.startswith(JSONHTTPCloudEventConverter.MIME_TYPE) - ) + + return has_binary_headers(headers) def event_supported(self, event: object) -> bool: return type(event) in self.SUPPORTED_VERSIONS diff --git a/cloudevents/sdk/converters/structured.py b/cloudevents/sdk/converters/structured.py index d6ba6548..c147042e 100644 --- a/cloudevents/sdk/converters/structured.py +++ b/cloudevents/sdk/converters/structured.py @@ -16,23 +16,24 @@ from cloudevents.sdk import types from cloudevents.sdk.converters import base +from cloudevents.sdk.converters.util import has_binary_headers from cloudevents.sdk.event import base as event_base +# TODO: Singleton? class JSONHTTPCloudEventConverter(base.Converter): TYPE = "structured" MIME_TYPE = "application/cloudevents+json" def can_read( - self, - content_type: str, - headers: typing.Dict[str, str] = {"ce-specversion": None}, + self, content_type: str, headers: typing.Dict[str, str] = {}, ) -> bool: return ( isinstance(content_type, str) and content_type.startswith(self.MIME_TYPE) - ) or ("ce-specversion" not in headers) + or not has_binary_headers(headers) + ) def event_supported(self, event: object) -> bool: # structured format supported by both spec 0.1 and 0.2 diff --git a/cloudevents/sdk/converters/util.py b/cloudevents/sdk/converters/util.py new file mode 100644 index 00000000..b31c39c8 --- /dev/null +++ b/cloudevents/sdk/converters/util.py @@ -0,0 +1,10 @@ +import typing + + +def has_binary_headers(headers: typing.Dict[str, str]) -> bool: + return ( + "ce-specversion" in headers + and "ce-source" in headers + and "ce-type" in headers + and "ce-id" in headers + ) diff --git a/cloudevents/sdk/event/base.py b/cloudevents/sdk/event/base.py index 2004dbbe..504bba4b 100644 --- a/cloudevents/sdk/event/base.py +++ b/cloudevents/sdk/event/base.py @@ -16,10 +16,12 @@ import json import typing +import cloudevents.exceptions as cloud_exceptions from cloudevents.sdk import types - # TODO(slinkydeveloper) is this really needed? + + class EventGetterSetter(object): # ce-specversion @@ -159,6 +161,9 @@ def content_type(self, value: str): class BaseEvent(EventGetterSetter): + _ce_required_fields = set() + _ce_optional_fields = set() + def Properties(self, with_nullable=False) -> dict: props = dict() for name, value in self.__dict__.items(): @@ -215,7 +220,9 @@ def UnmarshalJSON( missing_fields = self._ce_required_fields - raw_ce.keys() if len(missing_fields) > 0: - raise ValueError(f"Missing required attributes: {missing_fields}") + raise cloud_exceptions.CloudEventMissingRequiredFields( + f"Missing required attributes: {missing_fields}" + ) for name, value in raw_ce.items(): if name == "data": @@ -233,8 +240,16 @@ def UnmarshalBinary( body: typing.Union[bytes, str], data_unmarshaller: types.UnmarshallerType, ): - if "ce-specversion" not in headers: - raise ValueError("Missing required attribute: 'specversion'") + required_binary_fields = { + f"ce-{field}" for field in self._ce_required_fields + } + missing_fields = required_binary_fields - headers.keys() + + if len(missing_fields) > 0: + raise cloud_exceptions.CloudEventMissingRequiredFields( + f"Missing required attributes: {missing_fields}" + ) + for header, value in headers.items(): header = header.lower() if header == "content-type": @@ -242,9 +257,6 @@ def UnmarshalBinary( elif header.startswith("ce-"): self.Set(header[3:], value) self.Set("data", data_unmarshaller(body)) - missing_attrs = self._ce_required_fields - self.Properties().keys() - if len(missing_attrs) > 0: - raise ValueError(f"Missing required attributes: {missing_attrs}") def MarshalBinary( self, data_marshaller: types.MarshallerType diff --git a/cloudevents/tests/test_http_events.py b/cloudevents/tests/test_http_events.py index 883e01b8..b1819bfc 100644 --- a/cloudevents/tests/test_http_events.py +++ b/cloudevents/tests/test_http_events.py @@ -20,9 +20,11 @@ import pytest from sanic import Sanic, response +import cloudevents.exceptions as cloud_exceptions from cloudevents.http import ( CloudEvent, from_http, + is_binary, to_binary_http, to_structured_http, ) @@ -47,7 +49,7 @@ }, ] -invalid_cloudevent_request_bodie = [ +invalid_cloudevent_request_body = [ { "source": "", "type": "cloudevent.event.type", @@ -87,21 +89,22 @@ async def echo(request): return response.raw(data, headers={k: event[k] for k in event}) -@pytest.mark.parametrize("body", invalid_cloudevent_request_bodie) +@pytest.mark.parametrize("body", invalid_cloudevent_request_body) def test_missing_required_fields_structured(body): - with pytest.raises((TypeError, NotImplementedError)): + with pytest.raises(cloud_exceptions.CloudEventMissingRequiredFields): # CloudEvent constructor throws TypeError if missing required field # and NotImplementedError because structured calls aren't # implemented. In this instance one of the required keys should have # prefix e-id instead of ce-id therefore it should throw _ = from_http( - json.dumps(body), attributes={"Content-Type": "application/json"} + json.dumps(body), + headers={"Content-Type": "application/cloudevents+json"}, ) @pytest.mark.parametrize("headers", invalid_test_headers) def test_missing_required_fields_binary(headers): - with pytest.raises((ValueError)): + with pytest.raises(cloud_exceptions.CloudEventMissingRequiredFields): # CloudEvent constructor throws TypeError if missing required field # and NotImplementedError because structured calls aren't # implemented. In this instance one of the required keys should have @@ -165,7 +168,7 @@ def test_emit_structured_event(specversion): @pytest.mark.parametrize("specversion", ["1.0", "0.3"]) def test_roundtrip_non_json_event(converter, specversion): input_data = io.BytesIO() - for i in range(100): + for _ in range(100): for j in range(20): assert 1 == input_data.write(j.to_bytes(1, byteorder="big")) compressed_data = bz2.compress(input_data.getvalue()) @@ -201,7 +204,7 @@ def test_missing_ce_prefix_binary_event(specversion): # breaking prefix e.g. e-id instead of ce-id prefixed_headers[key[1:]] = headers[key] - with pytest.raises(ValueError): + with pytest.raises(cloud_exceptions.CloudEventMissingRequiredFields): # CloudEvent constructor throws TypeError if missing required field # and NotImplementedError because structured calls aren't # implemented. In this instance one of the required keys should have @@ -278,7 +281,7 @@ def test_empty_data_structured_event(specversion): # Testing if cloudevent breaks when no structured data field present attributes = { "specversion": specversion, - "datacontenttype": "application/json", + "datacontenttype": "application/cloudevents+json", "type": "word.found.name", "id": "96fb5f0b-001e-0108-6dfe-da6e2806f124", "time": "2018-10-23T12:28:22.4579346Z", @@ -308,7 +311,6 @@ def test_empty_data_binary_event(specversion): def test_valid_structured_events(specversion): # Test creating multiple cloud events events_queue = [] - headers = {} num_cloudevents = 30 for i in range(num_cloudevents): event = { @@ -335,9 +337,6 @@ def test_valid_structured_events(specversion): @pytest.mark.parametrize("specversion", ["1.0", "0.3"]) def test_structured_no_content_type(specversion): # Test creating multiple cloud events - events_queue = [] - headers = {} - num_cloudevents = 30 data = { "id": "id", "source": "source.com.test", @@ -362,28 +361,15 @@ def test_is_binary(): "ce-specversion": "1.0", "Content-Type": "text/plain", } - assert converters.is_binary(headers) - - headers = { - "Content-Type": "application/cloudevents+json", - } - assert not converters.is_binary(headers) - - headers = {} - assert not converters.is_binary(headers) - + assert is_binary(headers) -def test_is_structured(): headers = { "Content-Type": "application/cloudevents+json", } - assert converters.is_structured(headers) + assert not is_binary(headers) headers = {} - assert converters.is_structured(headers) - - headers = {"ce-specversion": "1.0"} - assert not converters.is_structured(headers) + assert not is_binary(headers) @pytest.mark.parametrize("specversion", ["1.0", "0.3"]) From b43ae567476494743555cb68660b48c3d779c9bd Mon Sep 17 00:00:00 2001 From: Curtis Mason <31265687+cumason123@users.noreply.github.com> Date: Thu, 13 Aug 2020 17:06:15 -0400 Subject: [PATCH 5/5] changelog 1.0.1 update (#101) Signed-off-by: Curtis Mason --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a66cf3e..7901b024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.1] ### Added +- CloudEvent exceptions and event type checking in http module ([#96]) - CloudEvent equality override ([#98]) ## [1.0.0] ### Added +- Update types and handle data_base64 structured ([#34]) - Added a user friendly CloudEvent class with data validation ([#36]) - CloudEvent structured cloudevent support ([#47]) +- Separated http methods into cloudevents.http module ([#60]) +- Implemented to_json and from_json in http module ([#72]) + +### Fixed +- Fixed top level extensions bug ([#71]) ### Removed - Removed support for Cloudevents V0.2 and V0.1 ([#43]) @@ -78,7 +85,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#23]: https://github.com/cloudevents/sdk-python/pull/23 [#25]: https://github.com/cloudevents/sdk-python/pull/25 [#27]: https://github.com/cloudevents/sdk-python/pull/27 +[#34]: https://github.com/cloudevents/sdk-python/pull/34 [#36]: https://github.com/cloudevents/sdk-python/pull/36 [#43]: https://github.com/cloudevents/sdk-python/pull/43 [#47]: https://github.com/cloudevents/sdk-python/pull/47 +[#60]: https://github.com/cloudevents/sdk-python/pull/60 +[#71]: https://github.com/cloudevents/sdk-python/pull/71 +[#72]: https://github.com/cloudevents/sdk-python/pull/72 +[#96]: https://github.com/cloudevents/sdk-python/pull/96 [#98]: https://github.com/cloudevents/sdk-python/pull/98 \ No newline at end of file