Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Text Translation] Updating the SDK from the latest TypeSpec #35450

Merged
merged 33 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions sdk/translation/azure-ai-translation-text/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
# Release History

## 1.0.0b2 (Unreleased)
## 1.0.0 (2024-05-21)

### Features Added
- Added support for AAD authentication.
- Added support for Entra Id authentication.

### Breaking Changes

- All calls to the client using parameter 'content' have been changed to use parameter 'request_body'.
- All calls to the client using parameter 'content' have been changed to use parameter 'body'.
- Users can call methods using just a string type instead of complex objects.

### Bugs Fixed

### Other Changes

## 1.0.0b1 (2023-04-19)

- Initial Release
33 changes: 18 additions & 15 deletions sdk/translation/azure-ai-translation-text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ az cognitiveservices account keys list --resource-group <your-resource-group-nam

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

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

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

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

```python
credential = TranslatorCredential(apikey, region)
text_translator = TextTranslationClient(credential=credential, endpoint=endpoint)
credential = AzureKeyCredential(apikey)
text_translator = TextTranslationClient(credential=credential, endpoint=endpoint, region=region)
```

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

```python
try:
response = text_translator.get_languages()
response = text_translator.get_supported_languages()
MikeyMCZ marked this conversation as resolved.
Show resolved Hide resolved

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

```python
try:
target_languages = ["cs", "es", "de"]
to = ["cs", "es", "de"]
input_text_elements = ["This is a test"]

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

if translation:
Expand Down Expand Up @@ -182,7 +182,10 @@ try:
input_text_elements = ["这是个测试。"]

response = text_translator.transliterate(
request_body=input_text_elements, language=language, from_script=from_script, to_script=to_script
body=input_text_elements,
language=language,
from_script=from_script,
to_script=to_script,
)
transliteration = response[0] if response else None

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

response = text_translator.translate(
request_body=input_text_elements, to=target_languages, include_sentence_length=include_sentence_length
body=input_text_elements, to=to, include_sentence_length=include_sentence_length
)
translation = response[0] if response else None

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

```python
try:
source_language = "en"
target_language = "es"
from_parameter = "en"
to = "es"
input_text_elements = ["fly"]

response = text_translator.lookup_dictionary_entries(
request_body=input_text_elements, from_parameter=source_language, to=target_language
body=input_text_elements, from_parameter=from_parameter, to=to
)
dictionary_entry = response[0] if response else None

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

```python
try:
source_language = "en"
target_language = "es"
from_parameter = "en"
to = "es"
input_text_elements = [DictionaryExampleTextItem(text="fly", translation="volar")]

response = text_translator.lookup_dictionary_examples(
content=input_text_elements, from_parameter=source_language, to=target_language
body=input_text_elements, from_parameter=from_parameter, to=to
)
dictionary_entry = response[0] if response else None

Expand Down
2 changes: 1 addition & 1 deletion sdk/translation/azure-ai-translation-text/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "python",
"TagPrefix": "python/translation/azure-ai-translation-text",
"Tag": "python/translation/azure-ai-translation-text_afde2bdc8c"
"Tag": "python/translation/azure-ai-translation-text_35ab9367d7"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from ._patch import TextTranslationClient, TranslatorCredential, TranslatorAADCredential
from ._patch import TextTranslationClient
from ._version import VERSION

__version__ = VERSION


from ._patch import patch_sdk as _patch_sdk

__all__ = [
"TranslatorCredential",
"TranslatorAADCredential",
"TextTranslationClient",
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
# --------------------------------------------------------------------------
# pylint: disable=protected-access, arguments-differ, signature-differs, broad-except

import copy
import calendar
import decimal
import functools
import sys
import logging
import base64
import re
import copy
import typing
import enum
import email.utils
Expand Down Expand Up @@ -339,7 +339,7 @@ def _get_model(module_name: str, model_name: str):

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

def __contains__(self, key: typing.Any) -> bool:
return key in self._data
Expand Down Expand Up @@ -378,16 +378,13 @@ def get(self, key: str, default: typing.Any = None) -> typing.Any:
return default

@typing.overload
def pop(self, key: str) -> typing.Any:
...
def pop(self, key: str) -> typing.Any: ...

@typing.overload
def pop(self, key: str, default: _T) -> _T:
...
def pop(self, key: str, default: _T) -> _T: ...

@typing.overload
def pop(self, key: str, default: typing.Any) -> typing.Any:
...
def pop(self, key: str, default: typing.Any) -> typing.Any: ...

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

@typing.overload
def setdefault(self, key: str, default: None = None) -> None:
...
def setdefault(self, key: str, default: None = None) -> None: ...

@typing.overload
def setdefault(self, key: str, default: typing.Any) -> typing.Any:
...
def setdefault(self, key: str, default: typing.Any) -> typing.Any: ...

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


def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
if _is_model(obj):
return obj
return _deserialize(model_deserializer, obj)


def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj):
if obj is None:
return obj
return _deserialize_with_callable(if_obj_deserializer, obj)


