Skip to content

Commit 3a79e2c

Browse files
authored
Adding new Reaction, Sticker and Interactive types of messages. (Azure#38693)
Merging Interactive messages PR on 2/10/2025 * Adding interactive types * Typespec update commit * version update * adding samples to new types. * Adding working samples:) * sdk review * reverting emitter overrites * updating samples * asset json update * fixing pipeline * build fix * build fix * adding new samples * update to new version * test updates * build fix * build fix * build fix * build fix * build fix * version update * merge latest api spec commit. * readme updates * build fix
1 parent d4809af commit 3a79e2c

37 files changed

+1777
-274
lines changed

sdk/communication/azure-communication-messages/CHANGELOG.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
# Release History
22

3-
## 1.1.1 (Unreleased)
3+
## 1.2.0b1 (2025-01-15-preview)
4+
This is feature addition public preview release.
45

56
### Features Added
6-
7-
### Breaking Changes
8-
9-
### Bugs Fixed
10-
11-
### Other Changes
7+
- Using `NotificationMessagesClient`
8+
- Send Interactive messages
9+
- WhatsApp List Interactive Message
10+
- WhatsApp Reply Button Interactive Message
11+
- WhatsApp Url Interactive Message
12+
- Send Reactions messages
13+
- Send Stickers messages
1214

1315
## 1.1.0 (2024-10-18)
1416
This is feature addition release.

sdk/communication/azure-communication-messages/README.md

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,43 @@ Use the returned token credential to authenticate the client:
5151

5252
### Examples
5353

54+
Send Text WhatsApp message using AdvancedMessages python SDK.
5455
```python
55-
>>> from azure.communication.messages import NotificationMessagesClient
56-
>>> from azure.identity import DefaultAzureCredential
57-
>>> from azure.core.exceptions import HttpResponseError
56+
import os
57+
import sys
5858

59-
>>> client = NotificationMessagesClient(endpoint='<endpoint>', credential=DefaultAzureCredential())
60-
>>> try:
61-
# write test code here
62-
except HttpResponseError as e:
63-
print('service responds error: {}'.format(e.response.json()))
59+
sys.path.append("..")
60+
61+
class SendWhatsAppMessageSample(object):
62+
63+
connection_string = os.getenv("COMMUNICATION_SAMPLES_CONNECTION_STRING")
64+
phone_number = os.getenv("RECIPIENT_PHONE_NUMBER")
65+
channel_id = os.getenv("WHATSAPP_CHANNEL_ID")
66+
67+
def send_text_send_message(self):
68+
69+
from azure.communication.messages import NotificationMessagesClient
70+
from azure.communication.messages.models import TextNotificationContent
71+
from azure.identity import DefaultAzureCredential
72+
73+
messaging_client = NotificationMessagesClient(
74+
endpoint=self.endpoint_string, credential=DefaultAzureCredential()
75+
)
76+
text_options = TextNotificationContent(
77+
channel_registration_id=self.channel_id,
78+
to=[self.phone_number],
79+
content="Hello World via Notification Messaging SDK.",
80+
)
81+
82+
# calling send() with whatsapp message details
83+
message_responses = messaging_client.send(text_options)
84+
response = message_responses.receipts[0]
85+
print("Message with message id {} was successful sent to {}".format(response.message_id, response.to))
86+
87+
88+
if __name__ == "__main__":
89+
sample = SendWhatsAppMessageSample()
90+
sample.send_text_send_message()
6491

6592
```
6693

@@ -101,4 +128,4 @@ additional questions or comments.
101128
[source]: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-messages
102129
[product_docs]: https://learn.microsoft.com/azure/communication-services/overview
103130
[pypi]: https://pypi.org
104-
[nextsteps]: https://learn.microsoft.com/azure/communication-services/concepts/advanced-messaging/whatsapp/whatsapp-overview
131+
[nextsteps]: https://learn.microsoft.com/azure/communication-services/quickstarts/advanced-messaging/whatsapp/get-started

sdk/communication/azure-communication-messages/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "python",
44
"TagPrefix": "python/communication/azure-communication-messages",
5-
"Tag": "python/communication/azure-communication-messages_302bf9560e"
5+
"Tag": "python/communication/azure-communication-messages_25cd70fad7"
66
}

sdk/communication/azure-communication-messages/azure/communication/messages/__init__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@
55
# Code generated by Microsoft (R) Python Code Generator.
66
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
77
# --------------------------------------------------------------------------
8+
# pylint: disable=wrong-import-position
89

