Skip to content

Commit 802609d

Browse files
MikeyMCZMichal Maternakristapratico
authored
[Text Translation] Updating the SDK from the latest TypeSpec (#35450)
* [Text Translation] Updating the SDK from the latest TypeSpec * Using latest TypeSpec * Fixing PR comments * Lint fixes * Using the latest TypeSpec * Fixing PR comments * Using latest typespec * Switch to public TypeSpec location * Format * Fixes * format * fix * Fixes * Fix documentation * Lint fixes * Using latest TypeSpec * Switch to Entra Id name from AAD * format * Fixing tests * Fixing PR comment * Fixes * pyright rules * Fix PR comment * Fixing docs * Preparing for a release * Fixing PR comment * Fixing PR comments * Fix mypy * Fix the optional endpoint for async tests * Update sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_patch.py Co-authored-by: Krista Pratico <[email protected]> * Updated Changelog * Fix the changelog --------- Co-authored-by: Michal Materna <[email protected]> Co-authored-by: Krista Pratico <[email protected]>
1 parent 3353cb4 commit 802609d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1099
-1031
lines changed

sdk/translation/azure-ai-translation-text/CHANGELOG.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
# Release History
22

3-
## 1.0.0b2 (Unreleased)
3+
## 1.0.0 (2024-05-21)
44

55
### Features Added
6-
- Added support for AAD authentication.
6+
- Added support for Entra Id authentication.
77

88
### Breaking Changes
99

10-
- All calls to the client using parameter 'content' have been changed to use parameter 'request_body'.
10+
- All calls to the client using parameter `content` have been changed to use parameter `body`.
1111
- Users can call methods using just a string type instead of complex objects.
12-
13-
### Bugs Fixed
14-
15-
### Other Changes
12+
- `get_languages` methods were changed to `get_supported_languages`.
1613

1714
## 1.0.0b1 (2023-04-19)
1815

sdk/translation/azure-ai-translation-text/README.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,16 @@ az cognitiveservices account keys list --resource-group <your-resource-group-nam
5555

5656
#### Create a `TextTranslationClient` using an API key and Region credential
5757

58-
Once you have the value for the API key and Region, create an `TranslatorCredential`. This will allow you to
58+
Once you have the value for the API key and Region, create an `AzureKeyCredential`. This will allow you to
5959
update the API key without creating a new client.
6060

6161
With the value of the `endpoint`, `credential` and a `region`, you can create the [TextTranslationClient][client_sample]:
6262

6363
<!-- SNIPPET: sample_text_translation_client.create_text_translation_client_with_credential -->
6464

6565
```python
66-
credential = TranslatorCredential(apikey, region)
67-
text_translator = TextTranslationClient(credential=credential, endpoint=endpoint)
66+
credential = AzureKeyCredential(apikey)
67+
text_translator = TextTranslationClient(credential=credential, endpoint=endpoint, region=region)
6868
```
6969

7070
<!-- END SNIPPET -->
@@ -92,7 +92,7 @@ Gets the set of languages currently supported by other operations of the Transla
9292

9393
```python
9494
try:
95-
response = text_translator.get_languages()
95+
response = text_translator.get_supported_languages()
9696

9797
print(
9898
f"Number of supported languages for translate operation: {len(response.translation) if response.translation is not None else 0}"
@@ -140,10 +140,10 @@ Renders single source-language text to multiple target-language texts with a sin
140140

141141
```python
142142
try:
143-
target_languages = ["cs", "es", "de"]
143+
to = ["cs", "es", "de"]
144144
input_text_elements = ["This is a test"]
145145

146-
response = text_translator.translate(request_body=input_text_elements, to=target_languages)
146+
response = text_translator.translate(body=input_text_elements, to=to)
147147
translation = response[0] if response else None
148148

149149
if translation:
@@ -182,7 +182,10 @@ try:
182182
input_text_elements = ["这是个测试。"]
183183

184184
response = text_translator.transliterate(
185-
request_body=input_text_elements, language=language, from_script=from_script, to_script=to_script
185+
body=input_text_elements,
186+
language=language,
187+
from_script=from_script,
188+
to_script=to_script,
186189
)
187190
transliteration = response[0] if response else None
188191

@@ -212,11 +215,11 @@ Identifies the positioning of sentence boundaries in a piece of text.
212215
```python
213216
try:
214217
include_sentence_length = True
215-
target_languages = ["cs"]
218+
to = ["cs"]
216219
input_text_elements = ["The answer lies in machine translation. This is a test."]
217220

218221
response = text_translator.translate(
219-
request_body=input_text_elements, to=target_languages, include_sentence_length=include_sentence_length
222+
body=input_text_elements, to=to, include_sentence_length=include_sentence_length
220223
)
221224
translation = response[0] if response else None
222225

@@ -252,12 +255,12 @@ Returns equivalent words for the source term in the target language.
252255

253256
```python
254257
try:
255-
source_language = "en"
256-
target_language = "es"
258+
from_parameter = "en"
259+
to = "es"
257260
input_text_elements = ["fly"]
258261

259262
response = text_translator.lookup_dictionary_entries(
260-
request_body=input_text_elements, from_parameter=source_language, to=target_language
263+
body=input_text_elements, from_parameter=from_parameter, to=to
261264
)
262265
dictionary_entry = response[0] if response else None
263266

@@ -288,12 +291,12 @@ Returns grammatical structure and context examples for the source term and targe
288291

289292
```python
290293
try:
291-
source_language = "en"
292-
target_language = "es"
294+
from_parameter = "en"
295+
to = "es"
293296
input_text_elements = [DictionaryExampleTextItem(text="fly", translation="volar")]
294297

295298
response = text_translator.lookup_dictionary_examples(
296-
content=input_text_elements, from_parameter=source_language, to=target_language
299+
body=input_text_elements, from_parameter=from_parameter, to=to
297300
)
298301
dictionary_entry = response[0] if response else None
299302

sdk/translation/azure-ai-translation-text/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/translation/azure-ai-translation-text",
5-
"Tag": "python/translation/azure-ai-translation-text_afde2bdc8c"
5+
"Tag": "python/translation/azure-ai-translation-text_35ab9367d7"
66
}

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
77
# --------------------------------------------------------------------------
88

9-
from ._patch import TextTranslationClient, TranslatorCredential, TranslatorAADCredential
9+
from ._patch import TextTranslationClient
1010
from ._version import VERSION
1111

1212
__version__ = VERSION
1313

14+
1415
from ._patch import patch_sdk as _patch_sdk
1516

1617
__all__ = [
17-
"TranslatorCredential",
18-
"TranslatorAADCredential",
1918
"TextTranslationClient",
2019
]
2120

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_model_base.py

Lines changed: 80 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
# --------------------------------------------------------------------------
77
# pylint: disable=protected-access, arguments-differ, signature-differs, broad-except
88

9+
import copy
910
import calendar
1011
import decimal
1112
import functools
1213
import sys
1314
import logging
1415
import base64
1516
import re
16-
import copy
1717
import typing
1818
import enum
1919
import email.utils
@@ -339,7 +339,7 @@ def _get_model(module_name: str, model_name: str):
339339

340340
class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=unsubscriptable-object
341341
def __init__(self, data: typing.Dict[str, typing.Any]) -> None:
342-
self._data = copy.deepcopy(data)
342+
self._data = data
343343

344344
def __contains__(self, key: typing.Any) -> bool:
345345
return key in self._data
@@ -378,16 +378,13 @@ def get(self, key: str, default: typing.Any = None) -> typing.Any:
378378
return default
379379

380380
@typing.overload
381-
def pop(self, key: str) -> typing.Any:
382-
...
381+
def pop(self, key: str) -> typing.Any: ...
383382

384383
@typing.overload
385-
def pop(self, key: str, default: _T) -> _T:
386-
...
384+
def pop(self, key: str, default: _T) -> _T: ...
387385

388386
@typing.overload
389-
def pop(self, key: str, default: typing.Any) -> typing.Any:
390-
...
387+
def pop(self, key: str, default: typing.Any) -> typing.Any: ...
391388

392389
def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
393390
if default is _UNSET:
@@ -404,12 +401,10 @@ def update(self, *args: typing.Any, **kwargs: typing.Any) -> None:
404401
self._data.update(*args, **kwargs)
405402

406403
@typing.overload
407-
def setdefault(self, key: str, default: None = None) -> None:
408-
...
404+
def setdefault(self, key: str, default: None = None) -> None: ...
409405

410406
@typing.overload
411-
def setdefault(self, key: str, default: typing.Any) -> typing.Any:
412-
...
407+
def setdefault(self, key: str, default: typing.Any) -> typing.Any: ...
413408

414409
def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
415410
if default is _UNSET:
@@ -594,6 +589,64 @@ def _as_dict_value(v: typing.Any, exclude_readonly: bool = False) -> typing.Any:
594589
return v.as_dict(exclude_readonly=exclude_readonly) if hasattr(v, "as_dict") else v
595590

596591

592+
def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
593+
if _is_model(obj):
594+
return obj
595+
return _deserialize(model_deserializer, obj)
596+
597+
598+
def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj):
599+
if obj is None:
600+
return obj
601+
return _deserialize_with_callable(if_obj_deserializer, obj)
602+
603+
604+
def _deserialize_with_union(deserializers, obj):
605+
for deserializer in deserializers:
606+
try:
607+
return _deserialize(deserializer, obj)
608+
except DeserializationError:
609+
pass
610+
raise DeserializationError()
611+
612+
613+
def _deserialize_dict(
614+
value_deserializer: typing.Optional[typing.Callable],
615+
module: typing.Optional[str],
616+
obj: typing.Dict[typing.Any, typing.Any],
617+
):
618+
if obj is None:
619+
return obj
620+
return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()}
621+
622+
623+
def _deserialize_multiple_sequence(
624+
entry_deserializers: typing.List[typing.Optional[typing.Callable]],
625+
module: typing.Optional[str],
626+
obj,
627+
):
628+
if obj is None:
629+
return obj
630+
return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers))
631+
632+
633+
def _deserialize_sequence(
634+
deserializer: typing.Optional[typing.Callable],
635+
module: typing.Optional[str],
636+
obj,
637+
):
638+
if obj is None:
639+
return obj
640+
return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)
641+
642+
643+
def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]:
644+
return sorted(
645+
types,
646+
key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"),
647+
)
648+
649+
597650
def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, R0912
598651
annotation: typing.Any,
599652
module: typing.Optional[str],
@@ -621,11 +674,6 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
621674
if rf:
622675
rf._is_model = True
623676

624-
def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
625-
if _is_model(obj):
626-
return obj
627-
return _deserialize(model_deserializer, obj)
628-
629677
return functools.partial(_deserialize_model, annotation) # pyright: ignore
630678
except Exception:
631679
pass
@@ -640,36 +688,27 @@ def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj
640688
# is it optional?
641689
try:
642690
if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore
643-
if_obj_deserializer = _get_deserialize_callable_from_annotation(
644-
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore
645-
)
646-
647-
def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj):
648-
if obj is None:
649-
return obj
650-
return _deserialize_with_callable(if_obj_deserializer, obj)
651-
652-
return functools.partial(_deserialize_with_optional, if_obj_deserializer)
691+
if len(annotation.__args__) <= 2: # pyright: ignore
692+
if_obj_deserializer = _get_deserialize_callable_from_annotation(
693+
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore
694+
)
695+
696+
return functools.partial(_deserialize_with_optional, if_obj_deserializer)
697+
# the type is Optional[Union[...]], we need to remove the None type from the Union
698+
annotation_copy = copy.copy(annotation)
699+
annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore
700+
return _get_deserialize_callable_from_annotation(annotation_copy, module, rf)
653701
except AttributeError:
654702
pass
655703

704+
# is it union?
656705
if getattr(annotation, "__origin__", None) is typing.Union:
657706
# initial ordering is we make `string` the last deserialization option, because it is often them most generic
658707
deserializers = [
659708
_get_deserialize_callable_from_annotation(arg, module, rf)
660-
for arg in sorted(
661-
annotation.__args__, key=lambda x: hasattr(x, "__name__") and x.__name__ == "str" # pyright: ignore
662-
)
709+
for arg in _sorted_annotations(annotation.__args__) # pyright: ignore
663710
]
664711

665-
def _deserialize_with_union(deserializers, obj):
666-
for deserializer in deserializers:
667-
try:
668-
return _deserialize(deserializer, obj)
669-
except DeserializationError:
670-
pass
671-
raise DeserializationError()
672-
673712
return functools.partial(_deserialize_with_union, deserializers)
674713

675714
try:
@@ -678,53 +717,27 @@ def _deserialize_with_union(deserializers, obj):
678717
annotation.__args__[1], module, rf # pyright: ignore
679718
)
680719

681-
def _deserialize_dict(
682-
value_deserializer: typing.Optional[typing.Callable],
683-
obj: typing.Dict[typing.Any, typing.Any],
684-
):
685-
if obj is None:
686-
return obj
687-
return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()}
688-
689720
return functools.partial(
690721
_deserialize_dict,
691722
value_deserializer,
723+
module,
692724
)
693725
except (AttributeError, IndexError):
694726
pass
695727
try:
696728
if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore
697729
if len(annotation.__args__) > 1: # pyright: ignore
698730

699-
def _deserialize_multiple_sequence(
700-
entry_deserializers: typing.List[typing.Optional[typing.Callable]],
701-
obj,
702-
):
703-
if obj is None:
704-
return obj
705-
return type(obj)(
706-
_deserialize(deserializer, entry, module)
707-
for entry, deserializer in zip(obj, entry_deserializers)
708-
)
709-
710731
entry_deserializers = [
711732
_get_deserialize_callable_from_annotation(dt, module, rf)
712733
for dt in annotation.__args__ # pyright: ignore
713734
]
714-
return functools.partial(_deserialize_multiple_sequence, entry_deserializers)
735+
return functools.partial(_deserialize_multiple_sequence, entry_deserializers, module)
715736
deserializer = _get_deserialize_callable_from_annotation(
716737
annotation.__args__[0], module, rf # pyright: ignore
717738
)
718739

719-
def _deserialize_sequence(
720-
deserializer: typing.Optional[typing.Callable],
721-
obj,
722-
):
723-
if obj is None:
724-
return obj
725-
return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)
726-
727-
return functools.partial(_deserialize_sequence, deserializer)
740+
return functools.partial(_deserialize_sequence, deserializer, module)
728741
except (TypeError, IndexError, AttributeError, SyntaxError):
729742
pass
730743

0 commit comments

Comments
 (0)