def _deserialize_with_union(deserializers, obj):
for deserializer in deserializers:
try:
return _deserialize(deserializer, obj)
except DeserializationError:
pass
raise DeserializationError()


def _deserialize_dict(
value_deserializer: typing.Optional[typing.Callable],
module: typing.Optional[str],
obj: typing.Dict[typing.Any, typing.Any],
):
if obj is None:
return obj
return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()}


def _deserialize_multiple_sequence(
entry_deserializers: typing.List[typing.Optional[typing.Callable]],
module: typing.Optional[str],
obj,
):
if obj is None:
return obj
return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers))


def _deserialize_sequence(
deserializer: typing.Optional[typing.Callable],
module: typing.Optional[str],
obj,
):
if obj is None:
return obj
return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)


def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]:
return sorted(
types,
key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"),
)


def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, R0912
annotation: typing.Any,
module: typing.Optional[str],
Expand Down Expand Up @@ -621,11 +674,6 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
if rf:
rf._is_model = True

def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj):
if _is_model(obj):
return obj
return _deserialize(model_deserializer, obj)

return functools.partial(_deserialize_model, annotation) # pyright: ignore
except Exception:
pass
Expand All @@ -640,36 +688,27 @@ def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj
# is it optional?
try:
if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore
if_obj_deserializer = _get_deserialize_callable_from_annotation(
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore
)

def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj):
if obj is None:
return obj
return _deserialize_with_callable(if_obj_deserializer, obj)

return functools.partial(_deserialize_with_optional, if_obj_deserializer)
if len(annotation.__args__) <= 2: # pyright: ignore
if_obj_deserializer = _get_deserialize_callable_from_annotation(
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore
)

return functools.partial(_deserialize_with_optional, if_obj_deserializer)
# the type is Optional[Union[...]], we need to remove the None type from the Union
annotation_copy = copy.copy(annotation)
annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore
return _get_deserialize_callable_from_annotation(annotation_copy, module, rf)
except AttributeError:
pass

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

def _deserialize_with_union(deserializers, obj):
for deserializer in deserializers:
try:
return _deserialize(deserializer, obj)
except DeserializationError:
pass
raise DeserializationError()

return functools.partial(_deserialize_with_union, deserializers)

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

def _deserialize_dict(
value_deserializer: typing.Optional[typing.Callable],
obj: typing.Dict[typing.Any, typing.Any],
):
if obj is None:
return obj
return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()}

return functools.partial(
_deserialize_dict,
value_deserializer,
module,
)
except (AttributeError, IndexError):
pass
try:
if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore
if len(annotation.__args__) > 1: # pyright: ignore

def _deserialize_multiple_sequence(
entry_deserializers: typing.List[typing.Optional[typing.Callable]],
obj,
):
if obj is None:
return obj
return type(obj)(
_deserialize(deserializer, entry, module)
for entry, deserializer in zip(obj, entry_deserializers)
)

entry_deserializers = [
_get_deserialize_callable_from_annotation(dt, module, rf)
for dt in annotation.__args__ # pyright: ignore
]
return functools.partial(_deserialize_multiple_sequence, entry_deserializers)
return functools.partial(_deserialize_multiple_sequence, entry_deserializers, module)
deserializer = _get_deserialize_callable_from_annotation(
annotation.__args__[0], module, rf # pyright: ignore
)

def _deserialize_sequence(
deserializer: typing.Optional[typing.Callable],
obj,
):
if obj is None:
return obj
return type(obj)(_deserialize(deserializer, entry, module) for entry in obj)

return functools.partial(_deserialize_sequence, deserializer)
return functools.partial(_deserialize_sequence, deserializer, module)
except (TypeError, IndexError, AttributeError, SyntaxError):
pass

Expand Down
Loading
Loading