9-
from ._client import NotificationMessagesClient
10-
from ._client import MessageTemplateClient
10+
from typing import TYPE_CHECKING
11+
12+
if TYPE_CHECKING:
13+
from ._patch import * # pylint: disable=unused-wildcard-import
14+
15+
from ._client import NotificationMessagesClient # type: ignore
16+
from ._client import MessageTemplateClient # type: ignore
1117
from ._version import VERSION
1218

1319
__version__ = VERSION
1420

1521
try:
1622
from ._patch import __all__ as _patch_all
17-
from ._patch import * # pylint: disable=unused-wildcard-import
23+
from ._patch import *
1824
except ImportError:
1925
_patch_all = []
2026
from ._patch import patch_sdk as _patch_sdk
@@ -23,6 +29,6 @@
2329
"NotificationMessagesClient",
2430
"MessageTemplateClient",
2531
]
26-
__all__.extend([p for p in _patch_all if p not in __all__])
32+
__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore
2733

2834
_patch_sdk()

sdk/communication/azure-communication-messages/azure/communication/messages/_api_versions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class ApiVersion(str, Enum, metaclass=CaseInsensitiveEnumMeta):
1111
V2023_08_24_PREVIEW = "2023-08-24-preview"
1212
V2024_02_01 = "2024-02-01"
1313
V2024_08_30 = "2024-08-30"
14+
V2025_01_15_PREVIEW = "2025-01-15-preview"
1415

1516

16-
DEFAULT_VERSION = ApiVersion.V2024_08_30.value
17+
DEFAULT_VERSION = ApiVersion.V2025_01_15_preview.value

sdk/communication/azure-communication-messages/azure/communication/messages/_client.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,22 @@
2020
from ._serialization import Deserializer, Serializer
2121

2222
if TYPE_CHECKING:
23-
# pylint: disable=unused-import,ungrouped-imports
2423
from azure.core.credentials import TokenCredential
2524

2625

27-
class NotificationMessagesClient(
28-
NotificationMessagesClientOperationsMixin
29-
): # pylint: disable=client-accepts-api-version-keyword
26+
class NotificationMessagesClient(NotificationMessagesClientOperationsMixin):
3027
"""NotificationMessagesClient.
3128
3229
:param endpoint: The communication resource, for example
3330
https://my-resource.communication.azure.com. Required.
3431
:type endpoint: str
35-
:param credential: Credential used to authenticate requests to the service. Is either a
36-
TokenCredential type or a AzureKeyCredential type. Required.
32+
:param credential: Credential used to authenticate requests to the service. Is either a token
33+
credential type or a AzureKeyCredential type. Required.
3734
:type credential: ~azure.core.credentials.TokenCredential or
3835
~azure.core.credentials.AzureKeyCredential
39-
:keyword api_version: The API version to use for this operation. Default value is "2024-08-30".
40-
Note that overriding this default value may result in unsupported behavior.
36+
:keyword api_version: The API version to use for this operation. Default value is
37+
"2025-01-15-preview". Note that overriding this default value may result in unsupported
38+
behavior.
4139
:paramtype api_version: str
4240
"""
4341

@@ -104,18 +102,19 @@ def __exit__(self, *exc_details: Any) -> None:
104102
self._client.__exit__(*exc_details)
105103

106104

