diff --git a/sdk/vision/azure-ai-vision-imageanalysis/MANIFEST.in b/sdk/vision/azure-ai-vision-imageanalysis/MANIFEST.in index 0239ba4fd05b..19b8f97e43b7 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/MANIFEST.in +++ b/sdk/vision/azure-ai-vision-imageanalysis/MANIFEST.in @@ -1,8 +1,8 @@ include *.md include LICENSE include azure/ai/vision/imageanalysis/py.typed -recursive-include tests *.py *.md sample.jpg -recursive-include samples *.py *.md sample.jpg run_all_samples.cmd run_all_samples.ps1 +recursive-include tests *.py +recursive-include samples *.py *.md include azure/__init__.py include azure/ai/__init__.py include azure/ai/vision/__init__.py \ No newline at end of file diff --git a/sdk/vision/azure-ai-vision-imageanalysis/_meta.json b/sdk/vision/azure-ai-vision-imageanalysis/_meta.json index e63fcb6c8802..0a6213521af8 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/_meta.json +++ b/sdk/vision/azure-ai-vision-imageanalysis/_meta.json @@ -1,6 +1,6 @@ { - "commit": "bef35d01d2572ba131d7f2d4cd8d6313ec649525", + "commit": "9029d073924ec35c84b2973464bdd1f899fed75e", "repository_url": "https://github.com/Azure/azure-rest-api-specs", - "typespec_src": "specification/cognitiveservices/Vision.ImageAnalysis", - "@azure-tools/typespec-python": "0.15.0" + "typespec_src": "specification/ai/ImageAnalysis", + "@azure-tools/typespec-python": "0.40.0" } \ No newline at end of file diff --git a/sdk/vision/azure-ai-vision-imageanalysis/apiview-properties.json b/sdk/vision/azure-ai-vision-imageanalysis/apiview-properties.json new file mode 100644 index 000000000000..fbcee971ec43 --- /dev/null +++ b/sdk/vision/azure-ai-vision-imageanalysis/apiview-properties.json @@ -0,0 +1,25 @@ +{ + "CrossLanguagePackageId": "ImageAnalysis", + "CrossLanguageDefinitionId": { + "azure.ai.vision.imageanalysis.models.CaptionResult": "ImageAnalysis.CaptionResult", + "azure.ai.vision.imageanalysis.models.CropRegion": "ImageAnalysis.CropRegion", + "azure.ai.vision.imageanalysis.models.DenseCaption": "ImageAnalysis.DenseCaption", + "azure.ai.vision.imageanalysis.models.DenseCaptionsResult": "ImageAnalysis.DenseCaptionsResult", + "azure.ai.vision.imageanalysis.models.DetectedObject": "ImageAnalysis.DetectedObject", + "azure.ai.vision.imageanalysis.models.DetectedPerson": "ImageAnalysis.DetectedPerson", + "azure.ai.vision.imageanalysis.models.DetectedTag": "ImageAnalysis.DetectedTag", + "azure.ai.vision.imageanalysis.models.DetectedTextBlock": "ImageAnalysis.DetectedTextBlock", + "azure.ai.vision.imageanalysis.models.DetectedTextLine": "ImageAnalysis.DetectedTextLine", + "azure.ai.vision.imageanalysis.models.DetectedTextWord": "ImageAnalysis.DetectedTextWord", + "azure.ai.vision.imageanalysis.models.ImageAnalysisResult": "ImageAnalysis.ImageAnalysisResult", + "azure.ai.vision.imageanalysis.models.ImageBoundingBox": "ImageAnalysis.ImageBoundingBox", + "azure.ai.vision.imageanalysis.models.ImageMetadata": "ImageAnalysis.ImageMetadata", + "azure.ai.vision.imageanalysis.models.ImagePoint": "ImageAnalysis.ImagePoint", + "azure.ai.vision.imageanalysis.models.ObjectsResult": "ImageAnalysis.ObjectsResult", + "azure.ai.vision.imageanalysis.models.PeopleResult": "ImageAnalysis.PeopleResult", + "azure.ai.vision.imageanalysis.models.ReadResult": "ImageAnalysis.ReadResult", + "azure.ai.vision.imageanalysis.models.SmartCropsResult": "ImageAnalysis.SmartCropsResult", + "azure.ai.vision.imageanalysis.models.TagsResult": "ImageAnalysis.TagsResult", + "azure.ai.vision.imageanalysis.models.VisualFeatures": "ImageAnalysis.VisualFeatures" + } +} \ No newline at end of file diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/__init__.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/__init__.py index f7462abd47f7..21604fac8886 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/__init__.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/__init__.py @@ -5,18 +5,28 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._patch import ImageAnalysisClient +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._client import ImageAnalysisClient # type: ignore from ._version import VERSION __version__ = VERSION - +try: + from ._patch import __all__ as _patch_all + from ._patch import * +except ImportError: + _patch_all = [] from ._patch import patch_sdk as _patch_sdk __all__ = [ "ImageAnalysisClient", ] - +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_client.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_client.py index 95ffe98935a9..838e7e7eb22f 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_client.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_client.py @@ -20,18 +20,17 @@ from ._serialization import Deserializer, Serializer if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials import TokenCredential -class ImageAnalysisClient(ImageAnalysisClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword +class ImageAnalysisClient(ImageAnalysisClientOperationsMixin): """ImageAnalysisClient. :param endpoint: Azure AI Computer Vision endpoint (protocol and hostname, for example: - https://:code:``.cognitiveservices.azure.com). Required. + https://.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential used to authenticate requests to the service. Is either a - AzureKeyCredential type or a TokenCredential type. Required. + :param credential: Credential used to authenticate requests to the service. Is either a key + credential type or a token credential type. Required. :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials.TokenCredential :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_configuration.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_configuration.py index f743cd8decfa..d8e3880d91dd 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_configuration.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_configuration.py @@ -14,21 +14,20 @@ from ._version import VERSION if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials import TokenCredential -class ImageAnalysisClientConfiguration: # pylint: disable=too-many-instance-attributes,name-too-long +class ImageAnalysisClientConfiguration: # pylint: disable=too-many-instance-attributes """Configuration for ImageAnalysisClient. Note that all parameters used to create this instance are saved as instance attributes. :param endpoint: Azure AI Computer Vision endpoint (protocol and hostname, for example: - https://:code:``.cognitiveservices.azure.com). Required. + https://.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential used to authenticate requests to the service. Is either a - AzureKeyCredential type or a TokenCredential type. Required. + :param credential: Credential used to authenticate requests to the service. Is either a key + credential type or a token credential type. Required. :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials.TokenCredential :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_model_base.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_model_base.py index 43fd8c7e9b1b..3072ee252ed9 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_model_base.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_model_base.py @@ -1,10 +1,11 @@ +# pylint: disable=too-many-lines # 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. # -------------------------------------------------------------------------- -# pylint: disable=protected-access, arguments-differ, signature-differs, broad-except +# pylint: disable=protected-access, broad-except import copy import calendar @@ -19,6 +20,7 @@ import email.utils from datetime import datetime, date, time, timedelta, timezone from json import JSONEncoder +import xml.etree.ElementTree as ET from typing_extensions import Self import isodate from azure.core.exceptions import DeserializationError @@ -123,7 +125,7 @@ def _serialize_datetime(o, format: typing.Optional[str] = None): def _is_readonly(p): try: - return p._visibility == ["read"] # pylint: disable=protected-access + return p._visibility == ["read"] except AttributeError: return False @@ -286,6 +288,12 @@ def _deserialize_decimal(attr): return decimal.Decimal(str(attr)) +def _deserialize_int_as_str(attr): + if isinstance(attr, int): + return attr + return int(attr) + + _DESERIALIZE_MAPPING = { datetime: _deserialize_datetime, date: _deserialize_date, @@ -307,9 +315,11 @@ def _deserialize_decimal(attr): def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): + if annotation is int and rf and rf._format == "str": + return _deserialize_int_as_str if rf and rf._format: return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) - return _DESERIALIZE_MAPPING.get(annotation) + return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore def _get_type_alias_type(module_name: str, alias_name: str): @@ -363,15 +373,34 @@ def __ne__(self, other: typing.Any) -> bool: return not self.__eq__(other) def keys(self) -> typing.KeysView[str]: + """ + :returns: a set-like object providing a view on D's keys + :rtype: ~typing.KeysView + """ return self._data.keys() def values(self) -> typing.ValuesView[typing.Any]: + """ + :returns: an object providing a view on D's values + :rtype: ~typing.ValuesView + """ return self._data.values() def items(self) -> typing.ItemsView[str, typing.Any]: + """ + :returns: set-like object providing a view on D's items + :rtype: ~typing.ItemsView + """ return self._data.items() def get(self, key: str, default: typing.Any = None) -> typing.Any: + """ + Get the value for key if key is in the dictionary, else default. + :param str key: The key to look up. + :param any default: The value to return if key is not in the dictionary. Defaults to None + :returns: D[k] if k in D, else d. + :rtype: any + """ try: return self[key] except KeyError: @@ -387,17 +416,38 @@ def pop(self, key: str, default: _T) -> _T: ... def pop(self, key: str, default: typing.Any) -> typing.Any: ... def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any: + """ + Removes specified key and return the corresponding value. + :param str key: The key to pop. + :param any default: The value to return if key is not in the dictionary + :returns: The value corresponding to the key. + :rtype: any + :raises KeyError: If key is not found and default is not given. + """ if default is _UNSET: return self._data.pop(key) return self._data.pop(key, default) def popitem(self) -> typing.Tuple[str, typing.Any]: + """ + Removes and returns some (key, value) pair + :returns: The (key, value) pair. + :rtype: tuple + :raises KeyError: if D is empty. + """ return self._data.popitem() def clear(self) -> None: + """ + Remove all items from D. + """ self._data.clear() def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: + """ + Updates D from mapping/iterable E and F. + :param any args: Either a mapping object or an iterable of key-value pairs. + """ self._data.update(*args, **kwargs) @typing.overload @@ -407,6 +457,13 @@ def setdefault(self, key: str, default: None = None) -> None: ... def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: + """ + Same as calling D.get(k, d), and setting D[k]=d if k not found + :param str key: The key to look up. + :param any default: The value to set if key is not in the dictionary + :returns: D[k] if k in D, else d. + :rtype: any + """ if default is _UNSET: return self._data.setdefault(key) return self._data.setdefault(key, default) @@ -441,6 +498,10 @@ def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-m return float(o) if isinstance(o, enum.Enum): return o.value + if isinstance(o, int): + if format == "str": + return str(o) + return o try: # First try datetime.datetime return _serialize_datetime(o, format) @@ -471,11 +532,16 @@ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typin return value if rf._is_model: return _deserialize(rf._type, value) + if isinstance(value, ET.Element): + value = _deserialize(rf._type, value) return _serialize(value, rf._format) class Model(_MyMutableMapping): _is_model = True + # label whether current class's _attr_to_rest_field has been calculated + # could not see _attr_to_rest_field directly because subclass inherits it from parent class + _calculated: typing.Set[str] = set() def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: class_name = self.__class__.__name__ @@ -486,10 +552,58 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: for rest_field in self._attr_to_rest_field.values() if rest_field._default is not _UNSET } - if args: - dict_to_pass.update( - {k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()} - ) + if args: # pylint: disable=too-many-nested-blocks + if isinstance(args[0], ET.Element): + existed_attr_keys = [] + model_meta = getattr(self, "_xml", {}) + + for rf in self._attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + # attribute + if prop_meta.get("attribute", False) and args[0].get(xml_name) is not None: + existed_attr_keys.append(xml_name) + dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].get(xml_name)) + continue + + # unwrapped element is array + if prop_meta.get("unwrapped", False): + # unwrapped array could either use prop items meta/prop meta + if prop_meta.get("itemsName"): + xml_name = prop_meta.get("itemsName") + xml_ns = prop_meta.get("itemNs") + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + items = args[0].findall(xml_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(xml_name) + dict_to_pass[rf._rest_name] = _deserialize(rf._type, items) + continue + + # text element is primitive type + if prop_meta.get("text", False): + if args[0].text is not None: + dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].text) + continue + + # wrapped element could be normal property or array, it should only have one element + item = args[0].find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + dict_to_pass[rf._rest_name] = _deserialize(rf._type, item) + + # rest thing is additional properties + for e in args[0]: + if e.tag not in existed_attr_keys: + dict_to_pass[e.tag] = _convert_element(e) + else: + dict_to_pass.update( + {k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()} + ) else: non_attr_kwargs = [k for k in kwargs if k not in self._attr_to_rest_field] if non_attr_kwargs: @@ -507,55 +621,70 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: def copy(self) -> "Model": return Model(self.__dict__) - def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: # pylint: disable=unused-argument - # we know the last three classes in mro are going to be 'Model', 'dict', and 'object' - mros = cls.__mro__[:-3][::-1] # ignore model, dict, and object parents, and reverse the mro order - attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property - k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type") - } - annotations = { - k: v - for mro_class in mros - if hasattr(mro_class, "__annotations__") # pylint: disable=no-member - for k, v in mro_class.__annotations__.items() # pylint: disable=no-member - } - for attr, rf in attr_to_rest_field.items(): - rf._module = cls.__module__ - if not rf._type: - rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None)) - if not rf._rest_name_input: - rf._rest_name_input = attr - cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items()) + def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: + if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated: + # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping', + # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object' + mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order + attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property + k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type") + } + annotations = { + k: v + for mro_class in mros + if hasattr(mro_class, "__annotations__") + for k, v in mro_class.__annotations__.items() + } + for attr, rf in attr_to_rest_field.items(): + rf._module = cls.__module__ + if not rf._type: + rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None)) + if not rf._rest_name_input: + rf._rest_name_input = attr + cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items()) + cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}") return super().__new__(cls) # pylint: disable=no-value-for-parameter def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None: for base in cls.__bases__: - if hasattr(base, "__mapping__"): # pylint: disable=no-member - base.__mapping__[discriminator or cls.__name__] = cls # type: ignore # pylint: disable=no-member + if hasattr(base, "__mapping__"): + base.__mapping__[discriminator or cls.__name__] = cls # type: ignore @classmethod - def _get_discriminator(cls, exist_discriminators) -> typing.Optional[str]: + def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField"]: for v in cls.__dict__.values(): - if ( - isinstance(v, _RestField) and v._is_discriminator and v._rest_name not in exist_discriminators - ): # pylint: disable=protected-access - return v._rest_name # pylint: disable=protected-access + if isinstance(v, _RestField) and v._is_discriminator and v._rest_name not in exist_discriminators: + return v return None @classmethod def _deserialize(cls, data, exist_discriminators): - if not hasattr(cls, "__mapping__"): # pylint: disable=no-member + if not hasattr(cls, "__mapping__"): return cls(data) discriminator = cls._get_discriminator(exist_discriminators) - exist_discriminators.append(discriminator) - mapped_cls = cls.__mapping__.get(data.get(discriminator), cls) # pyright: ignore # pylint: disable=no-member - if mapped_cls == cls: + if discriminator is None: return cls(data) - return mapped_cls._deserialize(data, exist_discriminators) # pylint: disable=protected-access + exist_discriminators.append(discriminator._rest_name) + if isinstance(data, ET.Element): + model_meta = getattr(cls, "_xml", {}) + prop_meta = getattr(discriminator, "_xml", {}) + xml_name = prop_meta.get("name", discriminator._rest_name) + xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + if data.get(xml_name) is not None: + discriminator_value = data.get(xml_name) + else: + discriminator_value = data.find(xml_name).text # pyright: ignore + else: + discriminator_value = data.get(discriminator._rest_name) + mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore + return mapped_cls._deserialize(data, exist_discriminators) def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]: - """Return a dict that can be JSONify using json.dump. + """Return a dict that can be turned into json using json.dump. :keyword bool exclude_readonly: Whether to remove the readonly properties. :returns: A dict JSON compatible object @@ -563,6 +692,7 @@ def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing. """ result = {} + readonly_props = [] if exclude_readonly: readonly_props = [p._rest_name for p in self._attr_to_rest_field.values() if _is_readonly(p)] for k, v in self.items(): @@ -617,6 +747,8 @@ def _deserialize_dict( ): if obj is None: return obj + if isinstance(obj, ET.Element): + obj = {child.tag: child for child in obj} return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()} @@ -637,6 +769,8 @@ def _deserialize_sequence( ): if obj is None: return obj + if isinstance(obj, ET.Element): + obj = list(obj) return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) @@ -647,12 +781,12 @@ def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.An ) -def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, R0912 +def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-branches annotation: typing.Any, module: typing.Optional[str], rf: typing.Optional["_RestField"] = None, ) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]: - if not annotation or annotation in [int, float]: + if not annotation: return None # is it a type alias? @@ -667,7 +801,7 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, except AttributeError: model_name = annotation if module is not None: - annotation = _get_model(module, model_name) + annotation = _get_model(module, model_name) # type: ignore try: if module and _is_model(annotation): @@ -727,7 +861,6 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, try: if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore if len(annotation.__args__) > 1: # pyright: ignore - entry_deserializers = [ _get_deserialize_callable_from_annotation(dt, module, rf) for dt in annotation.__args__ # pyright: ignore @@ -762,12 +895,23 @@ def _deserialize_default( def _deserialize_with_callable( deserializer: typing.Optional[typing.Callable[[typing.Any], typing.Any]], value: typing.Any, -): +): # pylint: disable=too-many-return-statements try: if value is None or isinstance(value, _Null): return None + if isinstance(value, ET.Element): + if deserializer is str: + return value.text or "" + if deserializer is int: + return int(value.text) if value.text else None + if deserializer is float: + return float(value.text) if value.text else None + if deserializer is bool: + return value.text == "true" if value.text else None if deserializer is None: return value + if deserializer in [int, float, bool]: + return deserializer(value) if isinstance(deserializer, CaseInsensitiveEnumMeta): try: return deserializer(value) @@ -797,6 +941,35 @@ def _deserialize( return _deserialize_with_callable(deserializer, value) +def _failsafe_deserialize( + deserializer: typing.Any, + value: typing.Any, + module: typing.Optional[str] = None, + rf: typing.Optional["_RestField"] = None, + format: typing.Optional[str] = None, +) -> typing.Any: + try: + return _deserialize(deserializer, value, module, rf, format) + except DeserializationError: + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + +def _failsafe_deserialize_xml( + deserializer: typing.Any, + value: typing.Any, +) -> typing.Any: + try: + return _deserialize_xml(deserializer, value) + except DeserializationError: + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + class _RestField: def __init__( self, @@ -808,6 +981,7 @@ def __init__( default: typing.Any = _UNSET, format: typing.Optional[str] = None, is_multipart_file_input: bool = False, + xml: typing.Optional[typing.Dict[str, typing.Any]] = None, ): self._type = type self._rest_name_input = name @@ -818,6 +992,7 @@ def __init__( self._default = default self._format = format self._is_multipart_file_input = is_multipart_file_input + self._xml = xml if xml is not None else {} @property def _class_type(self) -> typing.Any: @@ -868,6 +1043,7 @@ def rest_field( default: typing.Any = _UNSET, format: typing.Optional[str] = None, is_multipart_file_input: bool = False, + xml: typing.Optional[typing.Dict[str, typing.Any]] = None, ) -> typing.Any: return _RestField( name=name, @@ -876,6 +1052,7 @@ def rest_field( default=default, format=format, is_multipart_file_input=is_multipart_file_input, + xml=xml, ) @@ -884,5 +1061,175 @@ def rest_discriminator( name: typing.Optional[str] = None, type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin visibility: typing.Optional[typing.List[str]] = None, + xml: typing.Optional[typing.Dict[str, typing.Any]] = None, ) -> typing.Any: - return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility) + return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility, xml=xml) + + +def serialize_xml(model: Model, exclude_readonly: bool = False) -> str: + """Serialize a model to XML. + + :param Model model: The model to serialize. + :param bool exclude_readonly: Whether to exclude readonly properties. + :returns: The XML representation of the model. + :rtype: str + """ + return ET.tostring(_get_element(model, exclude_readonly), encoding="unicode") # type: ignore + + +def _get_element( + o: typing.Any, + exclude_readonly: bool = False, + parent_meta: typing.Optional[typing.Dict[str, typing.Any]] = None, + wrapped_element: typing.Optional[ET.Element] = None, +) -> typing.Union[ET.Element, typing.List[ET.Element]]: + if _is_model(o): + model_meta = getattr(o, "_xml", {}) + + # if prop is a model, then use the prop element directly, else generate a wrapper of model + if wrapped_element is None: + wrapped_element = _create_xml_element( + model_meta.get("name", o.__class__.__name__), + model_meta.get("prefix"), + model_meta.get("ns"), + ) + + readonly_props = [] + if exclude_readonly: + readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] + + for k, v in o.items(): + # do not serialize readonly properties + if exclude_readonly and k in readonly_props: + continue + + prop_rest_field = _get_rest_field(o._attr_to_rest_field, k) + if prop_rest_field: + prop_meta = getattr(prop_rest_field, "_xml").copy() + # use the wire name as xml name if no specific name is set + if prop_meta.get("name") is None: + prop_meta["name"] = k + else: + # additional properties will not have rest field, use the wire name as xml name + prop_meta = {"name": k} + + # if no ns for prop, use model's + if prop_meta.get("ns") is None and model_meta.get("ns"): + prop_meta["ns"] = model_meta.get("ns") + prop_meta["prefix"] = model_meta.get("prefix") + + if prop_meta.get("unwrapped", False): + # unwrapped could only set on array + wrapped_element.extend(_get_element(v, exclude_readonly, prop_meta)) + elif prop_meta.get("text", False): + # text could only set on primitive type + wrapped_element.text = _get_primitive_type_value(v) + elif prop_meta.get("attribute", False): + xml_name = prop_meta.get("name", k) + if prop_meta.get("ns"): + ET.register_namespace(prop_meta.get("prefix"), prop_meta.get("ns")) # pyright: ignore + xml_name = "{" + prop_meta.get("ns") + "}" + xml_name # pyright: ignore + # attribute should be primitive type + wrapped_element.set(xml_name, _get_primitive_type_value(v)) + else: + # other wrapped prop element + wrapped_element.append(_get_wrapped_element(v, exclude_readonly, prop_meta)) + return wrapped_element + if isinstance(o, list): + return [_get_element(x, exclude_readonly, parent_meta) for x in o] # type: ignore + if isinstance(o, dict): + result = [] + for k, v in o.items(): + result.append( + _get_wrapped_element( + v, + exclude_readonly, + { + "name": k, + "ns": parent_meta.get("ns") if parent_meta else None, + "prefix": parent_meta.get("prefix") if parent_meta else None, + }, + ) + ) + return result + + # primitive case need to create element based on parent_meta + if parent_meta: + return _get_wrapped_element( + o, + exclude_readonly, + { + "name": parent_meta.get("itemsName", parent_meta.get("name")), + "prefix": parent_meta.get("itemsPrefix", parent_meta.get("prefix")), + "ns": parent_meta.get("itemsNs", parent_meta.get("ns")), + }, + ) + + raise ValueError("Could not serialize value into xml: " + o) + + +def _get_wrapped_element( + v: typing.Any, + exclude_readonly: bool, + meta: typing.Optional[typing.Dict[str, typing.Any]], +) -> ET.Element: + wrapped_element = _create_xml_element( + meta.get("name") if meta else None, meta.get("prefix") if meta else None, meta.get("ns") if meta else None + ) + if isinstance(v, (dict, list)): + wrapped_element.extend(_get_element(v, exclude_readonly, meta)) + elif _is_model(v): + _get_element(v, exclude_readonly, meta, wrapped_element) + else: + wrapped_element.text = _get_primitive_type_value(v) + return wrapped_element + + +def _get_primitive_type_value(v) -> str: + if v is True: + return "true" + if v is False: + return "false" + if isinstance(v, _Null): + return "" + return str(v) + + +def _create_xml_element(tag, prefix=None, ns=None): + if prefix and ns: + ET.register_namespace(prefix, ns) + if ns: + return ET.Element("{" + ns + "}" + tag) + return ET.Element(tag) + + +def _deserialize_xml( + deserializer: typing.Any, + value: str, +) -> typing.Any: + element = ET.fromstring(value) # nosec + return _deserialize(deserializer, element) + + +def _convert_element(e: ET.Element): + # dict case + if len(e.attrib) > 0 or len({child.tag for child in e}) > 1: + dict_result: typing.Dict[str, typing.Any] = {} + for child in e: + if dict_result.get(child.tag) is not None: + if isinstance(dict_result[child.tag], list): + dict_result[child.tag].append(_convert_element(child)) + else: + dict_result[child.tag] = [dict_result[child.tag], _convert_element(child)] + else: + dict_result[child.tag] = _convert_element(child) + dict_result.update(e.attrib) + return dict_result + # array case + if len(e) > 0: + array_result: typing.List[typing.Any] = [] + for child in e: + array_result.append(_convert_element(child)) + return array_result + # primitive case + return e.text diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/__init__.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/__init__.py index 27c2169d2602..031981019ecd 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/__init__.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/__init__.py @@ -5,15 +5,21 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._operations import ImageAnalysisClientOperationsMixin +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._operations import ImageAnalysisClientOperationsMixin # type: ignore from ._patch import __all__ as _patch_all -from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ "ImageAnalysisClientOperationsMixin", ] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_operations.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_operations.py index 50aa5ad44859..0f03309322ac 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_operations.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_operations.py @@ -1,4 +1,3 @@ -# pylint: disable=too-many-lines,too-many-statements # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. @@ -9,7 +8,7 @@ from io import IOBase import json import sys -from typing import Any, Callable, Dict, IO, List, Optional, Type, TypeVar, Union, overload +from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union, overload from azure.core.exceptions import ( ClientAuthenticationError, @@ -17,6 +16,8 @@ ResourceExistsError, ResourceNotFoundError, ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, map_error, ) from azure.core.pipeline import PipelineResponse @@ -32,7 +33,7 @@ if sys.version_info >= (3, 9): from collections.abc import MutableMapping else: - from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports + from typing import MutableMapping # type: ignore JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -147,7 +148,8 @@ def _analyze_from_image_data( :paramtype visual_features: list[str or ~azure.ai.vision.imageanalysis.models.VisualFeatures] :keyword language: The desired language for result generation (a two-letter language code). If this option is not specified, the default value 'en' is used (English). - See https://aka.ms/cv-languages for a list of supported languages. Default value is None. + See `https://aka.ms/cv-languages `_ for a list of supported + languages. Default value is None. :paramtype language: str :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for Caption and Dense Captions features. @@ -173,121 +175,8 @@ def _analyze_from_image_data( :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "metadata": { - "height": 0, - "width": 0 - }, - "modelVersion": "str", - "captionResult": { - "confidence": 0.0, - "text": "str" - }, - "denseCaptionsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0, - "text": "str" - } - ] - }, - "objectsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "tags": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - ] - }, - "peopleResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0 - } - ] - }, - "readResult": { - "blocks": [ - { - "lines": [ - { - "boundingPolygon": [ - { - "x": 0, - "y": 0 - } - ], - "text": "str", - "words": [ - { - "boundingPolygon": [ - { - "x": - 0, - "y": - 0 - } - ], - "confidence": 0.0, - "text": "str" - } - ] - } - ] - } - ] - }, - "smartCropsResult": { - "values": [ - { - "aspectRatio": 0.0, - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - } - } - ] - }, - "tagsResult": { - "values": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - } """ - error_map: MutableMapping[int, Type[HttpResponseError]] = { + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -329,7 +218,10 @@ def _analyze_from_image_data( if response.status_code not in [200]: if _stream: - response.read() # Load the body in memory and close the socket + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -344,7 +236,7 @@ def _analyze_from_image_data( return deserialized # type: ignore @overload - def _analyze_from_url( # pylint: disable=protected-access + def _analyze_from_url( self, image_url: _models._models.ImageUrl, *, @@ -407,7 +299,8 @@ def _analyze_from_url( :paramtype visual_features: list[str or ~azure.ai.vision.imageanalysis.models.VisualFeatures] :keyword language: The desired language for result generation (a two-letter language code). If this option is not specified, the default value 'en' is used (English). - See https://aka.ms/cv-languages for a list of supported languages. Default value is None. + See `https://aka.ms/cv-languages `_ for a list of supported + languages. Default value is None. :paramtype language: str :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for Caption and Dense Captions features. @@ -433,126 +326,8 @@ def _analyze_from_url( :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - image_url = { - "url": "str" - } - - # response body for status code(s): 200 - response == { - "metadata": { - "height": 0, - "width": 0 - }, - "modelVersion": "str", - "captionResult": { - "confidence": 0.0, - "text": "str" - }, - "denseCaptionsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0, - "text": "str" - } - ] - }, - "objectsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "tags": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - ] - }, - "peopleResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0 - } - ] - }, - "readResult": { - "blocks": [ - { - "lines": [ - { - "boundingPolygon": [ - { - "x": 0, - "y": 0 - } - ], - "text": "str", - "words": [ - { - "boundingPolygon": [ - { - "x": - 0, - "y": - 0 - } - ], - "confidence": 0.0, - "text": "str" - } - ] - } - ] - } - ] - }, - "smartCropsResult": { - "values": [ - { - "aspectRatio": 0.0, - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - } - } - ] - }, - "tagsResult": { - "values": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - } """ - error_map: MutableMapping[int, Type[HttpResponseError]] = { + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -599,7 +374,10 @@ def _analyze_from_url( if response.status_code not in [200]: if _stream: - response.read() # Load the body in memory and close the socket + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_patch.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_patch.py index c88c2fa43a41..f7dd32510333 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_patch.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_operations/_patch.py @@ -1,8 +1,11 @@ -# 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. -# -------------------------------------------------------------------------- +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" from typing import List __all__: List[str] = [] # Add all objects you want publicly available to users at this package level diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_patch.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_patch.py index e89f5197c4e8..f7dd32510333 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_patch.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_patch.py @@ -5,154 +5,10 @@ """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize - """ -from typing import List, Any, Optional, Union -from azure.core.tracing.decorator import distributed_trace -from . import models as _models -from ._operations._operations import ImageAnalysisClientOperationsMixin -from ._client import ImageAnalysisClient as ImageAnalysisClientGenerated - - -class ImageAnalysisClient(ImageAnalysisClientGenerated): - """ImageAnalysisClient. - - :param endpoint: Azure AI Computer Vision endpoint (protocol and hostname, for example: - https://:code:``.cognitiveservices.azure.com). Required. - :type endpoint: str - :param credential: Credential used to authenticate requests to the service. Is either a - AzureKeyCredential type or a TokenCredential type. Required. - :type credential: ~azure.core.credentials.AzureKeyCredential or - ~azure.core.credentials.TokenCredential - :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". - Note that overriding this default value may result in unsupported behavior. - :paramtype api_version: str - """ - - @distributed_trace - def analyze_from_url( - self, - image_url: str, - visual_features: List[_models.VisualFeatures], - *, - language: Optional[str] = None, - gender_neutral_caption: Optional[bool] = None, - smart_crops_aspect_ratios: Optional[List[float]] = None, - model_version: Optional[str] = None, - **kwargs: Any - ) -> _models.ImageAnalysisResult: - """Performs a single Image Analysis operation. - - :param image_url: The publicly accessible URL of the image to analyze. - :type image_url: str - :param visual_features: A list of visual features to analyze. Required. Seven visual features - are supported: Caption, DenseCaptions, Read (OCR), Tags, Objects, SmartCrops, and People. At - least one visual feature must be specified. - :type visual_features: list[~azure.ai.vision.imageanalysis.models.VisualFeatures] - :keyword language: The desired language for result generation (a two-letter language code). - Defaults to 'en' (English). See https://aka.ms/cv-languages for a list of supported languages. - :paramtype language: str - :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for - Caption and Dense Captions features. Defaults to 'false'. - Captions may contain gender terms (for example: 'man', 'woman', or 'boy', 'girl'). - If you set this to 'true', those will be replaced with gender-neutral terms (for example: - 'person' or 'child'). - :paramtype gender_neutral_caption: bool - :keyword smart_crops_aspect_ratios: A list of aspect ratios to use for smart cropping. - Defaults to one crop region with an aspect ratio the service sees fit between - 0.5 and 2.0 (inclusive). Aspect ratios are calculated by dividing the target crop - width in pixels by the height in pixels. When set, supported values are - between 0.75 and 1.8 (inclusive). - :paramtype smart_crops_aspect_ratios: list[float] - :keyword model_version: The version of cloud AI-model used for analysis. Defaults to 'latest', - for the latest AI model with recent improvements. - The format is the following: 'latest' or 'YYYY-MM-DD' or 'YYYY-MM-DD-preview', - where 'YYYY', 'MM', 'DD' are the year, month and day associated with the model. - If you would like to make sure analysis results do not change over time, set this - value to a specific model version. - :paramtype model_version: str - :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping - :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - - visual_features_impl: List[Union[str, _models.VisualFeatures]] = list(visual_features) - - return ImageAnalysisClientOperationsMixin._analyze_from_url( # pylint: disable=protected-access - self, - image_url=_models._models.ImageUrl(url=image_url), # pylint: disable=protected-access - visual_features=visual_features_impl, - language=language, - gender_neutral_caption=gender_neutral_caption, - smart_crops_aspect_ratios=smart_crops_aspect_ratios, - model_version=model_version, - **kwargs - ) - - @distributed_trace - def analyze( - self, - image_data: bytes, - visual_features: List[_models.VisualFeatures], - *, - language: Optional[str] = None, - gender_neutral_caption: Optional[bool] = None, - smart_crops_aspect_ratios: Optional[List[float]] = None, - model_version: Optional[str] = None, - **kwargs: Any - ) -> _models.ImageAnalysisResult: - """Performs a single Image Analysis operation. - - :param image_data: A buffer containing the whole image to be analyzed. - :type image_data: bytes - :param visual_features: A list of visual features to analyze. Required. Seven visual features - are supported: Caption, DenseCaptions, Read (OCR), Tags, Objects, SmartCrops, and People. At - least one visual feature must be specified. - :type visual_features: list[~azure.ai.vision.imageanalysis.models.VisualFeatures] - :keyword language: The desired language for result generation (a two-letter language code). - Defaults to 'en' (English). See https://aka.ms/cv-languages for a list of supported languages. - :paramtype language: str - :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for - Caption and Dense Captions features. Defaults to 'false'. - Captions may contain gender terms (for example: 'man', 'woman', or 'boy', 'girl'). - If you set this to 'true', those will be replaced with gender-neutral terms (for example: - 'person' or 'child'). - :paramtype gender_neutral_caption: bool - :keyword smart_crops_aspect_ratios: A list of aspect ratios to use for smart cropping. - Defaults to one crop region with an aspect ratio the service sees fit between - 0.5 and 2.0 (inclusive). Aspect ratios are calculated by dividing the target crop - width in pixels by the height in pixels. When set, supported values are - between 0.75 and 1.8 (inclusive). - :paramtype smart_crops_aspect_ratios: list[float] - :keyword model_version: The version of cloud AI-model used for analysis. Defaults to 'latest', - for the latest AI model with recent improvements. - The format is the following: 'latest' or 'YYYY-MM-DD' or 'YYYY-MM-DD-preview', - where 'YYYY', 'MM', 'DD' are the year, month and day associated with the model. - If you would like to make sure analysis results do not change over time, set this - value to a specific model version. - :paramtype model_version: str - :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping - :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - - visual_features_impl: List[Union[str, _models.VisualFeatures]] = list(visual_features) - - return ImageAnalysisClientOperationsMixin._analyze_from_image_data( # pylint: disable=protected-access - self, - image_data=image_data, - visual_features=visual_features_impl, - language=language, - gender_neutral_caption=gender_neutral_caption, - smart_crops_aspect_ratios=smart_crops_aspect_ratios, - model_version=model_version, - **kwargs - ) - +from typing import List -__all__: List[str] = [ - "ImageAnalysisClient" -] # Add all objects you want publicly available to users at this package level +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_serialization.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_serialization.py index 8139854b97bb..7a0232de5ddc 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_serialization.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_serialization.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines # -------------------------------------------------------------------------- # # Copyright (c) Microsoft Corporation. All rights reserved. @@ -24,7 +25,6 @@ # # -------------------------------------------------------------------------- -# pylint: skip-file # pyright: reportUnnecessaryTypeIgnoreComment=false from base64 import b64decode, b64encode @@ -48,11 +48,8 @@ IO, Mapping, Callable, - TypeVar, MutableMapping, - Type, List, - Mapping, ) try: @@ -62,13 +59,13 @@ import xml.etree.ElementTree as ET import isodate # type: ignore +from typing_extensions import Self from azure.core.exceptions import DeserializationError, SerializationError from azure.core.serialization import NULL as CoreNull _BOM = codecs.BOM_UTF8.decode(encoding="utf-8") -ModelType = TypeVar("ModelType", bound="Model") JSON = MutableMapping[str, Any] @@ -91,6 +88,8 @@ def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: :param data: Input, could be bytes or stream (will be decoded with UTF8) or text :type data: str or bytes or IO :param str content_type: The content type. + :return: The deserialized data. + :rtype: object """ if hasattr(data, "read"): # Assume a stream @@ -112,7 +111,7 @@ def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: try: return json.loads(data_as_str) except ValueError as err: - raise DeserializationError("JSON is invalid: {}".format(err), err) + raise DeserializationError("JSON is invalid: {}".format(err), err) from err elif "xml" in (content_type or []): try: @@ -155,6 +154,11 @@ def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], Use bytes and headers to NOT use any requests/aiohttp or whatever specific implementation. Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object """ # Try to use content-type from headers if available content_type = None @@ -179,80 +183,31 @@ def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], except NameError: _long_type = int - -class UTC(datetime.tzinfo): - """Time Zone info for handling UTC""" - - def utcoffset(self, dt): - """UTF offset for UTC is 0.""" - return datetime.timedelta(0) - - def tzname(self, dt): - """Timestamp representation.""" - return "Z" - - def dst(self, dt): - """No daylight saving for UTC.""" - return datetime.timedelta(hours=1) - - -try: - from datetime import timezone as _FixedOffset # type: ignore -except ImportError: # Python 2.7 - - class _FixedOffset(datetime.tzinfo): # type: ignore - """Fixed offset in minutes east from UTC. - Copy/pasted from Python doc - :param datetime.timedelta offset: offset in timedelta format - """ - - def __init__(self, offset): - self.__offset = offset - - def utcoffset(self, dt): - return self.__offset - - def tzname(self, dt): - return str(self.__offset.total_seconds() / 3600) - - def __repr__(self): - return "".format(self.tzname(None)) - - def dst(self, dt): - return datetime.timedelta(0) - - def __getinitargs__(self): - return (self.__offset,) - - -try: - from datetime import timezone - - TZ_UTC = timezone.utc -except ImportError: - TZ_UTC = UTC() # type: ignore +TZ_UTC = datetime.timezone.utc _FLATTEN = re.compile(r"(? None: self.additional_properties: Optional[Dict[str, Any]] = {} - for k in kwargs: + for k in kwargs: # pylint: disable=consider-using-dict-items if k not in self._attribute_map: _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) elif k in self._validation and self._validation[k].get("readonly", False): @@ -300,13 +262,23 @@ def __init__(self, **kwargs: Any) -> None: setattr(self, k, kwargs[k]) def __eq__(self, other: Any) -> bool: - """Compare objects by comparing all attributes.""" + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ if isinstance(other, self.__class__): return self.__dict__ == other.__dict__ return False def __ne__(self, other: Any) -> bool: - """Compare objects by comparing all attributes.""" + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ return not self.__eq__(other) def __str__(self) -> str: @@ -326,7 +298,11 @@ def is_xml_model(cls) -> bool: @classmethod def _create_xml_node(cls): - """Create XML node.""" + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ try: xml_map = cls._xml_map # type: ignore except AttributeError: @@ -346,7 +322,9 @@ def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: :rtype: dict """ serializer = Serializer(self._infer_class_models()) - return serializer._serialize(self, keep_readonly=keep_readonly, **kwargs) # type: ignore + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) def as_dict( self, @@ -380,12 +358,15 @@ def my_key_transformer(key, attr_desc, value): If you want XML serialization, you can pass the kwargs is_xml=True. + :param bool keep_readonly: If you want to serialize the readonly attributes :param function key_transformer: A key transformer function. :returns: A dict JSON compatible object :rtype: dict """ serializer = Serializer(self._infer_class_models()) - return serializer._serialize(self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs) # type: ignore + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) @classmethod def _infer_class_models(cls): @@ -395,30 +376,31 @@ def _infer_class_models(cls): client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} if cls.__name__ not in client_models: raise ValueError("Not Autorest generated code") - except Exception: + except Exception: # pylint: disable=broad-exception-caught # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. client_models = {cls.__name__: cls} return client_models @classmethod - def deserialize(cls: Type[ModelType], data: Any, content_type: Optional[str] = None) -> ModelType: + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: """Parse a str using the RestAPI syntax and return a model. :param str data: A str using RestAPI structure. JSON by default. :param str content_type: JSON by default, set application/xml if XML. :returns: An instance of this model - :raises: DeserializationError if something went wrong + :raises DeserializationError: if something went wrong + :rtype: Self """ deserializer = Deserializer(cls._infer_class_models()) return deserializer(cls.__name__, data, content_type=content_type) # type: ignore @classmethod def from_dict( - cls: Type[ModelType], + cls, data: Any, key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, content_type: Optional[str] = None, - ) -> ModelType: + ) -> Self: """Parse a dict using given key extractor return a model. By default consider key @@ -426,9 +408,11 @@ def from_dict( and last_rest_key_case_insensitive_extractor) :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. :param str content_type: JSON by default, set application/xml if XML. :returns: An instance of this model - :raises: DeserializationError if something went wrong + :raises DeserializationError: if something went wrong + :rtype: Self """ deserializer = Deserializer(cls._infer_class_models()) deserializer.key_extractors = ( # type: ignore @@ -448,21 +432,25 @@ def _flatten_subtype(cls, key, objects): return {} result = dict(cls._subtype_map[key]) for valuetype in cls._subtype_map[key].values(): - result.update(objects[valuetype]._flatten_subtype(key, objects)) + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access return result @classmethod def _classify(cls, response, objects): """Check the class _subtype_map for any child classes. We want to ignore any inherited _subtype_maps. - Remove the polymorphic key from the initial data. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class """ for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): subtype_value = None if not isinstance(response, ET.Element): rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] - subtype_value = response.pop(rest_api_response_key, None) or response.pop(subtype_key, None) + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) else: subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) if subtype_value: @@ -501,11 +489,13 @@ def _decode_attribute_map_key(key): inside the received data. :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str """ return key.replace("\\.", ".") -class Serializer(object): +class Serializer: # pylint: disable=too-many-public-methods """Request object model serializer.""" basic_types = {str: "str", int: "int", bool: "bool", float: "float"} @@ -540,7 +530,7 @@ class Serializer(object): "multiple": lambda x, y: x % y != 0, } - def __init__(self, classes: Optional[Mapping[str, type]] = None): + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: self.serialize_type = { "iso-8601": Serializer.serialize_iso, "rfc-1123": Serializer.serialize_rfc, @@ -560,13 +550,16 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None): self.key_transformer = full_restapi_key_transformer self.client_side_validation = True - def _serialize(self, target_obj, data_type=None, **kwargs): + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): """Serialize data into a string according to type. - :param target_obj: The data to be serialized. + :param object target_obj: The data to be serialized. :param str data_type: The type to be serialized from. :rtype: str, dict - :raises: SerializationError if serialization fails. + :raises SerializationError: if serialization fails. + :returns: The serialized data. """ key_transformer = kwargs.get("key_transformer", self.key_transformer) keep_readonly = kwargs.get("keep_readonly", False) @@ -592,12 +585,14 @@ def _serialize(self, target_obj, data_type=None, **kwargs): serialized = {} if is_xml_model_serialization: - serialized = target_obj._create_xml_node() + serialized = target_obj._create_xml_node() # pylint: disable=protected-access try: - attributes = target_obj._attribute_map + attributes = target_obj._attribute_map # pylint: disable=protected-access for attr, attr_desc in attributes.items(): attr_name = attr - if not keep_readonly and target_obj._validation.get(attr_name, {}).get("readonly", False): + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): continue if attr_name == "additional_properties" and attr_desc["key"] == "": @@ -633,7 +628,8 @@ def _serialize(self, target_obj, data_type=None, **kwargs): if isinstance(new_attr, list): serialized.extend(new_attr) # type: ignore elif isinstance(new_attr, ET.Element): - # If the down XML has no XML/Name, we MUST replace the tag with the local tag. But keeping the namespaces. + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. if "name" not in getattr(orig_attr, "_xml_map", {}): splitted_tag = new_attr.tag.split("}") if len(splitted_tag) == 2: # Namespace @@ -664,17 +660,17 @@ def _serialize(self, target_obj, data_type=None, **kwargs): except (AttributeError, KeyError, TypeError) as err: msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) raise SerializationError(msg) from err - else: - return serialized + return serialized def body(self, data, data_type, **kwargs): """Serialize data intended for a request body. - :param data: The data to be serialized. + :param object data: The data to be serialized. :param str data_type: The type to be serialized from. :rtype: dict - :raises: SerializationError if serialization fails. - :raises: ValueError if data is None + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body """ # Just in case this is a dict @@ -703,7 +699,7 @@ def body(self, data, data_type, **kwargs): attribute_key_case_insensitive_extractor, last_rest_key_case_insensitive_extractor, ] - data = deserializer._deserialize(data_type, data) + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access except DeserializationError as err: raise SerializationError("Unable to build a model: " + str(err)) from err @@ -712,11 +708,13 @@ def body(self, data, data_type, **kwargs): def url(self, name, data, data_type, **kwargs): """Serialize data intended for a URL path. - :param data: The data to be serialized. + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. :param str data_type: The type to be serialized from. :rtype: str - :raises: TypeError if serialization fails. - :raises: ValueError if data is None + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None """ try: output = self.serialize_data(data, data_type, **kwargs) @@ -728,21 +726,20 @@ def url(self, name, data, data_type, **kwargs): output = output.replace("{", quote("{")).replace("}", quote("}")) else: output = quote(str(output), safe="") - except SerializationError: - raise TypeError("{} must be type {}.".format(name, data_type)) - else: - return output + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output def query(self, name, data, data_type, **kwargs): """Serialize data intended for a URL query. - :param data: The data to be serialized. + :param str name: The name of the query parameter. + :param object data: The data to be serialized. :param str data_type: The type to be serialized from. - :keyword bool skip_quote: Whether to skip quote the serialized result. - Defaults to False. :rtype: str, list - :raises: TypeError if serialization fails. - :raises: ValueError if data is None + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter """ try: # Treat the list aside, since we don't want to encode the div separator @@ -759,19 +756,20 @@ def query(self, name, data, data_type, **kwargs): output = str(output) else: output = quote(str(output), safe="") - except SerializationError: - raise TypeError("{} must be type {}.".format(name, data_type)) - else: - return str(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) def header(self, name, data, data_type, **kwargs): """Serialize data intended for a request header. - :param data: The data to be serialized. + :param str name: The name of the header. + :param object data: The data to be serialized. :param str data_type: The type to be serialized from. :rtype: str - :raises: TypeError if serialization fails. - :raises: ValueError if data is None + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header """ try: if data_type in ["[str]"]: @@ -780,21 +778,20 @@ def header(self, name, data, data_type, **kwargs): output = self.serialize_data(data, data_type, **kwargs) if data_type == "bool": output = json.dumps(output) - except SerializationError: - raise TypeError("{} must be type {}.".format(name, data_type)) - else: - return str(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) def serialize_data(self, data, data_type, **kwargs): """Serialize generic data according to supplied data type. - :param data: The data to be serialized. + :param object data: The data to be serialized. :param str data_type: The type to be serialized from. - :param bool required: Whether it's essential that the data not be - empty or None - :raises: AttributeError if required data is None. - :raises: ValueError if data is None - :raises: SerializationError if serialization fails. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list """ if data is None: raise ValueError("No value for given attribute") @@ -805,7 +802,7 @@ def serialize_data(self, data, data_type, **kwargs): if data_type in self.basic_types.values(): return self.serialize_basic(data, data_type, **kwargs) - elif data_type in self.serialize_type: + if data_type in self.serialize_type: return self.serialize_type[data_type](data, **kwargs) # If dependencies is empty, try with current data class @@ -821,11 +818,10 @@ def serialize_data(self, data, data_type, **kwargs): except (ValueError, TypeError) as err: msg = "Unable to serialize value: {!r} as type: {!r}." raise SerializationError(msg.format(data, data_type)) from err - else: - return self._serialize(data, **kwargs) + return self._serialize(data, **kwargs) @classmethod - def _get_custom_serializers(cls, data_type, **kwargs): + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) if custom_serializer: return custom_serializer @@ -841,23 +837,26 @@ def serialize_basic(cls, data, data_type, **kwargs): - basic_types_serializers dict[str, callable] : If set, use the callable as serializer - is_xml bool : If set, use xml_basic_types_serializers - :param data: Object to be serialized. + :param obj data: Object to be serialized. :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object """ custom_serializer = cls._get_custom_serializers(data_type, **kwargs) if custom_serializer: return custom_serializer(data) if data_type == "str": return cls.serialize_unicode(data) - return eval(data_type)(data) # nosec + return eval(data_type)(data) # nosec # pylint: disable=eval-used @classmethod def serialize_unicode(cls, data): """Special handling for serializing unicode strings in Py2. Encode to UTF-8 if unicode, otherwise handle as a str. - :param data: Object to be serialized. + :param str data: Object to be serialized. :rtype: str + :return: serialized object """ try: # If I received an enum, return its value return data.value @@ -871,8 +870,7 @@ def serialize_unicode(cls, data): return data except NameError: return str(data) - else: - return str(data) + return str(data) def serialize_iter(self, data, iter_type, div=None, **kwargs): """Serialize iterable. @@ -882,15 +880,13 @@ def serialize_iter(self, data, iter_type, div=None, **kwargs): serialization_ctxt['type'] should be same as data_type. - is_xml bool : If set, serialize as XML - :param list attr: Object to be serialized. + :param list data: Object to be serialized. :param str iter_type: Type of object in the iterable. - :param bool required: Whether the objects in the iterable must - not be None or empty. :param str div: If set, this str will be used to combine the elements in the iterable into a combined string. Default is 'None'. - :keyword bool do_quote: Whether to quote the serialized result of each iterable element. Defaults to False. :rtype: list, str + :return: serialized iterable """ if isinstance(data, str): raise SerializationError("Refuse str type as a valid iter type.") @@ -945,9 +941,8 @@ def serialize_dict(self, attr, dict_type, **kwargs): :param dict attr: Object to be serialized. :param str dict_type: Type of object in the dictionary. - :param bool required: Whether the objects in the dictionary must - not be None or empty. :rtype: dict + :return: serialized dictionary """ serialization_ctxt = kwargs.get("serialization_ctxt", {}) serialized = {} @@ -971,7 +966,7 @@ def serialize_dict(self, attr, dict_type, **kwargs): return serialized - def serialize_object(self, attr, **kwargs): + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements """Serialize a generic object. This will be handled as a dictionary. If object passed in is not a basic type (str, int, float, dict, list) it will simply be @@ -979,6 +974,7 @@ def serialize_object(self, attr, **kwargs): :param dict attr: Object to be serialized. :rtype: dict or str + :return: serialized object """ if attr is None: return None @@ -1003,7 +999,7 @@ def serialize_object(self, attr, **kwargs): return self.serialize_decimal(attr) # If it's a model or I know this dependency, serialize as a Model - elif obj_type in self.dependencies.values() or isinstance(attr, Model): + if obj_type in self.dependencies.values() or isinstance(attr, Model): return self._serialize(attr) if obj_type == dict: @@ -1034,56 +1030,61 @@ def serialize_enum(attr, enum_obj=None): try: enum_obj(result) # type: ignore return result - except ValueError: + except ValueError as exc: for enum_value in enum_obj: # type: ignore if enum_value.value.lower() == str(attr).lower(): return enum_value.value error = "{!r} is not valid value for enum {!r}" - raise SerializationError(error.format(attr, enum_obj)) + raise SerializationError(error.format(attr, enum_obj)) from exc @staticmethod - def serialize_bytearray(attr, **kwargs): + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument """Serialize bytearray into base-64 string. - :param attr: Object to be serialized. + :param str attr: Object to be serialized. :rtype: str + :return: serialized base64 """ return b64encode(attr).decode() @staticmethod - def serialize_base64(attr, **kwargs): + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument """Serialize str into base-64 string. - :param attr: Object to be serialized. + :param str attr: Object to be serialized. :rtype: str + :return: serialized base64 """ encoded = b64encode(attr).decode("ascii") return encoded.strip("=").replace("+", "-").replace("/", "_") @staticmethod - def serialize_decimal(attr, **kwargs): + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument """Serialize Decimal object to float. - :param attr: Object to be serialized. + :param decimal attr: Object to be serialized. :rtype: float + :return: serialized decimal """ return float(attr) @staticmethod - def serialize_long(attr, **kwargs): + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument """Serialize long (Py2) or int (Py3). - :param attr: Object to be serialized. + :param int attr: Object to be serialized. :rtype: int/long + :return: serialized long """ return _long_type(attr) @staticmethod - def serialize_date(attr, **kwargs): + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument """Serialize Date object into ISO-8601 formatted string. :param Date attr: Object to be serialized. :rtype: str + :return: serialized date """ if isinstance(attr, str): attr = isodate.parse_date(attr) @@ -1091,11 +1092,12 @@ def serialize_date(attr, **kwargs): return t @staticmethod - def serialize_time(attr, **kwargs): + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument """Serialize Time object into ISO-8601 formatted string. :param datetime.time attr: Object to be serialized. :rtype: str + :return: serialized time """ if isinstance(attr, str): attr = isodate.parse_time(attr) @@ -1105,30 +1107,32 @@ def serialize_time(attr, **kwargs): return t @staticmethod - def serialize_duration(attr, **kwargs): + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument """Serialize TimeDelta object into ISO-8601 formatted string. :param TimeDelta attr: Object to be serialized. :rtype: str + :return: serialized duration """ if isinstance(attr, str): attr = isodate.parse_duration(attr) return isodate.duration_isoformat(attr) @staticmethod - def serialize_rfc(attr, **kwargs): + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument """Serialize Datetime object into RFC-1123 formatted string. :param Datetime attr: Object to be serialized. :rtype: str - :raises: TypeError if format invalid. + :raises TypeError: if format invalid. + :return: serialized rfc """ try: if not attr.tzinfo: _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") utc = attr.utctimetuple() - except AttributeError: - raise TypeError("RFC1123 object must be valid Datetime object.") + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( Serializer.days[utc.tm_wday], @@ -1141,12 +1145,13 @@ def serialize_rfc(attr, **kwargs): ) @staticmethod - def serialize_iso(attr, **kwargs): + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument """Serialize Datetime object into ISO-8601 formatted string. :param Datetime attr: Object to be serialized. :rtype: str - :raises: SerializationError if format invalid. + :raises SerializationError: if format invalid. + :return: serialized iso """ if isinstance(attr, str): attr = isodate.parse_datetime(attr) @@ -1172,13 +1177,14 @@ def serialize_iso(attr, **kwargs): raise TypeError(msg) from err @staticmethod - def serialize_unix(attr, **kwargs): + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument """Serialize Datetime object into IntTime format. This is represented as seconds. :param Datetime attr: Object to be serialized. :rtype: int - :raises: SerializationError if format invalid + :raises SerializationError: if format invalid + :return: serialied unix """ if isinstance(attr, int): return attr @@ -1186,11 +1192,11 @@ def serialize_unix(attr, **kwargs): if not attr.tzinfo: _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") return int(calendar.timegm(attr.utctimetuple())) - except AttributeError: - raise TypeError("Unix time object must be valid Datetime object.") + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc -def rest_key_extractor(attr, attr_desc, data): +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument key = attr_desc["key"] working_data = data @@ -1211,7 +1217,9 @@ def rest_key_extractor(attr, attr_desc, data): return working_data.get(key) -def rest_key_case_insensitive_extractor(attr, attr_desc, data): +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): key = attr_desc["key"] working_data = data @@ -1232,17 +1240,29 @@ def rest_key_case_insensitive_extractor(attr, attr_desc, data): return attribute_key_case_insensitive_extractor(key, None, working_data) -def last_rest_key_extractor(attr, attr_desc, data): - """Extract the attribute in "data" based on the last part of the JSON path key.""" +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ key = attr_desc["key"] dict_keys = _FLATTEN.split(key) return attribute_key_extractor(dict_keys[-1], None, data) -def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument """Extract the attribute in "data" based on the last part of the JSON path key. This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute """ key = attr_desc["key"] dict_keys = _FLATTEN.split(key) @@ -1279,7 +1299,7 @@ def _extract_name_from_internal_type(internal_type): return xml_name -def xml_key_extractor(attr, attr_desc, data): +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements if isinstance(data, dict): return None @@ -1331,22 +1351,21 @@ def xml_key_extractor(attr, attr_desc, data): if is_iter_type: if is_wrapped: return None # is_wrapped no node, we want None - else: - return [] # not wrapped, assume empty list + return [] # not wrapped, assume empty list return None # Assume it's not there, maybe an optional node. # If is_iter_type and not wrapped, return all found children if is_iter_type: if not is_wrapped: return children - else: # Iter and wrapped, should have found one node only (the wrap one) - if len(children) != 1: - raise DeserializationError( - "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( - xml_name - ) + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name ) - return list(children[0]) # Might be empty list and that's ok. + ) + return list(children[0]) # Might be empty list and that's ok. # Here it's not a itertype, we should have found one element only or empty if len(children) > 1: @@ -1354,7 +1373,7 @@ def xml_key_extractor(attr, attr_desc, data): return children[0] -class Deserializer(object): +class Deserializer: """Response object model deserializer. :param dict classes: Class type dictionary for deserializing complex types. @@ -1363,9 +1382,9 @@ class Deserializer(object): basic_types = {str: "str", int: "int", bool: "bool", float: "float"} - valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}" r"\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") - def __init__(self, classes: Optional[Mapping[str, type]] = None): + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: self.deserialize_type = { "iso-8601": Deserializer.deserialize_iso, "rfc-1123": Deserializer.deserialize_rfc, @@ -1401,27 +1420,29 @@ def __call__(self, target_obj, response_data, content_type=None): :param str target_obj: Target data type to deserialize to. :param requests.Response response_data: REST response object. :param str content_type: Swagger "produces" if available. - :raises: DeserializationError if deserialization fails. + :raises DeserializationError: if deserialization fails. :return: Deserialized object. + :rtype: object """ data = self._unpack_content(response_data, content_type) return self._deserialize(target_obj, data) - def _deserialize(self, target_obj, data): + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements """Call the deserializer on a model. Data needs to be already deserialized as JSON or XML ElementTree :param str target_obj: Target data type to deserialize to. :param object data: Object to deserialize. - :raises: DeserializationError if deserialization fails. + :raises DeserializationError: if deserialization fails. :return: Deserialized object. + :rtype: object """ # This is already a model, go recursive just in case if hasattr(data, "_attribute_map"): constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] try: - for attr, mapconfig in data._attribute_map.items(): + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access if attr in constants: continue value = getattr(data, attr) @@ -1440,13 +1461,13 @@ def _deserialize(self, target_obj, data): if isinstance(response, str): return self.deserialize_data(data, response) - elif isinstance(response, type) and issubclass(response, Enum): + if isinstance(response, type) and issubclass(response, Enum): return self.deserialize_enum(data, response) if data is None or data is CoreNull: return data try: - attributes = response._attribute_map # type: ignore + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access d_attrs = {} for attr, attr_desc in attributes.items(): # Check empty string. If it's not empty, someone has a real "additionalProperties"... @@ -1476,9 +1497,8 @@ def _deserialize(self, target_obj, data): except (AttributeError, TypeError, KeyError) as err: msg = "Unable to deserialize to object: " + class_name # type: ignore raise DeserializationError(msg) from err - else: - additional_properties = self._build_additional_properties(attributes, data) - return self._instantiate_model(response, d_attrs, additional_properties) + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) def _build_additional_properties(self, attribute_map, data): if not self.additional_properties_detection: @@ -1505,6 +1525,8 @@ def _classify_target(self, target, data): :param str target: The target object type to deserialize to. :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple """ if target is None: return None, None @@ -1516,7 +1538,7 @@ def _classify_target(self, target, data): return target, target try: - target = target._classify(data, self.dependencies) # type: ignore + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access except AttributeError: pass # Target is not a Model, no classify return target, target.__class__.__name__ # type: ignore @@ -1531,10 +1553,12 @@ def failsafe_deserialize(self, target_obj, data, content_type=None): :param str target_obj: The target object type to deserialize to. :param str/dict data: The response data to deserialize. :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object """ try: return self(target_obj, data, content_type=content_type) - except: + except: # pylint: disable=bare-except _LOGGER.debug( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True ) @@ -1552,10 +1576,12 @@ def _unpack_content(raw_data, content_type=None): If raw_data is something else, bypass all logic and return it directly. - :param raw_data: Data to be processed. - :param content_type: How to parse if raw_data is a string/bytes. + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. :raises JSONDecodeError: If JSON is requested and parsing is impossible. :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. """ # Assume this is enough to detect a Pipeline Response without importing it context = getattr(raw_data, "context", {}) @@ -1579,24 +1605,35 @@ def _unpack_content(raw_data, content_type=None): def _instantiate_model(self, response, attrs, additional_properties=None): """Instantiate a response model passing in deserialized args. - :param response: The response model class. - :param d_attrs: The deserialized response attributes. + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. """ if callable(response): subtype = getattr(response, "_subtype_map", {}) try: - readonly = [k for k, v in response._validation.items() if v.get("readonly")] - const = [k for k, v in response._validation.items() if v.get("constant")] + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} response_obj = response(**kwargs) for attr in readonly: setattr(response_obj, attr, attrs.get(attr)) if additional_properties: - response_obj.additional_properties = additional_properties + response_obj.additional_properties = additional_properties # type: ignore return response_obj except TypeError as err: msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore - raise DeserializationError(msg + str(err)) + raise DeserializationError(msg + str(err)) from err else: try: for attr, value in attrs.items(): @@ -1605,15 +1642,16 @@ def _instantiate_model(self, response, attrs, additional_properties=None): except Exception as exp: msg = "Unable to populate response model. " msg += "Type: {}, Error: {}".format(type(response), exp) - raise DeserializationError(msg) + raise DeserializationError(msg) from exp - def deserialize_data(self, data, data_type): + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements """Process data for deserialization according to data type. :param str data: The response string to be deserialized. :param str data_type: The type to deserialize to. - :raises: DeserializationError if deserialization fails. + :raises DeserializationError: if deserialization fails. :return: Deserialized object. + :rtype: object """ if data is None: return data @@ -1627,7 +1665,11 @@ def deserialize_data(self, data, data_type): if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): return data - is_a_text_parsing_type = lambda x: x not in ["object", "[]", r"{}"] + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: return None data_val = self.deserialize_type[data_type](data) @@ -1647,14 +1689,14 @@ def deserialize_data(self, data, data_type): msg = "Unable to deserialize response data." msg += " Data: {}, {}".format(data, data_type) raise DeserializationError(msg) from err - else: - return self._deserialize(obj_type, data) + return self._deserialize(obj_type, data) def deserialize_iter(self, attr, iter_type): """Deserialize an iterable. :param list attr: Iterable to be deserialized. :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. :rtype: list """ if attr is None: @@ -1671,6 +1713,7 @@ def deserialize_dict(self, attr, dict_type): :param dict/list attr: Dictionary to be deserialized. Also accepts a list of key, value pairs. :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. :rtype: dict """ if isinstance(attr, list): @@ -1681,13 +1724,14 @@ def deserialize_dict(self, attr, dict_type): attr = {el.tag: el.text for el in attr} return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} - def deserialize_object(self, attr, **kwargs): + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements """Deserialize a generic object. This will be handled as a dictionary. :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. :rtype: dict - :raises: TypeError if non-builtin datatype encountered. + :raises TypeError: if non-builtin datatype encountered. """ if attr is None: return None @@ -1720,11 +1764,10 @@ def deserialize_object(self, attr, **kwargs): pass return deserialized - else: - error = "Cannot deserialize generic object with type: " - raise TypeError(error + str(obj_type)) + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) - def deserialize_basic(self, attr, data_type): + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements """Deserialize basic builtin data type from string. Will attempt to convert to str, int, float and bool. This function will also accept '1', '0', 'true' and 'false' as @@ -1732,8 +1775,9 @@ def deserialize_basic(self, attr, data_type): :param str attr: response string to be deserialized. :param str data_type: deserialization data type. + :return: Deserialized basic type. :rtype: str, int, float or bool - :raises: TypeError if string format is not valid. + :raises TypeError: if string format is not valid. """ # If we're here, data is supposed to be a basic type. # If it's still an XML node, take the text @@ -1743,24 +1787,23 @@ def deserialize_basic(self, attr, data_type): if data_type == "str": # None or '', node is empty string. return "" - else: - # None or '', node with a strong type is None. - # Don't try to model "empty bool" or "empty int" - return None + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None if data_type == "bool": if attr in [True, False, 1, 0]: return bool(attr) - elif isinstance(attr, str): + if isinstance(attr, str): if attr.lower() in ["true", "1"]: return True - elif attr.lower() in ["false", "0"]: + if attr.lower() in ["false", "0"]: return False raise TypeError("Invalid boolean value: {}".format(attr)) if data_type == "str": return self.deserialize_unicode(attr) - return eval(data_type)(attr) # nosec + return eval(data_type)(attr) # nosec # pylint: disable=eval-used @staticmethod def deserialize_unicode(data): @@ -1768,6 +1811,7 @@ def deserialize_unicode(data): as a string. :param str data: response string to be deserialized. + :return: Deserialized string. :rtype: str or unicode """ # We might be here because we have an enum modeled as string, @@ -1781,8 +1825,7 @@ def deserialize_unicode(data): return data except NameError: return str(data) - else: - return str(data) + return str(data) @staticmethod def deserialize_enum(data, enum_obj): @@ -1794,6 +1837,7 @@ def deserialize_enum(data, enum_obj): :param str data: Response string to be deserialized. If this value is None or invalid it will be returned as-is. :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. :rtype: Enum """ if isinstance(data, enum_obj) or data is None: @@ -1804,9 +1848,9 @@ def deserialize_enum(data, enum_obj): # Workaround. We might consider remove it in the future. try: return list(enum_obj.__members__.values())[data] - except IndexError: + except IndexError as exc: error = "{!r} is not a valid index for enum {!r}" - raise DeserializationError(error.format(data, enum_obj)) + raise DeserializationError(error.format(data, enum_obj)) from exc try: return enum_obj(str(data)) except ValueError: @@ -1822,8 +1866,9 @@ def deserialize_bytearray(attr): """Deserialize string into bytearray. :param str attr: response string to be deserialized. + :return: Deserialized bytearray :rtype: bytearray - :raises: TypeError if string format invalid. + :raises TypeError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1834,8 +1879,9 @@ def deserialize_base64(attr): """Deserialize base64 encoded string into string. :param str attr: response string to be deserialized. + :return: Deserialized base64 string :rtype: bytearray - :raises: TypeError if string format invalid. + :raises TypeError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1849,8 +1895,9 @@ def deserialize_decimal(attr): """Deserialize string into Decimal object. :param str attr: response string to be deserialized. - :rtype: Decimal - :raises: DeserializationError if string format invalid. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal """ if isinstance(attr, ET.Element): attr = attr.text @@ -1865,8 +1912,9 @@ def deserialize_long(attr): """Deserialize string into long (Py2) or int (Py3). :param str attr: response string to be deserialized. + :return: Deserialized int :rtype: long or int - :raises: ValueError if string format invalid. + :raises ValueError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1877,8 +1925,9 @@ def deserialize_duration(attr): """Deserialize ISO-8601 formatted string into TimeDelta object. :param str attr: response string to be deserialized. + :return: Deserialized duration :rtype: TimeDelta - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1887,16 +1936,16 @@ def deserialize_duration(attr): except (ValueError, OverflowError, AttributeError) as err: msg = "Cannot deserialize duration object." raise DeserializationError(msg) from err - else: - return duration + return duration @staticmethod def deserialize_date(attr): """Deserialize ISO-8601 formatted string into Date object. :param str attr: response string to be deserialized. + :return: Deserialized date :rtype: Date - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1910,8 +1959,9 @@ def deserialize_time(attr): """Deserialize ISO-8601 formatted string into time object. :param str attr: response string to be deserialized. + :return: Deserialized time :rtype: datetime.time - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1924,31 +1974,32 @@ def deserialize_rfc(attr): """Deserialize RFC-1123 formatted string into Datetime object. :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime :rtype: Datetime - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text try: parsed_date = email.utils.parsedate_tz(attr) # type: ignore date_obj = datetime.datetime( - *parsed_date[:6], tzinfo=_FixedOffset(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) ) if not date_obj.tzinfo: date_obj = date_obj.astimezone(tz=TZ_UTC) except ValueError as err: msg = "Cannot deserialize to rfc datetime object." raise DeserializationError(msg) from err - else: - return date_obj + return date_obj @staticmethod def deserialize_iso(attr): """Deserialize ISO-8601 formatted string into Datetime object. :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime :rtype: Datetime - :raises: DeserializationError if string format invalid. + :raises DeserializationError: if string format invalid. """ if isinstance(attr, ET.Element): attr = attr.text @@ -1976,8 +2027,7 @@ def deserialize_iso(attr): except (ValueError, OverflowError, AttributeError) as err: msg = "Cannot deserialize datetime object." raise DeserializationError(msg) from err - else: - return date_obj + return date_obj @staticmethod def deserialize_unix(attr): @@ -1985,8 +2035,9 @@ def deserialize_unix(attr): This is represented as seconds. :param int attr: Object to be serialized. + :return: Deserialized datetime :rtype: Datetime - :raises: DeserializationError if format invalid + :raises DeserializationError: if format invalid """ if isinstance(attr, ET.Element): attr = int(attr.text) # type: ignore @@ -1996,5 +2047,4 @@ def deserialize_unix(attr): except ValueError as err: msg = "Cannot deserialize to unix datetime object." raise DeserializationError(msg) from err - else: - return date_obj + return date_obj diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_vendor.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_vendor.py index fa6d8f4932a6..691bc227ff1a 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_vendor.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_vendor.py @@ -11,7 +11,6 @@ from ._configuration import ImageAnalysisClientConfiguration if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core import PipelineClient from ._serialization import Deserializer, Serializer diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_version.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_version.py index 83602e6274bc..be71c81bd282 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_version.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/_version.py @@ -6,4 +6,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.1" +VERSION = "1.0.0b1" diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/__init__.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/__init__.py index 4e185770e8d5..bc05e8a9b30d 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/__init__.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/__init__.py @@ -5,15 +5,25 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._patch import ImageAnalysisClient +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import +from ._client import ImageAnalysisClient # type: ignore + +try: + from ._patch import __all__ as _patch_all + from ._patch import * +except ImportError: + _patch_all = [] from ._patch import patch_sdk as _patch_sdk __all__ = [ "ImageAnalysisClient", ] - +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_client.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_client.py index 8e6eb780fc7f..f330ce4939d4 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_client.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_client.py @@ -20,18 +20,17 @@ from ._operations import ImageAnalysisClientOperationsMixin if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials_async import AsyncTokenCredential -class ImageAnalysisClient(ImageAnalysisClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword +class ImageAnalysisClient(ImageAnalysisClientOperationsMixin): """ImageAnalysisClient. :param endpoint: Azure AI Computer Vision endpoint (protocol and hostname, for example: - https://:code:``.cognitiveservices.azure.com). Required. + https://.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential used to authenticate requests to the service. Is either a - AzureKeyCredential type or a TokenCredential type. Required. + :param credential: Credential used to authenticate requests to the service. Is either a key + credential type or a token credential type. Required. :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials_async.AsyncTokenCredential :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_configuration.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_configuration.py index 94e384b56cb5..e2caaff67b98 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_configuration.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_configuration.py @@ -14,21 +14,20 @@ from .._version import VERSION if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core.credentials_async import AsyncTokenCredential -class ImageAnalysisClientConfiguration: # pylint: disable=too-many-instance-attributes,name-too-long +class ImageAnalysisClientConfiguration: # pylint: disable=too-many-instance-attributes """Configuration for ImageAnalysisClient. Note that all parameters used to create this instance are saved as instance attributes. :param endpoint: Azure AI Computer Vision endpoint (protocol and hostname, for example: - https://:code:``.cognitiveservices.azure.com). Required. + https://.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential used to authenticate requests to the service. Is either a - AzureKeyCredential type or a TokenCredential type. Required. + :param credential: Credential used to authenticate requests to the service. Is either a key + credential type or a token credential type. Required. :type credential: ~azure.core.credentials.AzureKeyCredential or ~azure.core.credentials_async.AsyncTokenCredential :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/__init__.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/__init__.py index 27c2169d2602..031981019ecd 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/__init__.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/__init__.py @@ -5,15 +5,21 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._operations import ImageAnalysisClientOperationsMixin +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._operations import ImageAnalysisClientOperationsMixin # type: ignore from ._patch import __all__ as _patch_all -from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ "ImageAnalysisClientOperationsMixin", ] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_operations.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_operations.py index 3c679fc3beb0..c03d90e8cf79 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_operations.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_operations.py @@ -1,4 +1,4 @@ -# pylint: disable=too-many-lines,too-many-statements +# pylint: disable=line-too-long,useless-suppression # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. @@ -9,7 +9,7 @@ from io import IOBase import json import sys -from typing import Any, Callable, Dict, IO, List, Optional, Type, TypeVar, Union, overload +from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union, overload from azure.core.exceptions import ( ClientAuthenticationError, @@ -17,6 +17,8 @@ ResourceExistsError, ResourceNotFoundError, ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, map_error, ) from azure.core.pipeline import PipelineResponse @@ -35,7 +37,7 @@ if sys.version_info >= (3, 9): from collections.abc import MutableMapping else: - from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports + from typing import MutableMapping # type: ignore JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -66,7 +68,8 @@ async def _analyze_from_image_data( :paramtype visual_features: list[str or ~azure.ai.vision.imageanalysis.models.VisualFeatures] :keyword language: The desired language for result generation (a two-letter language code). If this option is not specified, the default value 'en' is used (English). - See https://aka.ms/cv-languages for a list of supported languages. Default value is None. + See `https://aka.ms/cv-languages `_ for a list of supported + languages. Default value is None. :paramtype language: str :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for Caption and Dense Captions features. @@ -92,121 +95,8 @@ async def _analyze_from_image_data( :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == { - "metadata": { - "height": 0, - "width": 0 - }, - "modelVersion": "str", - "captionResult": { - "confidence": 0.0, - "text": "str" - }, - "denseCaptionsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0, - "text": "str" - } - ] - }, - "objectsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "tags": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - ] - }, - "peopleResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0 - } - ] - }, - "readResult": { - "blocks": [ - { - "lines": [ - { - "boundingPolygon": [ - { - "x": 0, - "y": 0 - } - ], - "text": "str", - "words": [ - { - "boundingPolygon": [ - { - "x": - 0, - "y": - 0 - } - ], - "confidence": 0.0, - "text": "str" - } - ] - } - ] - } - ] - }, - "smartCropsResult": { - "values": [ - { - "aspectRatio": 0.0, - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - } - } - ] - }, - "tagsResult": { - "values": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - } """ - error_map: MutableMapping[int, Type[HttpResponseError]] = { + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -248,7 +138,10 @@ async def _analyze_from_image_data( if response.status_code not in [200]: if _stream: - await response.read() # Load the body in memory and close the socket + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -263,7 +156,7 @@ async def _analyze_from_image_data( return deserialized # type: ignore @overload - async def _analyze_from_url( # pylint: disable=protected-access + async def _analyze_from_url( self, image_url: _models._models.ImageUrl, *, @@ -326,7 +219,8 @@ async def _analyze_from_url( :paramtype visual_features: list[str or ~azure.ai.vision.imageanalysis.models.VisualFeatures] :keyword language: The desired language for result generation (a two-letter language code). If this option is not specified, the default value 'en' is used (English). - See https://aka.ms/cv-languages for a list of supported languages. Default value is None. + See `https://aka.ms/cv-languages `_ for a list of supported + languages. Default value is None. :paramtype language: str :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for Caption and Dense Captions features. @@ -352,126 +246,8 @@ async def _analyze_from_url( :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # JSON input template you can fill out and use as your body input. - image_url = { - "url": "str" - } - - # response body for status code(s): 200 - response == { - "metadata": { - "height": 0, - "width": 0 - }, - "modelVersion": "str", - "captionResult": { - "confidence": 0.0, - "text": "str" - }, - "denseCaptionsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0, - "text": "str" - } - ] - }, - "objectsResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "tags": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - ] - }, - "peopleResult": { - "values": [ - { - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - }, - "confidence": 0.0 - } - ] - }, - "readResult": { - "blocks": [ - { - "lines": [ - { - "boundingPolygon": [ - { - "x": 0, - "y": 0 - } - ], - "text": "str", - "words": [ - { - "boundingPolygon": [ - { - "x": - 0, - "y": - 0 - } - ], - "confidence": 0.0, - "text": "str" - } - ] - } - ] - } - ] - }, - "smartCropsResult": { - "values": [ - { - "aspectRatio": 0.0, - "boundingBox": { - "h": 0, - "w": 0, - "x": 0, - "y": 0 - } - } - ] - }, - "tagsResult": { - "values": [ - { - "confidence": 0.0, - "name": "str" - } - ] - } - } """ - error_map: MutableMapping[int, Type[HttpResponseError]] = { + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -518,7 +294,10 @@ async def _analyze_from_url( if response.status_code not in [200]: if _stream: - await response.read() # Load the body in memory and close the socket + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_patch.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_patch.py index c88c2fa43a41..f7dd32510333 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_patch.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_operations/_patch.py @@ -1,8 +1,11 @@ -# 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. -# -------------------------------------------------------------------------- +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" from typing import List __all__: List[str] = [] # Add all objects you want publicly available to users at this package level diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_patch.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_patch.py index 4b6076ad0f72..f7dd32510333 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_patch.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_patch.py @@ -5,154 +5,10 @@ """Customize generated code here. Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize - """ -from typing import List, Any, Optional, Union -from azure.core.tracing.decorator_async import distributed_trace_async -from .. import models as _models -from ._operations._operations import ImageAnalysisClientOperationsMixin -from ._client import ImageAnalysisClient as ImageAnalysisClientGenerated - - -class ImageAnalysisClient(ImageAnalysisClientGenerated): - """ImageAnalysisClient. - - :param endpoint: Azure AI Computer Vision endpoint (protocol and hostname, for example: - https://:code:``.cognitiveservices.azure.com). Required. - :type endpoint: str - :param credential: Credential used to authenticate requests to the service. Is either a - AzureKeyCredential type or a TokenCredential type. Required. - :type credential: ~azure.core.credentials.AzureKeyCredential or - ~azure.core.credentials.TokenCredential - :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". - Note that overriding this default value may result in unsupported behavior. - :paramtype api_version: str - """ - - @distributed_trace_async - async def analyze_from_url( - self, - image_url: str, - visual_features: List[_models.VisualFeatures], - *, - language: Optional[str] = None, - gender_neutral_caption: Optional[bool] = None, - smart_crops_aspect_ratios: Optional[List[float]] = None, - model_version: Optional[str] = None, - **kwargs: Any - ) -> _models.ImageAnalysisResult: - """Performs a single Image Analysis operation. - - :param image_url: The publicly accessible URL of the image to analyze. - :type image_url: str - :param visual_features: A list of visual features to analyze. Required. Seven visual features - are supported: Caption, DenseCaptions, Read (OCR), Tags, Objects, SmartCrops, and People. At - least one visual feature must be specified. - :type visual_features: list[~azure.ai.vision.imageanalysis.models.VisualFeatures] - :keyword language: The desired language for result generation (a two-letter language code). - Defaults to 'en' (English). See https://aka.ms/cv-languages for a list of supported languages. - :paramtype language: str - :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for - Caption and Dense Captions features. Defaults to 'false'. - Captions may contain gender terms (for example: 'man', 'woman', or 'boy', 'girl'). - If you set this to 'true', those will be replaced with gender-neutral terms (for example: - 'person' or 'child'). - :paramtype gender_neutral_caption: bool - :keyword smart_crops_aspect_ratios: A list of aspect ratios to use for smart cropping. - Defaults to one crop region with an aspect ratio the service sees fit between - 0.5 and 2.0 (inclusive). Aspect ratios are calculated by dividing the target crop - width in pixels by the height in pixels. When set, supported values are - between 0.75 and 1.8 (inclusive). - :paramtype smart_crops_aspect_ratios: list[float] - :keyword model_version: The version of cloud AI-model used for analysis. Defaults to 'latest', - for the latest AI model with recent improvements. - The format is the following: 'latest' or 'YYYY-MM-DD' or 'YYYY-MM-DD-preview', - where 'YYYY', 'MM', 'DD' are the year, month and day associated with the model. - If you would like to make sure analysis results do not change over time, set this - value to a specific model version. - :paramtype model_version: str - :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping - :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - - visual_features_impl: List[Union[str, _models.VisualFeatures]] = list(visual_features) - - return await ImageAnalysisClientOperationsMixin._analyze_from_url( # pylint: disable=protected-access - self, - image_url=_models._models.ImageUrl(url=image_url), # pylint: disable=protected-access - visual_features=visual_features_impl, - language=language, - gender_neutral_caption=gender_neutral_caption, - smart_crops_aspect_ratios=smart_crops_aspect_ratios, - model_version=model_version, - **kwargs - ) - - @distributed_trace_async - async def analyze( - self, - image_data: bytes, - visual_features: List[_models.VisualFeatures], - *, - language: Optional[str] = None, - gender_neutral_caption: Optional[bool] = None, - smart_crops_aspect_ratios: Optional[List[float]] = None, - model_version: Optional[str] = None, - **kwargs: Any - ) -> _models.ImageAnalysisResult: - """Performs a single Image Analysis operation. - - :param image_data: A buffer containing the whole image to be analyzed. - :type image_data: bytes - :param visual_features: A list of visual features to analyze. Required. Seven visual features - are supported: Caption, DenseCaptions, Read (OCR), Tags, Objects, SmartCrops, and People. At - least one visual feature must be specified. - :type visual_features: list[~azure.ai.vision.imageanalysis.models.VisualFeatures] - :keyword language: The desired language for result generation (a two-letter language code). - Defaults to 'en' (English). See https://aka.ms/cv-languages for a list of supported languages. - :paramtype language: str - :keyword gender_neutral_caption: Boolean flag for enabling gender-neutral captioning for - Caption and Dense Captions features. Defaults to 'false'. - Captions may contain gender terms (for example: 'man', 'woman', or 'boy', 'girl'). - If you set this to 'true', those will be replaced with gender-neutral terms (for example: - 'person' or 'child'). - :paramtype gender_neutral_caption: bool - :keyword smart_crops_aspect_ratios: A list of aspect ratios to use for smart cropping. - Defaults to one crop region with an aspect ratio the service sees fit between - 0.5 and 2.0 (inclusive). Aspect ratios are calculated by dividing the target crop - width in pixels by the height in pixels. When set, supported values are - between 0.75 and 1.8 (inclusive). - :paramtype smart_crops_aspect_ratios: list[float] - :keyword model_version: The version of cloud AI-model used for analysis. Defaults to 'latest', - for the latest AI model with recent improvements. - The format is the following: 'latest' or 'YYYY-MM-DD' or 'YYYY-MM-DD-preview', - where 'YYYY', 'MM', 'DD' are the year, month and day associated with the model. - If you would like to make sure analysis results do not change over time, set this - value to a specific model version. - :paramtype model_version: str - :return: ImageAnalysisResult. The ImageAnalysisResult is compatible with MutableMapping - :rtype: ~azure.ai.vision.imageanalysis.models.ImageAnalysisResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - - visual_features_impl: List[Union[str, _models.VisualFeatures]] = list(visual_features) - - return await ImageAnalysisClientOperationsMixin._analyze_from_image_data( # pylint: disable=protected-access - self, - image_data=image_data, - visual_features=visual_features_impl, - language=language, - gender_neutral_caption=gender_neutral_caption, - smart_crops_aspect_ratios=smart_crops_aspect_ratios, - model_version=model_version, - **kwargs - ) - +from typing import List -__all__: List[str] = [ - "ImageAnalysisClient" -] # Add all objects you want publicly available to users at this package level +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_vendor.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_vendor.py index 405dfaff4c07..c6bb458368b5 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_vendor.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/aio/_vendor.py @@ -11,7 +11,6 @@ from ._configuration import ImageAnalysisClientConfiguration if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from azure.core import AsyncPipelineClient from .._serialization import Deserializer, Serializer diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/__init__.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/__init__.py index 70b7035de73d..cd1048847138 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/__init__.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/__init__.py @@ -5,30 +5,41 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._models import CaptionResult -from ._models import CropRegion -from ._models import DenseCaption -from ._models import DenseCaptionsResult -from ._models import DetectedObject -from ._models import DetectedPerson -from ._models import DetectedTag -from ._models import DetectedTextBlock -from ._models import DetectedTextLine -from ._models import DetectedTextWord -from ._models import ImageAnalysisResult -from ._models import ImageBoundingBox -from ._models import ImageMetadata -from ._models import ImagePoint -from ._models import ObjectsResult -from ._models import PeopleResult -from ._models import ReadResult -from ._models import SmartCropsResult -from ._models import TagsResult +from typing import TYPE_CHECKING -from ._enums import VisualFeatures +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + + +from ._models import ( # type: ignore + CaptionResult, + CropRegion, + DenseCaption, + DenseCaptionsResult, + DetectedObject, + DetectedPerson, + DetectedTag, + DetectedTextBlock, + DetectedTextLine, + DetectedTextWord, + ImageAnalysisResult, + ImageBoundingBox, + ImageMetadata, + ImagePoint, + ObjectsResult, + PeopleResult, + ReadResult, + SmartCropsResult, + TagsResult, +) + +from ._enums import ( # type: ignore + VisualFeatures, +) from ._patch import __all__ as _patch_all -from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ @@ -53,5 +64,5 @@ "TagsResult", "VisualFeatures", ] -__all__.extend([p for p in _patch_all if p not in __all__]) +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/_models.py b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/_models.py index f4ff4c276926..0df2ca4c94cd 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/_models.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/azure/ai/vision/imageanalysis/models/_models.py @@ -1,11 +1,11 @@ # coding=utf-8 -# pylint: disable=too-many-lines # -------------------------------------------------------------------------- # 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) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=useless-super-delegation from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload @@ -13,14 +13,12 @@ from .._model_base import rest_field if TYPE_CHECKING: - # pylint: disable=unused-import,ungrouped-imports from .. import models as _models class CaptionResult(_model_base.Model): """Represents a generated phrase that describes the content of the whole image. - :ivar confidence: A score, in the range of 0 to 1 (inclusive), representing the confidence that this description is accurate. Higher values indicating higher confidence. Required. @@ -29,11 +27,11 @@ class CaptionResult(_model_base.Model): :vartype text: str """ - confidence: float = rest_field() + confidence: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A score, in the range of 0 to 1 (inclusive), representing the confidence that this description is accurate. Higher values indicating higher confidence. Required.""" - text: str = rest_field() + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The text of the caption. Required.""" @overload @@ -42,16 +40,16 @@ def __init__( *, confidence: float, text: str, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -60,7 +58,6 @@ class CropRegion(_model_base.Model): The region preserves as much content as possible from the analyzed image, with priority given to detected faces. - :ivar aspect_ratio: The aspect ratio of the crop region. Aspect ratio is calculated by dividing the width of the region in pixels by its height in pixels. @@ -72,14 +69,16 @@ class CropRegion(_model_base.Model): :vartype bounding_box: ~azure.ai.vision.imageanalysis.models.ImageBoundingBox """ - aspect_ratio: float = rest_field(name="aspectRatio") + aspect_ratio: float = rest_field(name="aspectRatio", visibility=["read", "create", "update", "delete", "query"]) """The aspect ratio of the crop region. Aspect ratio is calculated by dividing the width of the region in pixels by its height in pixels. The aspect ratio will be in the range 0.75 to 1.8 (inclusive) if provided by the developer during the analyze call. Otherwise, it will be in the range 0.5 to 2.0 (inclusive). Required.""" - bounding_box: "_models.ImageBoundingBox" = rest_field(name="boundingBox") + bounding_box: "_models.ImageBoundingBox" = rest_field( + name="boundingBox", visibility=["read", "create", "update", "delete", "query"] + ) """The bounding box of the region. Required.""" @overload @@ -88,16 +87,16 @@ def __init__( *, aspect_ratio: float, bounding_box: "_models.ImageBoundingBox", - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -105,7 +104,6 @@ class DenseCaption(_model_base.Model): """Represents a generated phrase that describes the content of the whole image or a region in the image. - :ivar confidence: A score, in the range of 0 to 1 (inclusive), representing the confidence that this description is accurate. Higher values indicating higher confidence. Required. @@ -116,13 +114,15 @@ class DenseCaption(_model_base.Model): :vartype bounding_box: ~azure.ai.vision.imageanalysis.models.ImageBoundingBox """ - confidence: float = rest_field() + confidence: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A score, in the range of 0 to 1 (inclusive), representing the confidence that this description is accurate. Higher values indicating higher confidence. Required.""" - text: str = rest_field() + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The text of the caption. Required.""" - bounding_box: "_models.ImageBoundingBox" = rest_field(name="boundingBox") + bounding_box: "_models.ImageBoundingBox" = rest_field( + name="boundingBox", visibility=["read", "create", "update", "delete", "query"] + ) """The image region of which this caption applies. Required.""" @overload @@ -132,16 +132,16 @@ def __init__( confidence: float, text: str, bounding_box: "_models.ImageBoundingBox", - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -149,12 +149,13 @@ class DenseCaptionsResult(_model_base.Model): """Represents a list of up to 10 image captions for different regions of the image. The first caption always applies to the whole image. - :ivar list: The list of image captions. Required. :vartype list: list[~azure.ai.vision.imageanalysis.models.DenseCaption] """ - list: List["_models.DenseCaption"] = rest_field(name="values") + list: List["_models.DenseCaption"] = rest_field( + name="values", visibility=["read", "create", "update", "delete", "query"] + ) """The list of image captions. Required.""" @overload @@ -162,32 +163,33 @@ def __init__( self, *, list: List["_models.DenseCaption"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class DetectedObject(_model_base.Model): """Represents a physical object detected in an image. - :ivar bounding_box: A rectangular boundary where the object was detected. Required. :vartype bounding_box: ~azure.ai.vision.imageanalysis.models.ImageBoundingBox :ivar tags: A single-item list containing the object information. Required. :vartype tags: list[~azure.ai.vision.imageanalysis.models.DetectedTag] """ - bounding_box: "_models.ImageBoundingBox" = rest_field(name="boundingBox") + bounding_box: "_models.ImageBoundingBox" = rest_field( + name="boundingBox", visibility=["read", "create", "update", "delete", "query"] + ) """A rectangular boundary where the object was detected. Required.""" - tags: List["_models.DetectedTag"] = rest_field() + tags: List["_models.DetectedTag"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A single-item list containing the object information. Required.""" @overload @@ -196,25 +198,22 @@ def __init__( *, bounding_box: "_models.ImageBoundingBox", tags: List["_models.DetectedTag"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class DetectedPerson(_model_base.Model): """Represents a person detected in an image. - Readonly variables are only populated by the server, and will be ignored when sending a request. - - :ivar bounding_box: A rectangular boundary where the person was detected. Required. :vartype bounding_box: ~azure.ai.vision.imageanalysis.models.ImageBoundingBox :ivar confidence: A score, in the range of 0 to 1 (inclusive), representing the confidence that @@ -236,7 +235,6 @@ class DetectedTag(_model_base.Model): scenery, or action that appear in the image. - :ivar confidence: A score, in the range of 0 to 1 (inclusive), representing the confidence that this entity was observed. Higher values indicating higher confidence. Required. @@ -245,11 +243,11 @@ class DetectedTag(_model_base.Model): :vartype name: str """ - confidence: float = rest_field() + confidence: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A score, in the range of 0 to 1 (inclusive), representing the confidence that this entity was observed. Higher values indicating higher confidence. Required.""" - name: str = rest_field() + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Name of the entity. Required.""" @overload @@ -258,28 +256,27 @@ def __init__( *, confidence: float, name: str, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class DetectedTextBlock(_model_base.Model): """Represents a single block of detected text in the image. - :ivar lines: A list of text lines in this block. Required. :vartype lines: list[~azure.ai.vision.imageanalysis.models.DetectedTextLine] """ - lines: List["_models.DetectedTextLine"] = rest_field() + lines: List["_models.DetectedTextLine"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A list of text lines in this block. Required.""" @overload @@ -287,23 +284,22 @@ def __init__( self, *, lines: List["_models.DetectedTextLine"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class DetectedTextLine(_model_base.Model): """Represents a single line of text in the image. - :ivar text: Text content of the detected text line. Required. :vartype text: str :ivar bounding_polygon: A bounding polygon around the text line. At the moment only @@ -313,12 +309,14 @@ class DetectedTextLine(_model_base.Model): :vartype words: list[~azure.ai.vision.imageanalysis.models.DetectedTextWord] """ - text: str = rest_field() + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Text content of the detected text line. Required.""" - bounding_polygon: List["_models.ImagePoint"] = rest_field(name="boundingPolygon") + bounding_polygon: List["_models.ImagePoint"] = rest_field( + name="boundingPolygon", visibility=["read", "create", "update", "delete", "query"] + ) """A bounding polygon around the text line. At the moment only quadrilaterals are supported (represented by 4 image points). Required.""" - words: List["_models.DetectedTextWord"] = rest_field() + words: List["_models.DetectedTextWord"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A list of words in this line. Required.""" @overload @@ -328,16 +326,16 @@ def __init__( text: str, bounding_polygon: List["_models.ImagePoint"], words: List["_models.DetectedTextWord"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -346,7 +344,6 @@ class DetectedTextWord(_model_base.Model): languages, such as Chinese, Japanese, and Korean, each character is represented as its own word. - :ivar text: Text content of the word. Required. :vartype text: str :ivar bounding_polygon: A bounding polygon around the word. At the moment only quadrilaterals @@ -358,12 +355,14 @@ class DetectedTextWord(_model_base.Model): :vartype confidence: float """ - text: str = rest_field() + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Text content of the word. Required.""" - bounding_polygon: List["_models.ImagePoint"] = rest_field(name="boundingPolygon") + bounding_polygon: List["_models.ImagePoint"] = rest_field( + name="boundingPolygon", visibility=["read", "create", "update", "delete", "query"] + ) """A bounding polygon around the word. At the moment only quadrilaterals are supported (represented by 4 image points). Required.""" - confidence: float = rest_field() + confidence: float = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The level of confidence that the word was detected. Confidence scores span the range of 0.0 to 1.0 (inclusive), with higher values indicating a higher confidence of detection. Required.""" @@ -374,23 +373,22 @@ def __init__( text: str, bounding_polygon: List["_models.ImagePoint"], confidence: float, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class ImageAnalysisResult(_model_base.Model): """Represents the outcome of an Image Analysis operation. - :ivar caption: The generated phrase that describes the content of the analyzed image. :vartype caption: ~azure.ai.vision.imageanalysis.models.CaptionResult :ivar dense_captions: The up to 10 generated phrases, the first describing the content of the @@ -410,34 +408,48 @@ class ImageAnalysisResult(_model_base.Model): :vartype read: ~azure.ai.vision.imageanalysis.models.ReadResult :ivar smart_crops: A list of crop regions at the desired as aspect ratios (if provided) that can be used as image thumbnails. - These regions preserve as much content as possible from the analyzed image, with priority - given to detected faces. + These regions preserve as much content as possible from the analyzed image, with priority given + to detected faces. :vartype smart_crops: ~azure.ai.vision.imageanalysis.models.SmartCropsResult :ivar tags: A list of content tags in the analyzed image. :vartype tags: ~azure.ai.vision.imageanalysis.models.TagsResult """ - caption: Optional["_models.CaptionResult"] = rest_field(name="captionResult") + caption: Optional["_models.CaptionResult"] = rest_field( + name="captionResult", visibility=["read", "create", "update", "delete", "query"] + ) """The generated phrase that describes the content of the analyzed image.""" - dense_captions: Optional["_models.DenseCaptionsResult"] = rest_field(name="denseCaptionsResult") + dense_captions: Optional["_models.DenseCaptionsResult"] = rest_field( + name="denseCaptionsResult", visibility=["read", "create", "update", "delete", "query"] + ) """The up to 10 generated phrases, the first describing the content of the whole image, and the others describing the content of different regions of the image.""" - metadata: "_models.ImageMetadata" = rest_field() + metadata: "_models.ImageMetadata" = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Metadata associated with the analyzed image. Required.""" - model_version: str = rest_field(name="modelVersion") + model_version: str = rest_field(name="modelVersion", visibility=["read", "create", "update", "delete", "query"]) """The cloud AI model used for the analysis. Required.""" - objects: Optional["_models.ObjectsResult"] = rest_field(name="objectsResult") + objects: Optional["_models.ObjectsResult"] = rest_field( + name="objectsResult", visibility=["read", "create", "update", "delete", "query"] + ) """A list of detected physical objects in the analyzed image, and their location.""" - people: Optional["_models.PeopleResult"] = rest_field(name="peopleResult") + people: Optional["_models.PeopleResult"] = rest_field( + name="peopleResult", visibility=["read", "create", "update", "delete", "query"] + ) """A list of detected people in the analyzed image, and their location.""" - read: Optional["_models.ReadResult"] = rest_field(name="readResult") + read: Optional["_models.ReadResult"] = rest_field( + name="readResult", visibility=["read", "create", "update", "delete", "query"] + ) """The extracted printed and hand-written text in the analyze image. Also knows as OCR.""" - smart_crops: Optional["_models.SmartCropsResult"] = rest_field(name="smartCropsResult") + smart_crops: Optional["_models.SmartCropsResult"] = rest_field( + name="smartCropsResult", visibility=["read", "create", "update", "delete", "query"] + ) """A list of crop regions at the desired as aspect ratios (if provided) that can be used as image thumbnails. These regions preserve as much content as possible from the analyzed image, with priority given to detected faces.""" - tags: Optional["_models.TagsResult"] = rest_field(name="tagsResult") + tags: Optional["_models.TagsResult"] = rest_field( + name="tagsResult", visibility=["read", "create", "update", "delete", "query"] + ) """A list of content tags in the analyzed image.""" @overload @@ -453,23 +465,22 @@ def __init__( read: Optional["_models.ReadResult"] = None, smart_crops: Optional["_models.SmartCropsResult"] = None, tags: Optional["_models.TagsResult"] = None, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class ImageBoundingBox(_model_base.Model): """A basic rectangle specifying a sub-region of the image. - :ivar x: X-coordinate of the top left point of the area, in pixels. Required. :vartype x: int :ivar y: Y-coordinate of the top left point of the area, in pixels. Required. @@ -480,13 +491,13 @@ class ImageBoundingBox(_model_base.Model): :vartype height: int """ - x: int = rest_field() + x: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """X-coordinate of the top left point of the area, in pixels. Required.""" - y: int = rest_field() + y: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Y-coordinate of the top left point of the area, in pixels. Required.""" - width: int = rest_field(name="w") + width: int = rest_field(name="w", visibility=["read", "create", "update", "delete", "query"]) """Width of the area, in pixels. Required.""" - height: int = rest_field(name="h") + height: int = rest_field(name="h", visibility=["read", "create", "update", "delete", "query"]) """Height of the area, in pixels. Required.""" @overload @@ -497,32 +508,31 @@ def __init__( y: int, width: int, height: int, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class ImageMetadata(_model_base.Model): """Metadata associated with the analyzed image. - :ivar height: The height of the image in pixels. Required. :vartype height: int :ivar width: The width of the image in pixels. Required. :vartype width: int """ - height: int = rest_field() + height: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The height of the image in pixels. Required.""" - width: int = rest_field() + width: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The width of the image in pixels. Required.""" @overload @@ -531,23 +541,22 @@ def __init__( *, height: int, width: int, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class ImagePoint(_model_base.Model): """Represents the coordinates of a single pixel in the image. - :ivar x: The horizontal x-coordinate of this point, in pixels. Zero values corresponds to the left-most pixels in the image. Required. :vartype x: int @@ -556,10 +565,10 @@ class ImagePoint(_model_base.Model): :vartype y: int """ - x: int = rest_field() + x: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The horizontal x-coordinate of this point, in pixels. Zero values corresponds to the left-most pixels in the image. Required.""" - y: int = rest_field() + y: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The vertical y-coordinate of this point, in pixels. Zero values corresponds to the top-most pixels in the image. Required.""" @@ -569,41 +578,57 @@ def __init__( *, x: int, y: int, - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class ImageUrl(_model_base.Model): """An object holding the publicly reachable URL of an image to analyze. - All required parameters must be populated in order to send to server. - :ivar url: Publicly reachable URL of an image to analyze. Required. :vartype url: str """ - url: str = rest_field() + url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Publicly reachable URL of an image to analyze. Required.""" + @overload + def __init__( + self, + *, + url: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + class ObjectsResult(_model_base.Model): """Represents a list of physical object detected in an image and their location. - :ivar list: A list of physical object detected in an image and their location. Required. :vartype list: list[~azure.ai.vision.imageanalysis.models.DetectedObject] """ - list: List["_models.DetectedObject"] = rest_field(name="values") + list: List["_models.DetectedObject"] = rest_field( + name="values", visibility=["read", "create", "update", "delete", "query"] + ) """A list of physical object detected in an image and their location. Required.""" @overload @@ -611,28 +636,29 @@ def __init__( self, *, list: List["_models.DetectedObject"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class PeopleResult(_model_base.Model): """Represents a list of people detected in an image and their location. - :ivar list: A list of people detected in an image and their location. Required. :vartype list: list[~azure.ai.vision.imageanalysis.models.DetectedPerson] """ - list: List["_models.DetectedPerson"] = rest_field(name="values") + list: List["_models.DetectedPerson"] = rest_field( + name="values", visibility=["read", "create", "update", "delete", "query"] + ) """A list of people detected in an image and their location. Required.""" @overload @@ -640,29 +666,28 @@ def __init__( self, *, list: List["_models.DetectedPerson"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) class ReadResult(_model_base.Model): """The results of a Read (OCR) operation. - :ivar blocks: A list of text blocks in the image. At the moment only one block is returned, containing all the text detected in the image. Required. :vartype blocks: list[~azure.ai.vision.imageanalysis.models.DetectedTextBlock] """ - blocks: List["_models.DetectedTextBlock"] = rest_field() + blocks: List["_models.DetectedTextBlock"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A list of text blocks in the image. At the moment only one block is returned, containing all the text detected in the image. Required.""" @@ -671,16 +696,16 @@ def __init__( self, *, blocks: List["_models.DetectedTextBlock"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -690,12 +715,13 @@ class SmartCropsResult(_model_base.Model): These regions preserve as much content as possible from the analyzed image, with priority given to detected faces. - :ivar list: A list of crop regions. Required. :vartype list: list[~azure.ai.vision.imageanalysis.models.CropRegion] """ - list: List["_models.CropRegion"] = rest_field(name="values") + list: List["_models.CropRegion"] = rest_field( + name="values", visibility=["read", "create", "update", "delete", "query"] + ) """A list of crop regions. Required.""" @overload @@ -703,16 +729,16 @@ def __init__( self, *, list: List["_models.CropRegion"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -721,12 +747,13 @@ class TagsResult(_model_base.Model): or actions that appear in the image. - :ivar list: A list of tags. Required. :vartype list: list[~azure.ai.vision.imageanalysis.models.DetectedTag] """ - list: List["_models.DetectedTag"] = rest_field(name="values") + list: List["_models.DetectedTag"] = rest_field( + name="values", visibility=["read", "create", "update", "delete", "query"] + ) """A list of tags. Required.""" @overload @@ -734,14 +761,14 @@ def __init__( self, *, list: List["_models.DetectedTag"], - ): ... + ) -> None: ... @overload - def __init__(self, mapping: Mapping[str, Any]): + def __init__(self, mapping: Mapping[str, Any]) -> None: """ :param mapping: raw JSON to initialize the model. :type mapping: Mapping[str, Any] """ - def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useless-super-delegation + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) diff --git a/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/conftest.py b/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/conftest.py new file mode 100644 index 000000000000..aab7c4da0e75 --- /dev/null +++ b/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/conftest.py @@ -0,0 +1,37 @@ +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import os +import pytest +from dotenv import load_dotenv +from devtools_testutils import ( + test_proxy, + add_general_regex_sanitizer, + add_body_key_sanitizer, + add_header_regex_sanitizer, +) + +load_dotenv() + + +# For security, please avoid record sensitive identity information in recordings +@pytest.fixture(scope="session", autouse=True) +def add_sanitizers(test_proxy): + imageanalysis_subscription_id = os.environ.get( + "IMAGEANALYSIS_SUBSCRIPTION_ID", "00000000-0000-0000-0000-000000000000" + ) + imageanalysis_tenant_id = os.environ.get("IMAGEANALYSIS_TENANT_ID", "00000000-0000-0000-0000-000000000000") + imageanalysis_client_id = os.environ.get("IMAGEANALYSIS_CLIENT_ID", "00000000-0000-0000-0000-000000000000") + imageanalysis_client_secret = os.environ.get("IMAGEANALYSIS_CLIENT_SECRET", "00000000-0000-0000-0000-000000000000") + add_general_regex_sanitizer(regex=imageanalysis_subscription_id, value="00000000-0000-0000-0000-000000000000") + add_general_regex_sanitizer(regex=imageanalysis_tenant_id, value="00000000-0000-0000-0000-000000000000") + add_general_regex_sanitizer(regex=imageanalysis_client_id, value="00000000-0000-0000-0000-000000000000") + add_general_regex_sanitizer(regex=imageanalysis_client_secret, value="00000000-0000-0000-0000-000000000000") + + add_header_regex_sanitizer(key="Set-Cookie", value="[set-cookie;]") + add_header_regex_sanitizer(key="Cookie", value="cookie;") + add_body_key_sanitizer(json_path="$..access_token", value="access_token") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/testpreparer.py b/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/testpreparer.py new file mode 100644 index 000000000000..b5c2e12ff257 --- /dev/null +++ b/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/testpreparer.py @@ -0,0 +1,26 @@ +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from azure.ai.vision.imageanalysis import ImageAnalysisClient +from devtools_testutils import AzureRecordedTestCase, PowerShellPreparer +import functools + + +class ImageAnalysisClientTestBase(AzureRecordedTestCase): + + def create_client(self, endpoint): + credential = self.get_credential(ImageAnalysisClient) + return self.create_client_from_credential( + ImageAnalysisClient, + credential=credential, + endpoint=endpoint, + ) + + +ImageAnalysisPreparer = functools.partial( + PowerShellPreparer, "imageanalysis", imageanalysis_endpoint="https://fake_imageanalysis_endpoint.com" +) diff --git a/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/testpreparer_async.py b/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/testpreparer_async.py new file mode 100644 index 000000000000..b3b83db7f333 --- /dev/null +++ b/sdk/vision/azure-ai-vision-imageanalysis/generated_tests/testpreparer_async.py @@ -0,0 +1,20 @@ +# 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) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from azure.ai.vision.imageanalysis.aio import ImageAnalysisClient +from devtools_testutils import AzureRecordedTestCase + + +class ImageAnalysisClientTestBaseAsync(AzureRecordedTestCase): + + def create_async_client(self, endpoint): + credential = self.get_credential(ImageAnalysisClient, is_async=True) + return self.create_client_from_credential( + ImageAnalysisClient, + credential=credential, + endpoint=endpoint, + ) diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_caption_image_file_async.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_caption_image_file_async.py index 35b3b001da4a..5f857c22d792 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_caption_image_file_async.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_caption_image_file_async.py @@ -48,16 +48,10 @@ async def sample_caption_image_file_async(): image_data = f.read() # Create an asynchronous Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Get a caption for the image, asynchronously. - result = await client.analyze( - image_data=image_data, - visual_features=[VisualFeatures.CAPTION] - ) + result = await client.analyze(image_data=image_data, visual_features=[VisualFeatures.CAPTION]) await client.close() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_async.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_async.py index 103b79406589..d1a0afcaad09 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_async.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_async.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -47,15 +48,11 @@ async def sample_ocr_image_url_async(): exit() # Create an asynchronous Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Extract text (OCR) from an image URL, asynchronously. result = await client.analyze_from_url( - image_url="https://aka.ms/azsdk/image-analysis/sample.jpg", - visual_features=[VisualFeatures.READ] + image_url="https://aka.ms/azsdk/image-analysis/sample.jpg", visual_features=[VisualFeatures.READ] ) await client.close() @@ -67,7 +64,9 @@ async def sample_ocr_image_url_async(): for line in result.read.blocks[0].lines: print(f" Line: '{line.text}', Bounding box {line.bounding_polygon}") for word in line.words: - print(f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}") + print( + f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}" + ) print(f" Image height: {result.metadata.height}") print(f" Image width: {result.metadata.width}") print(f" Model version: {result.model_version}") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_entra_id_auth_async.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_entra_id_auth_async.py index e3bc95c2197c..5af0ecbee3c3 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_entra_id_auth_async.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/async_samples/sample_ocr_image_url_entra_id_auth_async.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -52,8 +53,7 @@ async def sample_ocr_image_url_entra_id_auth_async(): # Extract text (OCR) from an image URL, asynchronously. result = await client.analyze_from_url( - image_url="https://aka.ms/azsdk/image-analysis/sample.jpg", - visual_features=[VisualFeatures.READ] + image_url="https://aka.ms/azsdk/image-analysis/sample.jpg", visual_features=[VisualFeatures.READ] ) await client.close() @@ -65,7 +65,9 @@ async def sample_ocr_image_url_entra_id_auth_async(): for line in result.read.blocks[0].lines: print(f" Line: '{line.text}', Bounding box {line.bounding_polygon}") for word in line.words: - print(f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}") + print( + f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}" + ) print(f" Image height: {result.metadata.height}") print(f" Image width: {result.metadata.width}") print(f" Model version: {result.model_version}") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_analyze_all_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_analyze_all_image_file.py index 08ce7f3d584c..04d0125c9cd9 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_analyze_all_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_analyze_all_image_file.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -70,11 +71,7 @@ def sample_analyze_all_image_file(): # [START create_client_with_logging] # Create an Image Analysis client with none redacted log - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key), - logging_enable=True - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key), logging_enable=True) # [END create_client_with_logging] # Analyze all visual features from an image stream. This will be a synchronously (blocking) call. @@ -112,7 +109,9 @@ def sample_analyze_all_image_file(): for line in result.read.blocks[0].lines: print(f" Line: '{line.text}', Bounding box {line.bounding_polygon}") for word in line.words: - print(f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}") + print( + f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}" + ) if result.tags is not None: print(" Tags:") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_file.py index d5fd0a12fc6d..8f2ab5556b0f 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_file.py @@ -46,10 +46,7 @@ def sample_caption_image_file(): # Create an Image Analysis client for synchronous operations, # using API key authentication - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # [END create_client] # [START caption] diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_url.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_url.py index fe9dad3aa4a1..c6d99f21b25e 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_url.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_caption_image_url.py @@ -44,10 +44,7 @@ def sample_caption_image_url(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # [START caption] # Get a caption for the image. This will be a synchronously (blocking) call. diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_dense_captions_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_dense_captions_image_file.py index 8f268cb76ee0..5e062467ca67 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_dense_captions_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_dense_captions_image_file.py @@ -48,10 +48,7 @@ def sample_dense_captions_image_file(): exit() # Create an Image Analysis client. - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Load image to analyze into a 'bytes' object. with open("sample.jpg", "rb") as f: diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_objects_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_objects_image_file.py index b3aec2ead684..0bf98d2d05a6 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_objects_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_objects_image_file.py @@ -41,20 +41,14 @@ def sample_objects_image_file(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Load image to analyze into a 'bytes' object with open("sample.jpg", "rb") as f: image_data = f.read() # Detect objects in an image stream. This will be a synchronously (blocking) call. - result = client.analyze( - image_data=image_data, - visual_features=[VisualFeatures.OBJECTS] - ) + result = client.analyze(image_data=image_data, visual_features=[VisualFeatures.OBJECTS]) # Print Objects analysis results to the console print("Image analysis results:") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_file.py index 3715bf4618a6..e76df8b1ff1b 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_file.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -47,10 +48,7 @@ def sample_ocr_image_file(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # [START read] # Load image to analyze into a 'bytes' object @@ -58,10 +56,7 @@ def sample_ocr_image_file(): image_data = f.read() # Extract text (OCR) from an image stream. This will be a synchronously (blocking) call. - result = client.analyze( - image_data=image_data, - visual_features=[VisualFeatures.READ] - ) + result = client.analyze(image_data=image_data, visual_features=[VisualFeatures.READ]) # Print text (OCR) analysis results to the console print("Image analysis results:") @@ -70,7 +65,9 @@ def sample_ocr_image_file(): for line in result.read.blocks[0].lines: print(f" Line: '{line.text}', Bounding box {line.bounding_polygon}") for word in line.words: - print(f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}") + print( + f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}" + ) # [END read] print(f" Image height: {result.metadata.height}") print(f" Image width: {result.metadata.width}") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_url.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_url.py index 96a835bb9cb3..e1c273355435 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_url.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_ocr_image_url.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -47,16 +48,12 @@ def sample_ocr_image_url(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # [START read] # Extract text (OCR) from an image stream. This will be a synchronously (blocking) call. result = client.analyze_from_url( - image_url="https://aka.ms/azsdk/image-analysis/sample.jpg", - visual_features=[VisualFeatures.READ] + image_url="https://aka.ms/azsdk/image-analysis/sample.jpg", visual_features=[VisualFeatures.READ] ) # Print text (OCR) analysis results to the console @@ -66,7 +63,9 @@ def sample_ocr_image_url(): for line in result.read.blocks[0].lines: print(f" Line: '{line.text}', Bounding box {line.bounding_polygon}") for word in line.words: - print(f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}") + print( + f" Word: '{word.text}', Bounding polygon {word.bounding_polygon}, Confidence {word.confidence:.4f}" + ) # [END read] print(f" Image height: {result.metadata.height}") print(f" Image width: {result.metadata.width}") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_people_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_people_image_file.py index c540bcf0c897..c506ea91d19a 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_people_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_people_image_file.py @@ -40,20 +40,14 @@ def sample_people_image_file(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Load image to analyze into a 'bytes' object with open("sample.jpg", "rb") as f: image_data = f.read() # Find people in an image stream. This will be a synchronously (blocking) call. - result = client.analyze( - image_data=image_data, - visual_features=[VisualFeatures.PEOPLE] - ) + result = client.analyze(image_data=image_data, visual_features=[VisualFeatures.PEOPLE]) # Print People analysis results to the console print("Image analysis results:") diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_smart_crops_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_smart_crops_image_file.py index c9d4cdeec8d2..b2aac22a02cb 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_smart_crops_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_smart_crops_image_file.py @@ -49,10 +49,7 @@ def sample_smart_crops_image_file(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Load image to analyze into a 'bytes' object with open("sample.jpg", "rb") as f: diff --git a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_tags_image_file.py b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_tags_image_file.py index d2cc94f3f746..b01784368120 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_tags_image_file.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/samples/sample_tags_image_file.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -42,10 +43,7 @@ def sample_tags_image_file(): exit() # Create an Image Analysis client - client = ImageAnalysisClient( - endpoint=endpoint, - credential=AzureKeyCredential(key) - ) + client = ImageAnalysisClient(endpoint=endpoint, credential=AzureKeyCredential(key)) # Load image to analyze into a 'bytes' object with open("sample.jpg", "rb") as f: diff --git a/sdk/vision/azure-ai-vision-imageanalysis/setup.py b/sdk/vision/azure-ai-vision-imageanalysis/setup.py index 47b02d2e77bf..5d8ef050c3db 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/setup.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/setup.py @@ -38,7 +38,7 @@ url="https://github.com/Azure/azure-sdk-for-python/tree/main/sdk", keywords="azure, azure sdk", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 4 - Beta", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", diff --git a/sdk/vision/azure-ai-vision-imageanalysis/tests/image_analysis_test_base.py b/sdk/vision/azure-ai-vision-imageanalysis/tests/image_analysis_test_base.py index 89a3b33e4d8a..62fa5a6f1569 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/tests/image_analysis_test_base.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/tests/image_analysis_test_base.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long,useless-suppression # ------------------------------------ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. @@ -56,7 +57,9 @@ def _create_client_for_standard_analysis(self, sync: bool, get_connection_url: b credential = AzureKeyCredential(key) self._create_client(endpoint, credential, sync, get_connection_url) - def _create_client_for_standard_analysis_with_entra_id_auth(self, sync: bool, get_connection_url: bool = False, **kwargs): + def _create_client_for_standard_analysis_with_entra_id_auth( + self, sync: bool, get_connection_url: bool = False, **kwargs + ): endpoint = kwargs.pop("vision_endpoint") # See /tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py for `get_credential` if sync: @@ -71,8 +74,14 @@ def _create_client_for_authentication_failure(self, sync: bool, **kwargs): credential = AzureKeyCredential(key) self._create_client(endpoint, credential, sync, False) - def _create_client(self, endpoint: str, credential: Union[AzureKeyCredential, TokenCredential], sync: bool, get_connection_url: bool): - + def _create_client( + self, + endpoint: str, + credential: Union[AzureKeyCredential, TokenCredential], + sync: bool, + get_connection_url: bool, + ): + if sync: self.client = sdk.ImageAnalysisClient( endpoint=endpoint, diff --git a/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_async_client.py b/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_async_client.py index 3bfceee97975..c5ae87d622f8 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_async_client.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_async_client.py @@ -79,7 +79,9 @@ async def test_analyze_async_single_feature_from_file_entra_id_auth(self, **kwar self._create_client_for_standard_analysis_with_entra_id_auth(sync=False, **kwargs) - await self._do_async_analysis(image_source=self.IMAGE_FILE,visual_features=[sdk.models.VisualFeatures.SMART_CROPS], **kwargs) + await self._do_async_analysis( + image_source=self.IMAGE_FILE, visual_features=[sdk.models.VisualFeatures.SMART_CROPS], **kwargs + ) await self.async_client.close() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_client.py b/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_client.py index 508be2b23f9f..99fb54a77213 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_client.py +++ b/sdk/vision/azure-ai-vision-imageanalysis/tests/test_image_analysis_client.py @@ -72,7 +72,7 @@ def test_analyze_sync_single_feature_from_url_entra_id_auth(self, **kwargs): self._create_client_for_standard_analysis_with_entra_id_auth(sync=True, **kwargs) - self._do_analysis(image_source=self.IMAGE_URL,visual_features=[sdk.models.VisualFeatures.OBJECTS], **kwargs) + self._do_analysis(image_source=self.IMAGE_URL, visual_features=[sdk.models.VisualFeatures.OBJECTS], **kwargs) self.client.close() diff --git a/sdk/vision/azure-ai-vision-imageanalysis/tsp-location.yaml b/sdk/vision/azure-ai-vision-imageanalysis/tsp-location.yaml index ad6a1e1e28d9..166e2e411afb 100644 --- a/sdk/vision/azure-ai-vision-imageanalysis/tsp-location.yaml +++ b/sdk/vision/azure-ai-vision-imageanalysis/tsp-location.yaml @@ -1,6 +1,4 @@ -additionalDirectories: [] -repo: Azure/azure-rest-api-specs directory: specification/ai/ImageAnalysis -commit: 3bcdb0ee47bfa6bcc79036b4c9e5fe287701f796 - - +commit: 9029d073924ec35c84b2973464bdd1f899fed75e +repo: Azure/azure-rest-api-specs +additionalDirectories: