From c0be246cbc809b4fca04b28cd65cf9003fb918aa Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 08:59:46 -0800 Subject: [PATCH 01/27] Kill Deserializer --- sdk/eventgrid/azure-eventgrid/CHANGELOG.md | 4 +- sdk/eventgrid/azure-eventgrid/README.md | 59 --------------- .../azure/eventgrid/__init__.py | 6 +- .../azure/eventgrid/_consumer.py | 68 ----------------- .../azure-eventgrid/migration_guide.md | 18 ----- .../azure-eventgrid/tests/test_eg_consumer.py | 73 ------------------- 6 files changed, 3 insertions(+), 225 deletions(-) delete mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_consumer.py delete mode 100644 sdk/eventgrid/azure-eventgrid/tests/test_eg_consumer.py diff --git a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md index ab2633b61902..ad24b8b49ea0 100644 --- a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md +++ b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md @@ -4,13 +4,11 @@ **Breaking Changes** - `EventGridSharedAccessSignatureCredential` is deprecated in favor of `AzureSasCredential`. - - `EventGridConsumer` is now renamed to `EventGridDeserializer`. - - `decode_cloud_event` is renamed to `deserialize_cloud_events`. - - `decode_eventgrid_event` is renamed to `deserialize_eventgrid_events`. - `azure.eventgrid.models` namespace along with all the models in it are now removed. `azure.eventgrid.SystemEventMappings` can be used to get the event model type mapping. - `topic_hostname` is renamed to `endpoint` in the `EventGridPublisherClient`. - `data` is now a required param for `CloudEvent`. - `azure.eventgrid.generate_shared_access_signature` method is now renamed to `generate_sas`. + - `EventGridConsumer`is now removed. Please see the samples to see how events can be deserialized. **Bug Fixes** - `EventGridEvent` has two additional required positional parameters namely, `data` and `data_version`. diff --git a/sdk/eventgrid/azure-eventgrid/README.md b/sdk/eventgrid/azure-eventgrid/README.md index 69cfb853a7f9..81361f7643e1 100644 --- a/sdk/eventgrid/azure-eventgrid/README.md +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -62,9 +62,6 @@ Information about the key concepts on Event Grid, see [Concepts in Azure Event G `EventGridPublisherClient` provides operations to send event data to topic hostname specified during client initialization. Either a list or a single instance of CloudEvent/EventGridEvent/CustomEvent can be sent. -### EventGridDeserializer -`EventGridDeserializer` is used to desrialize an event received. - ## Examples The following sections provide several code snippets covering some of the most common Event Grid tasks, including: @@ -123,62 +120,6 @@ client = EventGridPublisherClient(endpoint, credential) client.send(event) ``` -### Consume an Event Grid Event - -This example demonstrates consuming and deserializing an eventgrid event. - -```Python -import os -from azure.eventgrid import EventGridDeserializer - -consumer = EventGridDeserializer() - -eg_storage_dict = { - "id":"bbab625-dc56-4b22-abeb-afcc72e5290c", - "subject":"/blobServices/default/containers/oc2d2817345i200097container/blobs/oc2d2817345i20002296blob", - "data":{ - "api":"PutBlockList", - }, - "eventType":"Microsoft.Storage.BlobCreated", - "dataVersion":"2.0", - "metadataVersion":"1", - "eventTime":"2020-08-07T02:28:23.867525Z", - "topic":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.EventGrid/topics/eventgridegsub" -} - -deserialized_event = consumer.deserialize_eventgrid_events(eg_storage_dict) - -# both allow access to raw properties as strings -time_string = deserialized_event.event_time -``` - -### Consume a Cloud Event - -This example demonstrates consuming and deserializing a cloud event. - -```Python -import os -from azure.eventgrid import EventGridDeserializer - -consumer = EventGridDeserializer() - -cloud_storage_dict = { - "id":"a0517898-9fa4-4e70-b4a3-afda1dd68672", - "source":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-account}", - "data":{ - "api":"PutBlockList", - }, - "type":"Microsoft.Storage.BlobCreated", - "time":"2020-08-07T01:11:49.765846Z", - "specversion":"1.0" -} - -deserialized_event = consumer.deserialize_cloud_events(cloud_storage_dict) - -# both allow access to raw properties as strings -time_string = deserialized_event.time -``` - ## Troubleshooting - Enable `azure.eventgrid` logger to collect traces from the library. diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py index 9b31b705f32c..3de9b3db4702 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py @@ -5,14 +5,12 @@ # -------------------------------------------------------------------------- from ._publisher_client import EventGridPublisherClient -from ._consumer import EventGridDeserializer from ._event_mappings import SystemEventMappings from ._helpers import generate_sas from ._models import CloudEvent, CustomEvent, EventGridEvent from ._version import VERSION -__all__ = ['EventGridPublisherClient', 'EventGridDeserializer', - 'CloudEvent', 'CustomEvent', 'EventGridEvent', 'generate_sas', - 'SystemEventMappings' +__all__ = ['EventGridPublisherClient', 'CloudEvent', 'CustomEvent', + 'EventGridEvent', 'generate_sas', 'SystemEventMappings' ] __version__ = VERSION diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_consumer.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_consumer.py deleted file mode 100644 index 9246457378c1..000000000000 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_consumer.py +++ /dev/null @@ -1,68 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from typing import cast, TYPE_CHECKING -import logging -from ._models import CloudEvent, EventGridEvent - -if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports - from typing import Any, Union - -_LOGGER = logging.getLogger(__name__) - -class EventGridDeserializer(object): - """ - A consumer responsible for deserializing event handler messages, to allow for - access to strongly typed Event objects. - """ - def deserialize_cloud_events(self, cloud_event, **kwargs): # pylint: disable=no-self-use - # type: (Union[str, dict, bytes], Any) -> CloudEvent - """Single event following CloudEvent schema will be parsed and returned as Deserialized Event. - Use `.data` to get the data in the raw format. To check the list of recognizable system topics, - visit https://docs.microsoft.com/azure/event-grid/system-topics. - - :param cloud_event: The event to be deserialized. - :type cloud_event: Union[str, dict, bytes] - :rtype: CloudEvent - - :raise: :class:`ValueError`, when events do not follow CloudEvent schema. - """ - encode = kwargs.pop('encoding', 'utf-8') - try: - cloud_event = CloudEvent._from_json(cloud_event, encode) # pylint: disable=protected-access - deserialized_event = CloudEvent._from_generated(cloud_event) # pylint: disable=protected-access - return deserialized_event - except Exception as err: - _LOGGER.error('Your event: %s', cloud_event) - _LOGGER.error(err) - raise ValueError('Error: cannot deserialize event. Event does not have a valid format. \ - Event must be a string, dict, or bytes following the CloudEvent schema.') - - def deserialize_eventgrid_events(self, eventgrid_event, **kwargs): # pylint: disable=no-self-use - # type: (Union[str, dict, bytes], Any) -> EventGridEvent - """Single event following EventGridEvent schema will be parsed and returned as Deserialized Event. - Use `.data` to get the data in the raw format. To check the list of recognizable system topics, - visit https://docs.microsoft.com/azure/event-grid/system-topics. - - :param eventgrid_event: The event to be deserialized. - :type eventgrid_event: Union[str, dict, bytes] - :rtype: EventGridEvent - - :raise: :class:`ValueError`, when events do not follow EventGridEvent schema. - """ - encode = kwargs.pop('encoding', 'utf-8') - try: - eventgrid_event = EventGridEvent._from_json(eventgrid_event, encode) # pylint: disable=protected-access - deserialized_event = EventGridEvent.deserialize(eventgrid_event) - return cast(EventGridEvent, deserialized_event) - except Exception as err: - _LOGGER.error('Your event: %s', eventgrid_event) - _LOGGER.error(err) - raise ValueError('Error: cannot deserialize event. Event does not have a valid format. \ - Event must be a string, dict, or bytes following the CloudEvent schema.') diff --git a/sdk/eventgrid/azure-eventgrid/migration_guide.md b/sdk/eventgrid/azure-eventgrid/migration_guide.md index 7f6e285f5403..a6349e21961e 100644 --- a/sdk/eventgrid/azure-eventgrid/migration_guide.md +++ b/sdk/eventgrid/azure-eventgrid/migration_guide.md @@ -65,14 +65,6 @@ cloud_event = { |---|---|---| |`EventGridClient(credentials)`|`EventGridPublisherClient(endpoint, credential)`|[Sample for client construction](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs5_publish_events_using_cloud_events_1.0_schema.py)| -* Additionally, we now have an `EventGridDeserializer` that should be used to deserialize the events. This class is used only to decode data into a `CloudEvent` or an `EventGridEvent`. Hence, there are no credentials required to construct this as shown below. - -```Python -from azure.eventgrid import EventGridDeserializer - -eg_consumer = EventGridDeserializer() -``` - ### Publishing Events The `publish_events` API is replaced with `send` in v2.0. Additionally, `send` API accepts `CloudEvent`, `CustomEvent` along with `EventGridEvent` @@ -81,16 +73,6 @@ The `publish_events` API is replaced with `send` in v2.0. Additionally, `send` A |---|---|---| |`EventGridClient(credentials).publish_events(topic_hostname, events)`|`EventGridPublisherClient(endpoint, credential).send(events)`|[Sample for client construction](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs5_publish_events_using_cloud_events_1.0_schema.py)| -### Consuming Events - -In v2.0, `EventGridDeserializer` can be used to decode both Cloud Events and EventGrid Events. Please find the samples [here](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventgrid/azure-eventgrid/samples/consume_samples) to see detailed examples of the consumer. - -```Python -EventGridDeserializer().deserialize_cloud_events(cloud_event_dict) - -EventGridDeserializer().deserialize_eventgrid_events(eventgrid_event_dict) -``` - ## Additional samples More examples can be found at [here](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventgrid/azure-eventgrid/samples) diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_consumer.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_consumer.py deleted file mode 100644 index 16ff5cc68e70..000000000000 --- a/sdk/eventgrid/azure-eventgrid/tests/test_eg_consumer.py +++ /dev/null @@ -1,73 +0,0 @@ -#------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -#-------------------------------------------------------------------------- - -import logging -import sys -import os -import pytest -import json -import datetime as dt - -from devtools_testutils import AzureMgmtTestCase -from msrest.serialization import UTC -from azure.eventgrid import EventGridDeserializer, CloudEvent, EventGridEvent -from _mocks import ( - cloud_storage_dict, - cloud_storage_string, - cloud_storage_bytes, - cloud_custom_dict, - cloud_custom_string, - cloud_custom_bytes, - eg_custom_dict, - eg_custom_string, - eg_custom_bytes, - eg_storage_dict, - eg_storage_string, - eg_storage_bytes - ) - -class EventGridDeserializerTests(AzureMgmtTestCase): - - # Cloud Event tests - def test_eg_consumer_cloud_storage_dict(self, **kwargs): - client = EventGridDeserializer() - deserialized_event = client.deserialize_cloud_events(cloud_storage_dict) - assert deserialized_event.__class__ == CloudEvent - assert deserialized_event.data.__class__ == dict - - def test_eg_consumer_cloud_storage_string(self, **kwargs): - client = EventGridDeserializer() - deserialized_event = client.deserialize_cloud_events(cloud_storage_string) - assert deserialized_event.__class__ == CloudEvent - assert deserialized_event.data.__class__ == dict - - def test_eg_consumer_cloud_storage_bytes(self, **kwargs): - client = EventGridDeserializer() - deserialized_event = client.deserialize_cloud_events(cloud_storage_bytes) - assert deserialized_event.__class__ == CloudEvent - assert deserialized_event.data.__class__ == dict - - # EG Event tests - - def test_eg_consumer_eg_storage_dict(self, **kwargs): - client = EventGridDeserializer() - deserialized_event = client.deserialize_eventgrid_events(eg_storage_dict) - assert deserialized_event.__class__ == EventGridEvent - assert deserialized_event.data.__class__ == dict - - - def test_eg_consumer_eg_storage_string(self, **kwargs): - client = EventGridDeserializer() - deserialized_event = client.deserialize_eventgrid_events(eg_storage_string) - assert deserialized_event.__class__ == EventGridEvent - assert deserialized_event.data.__class__ == dict - - - def test_eg_consumer_eg_storage_bytes(self, **kwargs): - client = EventGridDeserializer() - deserialized_event = client.deserialize_eventgrid_events(eg_storage_bytes) - assert deserialized_event.__class__ == EventGridEvent - assert deserialized_event.data.__class__ == dict From 56e3980a2eb6535486caa05618e168400e51a2d9 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 09:08:47 -0800 Subject: [PATCH 02/27] kill cuatom events --- sdk/eventgrid/azure-eventgrid/README.md | 2 +- .../azure/eventgrid/__init__.py | 4 +- .../azure/eventgrid/_models.py | 15 ----- .../azure/eventgrid/_publisher_client.py | 9 +-- .../azure/eventgrid/_shared/__init__.py | 8 --- .../azure/eventgrid/_shared/mixins.py | 58 ------------------- .../eventgrid/aio/_publisher_client_async.py | 9 +-- .../tests/test_eg_publisher_client.py | 11 ++-- .../tests/test_eg_publisher_client_async.py | 12 ++-- 9 files changed, 15 insertions(+), 113 deletions(-) delete mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/__init__.py delete mode 100644 sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/mixins.py diff --git a/sdk/eventgrid/azure-eventgrid/README.md b/sdk/eventgrid/azure-eventgrid/README.md index 81361f7643e1..206dc9c8f289 100644 --- a/sdk/eventgrid/azure-eventgrid/README.md +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -60,7 +60,7 @@ Information about the key concepts on Event Grid, see [Concepts in Azure Event G ### EventGridPublisherClient `EventGridPublisherClient` provides operations to send event data to topic hostname specified during client initialization. -Either a list or a single instance of CloudEvent/EventGridEvent/CustomEvent can be sent. +Either a list or a single instance of CloudEvent/EventGridEvent can be sent.liAlternatively, a lis or a single instance of the dict representation of CloudEvent/EventGridEvent or a Custom Schema can also be published. ## Examples diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py index 3de9b3db4702..debf1df65b69 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py @@ -7,10 +7,10 @@ from ._publisher_client import EventGridPublisherClient from ._event_mappings import SystemEventMappings from ._helpers import generate_sas -from ._models import CloudEvent, CustomEvent, EventGridEvent +from ._models import CloudEvent, EventGridEvent from ._version import VERSION -__all__ = ['EventGridPublisherClient', 'CloudEvent', 'CustomEvent', +__all__ = ['EventGridPublisherClient', 'CloudEvent', 'EventGridEvent', 'generate_sas', 'SystemEventMappings' ] __version__ = VERSION diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 4be822e73ee2..8d9a782154fb 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -10,7 +10,6 @@ import six from msrest.serialization import UTC from ._generated.models import EventGridEvent as InternalEventGridEvent, CloudEvent as InternalCloudEvent -from ._shared.mixins import DictMixin class EventMixin(object): @@ -221,17 +220,3 @@ def __init__(self, data, subject, event_type, data_version, **kwargs): kwargs.setdefault('data_version', data_version) super(EventGridEvent, self).__init__(**kwargs) - - -class CustomEvent(DictMixin): - """The wrapper class for a CustomEvent, to be used when publishing events. - :param dict args: dict - """ - - def __init__(self, *args, **kwargs): - # type: (Any, Any) -> None - self._update(*args, **kwargs) - - def _update(self, *args, **kwargs): - for k, v in dict(*args, **kwargs).items(): - self[k] = v diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py index 06cda52dc996..02fd405b1aa6 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_publisher_client.py @@ -22,7 +22,7 @@ UserAgentPolicy ) -from ._models import CloudEvent, EventGridEvent, CustomEvent +from ._models import CloudEvent, EventGridEvent from ._helpers import ( _get_endpoint_only_fqdn, _get_authentication_policy, @@ -41,18 +41,15 @@ SendType = Union[ CloudEvent, EventGridEvent, - CustomEvent, Dict, List[CloudEvent], List[EventGridEvent], - List[CustomEvent], List[Dict] ] ListEventType = Union[ List[CloudEvent], List[EventGridEvent], - List[CustomEvent], List[Dict] ] @@ -106,7 +103,7 @@ def send(self, events, **kwargs): inefficient to loop the send method for each event instead of just using a list and we highly recommend against it. - :param events: A list of CloudEvent/EventGridEvent/CustomEvent to be sent. + :param events: A list of CloudEvent/EventGridEvent to be sent. :type events: SendType :keyword str content_type: The type of content to be used to send the events. Has default value "application/json; charset=utf-8" for EventGridEvents, @@ -132,8 +129,6 @@ def send(self, events, **kwargs): if isinstance(events[0], EventGridEvent) or _is_eventgrid_event(events[0]): for event in events: _eventgrid_data_typecheck(event) - elif isinstance(events[0], CustomEvent): - events = [dict(e) for e in events] # type: ignore return self._client.publish_custom_event_events(self._endpoint, cast(List, events), **kwargs) def close(self): diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/__init__.py deleted file mode 100644 index 4897306df708..000000000000 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------- - -from .mixins import DictMixin -__all__ = ['DictMixin'] diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/mixins.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/mixins.py deleted file mode 100644 index 411fd236b681..000000000000 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_shared/mixins.py +++ /dev/null @@ -1,58 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- -# pylint:disable=protected-access - -class DictMixin(object): - - def __setitem__(self, key, item): - self.__dict__[key] = item - - def __getitem__(self, key): - return self.__dict__[key] - - def __contains__(self, key): - return key in self.__dict__ - - def __repr__(self): - return str(self) - - def __len__(self): - return len(self.keys()) - - def __delitem__(self, key): - self.__dict__[key] = None - - def __eq__(self, other): - """Compare objects by comparing all attributes.""" - if isinstance(other, self.__class__): - return self.__dict__ == other.__dict__ - return False - - def __ne__(self, other): - """Compare objects by comparing all attributes.""" - return not self.__eq__(other) - - def __str__(self): - return str({k: v for k, v in self.__dict__.items() if not k.startswith('_')}) - - def has_key(self, k): - return k in self.__dict__ - - def update(self, *args, **kwargs): - return self.__dict__.update(*args, **kwargs) - - def keys(self): - return [k for k in self.__dict__ if not k.startswith('_')] - - def values(self): - return [v for k, v in self.__dict__.items() if not k.startswith('_')] - - def items(self): - return [(k, v) for k, v in self.__dict__.items() if not k.startswith('_')] - - def get(self, key, default=None): - if key in self.__dict__: - return self.__dict__[key] - return default diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py index ac58142b78d2..cd485ff82ea4 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py @@ -23,7 +23,7 @@ UserAgentPolicy ) from .._policies import CloudEventDistributedTracingPolicy -from .._models import CloudEvent, EventGridEvent, CustomEvent +from .._models import CloudEvent, EventGridEvent from .._helpers import ( _get_endpoint_only_fqdn, _get_authentication_policy, @@ -38,18 +38,15 @@ SendType = Union[ CloudEvent, EventGridEvent, - CustomEvent, Dict, List[CloudEvent], List[EventGridEvent], - List[CustomEvent], List[Dict] ] ListEventType = Union[ List[CloudEvent], List[EventGridEvent], - List[CustomEvent], List[Dict] ] @@ -108,7 +105,7 @@ async def send( inefficient to loop the send method for each event instead of just using a list and we highly recommend against it. - :param events: A list of CloudEvent/EventGridEvent/CustomEvent to be sent. + :param events: A list of CloudEvent/EventGridEvent to be sent. :type events: SendType :keyword str content_type: The type of content to be used to send the events. Has default value "application/json; charset=utf-8" for EventGridEvents, @@ -134,8 +131,6 @@ async def send( if isinstance(events[0], EventGridEvent) or _is_eventgrid_event(events[0]): for event in events: _eventgrid_data_typecheck(event) - elif isinstance(events[0], CustomEvent): - events = [dict(e) for e in events] # type: ignore return await self._client.publish_custom_event_events(self._endpoint, cast(List, events), **kwargs) async def __aenter__(self) -> "EventGridPublisherClient": diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py index 3f578a4889f3..dc8f7ff64fb4 100644 --- a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py @@ -17,7 +17,7 @@ from azure_devtools.scenario_tests import ReplayableTest from azure.core.credentials import AzureKeyCredential, AzureSasCredential -from azure.eventgrid import EventGridPublisherClient, CloudEvent, EventGridEvent, CustomEvent, generate_sas +from azure.eventgrid import EventGridPublisherClient, CloudEvent, EventGridEvent, generate_sas from eventgrid_preparer import ( CachedEventGridTopicPreparer @@ -216,8 +216,7 @@ def test_send_signature_credential(self, resource_group, eventgrid_topic, eventg def test_send_custom_schema_event(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) - custom_event = CustomEvent( - { + custom_event = { "customSubject": "sample", "customEventType": "sample.event", "customDataVersion": "2.0", @@ -233,8 +232,7 @@ def test_send_custom_schema_event(self, resource_group, eventgrid_topic, eventgr def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) - custom_event1 = CustomEvent( - { + custom_event1 = { "customSubject": "sample", "customEventType": "sample.event", "customDataVersion": "2.0", @@ -243,8 +241,7 @@ def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, "customData": "sample data" } ) - custom_event2 = CustomEvent( - { + custom_event2 = { "customSubject": "sample2", "customEventType": "sample.event", "customDataVersion": "2.0", diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py index aca20a7c35e5..bcbd60c45f89 100644 --- a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py @@ -17,7 +17,7 @@ from azure_devtools.scenario_tests import ReplayableTest from azure.core.credentials import AzureKeyCredential, AzureSasCredential -from azure.eventgrid import CloudEvent, EventGridEvent, CustomEvent, generate_sas +from azure.eventgrid import CloudEvent, EventGridEvent, generate_sas from azure.eventgrid.aio import EventGridPublisherClient from eventgrid_preparer import ( @@ -234,8 +234,7 @@ async def test_send_signature_credential(self, resource_group, eventgrid_topic, async def test_send_custom_schema_event(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) - custom_event = CustomEvent( - { + custom_event = { "customSubject": "sample", "customEventType": "sample.event", "customDataVersion": "2.0", @@ -243,7 +242,6 @@ async def test_send_custom_schema_event(self, resource_group, eventgrid_topic, e "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data" } - ) await client.send(custom_event) @@ -253,8 +251,7 @@ async def test_send_custom_schema_event(self, resource_group, eventgrid_topic, e async def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) - custom_event1 = CustomEvent( - { + custom_event1 = { "customSubject": "sample", "customEventType": "sample.event", "customDataVersion": "2.0", @@ -263,8 +260,7 @@ async def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_ "customData": "sample data" } ) - custom_event2 = CustomEvent( - { + custom_event2 = { "customSubject": "sample2", "customEventType": "sample.event", "customDataVersion": "2.0", From bae007ddbc5df367035ac4c43e63e98bb3c7f706 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 15:20:44 -0800 Subject: [PATCH 03/27] cloud event --- .../azure/eventgrid/_models.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 8d9a782154fb..215224aea636 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -35,13 +35,16 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes """Properties of an event published to an Event Grid topic using the CloudEvent 1.0 Schema. All required parameters must be populated in order to send to Azure. + If data is of binary type, data_base64 can be used alternatively. Note that data and data_base64 + cannot be present at the same time. :param source: Required. Identifies the context in which an event happened. The combination of id and source must be unique for each distinct event. If publishing to a domain topic, source must be the domain name. :type source: str :param type: Required. Type of event related to the originating occurrence. :type type: str - :param data: Required. Event data specific to the event type. + :param data: Optional. Event data specific to the event type. This cannot be provided along with + data_base64. :type data: object :keyword time: Optional. The time (in UTC) the event was generated, in RFC3339 format. :type time: ~datetime.datetime @@ -57,11 +60,17 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes :keyword id: Optional. An identifier for the event. The combination of id and source must be unique for each distinct event. If not provided, a random UUID will be generated and used. :type id: Optional[str] + :keyword data_base64: Event data specific to the event type if the data is bytes. This must + be provided only when data is not provided and data is of bytes type. + :type data_base64: bytes :ivar source: Identifies the context in which an event happened. The combination of id and source must be unique for each distinct event. If publishing to a domain topic, source must be the domain name. :vartype source: str :ivar data: Event data specific to the event type. :vartype data: object + :ivar data_base64: Event data specific to the event type if the data is bytes. This must + be provided only when data is not provided and data is of bytes type. + :vartype data_base64: bytes :ivar type: Type of event related to the originating occurrence. :vartype type: str :ivar time: The time (in UTC) the event was generated, in RFC3339 format. @@ -79,8 +88,8 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes unique for each distinct event. If not provided, a random UUID will be generated and used. :vartype id: Optional[str] """ - def __init__(self, source, type, data, **kwargs): # pylint: disable=redefined-builtin - # type: (str, str, object, Any) -> None + def __init__(self, source, type, data=None, **kwargs): # pylint: disable=redefined-builtin + # type: (str, str, Optional[object], Any) -> None self.source = source self.type = type self.specversion = kwargs.pop("specversion", "1.0") @@ -90,8 +99,12 @@ def __init__(self, source, type, data, **kwargs): # pylint: disable=redefined-bu self.datacontenttype = kwargs.pop("datacontenttype", None) self.dataschema = kwargs.pop("dataschema", None) self.subject = kwargs.pop("subject", None) + self.data_base64 = kwargs.pop("data_base64", None) self.extensions = {} self.extensions.update(dict(kwargs.pop('extensions', {}))) + if self.data is not None and self.data_base64 is not None: + raise ValueError("data and data_base64 cannot be provided at the same time.\ + Use data_base64 only if you are sending bytes, and use data otherwise.") @classmethod def _from_generated(cls, cloud_event, **kwargs): @@ -118,14 +131,13 @@ def _to_generated(self, **kwargs): data_base64 = self.data data = None else: - data_base64 = None data = self.data return InternalCloudEvent( id=self.id, source=self.source, type=self.type, specversion=self.specversion, - data=data, + data=self.data_base64 or data, data_base64=data_base64, time=self.time, dataschema=self.dataschema, From 307223d78ea308a894afdd74838236681ffe1381 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 15:21:10 -0800 Subject: [PATCH 04/27] eg event --- sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 215224aea636..5e9df66aa227 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -222,8 +222,8 @@ class EventGridEvent(InternalEventGridEvent, EventMixin): 'data_version': {'key': 'dataVersion', 'type': 'str'}, } - def __init__(self, data, subject, event_type, data_version, **kwargs): - # type: (object, str, str, str, Any) -> None + def __init__(self, subject, event_type, data, data_version, **kwargs): + # type: (str, str, object, str, Any) -> None kwargs.setdefault('id', uuid.uuid4()) kwargs.setdefault('subject', subject) kwargs.setdefault("event_type", event_type) From 8c9c934d86c9d742bbc784eb16a7820bec48a9a8 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 15:24:18 -0800 Subject: [PATCH 05/27] SystemEventNames --- sdk/eventgrid/azure-eventgrid/CHANGELOG.md | 2 +- sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py | 4 ++-- .../azure-eventgrid/azure/eventgrid/_event_mappings.py | 2 +- sdk/eventgrid/azure-eventgrid/tests/test_serialization.py | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md index ad24b8b49ea0..c42197fc9521 100644 --- a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md +++ b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md @@ -4,7 +4,7 @@ **Breaking Changes** - `EventGridSharedAccessSignatureCredential` is deprecated in favor of `AzureSasCredential`. - - `azure.eventgrid.models` namespace along with all the models in it are now removed. `azure.eventgrid.SystemEventMappings` can be used to get the event model type mapping. + - `azure.eventgrid.models` namespace along with all the models in it are now removed. `azure.eventgrid.SystemEventNames` can be used to get the event model type mapping. - `topic_hostname` is renamed to `endpoint` in the `EventGridPublisherClient`. - `data` is now a required param for `CloudEvent`. - `azure.eventgrid.generate_shared_access_signature` method is now renamed to `generate_sas`. diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py index debf1df65b69..8c945af545a1 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py @@ -5,12 +5,12 @@ # -------------------------------------------------------------------------- from ._publisher_client import EventGridPublisherClient -from ._event_mappings import SystemEventMappings +from ._event_mappings import SystemEventNames from ._helpers import generate_sas from ._models import CloudEvent, EventGridEvent from ._version import VERSION __all__ = ['EventGridPublisherClient', 'CloudEvent', - 'EventGridEvent', 'generate_sas', 'SystemEventMappings' + 'EventGridEvent', 'generate_sas', 'SystemEventNames' ] __version__ = VERSION diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py index 8be2cdc39c03..cbd9c94828fc 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_event_mappings.py @@ -4,7 +4,7 @@ # -------------------------------------------------------------------------------------------- from enum import Enum -class SystemEventMappings(str, Enum): +class SystemEventNames(str, Enum): """ This enum represents the names of the various event types for the system events published to Azure Event Grid. To check the list of recognizable system topics, diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py b/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py index 5e31be63d638..5bed9c1c9212 100644 --- a/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py +++ b/sdk/eventgrid/azure-eventgrid/tests/test_serialization.py @@ -16,7 +16,7 @@ from msrest.serialization import UTC from azure.eventgrid import CloudEvent, EventGridEvent from azure.eventgrid._generated import models as internal_models -from azure.eventgrid import SystemEventMappings +from azure.eventgrid import SystemEventNames from _mocks import ( cloud_storage_dict, cloud_storage_string, @@ -112,8 +112,8 @@ def test_event_grid_event_raises_on_no_data(self): ) def test_import_from_sytem_events(self): - var = SystemEventMappings.ACSChatMemberAddedToThreadWithUserEventName + var = SystemEventNames.ACSChatMemberAddedToThreadWithUserEventName assert var == "Microsoft.Communication.ChatMemberAddedToThreadWithUser" - assert SystemEventMappings.KeyVaultKeyNearExpiryEventName == "Microsoft.KeyVault.KeyNearExpiry" - var = SystemEventMappings.ServiceBusActiveMessagesAvailableWithNoListenersEventName + assert SystemEventNames.KeyVaultKeyNearExpiryEventName == "Microsoft.KeyVault.KeyNearExpiry" + var = SystemEventNames.ServiceBusActiveMessagesAvailableWithNoListenersEventName assert var == "Microsoft.ServiceBus.ActiveMessagesAvailableWithNoListeners" From f45d34c9c688f75bc2f78f5714c557f504ffe937 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 15:29:28 -0800 Subject: [PATCH 06/27] more changes --- .../azure-eventgrid/azure/eventgrid/_models.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 5e9df66aa227..692b1487e079 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -88,14 +88,14 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes unique for each distinct event. If not provided, a random UUID will be generated and used. :vartype id: Optional[str] """ - def __init__(self, source, type, data=None, **kwargs): # pylint: disable=redefined-builtin - # type: (str, str, Optional[object], Any) -> None + def __init__(self, source, type, **kwargs): # pylint: disable=redefined-builtin + # type: (str, str, Any) -> None self.source = source self.type = type self.specversion = kwargs.pop("specversion", "1.0") self.id = kwargs.pop("id", str(uuid.uuid4())) self.time = kwargs.pop("time", dt.datetime.now(UTC()).isoformat()) - self.data = data + self.data = kwargs.pop("data", None) self.datacontenttype = kwargs.pop("datacontenttype", None) self.dataschema = kwargs.pop("dataschema", None) self.subject = kwargs.pop("subject", None) @@ -170,9 +170,6 @@ class EventGridEvent(InternalEventGridEvent, EventMixin): :keyword metadata_version: Optional. The schema version of the event metadata. If provided, must match Event Grid Schema exactly. If not provided, EventGrid will stamp onto event. :type metadata_version: str - :keyword data_version: Optional. The schema version of the data object. If not provided, - will be stamped with an empty value. - :type data_version: str :keyword id: Optional. An identifier for the event. In not provided, a random UUID will be generated and used. :type id: Optional[str] :keyword event_time: Optional.The time (in UTC) of the event. If not provided, @@ -192,8 +189,6 @@ class EventGridEvent(InternalEventGridEvent, EventMixin): :ivar metadata_version: The schema version of the event metadata. If provided, must match Event Grid Schema exactly. If not provided, EventGrid will stamp onto event. :vartype metadata_version: str - :ivar data_version: The schema version of the data object. If not provided, will be stamped with an empty value. - :vartype data_version: str :ivar id: An identifier for the event. In not provided, a random UUID will be generated and used. :vartype id: Optional[str] :ivar event_time: The time (in UTC) of the event. If not provided, From 76d0b71780dce13bd46dc7934a6fed1b6bc3dc64 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 15:30:07 -0800 Subject: [PATCH 07/27] doc string --- sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 692b1487e079..d513a7dc027d 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -43,7 +43,7 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes :type source: str :param type: Required. Type of event related to the originating occurrence. :type type: str - :param data: Optional. Event data specific to the event type. This cannot be provided along with + :keyword data: Optional. Event data specific to the event type. This cannot be provided along with data_base64. :type data: object :keyword time: Optional. The time (in UTC) the event was generated, in RFC3339 format. From 121245bb160a638798f2d54b6893dcb2a0de30e5 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 15:31:51 -0800 Subject: [PATCH 08/27] aio docstring --- .../azure/eventgrid/aio/_publisher_client_async.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py index cd485ff82ea4..f7a6bedcf2c8 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py @@ -57,6 +57,8 @@ class EventGridPublisherClient(): :param credential: The credential object used for authentication which implements SAS key authentication or SAS token authentication. :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials.AzureSasCredential + :rtype: None + :raises: :class:`ValueError`, when events do not follow specified SendType. """ def __init__( From e13c9bebd89b4cd2526c283850d9294fa554d7b7 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 23:03:17 -0800 Subject: [PATCH 09/27] samples --- .../azure/eventgrid/_models.py | 2 +- .../samples/champion_scenarios.md | 288 ++++++++++++++++++ 2 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index d513a7dc027d..b324e05f11f9 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -138,7 +138,7 @@ def _to_generated(self, **kwargs): type=self.type, specversion=self.specversion, data=self.data_base64 or data, - data_base64=data_base64, + data_base64=self.data_base64, time=self.time, dataschema=self.dataschema, datacontenttype=self.datacontenttype, diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md new file mode 100644 index 000000000000..8b7abeff14a7 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -0,0 +1,288 @@ +## Send Scenarios + +### Send a Single EventGridEvent as a strongly typed object + +```Python +import os +from azure.eventgrid import EventGridPublisherClient, EventGridEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event = EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) + +client.send(event) +``` + +### Send a Single CloudEvent as a strongly typed object + +```Python +import os +from azure.eventgrid import EventGridPublisherClient, CloudEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event = CloudEvent( + type="Contoso.Items.ItemReceived", + source="/contoso/items", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1" + ) + +client.send(event) +``` + +### Send multiple EventGridEvents as strongly typed objects + +```Python +import os +from azure.eventgrid import EventGridPublisherClient, EventGridEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event0 = EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) + +event1 = EventGridEvent( + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #2" + }, + subject="Door1", + data_version="2.0" + ) + +client.send([event0, event1]) +``` + +### Send multiple CloudEvents as a strongly typed objects + +```Python +import os +from azure.eventgrid import EventGridPublisherClient, CloudEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event0 = CloudEvent( + type="Contoso.Items.ItemReceived", + source="/contoso/items", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1" + ) +event1 = CloudEvent( + type="Contoso.Items.ItemReceived", + source="/contoso/items", + data={ + "itemSku": "Contoso Item SKU #2" + }, + subject="Door1" + ) + +client.send([event0, event1]) +``` + +### Send multiple EventGridEvents as dictionaries + +```Python +import os +from azure.eventgrid import EventGridPublisherClient, EventGridEvent +from azure.core.credentials import AzureKeyCredential +from datetime import datetime + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event0 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid11", + "eventTime": datetime(2021, 1, 21, 17, 37) +} + +event1 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #2" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid12", + "eventTime": datetime(2021, 1, 21, 17, 37) +} + +client.send([event0, event1]) +``` + +### Send multiple CloudEvents as dictionaries + +```Python +import os +from azure.eventgrid import EventGridPublisherClient, CloudEvent +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CLOUD_ACCESS_KEY"] +endpoint = os.environ["CLOUD_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event0 = { + "type": "Contoso.Items.ItemReceived", + "source": "/contoso/items", + "data": { + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "specversion": "1.0", + "id": "randomclouduuid11" +} + +event1 = { + "type": "Contoso.Items.ItemReceived", + "source": "/contoso/items", + "data": { + "itemSku": "Contoso Item SKU #2" + }, + "subject": "Door1", + "specversion": "1.0", + "id": "randomclouduuid12" +} + +client.send([event0, event1]) +``` + +### Send a CustomEvent schema + +```Python +import os +from azure.eventgrid import EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential + +topic_key = os.environ["CUSTOM_SCHEMA_ACCESS_KEY"] +endpoint = os.environ["CUSTOM_SCHEMA_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) + +event = { + "custom_event_type":"Contoso.Items.ItemReceived", + "data":{ + "itemSku": "Contoso Item SKU #2" + }, + "custom_subject":"Door1", + "custom_data_version":"2.0" +} +client.send(event) +``` + +## Receive Scenarios + +### Deserialize CloudEvents from storage queue + +```Python +from azure.eventgrid import CloudEvent +from azure.storage.queue import QueueServiceClient +import os +import json +from base64 import b64decode + +# all types of CloudEvents below produce same DeserializedEvent +connection_str = os.environ['STORAGE_QUEUE_CONN_STR'] +queue_name = os.environ['STORAGE_QUEUE_NAME'] + +with QueueServiceClient.from_connection_string(connection_str) as qsc: + payload = qsc.get_queue_client("eventgrid").peek_messages() + + ## deserialize payload into a lost of typed Events + events = [CloudEvent(**json.loads(b64decode(msg.content))) for msg in payload] + + for event in events: + print(type(event)) ## CloudEvent +``` + +### Deserialize CloudEvents from service bus message + +```Python +from azure.eventgrid import CloudEvent +from azure.servicebus import ServiceBusClient +import os +import json + +# all types of CloudEvents below produce same DeserializedEvent +connection_str = os.environ['SERVICE_BUS_CONN_STR'] +queue_name = os.environ['SERVICE_BUS_QUEUE_NAME'] + +with ServiceBusClient.from_connection_string(connection_str) as sb_client: + payload = sb_client.get_queue_receiver(queue_name).receive_messages() + + ## deserialize payload into a lost of typed Events + events = [CloudEvent(**json.loads(next(msg.body).decode('utf-8'))) for msg in payload] + + for event in events: + print(type(event)) ## CloudEvent + +``` + +### Deserialize CloudEvents payload + +```Python +from azure.eventgrid import CloudEvent +import json + +# all types of CloudEvents below produce same DeserializedEvent +cloud_custom_dict = "[{ \"id\":\"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033\",\ + \"source\":\"https://egtest.dev/cloudcustomevent\",\ + \"data\":{\"team\": \"event grid squad\"},\ + \"type\":\"Azure.Sdk.Sample\",\ + \"time\":\"2020-08-07T02:06:08.11969Z\",\ + \"specversion\":\"1.0\" }]" + +deserialized_dict_events = [CloudEvent(**msg) for msg in json.loads(cloud_custom_dict)] + +for event in deserialized_dict_events: + print(event.data) + print(type(event)) +``` From 2344688d9f55449669223d12caa3515421599218 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 23:32:24 -0800 Subject: [PATCH 10/27] lint fix --- sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index b324e05f11f9..005996087a1f 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -132,13 +132,14 @@ def _to_generated(self, **kwargs): data = None else: data = self.data + data_base64 = None return InternalCloudEvent( id=self.id, source=self.source, type=self.type, specversion=self.specversion, - data=self.data_base64 or data, - data_base64=self.data_base64, + data=data, + data_base64=self.data_base64 or data_base64, time=self.time, dataschema=self.dataschema, datacontenttype=self.datacontenttype, From ab431b48ba22b56a20ae30f399e5e28b07a2bf96 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Sun, 31 Jan 2021 23:34:50 -0800 Subject: [PATCH 11/27] lint --- .../azure-eventgrid/tests/test_eg_publisher_client.py | 3 --- .../azure-eventgrid/tests/test_eg_publisher_client_async.py | 2 -- 2 files changed, 5 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py index dc8f7ff64fb4..b6bbb6d3ee8f 100644 --- a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py @@ -224,7 +224,6 @@ def test_send_custom_schema_event(self, resource_group, eventgrid_topic, eventgr "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data" } - ) client.send(custom_event) @CachedResourceGroupPreparer(name_prefix='eventgridtest') @@ -240,7 +239,6 @@ def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data" } - ) custom_event2 = { "customSubject": "sample2", "customEventType": "sample.event", @@ -249,7 +247,6 @@ def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data 2" } - ) client.send([custom_event1, custom_event2]) def test_send_throws_with_bad_credential(self): diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py index bcbd60c45f89..db427be0833e 100644 --- a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client_async.py @@ -259,7 +259,6 @@ async def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_ "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data" } - ) custom_event2 = { "customSubject": "sample2", "customEventType": "sample.event", @@ -268,7 +267,6 @@ async def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_ "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data 2" } - ) await client.send([custom_event1, custom_event2]) @CachedResourceGroupPreparer(name_prefix='eventgridtest') From 654f93cb7859baaf0ade894cbfce31a16e83a85f Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 1 Feb 2021 12:44:08 -0800 Subject: [PATCH 12/27] updates --- .../samples/champion_scenarios.md | 134 +++++++++++------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md index 8b7abeff14a7..70af87208ad5 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -14,13 +14,13 @@ credential = AzureKeyCredential(topic_key) client = EventGridPublisherClient(endpoint, credential) event = EventGridEvent( - event_type="Contoso.Items.ItemReceived", - data={ - "itemSku": "Contoso Item SKU #1" - }, - subject="Door1", - data_version="2.0" - ) + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) client.send(event) ``` @@ -64,22 +64,22 @@ credential = AzureKeyCredential(topic_key) client = EventGridPublisherClient(endpoint, credential) event0 = EventGridEvent( - event_type="Contoso.Items.ItemReceived", - data={ - "itemSku": "Contoso Item SKU #1" - }, - subject="Door1", - data_version="2.0" - ) + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ) event1 = EventGridEvent( - event_type="Contoso.Items.ItemReceived", - data={ - "itemSku": "Contoso Item SKU #2" - }, - subject="Door1", - data_version="2.0" - ) + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #2" + }, + subject="Door1", + data_version="2.0" + ) client.send([event0, event1]) ``` @@ -123,7 +123,7 @@ client.send([event0, event1]) import os from azure.eventgrid import EventGridPublisherClient, EventGridEvent from azure.core.credentials import AzureKeyCredential -from datetime import datetime +from datetime import datetime, timedelta topic_key = os.environ["EG_ACCESS_KEY"] endpoint = os.environ["EG_TOPIC_HOSTNAME"] @@ -134,23 +134,23 @@ client = EventGridPublisherClient(endpoint, credential) event0 = { "eventType": "Contoso.Items.ItemReceived", "data": { - "itemSku": "Contoso Item SKU #1" - }, - "subject": "Door1", - "dataVersion": "2.0", + "itemSku": "Contoso Item SKU #1" + }, + "subject": "Door1", + "dataVersion": "2.0", "id": "randomuuid11", - "eventTime": datetime(2021, 1, 21, 17, 37) + "eventTime": datetime.utcnow() + timedelta(minutes=10) } event1 = { "eventType": "Contoso.Items.ItemReceived", "data": { - "itemSku": "Contoso Item SKU #2" - }, - "subject": "Door1", - "dataVersion": "2.0", + "itemSku": "Contoso Item SKU #2" + }, + "subject": "Door1", + "dataVersion": "2.0", "id": "randomuuid12", - "eventTime": datetime(2021, 1, 21, 17, 37) + "eventTime": datetime.utcnow() } client.send([event0, event1]) @@ -208,23 +208,23 @@ credential = AzureKeyCredential(topic_key) client = EventGridPublisherClient(endpoint, credential) event = { - "custom_event_type":"Contoso.Items.ItemReceived", - "data":{ - "itemSku": "Contoso Item SKU #2" - }, - "custom_subject":"Door1", - "custom_data_version":"2.0" + "custom_event_type":"Contoso.Items.ItemReceived", + "data":{ + "itemSku": "Contoso Item SKU #2" + }, + "custom_subject":"Door1", + "custom_data_version":"2.0" } client.send(event) ``` ## Receive Scenarios -### Deserialize CloudEvents from storage queue +### Deserialize EventGridEvents from storage queue ```Python from azure.eventgrid import CloudEvent -from azure.storage.queue import QueueServiceClient +from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy import os import json from base64 import b64decode @@ -234,24 +234,25 @@ connection_str = os.environ['STORAGE_QUEUE_CONN_STR'] queue_name = os.environ['STORAGE_QUEUE_NAME'] with QueueServiceClient.from_connection_string(connection_str) as qsc: - payload = qsc.get_queue_client("eventgrid").peek_messages() + payload = qsc.get_queue_client( + queue=queue_name,message_decode_policy=BinaryBase64DecodePolicy()).peek_messages() ## deserialize payload into a lost of typed Events - events = [CloudEvent(**json.loads(b64decode(msg.content))) for msg in payload] + events = [CloudEvent.from_dict(json.loads(msg.content)) for msg in payload] for event in events: print(type(event)) ## CloudEvent ``` -### Deserialize CloudEvents from service bus message +### Deserialize EventGridEvents from service bus message ```Python -from azure.eventgrid import CloudEvent +from azure.eventgrid import EventGridEvent from azure.servicebus import ServiceBusClient import os import json -# all types of CloudEvents below produce same DeserializedEvent +# all types of EventGridEvents below produce same DeserializedEvent connection_str = os.environ['SERVICE_BUS_CONN_STR'] queue_name = os.environ['SERVICE_BUS_QUEUE_NAME'] @@ -259,10 +260,10 @@ with ServiceBusClient.from_connection_string(connection_str) as sb_client: payload = sb_client.get_queue_receiver(queue_name).receive_messages() ## deserialize payload into a lost of typed Events - events = [CloudEvent(**json.loads(next(msg.body).decode('utf-8'))) for msg in payload] + events = [EventGridEvent.from_dict(json.loads(next(msg.body).decode('utf-8'))) for msg in payload] for event in events: - print(type(event)) ## CloudEvent + print(type(event)) ## EventGridEvent ``` @@ -273,16 +274,39 @@ from azure.eventgrid import CloudEvent import json # all types of CloudEvents below produce same DeserializedEvent -cloud_custom_dict = "[{ \"id\":\"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033\",\ - \"source\":\"https://egtest.dev/cloudcustomevent\",\ - \"data\":{\"team\": \"event grid squad\"},\ - \"type\":\"Azure.Sdk.Sample\",\ - \"time\":\"2020-08-07T02:06:08.11969Z\",\ - \"specversion\":\"1.0\" }]" +cloud_custom_dict = """[{ + "id":"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", + "source":"https://egtest.dev/cloudcustomevent", + "data":{ + "team": "event grid squad" + }, + "type":"Azure.Sdk.Sample", + "time":"2020-08-07T02:06:08.11969Z", + "specversion":"1.0" +}]""" deserialized_dict_events = [CloudEvent(**msg) for msg in json.loads(cloud_custom_dict)] for event in deserialized_dict_events: - print(event.data) - print(type(event)) + print(event.data) + print(type(event)) ``` + +## generate sas and use AzureSasCredential + +```Python +from azure.eventgrid import generate_sas, EventGridPublisherClient +from azure.core.credentials import AzureSasCredential +from datetime import datetime, timedelta +import os + + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] +expiration_date_utc = datetime.utcnow() + timedelta(hours=1) + +signature = generate_sas(endpoint, topic_key, expiration_date_utc) + +credential = AzureSasCredential(signature) +client = EventGridPublisherClient(endpoint, credential) +``` \ No newline at end of file From 9d2b2ead72dad2194344cc88ac6223ba817f77ad Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 1 Feb 2021 12:51:42 -0800 Subject: [PATCH 13/27] Update champion_scenarios.md --- sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md index 70af87208ad5..ae893be0cc45 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -235,7 +235,9 @@ queue_name = os.environ['STORAGE_QUEUE_NAME'] with QueueServiceClient.from_connection_string(connection_str) as qsc: payload = qsc.get_queue_client( - queue=queue_name,message_decode_policy=BinaryBase64DecodePolicy()).peek_messages() + queue=queue_name, + message_decode_policy=BinaryBase64DecodePolicy() + ).peek_messages() ## deserialize payload into a lost of typed Events events = [CloudEvent.from_dict(json.loads(msg.content)) for msg in payload] @@ -309,4 +311,4 @@ signature = generate_sas(endpoint, topic_key, expiration_date_utc) credential = AzureSasCredential(signature) client = EventGridPublisherClient(endpoint, credential) -``` \ No newline at end of file +``` From 5b0c8e4236be45f9a26e5b0890d006a3aeec0f3d Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 1 Feb 2021 13:15:08 -0800 Subject: [PATCH 14/27] updates --- .../azure-eventgrid/samples/champion_scenarios.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md index ae893be0cc45..39b87a9468df 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -123,7 +123,7 @@ client.send([event0, event1]) import os from azure.eventgrid import EventGridPublisherClient, EventGridEvent from azure.core.credentials import AzureKeyCredential -from datetime import datetime, timedelta +from datetime import datetime topic_key = os.environ["EG_ACCESS_KEY"] endpoint = os.environ["EG_TOPIC_HOSTNAME"] @@ -139,7 +139,7 @@ event0 = { "subject": "Door1", "dataVersion": "2.0", "id": "randomuuid11", - "eventTime": datetime.utcnow() + timedelta(minutes=10) + "eventTime": datetime.utcnow() } event1 = { @@ -299,13 +299,13 @@ for event in deserialized_dict_events: ```Python from azure.eventgrid import generate_sas, EventGridPublisherClient from azure.core.credentials import AzureSasCredential -from datetime import datetime, timedelta +from datetime import datetime import os topic_key = os.environ["EG_ACCESS_KEY"] endpoint = os.environ["EG_TOPIC_HOSTNAME"] -expiration_date_utc = datetime.utcnow() + timedelta(hours=1) +expiration_date_utc = datetime.utcnow() signature = generate_sas(endpoint, topic_key, expiration_date_utc) From 71a12dfc40e24571ef50c3246a32ab7c3e2cb93a Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 10:11:50 -0800 Subject: [PATCH 15/27] fix samples --- ...publish_custom_events_to_a_domain_topic.py | 36 ++++++------- .../cs3_consume_system_events.py | 29 ----------- .../cs4_consume_custom_events.py | 28 ---------- ...me_events_using_cloud_events_1.0_schema.py | 30 ----------- .../sample_consume_custom_payload.py | 20 ++++++++ .../sample_consume_from_storage_queue.py | 21 ++++++++ .../consume_cloud_custom_data_sample.py | 37 -------------- ...ume_eg_storage_blob_created_data_sample.py | 51 ------------------- 8 files changed, 59 insertions(+), 193 deletions(-) delete mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs3_consume_system_events.py delete mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs4_consume_custom_events.py delete mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs6_consume_events_using_cloud_events_1.0_schema.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_custom_payload.py create mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py delete mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_custom_data_sample.py delete mode 100644 sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eg_storage_blob_created_data_sample.py diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs2_publish_custom_events_to_a_domain_topic.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs2_publish_custom_events_to_a_domain_topic.py index b97e03435278..1068dcbe85da 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs2_publish_custom_events_to_a_domain_topic.py +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs2_publish_custom_events_to_a_domain_topic.py @@ -25,22 +25,22 @@ client = EventGridPublisherClient(domain_hostname, credential) client.send([ - EventGridEvent( - topic="MyCustomDomainTopic1", - event_type="Contoso.Items.ItemReceived", - data={ - "itemSku": "Contoso Item SKU #1" - }, - subject="Door1", - data_version="2.0" - ), - EventGridEvent( - topic="MyCustomDomainTopic2", - event_type="Contoso.Items.ItemReceived", - data={ - "itemSku": "Contoso Item SKU #2" - }, - subject="Door1", - data_version="2.0" - ) + EventGridEvent( + topic="MyCustomDomainTopic1", + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #1" + }, + subject="Door1", + data_version="2.0" + ), + EventGridEvent( + topic="MyCustomDomainTopic2", + event_type="Contoso.Items.ItemReceived", + data={ + "itemSku": "Contoso Item SKU #2" + }, + subject="Door1", + data_version="2.0" + ) ]) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs3_consume_system_events.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs3_consume_system_events.py deleted file mode 100644 index a5a7658e15f1..000000000000 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs3_consume_system_events.py +++ /dev/null @@ -1,29 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -""" -FILE: cs3_consume_system_events.py -DESCRIPTION: - These samples demonstrate deserializing a message from system event. -USAGE: - python cs3_consume_system_events.py -""" -import os -import json -from azure.eventgrid import EventGridDeserializer - -consumer = EventGridDeserializer() -path = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "./cs3_system_event.json")) - -with open(path, 'r') as f: - eg_event_received_message = json.loads(f.read()) -# returns List[DeserializedEvent] -event = consumer.deserialize_eventgrid_events(eg_event_received_message) - -datetime_object = event.event_time -print(datetime_object) - -storage_blobcreated_object = event.data -print(storage_blobcreated_object) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs4_consume_custom_events.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs4_consume_custom_events.py deleted file mode 100644 index 1855b13ce46b..000000000000 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs4_consume_custom_events.py +++ /dev/null @@ -1,28 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -""" -FILE: cs4_consume_custom_events.py -DESCRIPTION: - These samples demonstrate deserializing a custom event -USAGE: - python cs4_consume_custom_events.py -""" -import os -import json -from azure.eventgrid import EventGridDeserializer - -consumer = EventGridDeserializer() -path = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "./cs4_event_grid_event_custom_event.json")) - -with open(path, 'r') as f: - eg_event_received_message = json.loads(f.read()) - -# returns List[DeserializedEvent] -event = consumer.deserialize_eventgrid_events(eg_event_received_message) - -# returns { "itemSku": "Contoso Item SKU #1" } -data_dict = event.data -print(data_dict) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs6_consume_events_using_cloud_events_1.0_schema.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs6_consume_events_using_cloud_events_1.0_schema.py deleted file mode 100644 index b5723fc1fd50..000000000000 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs6_consume_events_using_cloud_events_1.0_schema.py +++ /dev/null @@ -1,30 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -""" -FILE: cs6_consume_events_using_cloud_events_1.0_schema.py -DESCRIPTION: - These samples demonstrate creating a list of CloudEvents and sending then as a list. -USAGE: - python cs6_consume_events_using_cloud_events_1.0_schema.py -""" -import os -import json -from azure.eventgrid import EventGridDeserializer - -consumer = EventGridDeserializer() -path = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "./cs6_cloud_event_system_event.json")) - -with open(path, 'r') as f: - cloud_event_received_message = json.loads(f.read()) - -# returns List[DeserializedEvent] -event = consumer.deserialize_cloud_events(cloud_event_received_message) - -datetime_object = event.time -print(datetime_object) - -storage_blobcreated_object = event.data -print(storage_blobcreated_object) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_custom_payload.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_custom_payload.py new file mode 100644 index 000000000000..f321d95e8e67 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_custom_payload.py @@ -0,0 +1,20 @@ +from azure.eventgrid import CloudEvent +import json + +# all types of CloudEvents below produce same DeserializedEvent +cloud_custom_dict = """[{ + "id":"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", + "source":"https://egtest.dev/cloudcustomevent", + "data":{ + "team": "event grid squad" + }, + "type":"Azure.Sdk.Sample", + "time":"2020-08-07T02:06:08.11969Z", + "specversion":"1.0" +}]""" + +deserialized_dict_events = [CloudEvent(**msg) for msg in json.loads(cloud_custom_dict)] + +for event in deserialized_dict_events: + print(event.data) + print(type(event)) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py new file mode 100644 index 000000000000..f62c752860f6 --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py @@ -0,0 +1,21 @@ +from azure.eventgrid import CloudEvent +from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy +import os +import json +from base64 import b64decode + +# all types of CloudEvents below produce same DeserializedEvent +connection_str = os.environ['STORAGE_QUEUE_CONN_STR'] +queue_name = os.environ['STORAGE_QUEUE_NAME'] + +with QueueServiceClient.from_connection_string(connection_str) as qsc: + payload = qsc.get_queue_client( + queue=queue_name, + message_decode_policy=BinaryBase64DecodePolicy() + ).peek_messages() + + ## deserialize payload into a lost of typed Events + events = [CloudEvent(**json.loads(msg.content)) for msg in payload] + + for event in events: + print(type(event)) ## CloudEvent diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_custom_data_sample.py b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_custom_data_sample.py deleted file mode 100644 index dfa631e7c11d..000000000000 --- a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_cloud_custom_data_sample.py +++ /dev/null @@ -1,37 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -""" -FILE: consume_cloud_custom_data_sample.py -DESCRIPTION: - These samples demonstrate consuming custom cloud data -USAGE: - python consume_cloud_custom_data_sample.py - Set the environment variables with your own values before running the sample: -""" -import json -from azure.eventgrid import EventGridDeserializer, CloudEvent - -# all types of CloudEvents below produce same DeserializedEvent -cloud_custom_dict = { - "id":"de0fd76c-4ef4-4dfb-ab3a-8f24a307e033", - "source":"https://egtest.dev/cloudcustomevent", - "data":{"team": "event grid squad"}, - "type":"Azure.Sdk.Sample", - "time":"2020-08-07T02:06:08.11969Z", - "specversion":"1.0" -} -cloud_custom_string = json.dumps(cloud_custom_dict) -cloud_custom_bytes = str(cloud_custom_string).encode("utf-8") - -client = EventGridDeserializer() -deserialized_dict_event = client.deserialize_cloud_events(cloud_custom_dict) -print(deserialized_dict_event) - -deserialized_str_event = client.deserialize_cloud_events(cloud_custom_string) -print(deserialized_str_event) - -deserialized_bytes_event = client.deserialize_cloud_events(cloud_custom_bytes) -print(deserialized_bytes_event) diff --git a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eg_storage_blob_created_data_sample.py b/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eg_storage_blob_created_data_sample.py deleted file mode 100644 index 4edd94abd828..000000000000 --- a/sdk/eventgrid/azure-eventgrid/samples/consume_samples/consume_eg_storage_blob_created_data_sample.py +++ /dev/null @@ -1,51 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -""" -FILE: consume_eg_storage_blob_created_data_sample.py -DESCRIPTION: - These samples demonstrate consuming custom eventgrid event data. -USAGE: - python consume_eg_storage_blob_created_data_sample.py - Set the environment variables with your own values before running the sample: -""" -import json -from azure.eventgrid import EventGridDeserializer, EventGridEvent - -# all types of EventGridEvents below produce same DeserializedEvent -eg_storage_dict = { - "id":"bbab6625-dc56-4b22-abeb-afcc72e5290c", - "subject":"/blobServices/default/containers/oc2d2817345i200097container/blobs/oc2d2817345i20002296blob", - "data":{ - "api":"PutBlockList", - "clientRequestId":"6d79dbfb-0e37-4fc4-981f-442c9ca65760", - "requestId":"831e1650-001e-001b-66ab-eeb76e000000", - "eTag":"0x8D4BCC2E4835CD0", - "contentType":"application/octet-stream", - "contentLength":524288, - "blobType":"BlockBlob", - "url":"https://oc2d2817345i60006.blob.core.windows.net/oc2d2817345i200097container/oc2d2817345i20002296blob", - "sequencer":"00000000000004420000000000028963", - "storageDiagnostics":{"batchId":"b68529f3-68cd-4744-baa4-3c0498ec19f0"} - }, - "eventType":"Microsoft.Storage.BlobCreated", - "dataVersion":"2.0", - "metadataVersion":"1", - "eventTime":"2020-08-07T02:28:23.867525Z", - "topic":"/subscriptions/faa080af-c1d8-40ad-9cce-e1a450ca5b57/resourceGroups/t-swpill-test/providers/Microsoft.EventGrid/topics/eventgridegsub" -} - -eg_storage_string = json.dumps(eg_storage_dict) -eg_storage_bytes = str(eg_storage_string).encode("utf-8") - -client = EventGridDeserializer() -deserialized_dict_event = client.deserialize_eventgrid_events(eg_storage_dict) -print(deserialized_dict_event) - -deserialized_str_event = client.deserialize_eventgrid_events(eg_storage_string) -print(deserialized_str_event) - -deserialized_bytes_event = client.deserialize_eventgrid_events(eg_storage_bytes) -print(deserialized_bytes_event) From 7cf7c974951ec9493941bbcf0dc0d935a906f971 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 10:29:22 -0800 Subject: [PATCH 16/27] md file --- .../samples/champion_scenarios.md | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md index 39b87a9468df..9a29b5f02fe5 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -1,3 +1,40 @@ +## Authentication + +### generate sas and use AzureSasCredential + +```Python +from azure.eventgrid import generate_sas, EventGridPublisherClient +from azure.core.credentials import AzureSasCredential +from datetime import datetime +import os + + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] +expiration_date_utc = datetime.utcnow() + +signature = generate_sas(endpoint, topic_key, expiration_date_utc) + +credential = AzureSasCredential(signature) +client = EventGridPublisherClient(endpoint, credential) +``` + +### use the azure key credential + +```Python +from azure.eventgrid import generate_sas, EventGridPublisherClient +from azure.core.credentials import AzureKeyCredential +from datetime import datetime +import os + + +topic_key = os.environ["EG_ACCESS_KEY"] +endpoint = os.environ["EG_TOPIC_HOSTNAME"] + +credential = AzureKeyCredential(topic_key) +client = EventGridPublisherClient(endpoint, credential) +``` + ## Send Scenarios ### Send a Single EventGridEvent as a strongly typed object @@ -294,21 +331,3 @@ for event in deserialized_dict_events: print(type(event)) ``` -## generate sas and use AzureSasCredential - -```Python -from azure.eventgrid import generate_sas, EventGridPublisherClient -from azure.core.credentials import AzureSasCredential -from datetime import datetime -import os - - -topic_key = os.environ["EG_ACCESS_KEY"] -endpoint = os.environ["EG_TOPIC_HOSTNAME"] -expiration_date_utc = datetime.utcnow() - -signature = generate_sas(endpoint, topic_key, expiration_date_utc) - -credential = AzureSasCredential(signature) -client = EventGridPublisherClient(endpoint, credential) -``` From 4450fbab530494978b44b7efaeb3342f80325692 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 10:34:28 -0800 Subject: [PATCH 17/27] custom-2 --- sdk/eventgrid/azure-eventgrid/CHANGELOG.md | 1 + .../azure-eventgrid/migration_guide.md | 2 +- ...lish_custom_schema_events_to_topic_sample.py | 17 ++++++++--------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md index c42197fc9521..a864c76264d9 100644 --- a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md +++ b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md @@ -9,6 +9,7 @@ - `data` is now a required param for `CloudEvent`. - `azure.eventgrid.generate_shared_access_signature` method is now renamed to `generate_sas`. - `EventGridConsumer`is now removed. Please see the samples to see how events can be deserialized. + - `CustomEvent` model is removed. Dictionaries must be used to send a custom schema. **Bug Fixes** - `EventGridEvent` has two additional required positional parameters namely, `data` and `data_version`. diff --git a/sdk/eventgrid/azure-eventgrid/migration_guide.md b/sdk/eventgrid/azure-eventgrid/migration_guide.md index a6349e21961e..6c3473af2307 100644 --- a/sdk/eventgrid/azure-eventgrid/migration_guide.md +++ b/sdk/eventgrid/azure-eventgrid/migration_guide.md @@ -67,7 +67,7 @@ cloud_event = { ### Publishing Events -The `publish_events` API is replaced with `send` in v2.0. Additionally, `send` API accepts `CloudEvent`, `CustomEvent` along with `EventGridEvent` +The `publish_events` API is replaced with `send` in v2.0. Additionally, `send` API accepts `CloudEvent`, `EventGridEvent` along with their dict representations. | In v1.3 | Equivalent in v2.0 | Sample | |---|---|---| diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py index 553060c28cb9..0e7a745f87ca 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py @@ -22,7 +22,7 @@ import datetime as dt from azure.core.credentials import AzureKeyCredential -from azure.eventgrid import EventGridPublisherClient, CustomEvent +from azure.eventgrid import EventGridPublisherClient key = os.environ["CUSTOM_SCHEMA_ACCESS_KEY"] endpoint = os.environ["CUSTOM_SCHEMA_TOPIC_HOSTNAME"] @@ -33,12 +33,12 @@ def publish_event(): client = EventGridPublisherClient(endpoint, credential) custom_schema_event = { - "customSubject": "sample", - "customEventType": "sample.event", - "customDataVersion": "2.0", - "customId": uuid.uuid4(), - "customEventTime": dt.datetime.now(UTC()).isoformat(), - "customData": "sample data" + "custom_event_type":"Contoso.Items.ItemReceived", + "data":{ + "itemSku": "Contoso Item SKU #2" + }, + "custom_subject":"Door1", + "custom_data_version":"2.0" } # publish events @@ -47,8 +47,7 @@ def publish_event(): event_list = [] # list of events to publish # create events and append to list for j in range(randint(1, 3)): - event = CustomEvent(custom_schema_event) - event_list.append(event) + event_list.append(custom_schema_event) # publish list of events client.send(event_list) From 6e9320fd3b502d1567d894e732871a0bc41cb032 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 10:36:22 -0800 Subject: [PATCH 18/27] oops --- .../sample_consume_from_storage_queue.py | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py deleted file mode 100644 index f62c752860f6..000000000000 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/sample_consume_from_storage_queue.py +++ /dev/null @@ -1,21 +0,0 @@ -from azure.eventgrid import CloudEvent -from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy -import os -import json -from base64 import b64decode - -# all types of CloudEvents below produce same DeserializedEvent -connection_str = os.environ['STORAGE_QUEUE_CONN_STR'] -queue_name = os.environ['STORAGE_QUEUE_NAME'] - -with QueueServiceClient.from_connection_string(connection_str) as qsc: - payload = qsc.get_queue_client( - queue=queue_name, - message_decode_policy=BinaryBase64DecodePolicy() - ).peek_messages() - - ## deserialize payload into a lost of typed Events - events = [CloudEvent(**json.loads(msg.content)) for msg in payload] - - for event in events: - print(type(event)) ## CloudEvent From d0639bb695dbb80f04612d297df8d10f094769a5 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 11:46:17 -0800 Subject: [PATCH 19/27] tests --- sdk/eventgrid/azure-eventgrid/CHANGELOG.md | 1 - ...d_cloud_event_bytes_using_data_base64.yaml | 38 +++++++++++++++ ...nd_cloud_event_data_base64_using_data.yaml | 38 +++++++++++++++ .../tests/test_eg_publisher_client.py | 46 +++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_bytes_using_data_base64.yaml create mode 100644 sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml diff --git a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md index a864c76264d9..6ab909fe9c25 100644 --- a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md +++ b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md @@ -6,7 +6,6 @@ - `EventGridSharedAccessSignatureCredential` is deprecated in favor of `AzureSasCredential`. - `azure.eventgrid.models` namespace along with all the models in it are now removed. `azure.eventgrid.SystemEventNames` can be used to get the event model type mapping. - `topic_hostname` is renamed to `endpoint` in the `EventGridPublisherClient`. - - `data` is now a required param for `CloudEvent`. - `azure.eventgrid.generate_shared_access_signature` method is now renamed to `generate_sas`. - `EventGridConsumer`is now removed. Please see the samples to see how events can be deserialized. - `CustomEvent` model is removed. Dictionaries must be used to send a custom schema. diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_bytes_using_data_base64.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_bytes_using_data_base64.yaml new file mode 100644 index 000000000000..9650046e2a3a --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_bytes_using_data_base64.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "b833bdc8-629d-4abd-8ae8-b66412de44df", "source": "http://samplesource.dev", + "data_base64": "Y2xvdWRldmVudA==", "type": "Sample.Cloud.Event", "time": "2021-02-02T19:33:06.109012Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '211' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/2.0.0b5 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 02 Feb 2021 19:33:05 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml new file mode 100644 index 000000000000..28d92399e3bd --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/tests/recordings/test_eg_publisher_client.test_send_cloud_event_data_base64_using_data.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '[{"id": "fd420598-f82a-440a-bc64-04122dbf801f", "source": "http://samplesource.dev", + "data_base64": "Y2xvdWRldmVudA==", "type": "Sample.Cloud.Event", "time": "2021-02-02T19:32:23.146005Z", + "specversion": "1.0"}]' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '211' + Content-Type: + - application/cloudevents-batch+json; charset=utf-8 + User-Agent: + - azsdk-python-eventgrid/2.0.0b5 Python/3.7.3 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://cloudeventgridtestegtopic.westus-1.eventgrid.azure.net/api/events?api-version=2018-01-01 + response: + body: + string: '' + headers: + api-supported-versions: + - '2018-01-01' + content-length: + - '0' + date: + - Tue, 02 Feb 2021 19:32:22 GMT + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py index b6bbb6d3ee8f..88b866d379d1 100644 --- a/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py +++ b/sdk/eventgrid/azure-eventgrid/tests/test_eg_publisher_client.py @@ -7,6 +7,7 @@ import logging import sys import os +import json import pytest import uuid from datetime import datetime, timedelta @@ -113,6 +114,51 @@ def test_send_cloud_event_data_dict(self, resource_group, eventgrid_topic, event ) client.send(cloud_event) + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_data_base64_using_data(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data = b'cloudevent', + type="Sample.Cloud.Event" + ) + + def callback(request): + req = json.loads(request.http_request.body) + assert req[0].get("data_base64") is not None + assert req[0].get("data") is None + + client.send(cloud_event, raw_response_hook=callback) + + @CachedResourceGroupPreparer(name_prefix='eventgridtest') + @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') + def test_send_cloud_event_bytes_using_data_base64(self, resource_group, eventgrid_topic, eventgrid_topic_primary_key, eventgrid_topic_endpoint): + akc_credential = AzureKeyCredential(eventgrid_topic_primary_key) + client = EventGridPublisherClient(eventgrid_topic_endpoint, akc_credential) + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data_base64 = b'cloudevent', + type="Sample.Cloud.Event" + ) + + def callback(request): + req = json.loads(request.http_request.body) + assert req[0].get("data_base64") is not None + assert req[0].get("data") is None + + client.send(cloud_event, raw_response_hook=callback) + + + def test_send_cloud_event_fails_on_providing_data_and_b64(self): + with pytest.raises(ValueError, match="data and data_base64 cannot be provided at the same time*"): + cloud_event = CloudEvent( + source = "http://samplesource.dev", + data_base64 = b'cloudevent', + data = "random data", + type="Sample.Cloud.Event" + ) @CachedResourceGroupPreparer(name_prefix='eventgridtest') @CachedEventGridTopicPreparer(name_prefix='cloudeventgridtest') From 349d360f76af915df988d58cbdefa821ef153c0c Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 14:53:07 -0800 Subject: [PATCH 20/27] Update sdk/eventgrid/azure-eventgrid/README.md Co-authored-by: Adam Ling (MSFT) --- sdk/eventgrid/azure-eventgrid/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventgrid/azure-eventgrid/README.md b/sdk/eventgrid/azure-eventgrid/README.md index 206dc9c8f289..3abe3f953e2f 100644 --- a/sdk/eventgrid/azure-eventgrid/README.md +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -60,7 +60,7 @@ Information about the key concepts on Event Grid, see [Concepts in Azure Event G ### EventGridPublisherClient `EventGridPublisherClient` provides operations to send event data to topic hostname specified during client initialization. -Either a list or a single instance of CloudEvent/EventGridEvent can be sent.liAlternatively, a lis or a single instance of the dict representation of CloudEvent/EventGridEvent or a Custom Schema can also be published. +Either a list or a single instance of CloudEvent/EventGridEvent can be sent. Alternatively, a list or a single instance of the dict representation of CloudEvent/EventGridEvent or a Custom Schema can also be published. ## Examples From da3d505ed585f5bd7c74bda91250bedfb94937dc Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 16:08:01 -0800 Subject: [PATCH 21/27] Apply suggestions from code review Co-authored-by: Adam Ling (MSFT) --- .../azure-eventgrid/azure/eventgrid/_models.py | 10 ++++------ .../azure/eventgrid/aio/_publisher_client_async.py | 1 - .../azure-eventgrid/samples/champion_scenarios.md | 6 ++---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 005996087a1f..29e27f6d18d4 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -43,8 +43,7 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes :type source: str :param type: Required. Type of event related to the originating occurrence. :type type: str - :keyword data: Optional. Event data specific to the event type. This cannot be provided along with - data_base64. + :keyword data: Optional. Event data specific to the event type. Only one of the `data` or `data_base64` argument must be present. :type data: object :keyword time: Optional. The time (in UTC) the event was generated, in RFC3339 format. :type time: ~datetime.datetime @@ -60,16 +59,15 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes :keyword id: Optional. An identifier for the event. The combination of id and source must be unique for each distinct event. If not provided, a random UUID will be generated and used. :type id: Optional[str] - :keyword data_base64: Event data specific to the event type if the data is bytes. This must - be provided only when data is not provided and data is of bytes type. + :keyword data_base64: Optional. Event data specific to the event type if the data is of bytes type. + Only data of bytes type is accepted by `data-base64` and only one of the `data` or `data_base64` argument must be present. :type data_base64: bytes :ivar source: Identifies the context in which an event happened. The combination of id and source must be unique for each distinct event. If publishing to a domain topic, source must be the domain name. :vartype source: str :ivar data: Event data specific to the event type. :vartype data: object - :ivar data_base64: Event data specific to the event type if the data is bytes. This must - be provided only when data is not provided and data is of bytes type. + :ivar data_base64: Event data specific to the event type if the data is of bytes type. :vartype data_base64: bytes :ivar type: Type of event related to the originating occurrence. :vartype type: str diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py index f7a6bedcf2c8..670b68a4ebf0 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/aio/_publisher_client_async.py @@ -58,7 +58,6 @@ class EventGridPublisherClient(): SAS key authentication or SAS token authentication. :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials.AzureSasCredential :rtype: None - :raises: :class:`ValueError`, when events do not follow specified SendType. """ def __init__( diff --git a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md index 9a29b5f02fe5..bbe965f352ea 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -37,7 +37,7 @@ client = EventGridPublisherClient(endpoint, credential) ## Send Scenarios -### Send a Single EventGridEvent as a strongly typed object +### Send a single EventGridEvent as a strongly typed object ```Python import os @@ -62,7 +62,7 @@ event = EventGridEvent( client.send(event) ``` -### Send a Single CloudEvent as a strongly typed object +### Send a single CloudEvent as a strongly typed object ```Python import os @@ -264,7 +264,6 @@ from azure.eventgrid import CloudEvent from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy import os import json -from base64 import b64decode # all types of CloudEvents below produce same DeserializedEvent connection_str = os.environ['STORAGE_QUEUE_CONN_STR'] @@ -330,4 +329,3 @@ for event in deserialized_dict_events: print(event.data) print(type(event)) ``` - From 7559f61951710f9b2f4f9db963caf66734b75402 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 16:52:24 -0800 Subject: [PATCH 22/27] change --- sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 29e27f6d18d4..37429e816ac2 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -44,6 +44,7 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes :param type: Required. Type of event related to the originating occurrence. :type type: str :keyword data: Optional. Event data specific to the event type. Only one of the `data` or `data_base64` argument must be present. + If data is of bytes type, we'll send it as data_base64 in the outgoing request. :type data: object :keyword time: Optional. The time (in UTC) the event was generated, in RFC3339 format. :type time: ~datetime.datetime From 78aebb70ac846e62d81af187eb4cf6906445adcd Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 17:02:09 -0800 Subject: [PATCH 23/27] Apply suggestions from code review --- sdk/eventgrid/azure-eventgrid/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventgrid/azure-eventgrid/README.md b/sdk/eventgrid/azure-eventgrid/README.md index 3abe3f953e2f..f66aebad2d89 100644 --- a/sdk/eventgrid/azure-eventgrid/README.md +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -60,7 +60,7 @@ Information about the key concepts on Event Grid, see [Concepts in Azure Event G ### EventGridPublisherClient `EventGridPublisherClient` provides operations to send event data to topic hostname specified during client initialization. -Either a list or a single instance of CloudEvent/EventGridEvent can be sent. Alternatively, a list or a single instance of the dict representation of CloudEvent/EventGridEvent or a Custom Schema can also be published. +CloudEvents and EventGridEvents can be sent either as a single event or a list of respective typed objects or their equivalent dict representations. To send a custom schema, a dict representation can be used. Please have a look at the [samples](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/eventgrid/azure-eventgrid/samples) for detailed examples. ## Examples From 2cb0908b46cbab8f598c4fb2c5fbd2844cf20852 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 17:27:03 -0800 Subject: [PATCH 24/27] lint --- sdk/eventgrid/azure-eventgrid/README.md | 6 ------ .../azure-eventgrid/azure/eventgrid/_models.py | 17 +++++++++-------- sdk/eventgrid/azure-eventgrid/samples/README.md | 6 ------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/README.md b/sdk/eventgrid/azure-eventgrid/README.md index f66aebad2d89..a17e52d45be0 100644 --- a/sdk/eventgrid/azure-eventgrid/README.md +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -149,9 +149,6 @@ These code samples show common champion scenario operations with the Azure Event * Publish Custom Events to a topic: [cs1_publish_custom_events_to_a_topic.py][python-eg-sample-customevent] * Publish Custom events to a domain topic: [cs2_publish_custom_events_to_a_domain_topic.py][python-eg-sample-customevent-to-domain] -* Deserialize a System Event: [cs3_consume_system_events.py][python-eg-sample-consume-systemevent] -* Deserialize a Custom Event: [cs4_consume_custom_events.py][python-eg-sample-consume-customevent] -* Deserialize a Cloud Event: [cs5_consume_events_using_cloud_events_1.0_schema.py][python-eg-sample-consume-cloudevent] * Publish a Cloud Event: [cs6_publish_events_using_cloud_events_1.0_schema.py][python-eg-sample-send-cloudevent] More samples can be found [here][python-eg-samples]. @@ -187,10 +184,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [python-eg-sample-customevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs1_publish_custom_events_to_a_topic.py [python-eg-sample-customevent-to-domain]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs2_publish_custom_events_to_a_domain_topic.py -[python-eg-sample-consume-systemevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs3_consume_system_events.py -[python-eg-sample-consume-customevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs4_consume_custom_events.py [python-eg-sample-send-cloudevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs5_publish_events_using_cloud_events_1.0_schema.py -[python-eg-sample-consume-cloudevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs6_consume_events_using_cloud_events_1.0_schema.py [publisher-service-doc]: https://docs.microsoft.com/azure/event-grid/concepts [cla]: https://cla.microsoft.com diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 37429e816ac2..62c38b0c105c 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -39,12 +39,12 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes cannot be present at the same time. :param source: Required. Identifies the context in which an event happened. The combination of id and source must - be unique for each distinct event. If publishing to a domain topic, source must be the domain name. + be unique for each distinct event. If publishing to a domain topic, source must be the domain name. :type source: str :param type: Required. Type of event related to the originating occurrence. :type type: str - :keyword data: Optional. Event data specific to the event type. Only one of the `data` or `data_base64` argument must be present. - If data is of bytes type, we'll send it as data_base64 in the outgoing request. + :keyword data: Optional. Event data specific to the event type. Only one of the `data` or `data_base64` + argument must be present. If data is of bytes type, we'll send it as data_base64 in the outgoing request. :type data: object :keyword time: Optional. The time (in UTC) the event was generated, in RFC3339 format. :type time: ~datetime.datetime @@ -61,10 +61,11 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes unique for each distinct event. If not provided, a random UUID will be generated and used. :type id: Optional[str] :keyword data_base64: Optional. Event data specific to the event type if the data is of bytes type. - Only data of bytes type is accepted by `data-base64` and only one of the `data` or `data_base64` argument must be present. + Only data of bytes type is accepted by `data-base64` and only one of the `data` or `data_base64` argument + must be present. :type data_base64: bytes :ivar source: Identifies the context in which an event happened. The combination of id and source must - be unique for each distinct event. If publishing to a domain topic, source must be the domain name. + be unique for each distinct event. If publishing to a domain topic, source must be the domain name. :vartype source: str :ivar data: Event data specific to the event type. :vartype data: object @@ -162,13 +163,13 @@ class EventGridEvent(InternalEventGridEvent, EventMixin): :param data: Required. Event data specific to the event type. :type data: object :param data_version: Required. The schema version of the data object. - If not provided, will be stamped with an empty value. + If not provided, will be stamped with an empty value. :type data_version: str :keyword topic: Optional. The resource path of the event source. If not provided, Event Grid will - stamp onto the event. + stamp onto the event. :type topic: str :keyword metadata_version: Optional. The schema version of the event metadata. If provided, - must match Event Grid Schema exactly. If not provided, EventGrid will stamp onto event. + must match Event Grid Schema exactly. If not provided, EventGrid will stamp onto event. :type metadata_version: str :keyword id: Optional. An identifier for the event. In not provided, a random UUID will be generated and used. :type id: Optional[str] diff --git a/sdk/eventgrid/azure-eventgrid/samples/README.md b/sdk/eventgrid/azure-eventgrid/samples/README.md index e59be381038a..7978488c9f90 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/README.md +++ b/sdk/eventgrid/azure-eventgrid/samples/README.md @@ -14,15 +14,9 @@ These code samples show common champion scenario operations with the Azure Event * Publish Custom Events to a topic: [cs1_publish_custom_events_to_a_topic.py][python-eg-sample-customevent] * Publish Custom events to a domain topic: [cs2_publish_custom_events_to_a_domain_topic.py][python-eg-sample-customevent-to-domain] -* Deserialize a System Event: [cs3_consume_system_events.py][python-eg-sample-consume-systemevent] -* Deserialize a Custom Event: [cs4_consume_custom_events.py][python-eg-sample-consume-customevent] -* Deserialize a Cloud Event: [cs5_consume_events_using_cloud_events_1.0_schema.py][python-eg-sample-consume-cloudevent] * Publish a Cloud Event: [cs6_publish_events_using_cloud_events_1.0_schema.py][python-eg-sample-send-cloudevent] [python-eg-sample-customevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs1_publish_custom_events_to_a_topic.py [python-eg-sample-customevent-to-domain]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs2_publish_custom_events_to_a_domain_topic.py -[python-eg-sample-consume-systemevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs3_consume_system_events.py -[python-eg-sample-consume-customevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs4_consume_custom_events.py [python-eg-sample-send-cloudevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs5_publish_events_using_cloud_events_1.0_schema.py -[python-eg-sample-consume-cloudevent]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios/cs6_consume_events_using_cloud_events_1.0_schema.py [publisher-service-doc]: https://docs.microsoft.com/azure/event-grid/concepts From e0e78c27716ac985fdfaf06803c89590f7f139d5 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 17:32:49 -0800 Subject: [PATCH 25/27] fix sample --- .../publish_custom_schema_events_to_topic_sample.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py index 0e7a745f87ca..1a4059a710d7 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py @@ -33,12 +33,12 @@ def publish_event(): client = EventGridPublisherClient(endpoint, credential) custom_schema_event = { - "custom_event_type":"Contoso.Items.ItemReceived", - "data":{ - "itemSku": "Contoso Item SKU #2" - }, - "custom_subject":"Door1", - "custom_data_version":"2.0" + "custom_subject": "sample", + "custom_EventType": "sample.event", + "customDataVersion": "2.0", + "customId": uuid.uuid4(), + "customEventTime": dt.datetime.now(UTC()).isoformat(), + "customData": "sample data" } # publish events From 6c0c6bbdc6825c621a542879e19a123c674f6090 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 21:04:58 -0800 Subject: [PATCH 26/27] Update sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py Co-authored-by: Adam Ling (MSFT) --- sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 62c38b0c105c..c886e78553a6 100644 --- a/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py +++ b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py @@ -44,7 +44,7 @@ class CloudEvent(EventMixin): #pylint:disable=too-many-instance-attributes :param type: Required. Type of event related to the originating occurrence. :type type: str :keyword data: Optional. Event data specific to the event type. Only one of the `data` or `data_base64` - argument must be present. If data is of bytes type, we'll send it as data_base64 in the outgoing request. + argument must be present. If data is of bytes type, it will be sent as data_base64 in the outgoing request. :type data: object :keyword time: Optional. The time (in UTC) the event was generated, in RFC3339 format. :type time: ~datetime.datetime From 9ecbadac685d6aab632111d3a19bbbebdfb2047a Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Tue, 2 Feb 2021 22:08:56 -0800 Subject: [PATCH 27/27] Update sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py --- .../publish_custom_schema_events_to_topic_sample.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py index 1a4059a710d7..870c129f0553 100644 --- a/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py +++ b/sdk/eventgrid/azure-eventgrid/samples/publish_samples/publish_custom_schema_events_to_topic_sample.py @@ -33,8 +33,8 @@ def publish_event(): client = EventGridPublisherClient(endpoint, credential) custom_schema_event = { - "custom_subject": "sample", - "custom_EventType": "sample.event", + "customSubject": "sample", + "customEventType": "sample.event", "customDataVersion": "2.0", "customId": uuid.uuid4(), "customEventTime": dt.datetime.now(UTC()).isoformat(),