107-
class MessageTemplateClient(MessageTemplateClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword
105+
class MessageTemplateClient(MessageTemplateClientOperationsMixin):
108106
"""MessageTemplateClient.
109107
110108
:param endpoint: The communication resource, for example
111109
https://my-resource.communication.azure.com. Required.
112110
:type endpoint: str
113-
:param credential: Credential used to authenticate requests to the service. Is either a
114-
TokenCredential type or a AzureKeyCredential type. Required.
111+
:param credential: Credential used to authenticate requests to the service. Is either a token
112+
credential type or a AzureKeyCredential type. Required.
115113
:type credential: ~azure.core.credentials.TokenCredential or
116114
~azure.core.credentials.AzureKeyCredential
117-
:keyword api_version: The API version to use for this operation. Default value is "2024-08-30".
118-
Note that overriding this default value may result in unsupported behavior.
115+
:keyword api_version: The API version to use for this operation. Default value is
116+
"2025-01-15-preview". Note that overriding this default value may result in unsupported
117+
behavior.
119118
:paramtype api_version: str
120119
"""
121120

sdk/communication/azure-communication-messages/azure/communication/messages/_configuration.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414
from ._version import VERSION
1515

1616
if TYPE_CHECKING:
17-
# pylint: disable=unused-import,ungrouped-imports
1817
from azure.core.credentials import TokenCredential
1918

2019

21-
class NotificationMessagesClientConfiguration: # pylint: disable=too-many-instance-attributes,name-too-long
20+
class NotificationMessagesClientConfiguration: # pylint: disable=too-many-instance-attributes
2221
"""Configuration for NotificationMessagesClient.
2322
2423
Note that all parameters used to create this instance are saved as instance
@@ -27,17 +26,18 @@ class NotificationMessagesClientConfiguration: # pylint: disable=too-many-insta
2726
:param endpoint: The communication resource, for example
2827
https://my-resource.communication.azure.com. Required.
2928
:type endpoint: str
30-
:param credential: Credential used to authenticate requests to the service. Is either a
31-
TokenCredential type or a AzureKeyCredential type. Required.
29+
:param credential: Credential used to authenticate requests to the service. Is either a token
30+
credential type or a AzureKeyCredential type. Required.
3231
:type credential: ~azure.core.credentials.TokenCredential or
3332
~azure.core.credentials.AzureKeyCredential
34-
:keyword api_version: The API version to use for this operation. Default value is "2024-08-30".
35-
Note that overriding this default value may result in unsupported behavior.
33+
:keyword api_version: The API version to use for this operation. Default value is
34+
"2025-01-15-preview". Note that overriding this default value may result in unsupported
35+
behavior.
3636
:paramtype api_version: str
3737
"""
3838

3939
def __init__(self, endpoint: str, credential: Union["TokenCredential", AzureKeyCredential], **kwargs: Any) -> None:
40-
api_version: str = kwargs.pop("api_version", "2024-08-30")
40+
api_version: str = kwargs.pop("api_version", "2025-01-15-preview")
4141

4242
if endpoint is None:
4343
raise ValueError("Parameter 'endpoint' must not be None.")
@@ -73,7 +73,7 @@ def _configure(self, **kwargs: Any) -> None:
7373
self.authentication_policy = self._infer_policy(**kwargs)
7474

7575

76-
class MessageTemplateClientConfiguration: # pylint: disable=too-many-instance-attributes,name-too-long
76+
class MessageTemplateClientConfiguration: # pylint: disable=too-many-instance-attributes
7777
"""Configuration for MessageTemplateClient.
7878
7979
Note that all parameters used to create this instance are saved as instance
@@ -82,17 +82,18 @@ class MessageTemplateClientConfiguration: # pylint: disable=too-many-instance-a
8282
:param endpoint: The communication resource, for example
8383
https://my-resource.communication.azure.com. Required.
8484
:type endpoint: str
85-
:param credential: Credential used to authenticate requests to the service. Is either a
86-
TokenCredential type or a AzureKeyCredential type. Required.
85+
:param credential: Credential used to authenticate requests to the service. Is either a token
86+
credential type or a AzureKeyCredential type. Required.
8787
:type credential: ~azure.core.credentials.TokenCredential or
8888
~azure.core.credentials.AzureKeyCredential
89-
:keyword api_version: The API version to use for this operation. Default value is "2024-08-30".
90-
Note that overriding this default value may result in unsupported behavior.
89+
:keyword api_version: The API version to use for this operation. Default value is
90+
"2025-01-15-preview". Note that overriding this default value may result in unsupported
91+
behavior.
9192
:paramtype api_version: str
9293
"""
9394

9495
def __init__(self, endpoint: str, credential: Union["TokenCredential", AzureKeyCredential], **kwargs: Any) -> None:
95-
api_version: str = kwargs.pop("api_version", "2024-08-30")
96+
api_version: str = kwargs.pop("api_version", "2025-01-15-preview")
9697

9798
if endpoint is None:
9899
raise ValueError("Parameter 'endpoint' must not be None.")

sdk/communication/azure-communication-messages/azure/communication/messages/_model_base.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
# pylint: disable=too-many-lines
12
# coding=utf-8
23
# --------------------------------------------------------------------------
34
# Copyright (c) Microsoft Corporation. All rights reserved.
45
# Licensed under the MIT License. See License.txt in the project root for
56
# license information.
67
# --------------------------------------------------------------------------
7-
# pylint: disable=protected-access, arguments-differ, signature-differs, broad-except, too-many-lines
8+
# pylint: disable=protected-access, broad-except
89

910
import copy
1011
import calendar
@@ -573,7 +574,7 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:
573574
def copy(self) -> "Model":
574575
return Model(self.__dict__)
575576

576-
def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: disable=unused-argument
577+
def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self:
577578
if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated:
578579
# we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping',
579580
# 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object'
@@ -584,8 +585,8 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: di
584585
annotations = {
585586
k: v
586587
for mro_class in mros
587-
if hasattr(mro_class, "__annotations__") # pylint: disable=no-member
588-
for k, v in mro_class.__annotations__.items() # pylint: disable=no-member
588+
if hasattr(mro_class, "__annotations__")
589+
for k, v in mro_class.__annotations__.items()
589590
}
590591
for attr, rf in attr_to_rest_field.items():
591592
rf._module = cls.__module__
@@ -600,8 +601,8 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: di
600601

601602
def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None:
602603
for base in cls.__bases__:
603-
if hasattr(base, "__mapping__"): # pylint: disable=no-member
604-
base.__mapping__[discriminator or cls.__name__] = cls # type: ignore # pylint: disable=no-member
604+
if hasattr(base, "__mapping__"):
605+
base.__mapping__[discriminator or cls.__name__] = cls # type: ignore
605606

606607
@classmethod
607608
def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField"]:
@@ -612,7 +613,7 @@ def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField
612613

613614
@classmethod
614615
def _deserialize(cls, data, exist_discriminators):
615-
if not hasattr(cls, "__mapping__"): # pylint: disable=no-member
616+
if not hasattr(cls, "__mapping__"):
616617
return cls(data)
617618
discriminator = cls._get_discriminator(exist_discriminators)
618619
if discriminator is None:
@@ -632,11 +633,11 @@ def _deserialize(cls, data, exist_discriminators):
632633
discriminator_value = data.find(xml_name).text # pyright: ignore
633634
else:
634635
discriminator_value = data.get(discriminator._rest_name)
635-
mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member
636+
mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore
636637
return mapped_cls._deserialize(data, exist_discriminators)
637638

638639
def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]:
639-
"""Return a dict that can be JSONify using json.dump.
640+
"""Return a dict that can be turned into json using json.dump.
640641
641642
:keyword bool exclude_readonly: Whether to remove the readonly properties.
642643
:returns: A dict JSON compatible object
@@ -733,7 +734,7 @@ def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.An
733734
)
734735

