diff --git a/sdk/eventgrid/azure-eventgrid/CHANGELOG.md b/sdk/eventgrid/azure-eventgrid/CHANGELOG.md index ab2633b61902..6ab909fe9c25 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. + - `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. **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..a17e52d45be0 100644 --- a/sdk/eventgrid/azure-eventgrid/README.md +++ b/sdk/eventgrid/azure-eventgrid/README.md @@ -60,10 +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. - -### EventGridDeserializer -`EventGridDeserializer` is used to desrialize an event received. +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 @@ -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. @@ -208,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]. @@ -246,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/__init__.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/__init__.py index 9b31b705f32c..8c945af545a1 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 ._event_mappings import SystemEventNames from ._helpers import generate_sas -from ._models import CloudEvent, CustomEvent, EventGridEvent +from ._models import CloudEvent, EventGridEvent from ._version import VERSION -__all__ = ['EventGridPublisherClient', 'EventGridDeserializer', - 'CloudEvent', 'CustomEvent', 'EventGridEvent', 'generate_sas', - 'SystemEventMappings' +__all__ = ['EventGridPublisherClient', 'CloudEvent', + 'EventGridEvent', 'generate_sas', 'SystemEventNames' ] __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/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/azure/eventgrid/_models.py b/sdk/eventgrid/azure-eventgrid/azure/eventgrid/_models.py index 4be822e73ee2..c886e78553a6 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): @@ -36,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. + 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. + :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, 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 @@ -58,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: 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. + 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 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. @@ -80,19 +88,23 @@ 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, **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) + 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): @@ -119,15 +131,15 @@ def _to_generated(self, **kwargs): data_base64 = self.data data = None else: - data_base64 = None data = self.data + data_base64 = None return InternalCloudEvent( id=self.id, source=self.source, type=self.type, specversion=self.specversion, data=data, - data_base64=data_base64, + data_base64=self.data_base64 or data_base64, time=self.time, dataschema=self.dataschema, datacontenttype=self.datacontenttype, @@ -151,17 +163,14 @@ 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 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, @@ -181,8 +190,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, @@ -211,8 +218,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) @@ -221,17 +228,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..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 @@ -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] ] @@ -60,6 +57,7 @@ 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 """ def __init__( @@ -108,7 +106,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 +132,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/migration_guide.md b/sdk/eventgrid/azure-eventgrid/migration_guide.md index 7f6e285f5403..6c3473af2307 100644 --- a/sdk/eventgrid/azure-eventgrid/migration_guide.md +++ b/sdk/eventgrid/azure-eventgrid/migration_guide.md @@ -65,32 +65,14 @@ 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` +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 | |---|---|---| |`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/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 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..bbe965f352ea --- /dev/null +++ b/sdk/eventgrid/azure-eventgrid/samples/champion_scenarios.md @@ -0,0 +1,331 @@ +## 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 + +```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.utcnow() +} + +event1 = { + "eventType": "Contoso.Items.ItemReceived", + "data": { + "itemSku": "Contoso Item SKU #2" + }, + "subject": "Door1", + "dataVersion": "2.0", + "id": "randomuuid12", + "eventTime": datetime.utcnow() +} + +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 EventGridEvents from storage queue + +```Python +from azure.eventgrid import CloudEvent +from azure.storage.queue import QueueServiceClient, BinaryBase64DecodePolicy +import os +import json + +# 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.from_dict(json.loads(msg.content)) for msg in payload] + + for event in events: + print(type(event)) ## CloudEvent +``` + +### Deserialize EventGridEvents from service bus message + +```Python +from azure.eventgrid import EventGridEvent +from azure.servicebus import ServiceBusClient +import os +import json + +# all types of EventGridEvents 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 = [EventGridEvent.from_dict(json.loads(next(msg.body).decode('utf-8'))) for msg in payload] + + for event in events: + print(type(event)) ## EventGridEvent + +``` + +### 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)) +``` 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/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) 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..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 @@ -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"] @@ -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) 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_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 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..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 @@ -17,7 +18,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 @@ -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') @@ -216,8 +262,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", @@ -225,7 +270,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') @@ -233,8 +277,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", @@ -242,9 +285,7 @@ def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_topic, "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data" } - ) - custom_event2 = CustomEvent( - { + custom_event2 = { "customSubject": "sample2", "customEventType": "sample.event", "customDataVersion": "2.0", @@ -252,7 +293,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 aca20a7c35e5..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 @@ -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", @@ -262,9 +259,7 @@ async def test_send_custom_schema_event_as_list(self, resource_group, eventgrid_ "customEventTime": dt.datetime.now(UTC()).isoformat(), "customData": "sample data" } - ) - custom_event2 = CustomEvent( - { + custom_event2 = { "customSubject": "sample2", "customEventType": "sample.event", "customDataVersion": "2.0", @@ -272,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') 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"