735736

736-
def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, R0912
737+
def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-branches
737738
annotation: typing.Any,
738739
module: typing.Optional[str],
739740
rf: typing.Optional["_RestField"] = None,
@@ -753,7 +754,7 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
753754
except AttributeError:
754755
model_name = annotation
755756
if module is not None:
756-
annotation = _get_model(module, model_name)
757+
annotation = _get_model(module, model_name) # type: ignore
757758

758759
try:
759760
if module and _is_model(annotation):
@@ -893,6 +894,22 @@ def _deserialize(
893894
return _deserialize_with_callable(deserializer, value)
894895

895896

897+
def _failsafe_deserialize(
898+
deserializer: typing.Any,
899+
value: typing.Any,
900+
module: typing.Optional[str] = None,
901+
rf: typing.Optional["_RestField"] = None,
902+
format: typing.Optional[str] = None,
903+
) -> typing.Any:
904+
try:
905+
return _deserialize(deserializer, value, module, rf, format)
906+
except DeserializationError:
907+
_LOGGER.warning(
908+
"Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True
909+
)
910+
return None
911+
912+
896913
class _RestField:
897914
def __init__(
898915
self,

sdk/communication/azure-communication-messages/azure/communication/messages/_operations/__init__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@
55
# Code generated by Microsoft (R) Python Code Generator.
66
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
77
# --------------------------------------------------------------------------
8+
# pylint: disable=wrong-import-position
89

9-
from ._operations import NotificationMessagesClientOperationsMixin
10-
from ._operations import MessageTemplateClientOperationsMixin
10+
from typing import TYPE_CHECKING
11+
12+
if TYPE_CHECKING:
13+
from ._patch import * # pylint: disable=unused-wildcard-import
14+
15+
from ._operations import NotificationMessagesClientOperationsMixin # type: ignore
16+
from ._operations import MessageTemplateClientOperationsMixin # type: ignore
1117

1218
from ._patch import __all__ as _patch_all
13-
from ._patch import * # pylint: disable=unused-wildcard-import
19+
from ._patch import *
1420
from ._patch import patch_sdk as _patch_sdk
1521

1622
__all__ = [
1723
"NotificationMessagesClientOperationsMixin",
1824
"MessageTemplateClientOperationsMixin",
1925
]
20-
__all__.extend([p for p in _patch_all if p not in __all__])
26+
__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore
2127
_patch_sdk()

0 commit comments

Comments
 (0)