diff --git a/sdk/contentsafety/azure-ai-contentsafety/_meta.json b/sdk/contentsafety/azure-ai-contentsafety/_meta.json new file mode 100644 index 000000000000..3a86c04e1eb0 --- /dev/null +++ b/sdk/contentsafety/azure-ai-contentsafety/_meta.json @@ -0,0 +1,6 @@ +{ + "commit": "274e6bec630de1762940d0f33adf105db3e42ebe", + "repository_url": "https://github.com/Azure/azure-rest-api-specs", + "typespec_src": "specification/cognitiveservices/ContentSafety", + "@azure-tools/typespec-python": "0.27.1" +} \ No newline at end of file diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_client.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_client.py index e2e1f2849fe6..6f9499cb95cc 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_client.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_client.py @@ -8,6 +8,7 @@ from copy import deepcopy from typing import Any, TYPE_CHECKING, Union +from typing_extensions import Self from azure.core import PipelineClient from azure.core.credentials import AzureKeyCredential @@ -29,11 +30,11 @@ class ContentSafetyClient(ContentSafetyClientOperationsMixin): # pylint: disabl :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -84,7 +85,7 @@ def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: request_copy = deepcopy(request) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) @@ -93,7 +94,7 @@ def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: def close(self) -> None: self._client.close() - def __enter__(self) -> "ContentSafetyClient": + def __enter__(self) -> Self: self._client.__enter__() return self @@ -107,11 +108,11 @@ class BlocklistClient(BlocklistClientOperationsMixin): # pylint: disable=client :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -162,7 +163,7 @@ def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: request_copy = deepcopy(request) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) @@ -171,7 +172,7 @@ def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: def close(self) -> None: self._client.close() - def __enter__(self) -> "BlocklistClient": + def __enter__(self) -> Self: self._client.__enter__() return self diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_configuration.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_configuration.py index 9d9a723f0355..5de9b5b0661f 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_configuration.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_configuration.py @@ -27,17 +27,17 @@ class ContentSafetyClientConfiguration: # pylint: disable=too-many-instance-att :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ def __init__(self, endpoint: str, credential: Union[AzureKeyCredential, "TokenCredential"], **kwargs: Any) -> None: - api_version: str = kwargs.pop("api_version", "2023-10-01") + api_version: str = kwargs.pop("api_version", "2024-09-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") @@ -82,17 +82,17 @@ class BlocklistClientConfiguration: # pylint: disable=too-many-instance-attribu :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ def __init__(self, endpoint: str, credential: Union[AzureKeyCredential, "TokenCredential"], **kwargs: Any) -> None: - api_version: str = kwargs.pop("api_version", "2023-10-01") + api_version: str = kwargs.pop("api_version", "2024-09-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_model_base.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_model_base.py index aec056aba7b7..7d82ac3456cb 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_model_base.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_model_base.py @@ -5,8 +5,8 @@ # license information. # -------------------------------------------------------------------------- # pylint: disable=protected-access, arguments-differ, signature-differs, broad-except -# pyright: reportGeneralTypeIssues=false +import copy import calendar import decimal import functools @@ -14,11 +14,12 @@ import logging import base64 import re -import copy import typing -import email +import enum +import email.utils from datetime import datetime, date, time, timedelta, timezone from json import JSONEncoder +from typing_extensions import Self import isodate from azure.core.exceptions import DeserializationError from azure.core import CaseInsensitiveEnumMeta @@ -35,6 +36,7 @@ __all__ = ["SdkJSONEncoder", "Model", "rest_field", "rest_discriminator"] TZ_UTC = timezone.utc +_T = typing.TypeVar("_T") def _timedelta_as_isostr(td: timedelta) -> str: @@ -242,7 +244,7 @@ def _deserialize_date(attr: typing.Union[str, date]) -> date: # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. if isinstance(attr, date): return attr - return isodate.parse_date(attr, defaultmonth=None, defaultday=None) + return isodate.parse_date(attr, defaultmonth=None, defaultday=None) # type: ignore def _deserialize_time(attr: typing.Union[str, time]) -> time: @@ -337,7 +339,7 @@ def _get_model(module_name: str, model_name: str): class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=unsubscriptable-object def __init__(self, data: typing.Dict[str, typing.Any]) -> None: - self._data = copy.deepcopy(data) + self._data = data def __contains__(self, key: typing.Any) -> bool: return key in self._data @@ -375,13 +377,14 @@ def get(self, key: str, default: typing.Any = None) -> typing.Any: except KeyError: return default - @typing.overload # type: ignore - def pop(self, key: str) -> typing.Any: # pylint: disable=no-member - ... + @typing.overload + def pop(self, key: str) -> typing.Any: ... + + @typing.overload + def pop(self, key: str, default: _T) -> _T: ... @typing.overload - def pop(self, key: str, default: typing.Any) -> typing.Any: - ... + def pop(self, key: str, default: typing.Any) -> typing.Any: ... def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any: if default is _UNSET: @@ -397,13 +400,11 @@ def clear(self) -> None: def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: self._data.update(*args, **kwargs) - @typing.overload # type: ignore - def setdefault(self, key: str) -> typing.Any: - ... + @typing.overload + def setdefault(self, key: str, default: None = None) -> None: ... @typing.overload - def setdefault(self, key: str, default: typing.Any) -> typing.Any: - ... + def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: if default is _UNSET: @@ -438,6 +439,8 @@ def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-m return _serialize_bytes(o, format) if isinstance(o, decimal.Decimal): return float(o) + if isinstance(o, enum.Enum): + return o.value try: # First try datetime.datetime return _serialize_datetime(o, format) @@ -462,7 +465,13 @@ def _get_rest_field( def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any: - return _deserialize(rf._type, value) if (rf and rf._is_model) else _serialize(value, rf._format if rf else None) + if not rf: + return _serialize(value, None) + if rf._is_multipart_file_input: + return value + if rf._is_model: + return _deserialize(rf._type, value) + return _serialize(value, rf._format) class Model(_MyMutableMapping): @@ -498,7 +507,7 @@ 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) -> "Model": # pylint: disable=unused-argument + 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 @@ -540,7 +549,7 @@ def _deserialize(cls, data, exist_discriminators): return cls(data) discriminator = cls._get_discriminator(exist_discriminators) exist_discriminators.append(discriminator) - mapped_cls = cls.__mapping__.get(data.get(discriminator), cls) # pylint: disable=no-member + mapped_cls = cls.__mapping__.get(data.get(discriminator), cls) # pyright: ignore # pylint: disable=no-member if mapped_cls == cls: return cls(data) return mapped_cls._deserialize(data, exist_discriminators) # pylint: disable=protected-access @@ -554,12 +563,20 @@ 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(): - if exclude_readonly and k in readonly_props: # pyright: ignore[reportUnboundVariable] + if exclude_readonly and k in readonly_props: # pyright: ignore continue - result[k] = Model._as_dict_value(v, exclude_readonly=exclude_readonly) + is_multipart_file_input = False + try: + is_multipart_file_input = next( + rf for rf in self._attr_to_rest_field.values() if rf._rest_name == k + )._is_multipart_file_input + except StopIteration: + pass + result[k] = v if is_multipart_file_input else Model._as_dict_value(v, exclude_readonly=exclude_readonly) return result @staticmethod @@ -567,12 +584,70 @@ def _as_dict_value(v: typing.Any, exclude_readonly: bool = False) -> typing.Any: if v is None or isinstance(v, _Null): return None if isinstance(v, (list, tuple, set)): - return [Model._as_dict_value(x, exclude_readonly=exclude_readonly) for x in v] + return type(v)(Model._as_dict_value(x, exclude_readonly=exclude_readonly) for x in v) if isinstance(v, dict): return {dk: Model._as_dict_value(dv, exclude_readonly=exclude_readonly) for dk, dv in v.items()} return v.as_dict(exclude_readonly=exclude_readonly) if hasattr(v, "as_dict") else v +def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj): + if _is_model(obj): + return obj + return _deserialize(model_deserializer, obj) + + +def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj): + if obj is None: + return obj + return _deserialize_with_callable(if_obj_deserializer, obj) + + +def _deserialize_with_union(deserializers, obj): + for deserializer in deserializers: + try: + return _deserialize(deserializer, obj) + except DeserializationError: + pass + raise DeserializationError() + + +def _deserialize_dict( + value_deserializer: typing.Optional[typing.Callable], + module: typing.Optional[str], + obj: typing.Dict[typing.Any, typing.Any], +): + if obj is None: + return obj + return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()} + + +def _deserialize_multiple_sequence( + entry_deserializers: typing.List[typing.Optional[typing.Callable]], + module: typing.Optional[str], + obj, +): + if obj is None: + return obj + return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers)) + + +def _deserialize_sequence( + deserializer: typing.Optional[typing.Callable], + module: typing.Optional[str], + obj, +): + if obj is None: + return obj + return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) + + +def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]: + return sorted( + types, + key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"), + ) + + def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, R0912 annotation: typing.Any, module: typing.Optional[str], @@ -600,106 +675,70 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915, if rf: rf._is_model = True - def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj): - if _is_model(obj): - return obj - return _deserialize(model_deserializer, obj) - - return functools.partial(_deserialize_model, annotation) + return functools.partial(_deserialize_model, annotation) # pyright: ignore except Exception: pass # is it a literal? try: - if sys.version_info >= (3, 8): - from typing import ( - Literal, - ) # pylint: disable=no-name-in-module, ungrouped-imports - else: - from typing_extensions import Literal # type: ignore # pylint: disable=ungrouped-imports - - if annotation.__origin__ == Literal: + if annotation.__origin__ is typing.Literal: # pyright: ignore return None except AttributeError: pass # is it optional? try: - if any(a for a in annotation.__args__ if a == type(None)): - if_obj_deserializer = _get_deserialize_callable_from_annotation( - next(a for a in annotation.__args__ if a != type(None)), module, rf - ) - - def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj): - if obj is None: - return obj - return _deserialize_with_callable(if_obj_deserializer, obj) - - return functools.partial(_deserialize_with_optional, if_obj_deserializer) + if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore + if len(annotation.__args__) <= 2: # pyright: ignore + if_obj_deserializer = _get_deserialize_callable_from_annotation( + next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore + ) + + return functools.partial(_deserialize_with_optional, if_obj_deserializer) + # the type is Optional[Union[...]], we need to remove the None type from the Union + annotation_copy = copy.copy(annotation) + annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore + return _get_deserialize_callable_from_annotation(annotation_copy, module, rf) except AttributeError: pass + # is it union? if getattr(annotation, "__origin__", None) is typing.Union: - deserializers = [_get_deserialize_callable_from_annotation(arg, module, rf) for arg in annotation.__args__] - - def _deserialize_with_union(deserializers, obj): - for deserializer in deserializers: - try: - return _deserialize(deserializer, obj) - except DeserializationError: - pass - raise DeserializationError() + # initial ordering is we make `string` the last deserialization option, because it is often them most generic + deserializers = [ + _get_deserialize_callable_from_annotation(arg, module, rf) + for arg in _sorted_annotations(annotation.__args__) # pyright: ignore + ] return functools.partial(_deserialize_with_union, deserializers) try: - if annotation._name == "Dict": - value_deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[1], module, rf) - - def _deserialize_dict( - value_deserializer: typing.Optional[typing.Callable], - obj: typing.Dict[typing.Any, typing.Any], - ): - if obj is None: - return obj - return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()} + if annotation._name == "Dict": # pyright: ignore + value_deserializer = _get_deserialize_callable_from_annotation( + annotation.__args__[1], module, rf # pyright: ignore + ) return functools.partial( _deserialize_dict, value_deserializer, + module, ) except (AttributeError, IndexError): pass try: - if annotation._name in ["List", "Set", "Tuple", "Sequence"]: - if len(annotation.__args__) > 1: - - def _deserialize_multiple_sequence( - entry_deserializers: typing.List[typing.Optional[typing.Callable]], - obj, - ): - if obj is None: - return obj - return type(obj)( - _deserialize(deserializer, entry, module) - for entry, deserializer in zip(obj, entry_deserializers) - ) + 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__ + _get_deserialize_callable_from_annotation(dt, module, rf) + for dt in annotation.__args__ # pyright: ignore ] - return functools.partial(_deserialize_multiple_sequence, entry_deserializers) - deserializer = _get_deserialize_callable_from_annotation(annotation.__args__[0], module, rf) - - def _deserialize_sequence( - deserializer: typing.Optional[typing.Callable], - obj, - ): - if obj is None: - return obj - return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) - - return functools.partial(_deserialize_sequence, deserializer) + return functools.partial(_deserialize_multiple_sequence, entry_deserializers, module) + deserializer = _get_deserialize_callable_from_annotation( + annotation.__args__[0], module, rf # pyright: ignore + ) + + return functools.partial(_deserialize_sequence, deserializer, module) except (TypeError, IndexError, AttributeError, SyntaxError): pass @@ -709,7 +748,11 @@ def _deserialize_default( ): if obj is None: return obj - return _deserialize_with_callable(deserializer, obj) + try: + return _deserialize_with_callable(deserializer, obj) + except Exception: + pass + return obj if get_deserializer(annotation, rf): return functools.partial(_deserialize_default, get_deserializer(annotation, rf)) @@ -765,6 +808,7 @@ def __init__( visibility: typing.Optional[typing.List[str]] = None, default: typing.Any = _UNSET, format: typing.Optional[str] = None, + is_multipart_file_input: bool = False, ): self._type = type self._rest_name_input = name @@ -774,6 +818,11 @@ def __init__( self._is_model = False self._default = default self._format = format + self._is_multipart_file_input = is_multipart_file_input + + @property + def _class_type(self) -> typing.Any: + return getattr(self._type, "args", [None])[0] @property def _rest_name(self) -> str: @@ -819,13 +868,22 @@ def rest_field( visibility: typing.Optional[typing.List[str]] = None, default: typing.Any = _UNSET, format: typing.Optional[str] = None, + is_multipart_file_input: bool = False, ) -> typing.Any: - return _RestField(name=name, type=type, visibility=visibility, default=default, format=format) + return _RestField( + name=name, + type=type, + visibility=visibility, + default=default, + format=format, + is_multipart_file_input=is_multipart_file_input, + ) 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, ) -> typing.Any: - return _RestField(name=name, type=type, is_discriminator=True) + return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility) diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_operations/_operations.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_operations/_operations.py index 175bc5ca04d6..26bd5899c8f7 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_operations/_operations.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_operations/_operations.py @@ -1,4 +1,4 @@ -# pylint: disable=too-many-lines +# pylint: disable=too-many-lines,too-many-statements # 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, Iterable, List, Optional, TypeVar, Union, overload +from typing import Any, Callable, Dict, IO, Iterable, List, Optional, Type, TypeVar, Union, overload import urllib.parse from azure.core.exceptions import ( @@ -18,6 +18,8 @@ ResourceExistsError, ResourceNotFoundError, ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, map_error, ) from azure.core.paging import ItemPaged @@ -29,6 +31,7 @@ from .. import models as _models from .._model_base import SdkJSONEncoder, _deserialize from .._serialization import Serializer +from .._validation import api_version_validation from .._vendor import BlocklistClientMixinABC, ContentSafetyClientMixinABC if sys.version_info >= (3, 9): @@ -43,12 +46,34 @@ _SERIALIZER.client_side_validation = False +def build_content_safety_analyze_image_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/image:analyze" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + def build_content_safety_analyze_text_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -58,31 +83,55 @@ def build_content_safety_analyze_text_request(**kwargs: Any) -> HttpRequest: # _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_content_safety_analyze_image_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long +def build_content_safety_detect_text_protected_material_request( # pylint: disable=name-too-long + **kwargs: Any, +) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/image:analyze" + _url = "/text:detectProtectedMaterial" # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_content_safety_shield_prompt_request(**kwargs: Any) -> HttpRequest: # pylint: disable=name-too-long + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/text:shieldPrompt" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) @@ -94,7 +143,7 @@ def build_blocklist_add_or_update_blocklist_items_request( # pylint: disable=na _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -109,9 +158,9 @@ def build_blocklist_add_or_update_blocklist_items_request( # pylint: disable=na _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) @@ -123,7 +172,7 @@ def build_blocklist_create_or_update_text_blocklist_request( # pylint: disable= _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -148,9 +197,12 @@ def build_blocklist_create_or_update_text_blocklist_request( # pylint: disable= def build_blocklist_delete_text_blocklist_request( # pylint: disable=name-too-long blocklist_name: str, **kwargs: Any ) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) + accept = _headers.pop("Accept", "application/json") + # Construct URL _url = "/text/blocklists/{blocklistName}" path_format_arguments = { @@ -162,7 +214,10 @@ def build_blocklist_delete_text_blocklist_request( # pylint: disable=name-too-l # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) def build_blocklist_get_text_blocklist_request( # pylint: disable=name-too-long @@ -171,7 +226,7 @@ def build_blocklist_get_text_blocklist_request( # pylint: disable=name-too-long _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -197,7 +252,7 @@ def build_blocklist_get_text_blocklist_item_request( # pylint: disable=name-too _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -224,12 +279,12 @@ def build_blocklist_list_text_blocklist_items_request( # pylint: disable=name-t top: Optional[int] = None, skip: Optional[int] = None, maxpagesize: Optional[int] = None, - **kwargs: Any + **kwargs: Any, ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -259,7 +314,7 @@ def build_blocklist_list_text_blocklists_request(**kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -281,7 +336,9 @@ def build_blocklist_remove_blocklist_items_request( # pylint: disable=name-too- _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2023-10-01")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-09-01")) + accept = _headers.pop("Accept", "application/json") + # Construct URL _url = "/text/blocklists/{blocklistName}:removeBlocklistItems" path_format_arguments = { @@ -296,11 +353,221 @@ def build_blocklist_remove_blocklist_items_request( # pylint: disable=name-too- # Construct headers if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) class ContentSafetyClientOperationsMixin(ContentSafetyClientMixinABC): + + @overload + def analyze_image( + self, options: _models.AnalyzeImageOptions, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Required. + :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "image": { + "blobUrl": "str", + "content": bytes("bytes", encoding="utf-8") + }, + "categories": [ + "str" + ], + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + + @overload + def analyze_image( + self, options: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Required. + :type options: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + + @overload + def analyze_image( + self, options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Required. + :type options: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + + @distributed_trace + def analyze_image( + self, options: Union[_models.AnalyzeImageOptions, JSON, IO[bytes]], **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Is one of the following types: AnalyzeImageOptions, + JSON, IO[bytes] Required. + :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions or JSON or IO[bytes] + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "image": { + "blobUrl": "str", + "content": bytes("bytes", encoding="utf-8") + }, + "categories": [ + "str" + ], + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + error_map: MutableMapping[int, Type[HttpResponseError]] = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.AnalyzeImageResult] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(options, (IOBase, bytes)): + _content = options + else: + _content = json.dumps(options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_content_safety_analyze_image_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + 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) + + if _stream: + deserialized = response.iter_bytes() + else: + deserialized = _deserialize(_models.AnalyzeImageResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + @overload def analyze_text( self, options: _models.AnalyzeTextOptions, *, content_type: str = "application/json", **kwargs: Any @@ -315,11 +582,42 @@ def analyze_text( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "text": "str", + "blocklistNames": [ + "str" + ], + "categories": [ + "str" + ], + "haltOnBlocklistHit": bool, + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ @overload @@ -336,11 +634,29 @@ def analyze_text( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ @overload @@ -357,11 +673,29 @@ def analyze_text( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ @distributed_trace @@ -376,16 +710,44 @@ def analyze_text( :param options: The text analysis request. Is one of the following types: AnalyzeTextOptions, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.AnalyzeTextOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. - :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "text": "str", + "blocklistNames": [ + "str" + ], + "categories": [ + "str" + ], + "haltOnBlocklistHit": bool, + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -414,7 +776,7 @@ def analyze_text( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -427,7 +789,10 @@ def analyze_text( 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) @@ -442,90 +807,352 @@ def analyze_text( return deserialized # type: ignore @overload - def analyze_image( - self, options: _models.AnalyzeImageOptions, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + def detect_text_protected_material( + self, + options: _models.DetectTextProtectedMaterialOptions, + *, + content_type: str = "application/json", + **kwargs: Any, + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + A synchronous API for detecting protected material in the given text. - :param options: The image analysis request. Required. - :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions + :param options: The request body to be detected, which may contain protected material. + Required. + :type options: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialOptions :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "text": "str" + } + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } """ @overload - def analyze_image( + def detect_text_protected_material( self, options: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + A synchronous API for detecting protected material in the given text. - :param options: The image analysis request. Required. + :param options: The request body to be detected, which may contain protected material. + Required. :type options: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } """ @overload - def analyze_image( + def detect_text_protected_material( self, options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + A synchronous API for detecting protected material in the given text. - :param options: The image analysis request. Required. + :param options: The request body to be detected, which may contain protected material. + Required. :type options: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } """ @distributed_trace - def analyze_image( - self, options: Union[_models.AnalyzeImageOptions, JSON, IO[bytes]], **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + @api_version_validation( + method_added_on="2024-09-01", + params_added_on={"2024-09-01": ["api_version", "content_type", "accept"]}, + ) + def detect_text_protected_material( + self, options: Union[_models.DetectTextProtectedMaterialOptions, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. + + A synchronous API for detecting protected material in the given text. + + :param options: The request body to be detected, which may contain protected material. Is one + of the following types: DetectTextProtectedMaterialOptions, JSON, IO[bytes] Required. + :type options: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialOptions or JSON or + IO[bytes] + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult + :raises ~azure.core.exceptions.HttpResponseError: - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + Example: + .. code-block:: python - :param options: The image analysis request. Is one of the following types: AnalyzeImageOptions, - JSON, IO[bytes] Required. - :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. + # JSON input template you can fill out and use as your body input. + options = { + "text": "str" + } + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } + """ + error_map: MutableMapping[int, Type[HttpResponseError]] = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DetectTextProtectedMaterialResult] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(options, (IOBase, bytes)): + _content = options + else: + _content = json.dumps(options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_content_safety_detect_text_protected_material_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + 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) + + if _stream: + deserialized = response.iter_bytes() + else: + deserialized = _deserialize(_models.DetectTextProtectedMaterialResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def shield_prompt( + self, options: _models.ShieldPromptOptions, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Required. + :type options: ~azure.ai.contentsafety.models.ShieldPromptOptions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "documents": [ + "str" + ], + "userPrompt": "str" + } + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } + """ + + @overload + def shield_prompt( + self, options: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Required. + :type options: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } + """ + + @overload + def shield_prompt( + self, options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Required. + :type options: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } + """ + + @distributed_trace + @api_version_validation( + method_added_on="2024-09-01", + params_added_on={"2024-09-01": ["api_version", "content_type", "accept"]}, + ) + def shield_prompt( + self, options: Union[_models.ShieldPromptOptions, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Is one of the following types: ShieldPromptOptions, JSON, IO[bytes] Required. + :type options: ~azure.ai.contentsafety.models.ShieldPromptOptions or JSON or IO[bytes] + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "documents": [ + "str" + ], + "userPrompt": "str" + } + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -537,7 +1164,7 @@ def analyze_image( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.AnalyzeImageResult] = kwargs.pop("cls", None) + cls: ClsType[_models.ShieldPromptResult] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None @@ -546,7 +1173,7 @@ def analyze_image( else: _content = json.dumps(options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_content_safety_analyze_image_request( + _request = build_content_safety_shield_prompt_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -554,7 +1181,7 @@ def analyze_image( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -567,14 +1194,17 @@ def analyze_image( 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) if _stream: deserialized = response.iter_bytes() else: - deserialized = _deserialize(_models.AnalyzeImageResult, response.json()) + deserialized = _deserialize(_models.ShieldPromptResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -583,6 +1213,7 @@ def analyze_image( class BlocklistClientOperationsMixin(BlocklistClientMixinABC): + @overload def add_or_update_blocklist_items( self, @@ -590,7 +1221,7 @@ def add_or_update_blocklist_items( options: _models.AddOrUpdateTextBlocklistItemsOptions, *, content_type: str = "application/json", - **kwargs: Any + **kwargs: Any, ) -> _models.AddOrUpdateTextBlocklistItemsResult: """Add or update BlocklistItems To Text Blocklist. @@ -604,12 +1235,37 @@ def add_or_update_blocklist_items( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ @overload @@ -628,12 +1284,25 @@ def add_or_update_blocklist_items( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ @overload @@ -652,12 +1321,25 @@ def add_or_update_blocklist_items( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ @distributed_trace @@ -665,7 +1347,7 @@ def add_or_update_blocklist_items( self, blocklist_name: str, options: Union[_models.AddOrUpdateTextBlocklistItemsOptions, JSON, IO[bytes]], - **kwargs: Any + **kwargs: Any, ) -> _models.AddOrUpdateTextBlocklistItemsResult: """Add or update BlocklistItems To Text Blocklist. @@ -678,17 +1360,39 @@ def add_or_update_blocklist_items( AddOrUpdateTextBlocklistItemsOptions, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. - :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -718,7 +1422,7 @@ def add_or_update_blocklist_items( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -731,7 +1435,10 @@ def add_or_update_blocklist_items( 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) @@ -752,7 +1459,7 @@ def create_or_update_text_blocklist( options: _models.TextBlocklist, *, content_type: str = "application/merge-patch+json", - **kwargs: Any + **kwargs: Any, ) -> _models.TextBlocklist: """Create Or Update Text Blocklist. @@ -765,11 +1472,24 @@ def create_or_update_text_blocklist( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistName": "str", + "description": "str" + } + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ @overload @@ -787,11 +1507,18 @@ def create_or_update_text_blocklist( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ @overload @@ -801,7 +1528,7 @@ def create_or_update_text_blocklist( options: IO[bytes], *, content_type: str = "application/merge-patch+json", - **kwargs: Any + **kwargs: Any, ) -> _models.TextBlocklist: """Create Or Update Text Blocklist. @@ -814,11 +1541,18 @@ def create_or_update_text_blocklist( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ @distributed_trace @@ -834,15 +1568,26 @@ def create_or_update_text_blocklist( :param options: The resource instance. Is one of the following types: TextBlocklist, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.TextBlocklist or JSON or IO[bytes] - :keyword content_type: This request has a JSON Merge Patch body. Default value is None. - :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistName": "str", + "description": "str" + } + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -872,7 +1617,7 @@ def create_or_update_text_blocklist( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -885,21 +1630,17 @@ def create_or_update_text_blocklist( if response.status_code not in [200, 201]: 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) - if response.status_code == 200: - if _stream: - deserialized = response.iter_bytes() - else: - deserialized = _deserialize(_models.TextBlocklist, response.json()) - - if response.status_code == 201: - if _stream: - deserialized = response.iter_bytes() - else: - deserialized = _deserialize(_models.TextBlocklist, response.json()) + if _stream: + deserialized = response.iter_bytes() + else: + deserialized = _deserialize(_models.TextBlocklist, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -920,7 +1661,7 @@ def delete_text_blocklist( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -940,7 +1681,7 @@ def delete_text_blocklist( # pylint: disable=inconsistent-return-statements params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -952,8 +1693,6 @@ def delete_text_blocklist( # pylint: disable=inconsistent-return-statements response = pipeline_response.http_response if response.status_code not in [204]: - if _stream: - response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -968,13 +1707,20 @@ def get_text_blocklist(self, blocklist_name: str, **kwargs: Any) -> _models.Text :param blocklist_name: Text blocklist name. Required. :type blocklist_name: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistName": "str", + "description": "str" + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -994,7 +1740,7 @@ def get_text_blocklist(self, blocklist_name: str, **kwargs: Any) -> _models.Text params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1007,7 +1753,10 @@ def get_text_blocklist(self, blocklist_name: str, **kwargs: Any) -> _models.Text 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) @@ -1034,13 +1783,22 @@ def get_text_blocklist_item( :param blocklist_item_id: The service will generate a BlocklistItemId, which will be a UUID. Required. :type blocklist_item_id: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklistItem. The TextBlocklistItem is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklistItem :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1061,7 +1819,7 @@ def get_text_blocklist_item( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1074,7 +1832,10 @@ def get_text_blocklist_item( 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) @@ -1105,6 +1866,17 @@ def list_text_blocklist_items( :return: An iterator like instance of TextBlocklistItem :rtype: ~azure.core.paging.ItemPaged[~azure.ai.contentsafety.models.TextBlocklistItem] :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} @@ -1112,7 +1884,7 @@ def list_text_blocklist_items( maxpagesize = kwargs.pop("maxpagesize", None) cls: ClsType[List[_models.TextBlocklistItem]] = kwargs.pop("cls", None) - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1133,9 +1905,7 @@ def prepare_request(next_link=None): params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1153,9 +1923,7 @@ def prepare_request(next_link=None): "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1178,8 +1946,6 @@ def get_next(next_link=None): response = pipeline_response.http_response if response.status_code not in [200]: - if _stream: - response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -1196,13 +1962,22 @@ def list_text_blocklists(self, **kwargs: Any) -> Iterable["_models.TextBlocklist :return: An iterator like instance of TextBlocklist :rtype: ~azure.core.paging.ItemPaged[~azure.ai.contentsafety.models.TextBlocklist] :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistName": "str", + "description": "str" + } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} cls: ClsType[List[_models.TextBlocklist]] = kwargs.pop("cls", None) - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1219,9 +1994,7 @@ def prepare_request(next_link=None): params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1239,9 +2012,7 @@ def prepare_request(next_link=None): "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1264,8 +2035,6 @@ def get_next(next_link=None): response = pipeline_response.http_response if response.status_code not in [200]: - if _stream: - response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -1280,7 +2049,7 @@ def remove_blocklist_items( # pylint: disable=inconsistent-return-statements options: _models.RemoveTextBlocklistItemsOptions, *, content_type: str = "application/json", - **kwargs: Any + **kwargs: Any, ) -> None: """Remove BlocklistItems From Text Blocklist. @@ -1297,6 +2066,16 @@ def remove_blocklist_items( # pylint: disable=inconsistent-return-statements :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItemIds": [ + "str" + ] + } """ @overload @@ -1346,7 +2125,7 @@ def remove_blocklist_items( # pylint: disable=inconsistent-return-statements self, blocklist_name: str, options: Union[_models.RemoveTextBlocklistItemsOptions, JSON, IO[bytes]], - **kwargs: Any + **kwargs: Any, ) -> None: """Remove BlocklistItems From Text Blocklist. @@ -1359,14 +2138,21 @@ def remove_blocklist_items( # pylint: disable=inconsistent-return-statements RemoveTextBlocklistItemsOptions, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.RemoveTextBlocklistItemsOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. - :paramtype content_type: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItemIds": [ + "str" + ] + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1396,7 +2182,7 @@ def remove_blocklist_items( # pylint: disable=inconsistent-return-statements params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1408,8 +2194,6 @@ def remove_blocklist_items( # pylint: disable=inconsistent-return-statements response = pipeline_response.http_response if response.status_code not in [204]: - if _stream: - response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_serialization.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_serialization.py index baa661cb82d2..8139854b97bb 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_serialization.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_serialization.py @@ -144,6 +144,8 @@ def _json_attemp(data): # context otherwise. _LOGGER.critical("Wasn't XML not JSON, failing") raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) @classmethod @@ -170,13 +172,6 @@ def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], return None -try: - basestring # type: ignore - unicode_str = unicode # type: ignore -except NameError: - basestring = str - unicode_str = str - _LOGGER = logging.getLogger(__name__) try: @@ -545,7 +540,7 @@ class Serializer(object): "multiple": lambda x, y: x % y != 0, } - def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): + def __init__(self, classes: Optional[Mapping[str, type]] = None): self.serialize_type = { "iso-8601": Serializer.serialize_iso, "rfc-1123": Serializer.serialize_rfc, @@ -561,7 +556,7 @@ def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): "[]": self.serialize_iter, "{}": self.serialize_dict, } - self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {} + self.dependencies: Dict[str, type] = dict(classes) if classes else {} self.key_transformer = full_restapi_key_transformer self.client_side_validation = True @@ -649,7 +644,7 @@ def _serialize(self, target_obj, data_type=None, **kwargs): else: # That's a basic type # Integrate namespace if necessary local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) - local_node.text = unicode_str(new_attr) + local_node.text = str(new_attr) serialized.append(local_node) # type: ignore else: # JSON for k in reversed(keys): # type: ignore @@ -994,7 +989,7 @@ def serialize_object(self, attr, **kwargs): return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) if obj_type is _long_type: return self.serialize_long(attr) - if obj_type is unicode_str: + if obj_type is str: return self.serialize_unicode(attr) if obj_type is datetime.datetime: return self.serialize_iso(attr) @@ -1370,7 +1365,7 @@ class Deserializer(object): 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}]?") - def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): + def __init__(self, classes: Optional[Mapping[str, type]] = None): self.deserialize_type = { "iso-8601": Deserializer.deserialize_iso, "rfc-1123": Deserializer.deserialize_rfc, @@ -1390,7 +1385,7 @@ def __init__(self, classes: Optional[Mapping[str, Type[ModelType]]] = None): "duration": (isodate.Duration, datetime.timedelta), "iso-8601": (datetime.datetime), } - self.dependencies: Dict[str, Type[ModelType]] = dict(classes) if classes else {} + self.dependencies: Dict[str, type] = dict(classes) if classes else {} self.key_extractors = [rest_key_extractor, xml_key_extractor] # Additional properties only works if the "rest_key_extractor" is used to # extract the keys. Making it to work whatever the key extractor is too much @@ -1443,12 +1438,12 @@ def _deserialize(self, target_obj, data): response, class_name = self._classify_target(target_obj, data) - if isinstance(response, basestring): + if isinstance(response, str): return self.deserialize_data(data, response) elif isinstance(response, type) and issubclass(response, Enum): return self.deserialize_enum(data, response) - if data is None: + if data is None or data is CoreNull: return data try: attributes = response._attribute_map # type: ignore @@ -1514,14 +1509,14 @@ def _classify_target(self, target, data): if target is None: return None, None - if isinstance(target, basestring): + if isinstance(target, str): try: target = self.dependencies[target] except KeyError: return target, target try: - target = target._classify(data, self.dependencies) + target = target._classify(data, self.dependencies) # type: ignore except AttributeError: pass # Target is not a Model, no classify return target, target.__class__.__name__ # type: ignore @@ -1577,7 +1572,7 @@ def _unpack_content(raw_data, content_type=None): if hasattr(raw_data, "_content_consumed"): return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) - if isinstance(raw_data, (basestring, bytes)) or hasattr(raw_data, "read"): + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore return raw_data @@ -1699,7 +1694,7 @@ def deserialize_object(self, attr, **kwargs): if isinstance(attr, ET.Element): # Do no recurse on XML, just return the tree as-is return attr - if isinstance(attr, basestring): + if isinstance(attr, str): return self.deserialize_basic(attr, "str") obj_type = type(attr) if obj_type in self.basic_types: @@ -1756,7 +1751,7 @@ def deserialize_basic(self, attr, data_type): if data_type == "bool": if attr in [True, False, 1, 0]: return bool(attr) - elif isinstance(attr, basestring): + elif isinstance(attr, str): if attr.lower() in ["true", "1"]: return True elif attr.lower() in ["false", "0"]: diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_validation.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_validation.py new file mode 100644 index 000000000000..752b2822f9d3 --- /dev/null +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/_validation.py @@ -0,0 +1,50 @@ +# -------------------------------------------------------------------------- +# 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 functools + + +def api_version_validation(**kwargs): + params_added_on = kwargs.pop("params_added_on", {}) + method_added_on = kwargs.pop("method_added_on", "") + + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + try: + # this assumes the client has an _api_version attribute + client = args[0] + client_api_version = client._config.api_version # pylint: disable=protected-access + except AttributeError: + return func(*args, **kwargs) + + if method_added_on > client_api_version: + raise ValueError( + f"'{func.__name__}' is not available in API version " + f"{client_api_version}. Pass service API version {method_added_on} or newer to your client." + ) + + unsupported = { + parameter: api_version + for api_version, parameters in params_added_on.items() + for parameter in parameters + if parameter in kwargs and api_version > client_api_version + } + if unsupported: + raise ValueError( + "".join( + [ + f"'{param}' is not available in API version {client_api_version}. " + f"Use service API version {version} or newer.\n" + for param, version in unsupported.items() + ] + ) + ) + return func(*args, **kwargs) + + return wrapper + + return decorator diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_client.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_client.py index 5b3f2b75f678..3cf257eb4fc6 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_client.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_client.py @@ -8,6 +8,7 @@ from copy import deepcopy from typing import Any, Awaitable, TYPE_CHECKING, Union +from typing_extensions import Self from azure.core import AsyncPipelineClient from azure.core.credentials import AzureKeyCredential @@ -29,11 +30,11 @@ class ContentSafetyClient(ContentSafetyClientOperationsMixin): # pylint: disabl :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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_async.AsyncTokenCredential - :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -88,7 +89,7 @@ def send_request( request_copy = deepcopy(request) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) @@ -97,7 +98,7 @@ def send_request( async def close(self) -> None: await self._client.close() - async def __aenter__(self) -> "ContentSafetyClient": + async def __aenter__(self) -> Self: await self._client.__aenter__() return self @@ -111,11 +112,11 @@ class BlocklistClient(BlocklistClientOperationsMixin): # pylint: disable=client :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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_async.AsyncTokenCredential - :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -170,7 +171,7 @@ def send_request( request_copy = deepcopy(request) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments) @@ -179,7 +180,7 @@ def send_request( async def close(self) -> None: await self._client.close() - async def __aenter__(self) -> "BlocklistClient": + async def __aenter__(self) -> Self: await self._client.__aenter__() return self diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_configuration.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_configuration.py index c19698582c6d..231f7da606fd 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_configuration.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_configuration.py @@ -27,11 +27,11 @@ class ContentSafetyClientConfiguration: # pylint: disable=too-many-instance-att :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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_async.AsyncTokenCredential - :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -39,7 +39,7 @@ class ContentSafetyClientConfiguration: # pylint: disable=too-many-instance-att def __init__( self, endpoint: str, credential: Union[AzureKeyCredential, "AsyncTokenCredential"], **kwargs: Any ) -> None: - api_version: str = kwargs.pop("api_version", "2023-10-01") + api_version: str = kwargs.pop("api_version", "2024-09-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") @@ -84,11 +84,11 @@ class BlocklistClientConfiguration: # pylint: disable=too-many-instance-attribu :param endpoint: Supported Cognitive Services endpoints (protocol and hostname, for example: https://:code:``.cognitiveservices.azure.com). Required. :type endpoint: str - :param credential: Credential needed for the client to connect to Azure. Is either a + :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_async.AsyncTokenCredential - :keyword api_version: The API version to use for this operation. Default value is "2023-10-01". + :keyword api_version: The API version to use for this operation. Default value is "2024-09-01". Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -96,7 +96,7 @@ class BlocklistClientConfiguration: # pylint: disable=too-many-instance-attribu def __init__( self, endpoint: str, credential: Union[AzureKeyCredential, "AsyncTokenCredential"], **kwargs: Any ) -> None: - api_version: str = kwargs.pop("api_version", "2023-10-01") + api_version: str = kwargs.pop("api_version", "2024-09-01") if endpoint is None: raise ValueError("Parameter 'endpoint' must not be None.") diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_operations/_operations.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_operations/_operations.py index 51040e157e2b..67ea312a20cf 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_operations/_operations.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/aio/_operations/_operations.py @@ -1,4 +1,4 @@ -# pylint: disable=too-many-lines +# pylint: disable=too-many-lines,too-many-statements # 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, AsyncIterable, Callable, Dict, IO, List, Optional, TypeVar, Union, overload +from typing import Any, AsyncIterable, Callable, Dict, IO, List, Optional, Type, TypeVar, Union, overload import urllib.parse from azure.core.async_paging import AsyncItemPaged, AsyncList @@ -19,6 +19,8 @@ ResourceExistsError, ResourceNotFoundError, ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, map_error, ) from azure.core.pipeline import PipelineResponse @@ -40,7 +42,10 @@ build_blocklist_remove_blocklist_items_request, build_content_safety_analyze_image_request, build_content_safety_analyze_text_request, + build_content_safety_detect_text_protected_material_request, + build_content_safety_shield_prompt_request, ) +from ..._validation import api_version_validation from .._vendor import BlocklistClientMixinABC, ContentSafetyClientMixinABC if sys.version_info >= (3, 9): @@ -53,6 +58,215 @@ class ContentSafetyClientOperationsMixin(ContentSafetyClientMixinABC): + + @overload + async def analyze_image( + self, options: _models.AnalyzeImageOptions, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Required. + :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "image": { + "blobUrl": "str", + "content": bytes("bytes", encoding="utf-8") + }, + "categories": [ + "str" + ], + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + + @overload + async def analyze_image( + self, options: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Required. + :type options: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + + @overload + async def analyze_image( + self, options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Required. + :type options: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + + @distributed_trace_async + async def analyze_image( + self, options: Union[_models.AnalyzeImageOptions, JSON, IO[bytes]], **kwargs: Any + ) -> _models.AnalyzeImageResult: + """Analyze Image. + + A synchronous API for the analysis of potentially harmful image content. Currently, it supports + four categories: Hate, SelfHarm, Sexual, and Violence. + + :param options: The image analysis request. Is one of the following types: AnalyzeImageOptions, + JSON, IO[bytes] Required. + :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions or JSON or IO[bytes] + :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "image": { + "blobUrl": "str", + "content": bytes("bytes", encoding="utf-8") + }, + "categories": [ + "str" + ], + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ] + } + """ + error_map: MutableMapping[int, Type[HttpResponseError]] = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.AnalyzeImageResult] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(options, (IOBase, bytes)): + _content = options + else: + _content = json.dumps(options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_content_safety_analyze_image_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + 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) + + if _stream: + deserialized = response.iter_bytes() + else: + deserialized = _deserialize(_models.AnalyzeImageResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + @overload async def analyze_text( self, options: _models.AnalyzeTextOptions, *, content_type: str = "application/json", **kwargs: Any @@ -67,11 +281,42 @@ async def analyze_text( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "text": "str", + "blocklistNames": [ + "str" + ], + "categories": [ + "str" + ], + "haltOnBlocklistHit": bool, + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ @overload @@ -88,11 +333,29 @@ async def analyze_text( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ @overload @@ -109,11 +372,29 @@ async def analyze_text( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ @distributed_trace_async @@ -128,16 +409,44 @@ async def analyze_text( :param options: The text analysis request. Is one of the following types: AnalyzeTextOptions, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.AnalyzeTextOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. - :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AnalyzeTextResult. The AnalyzeTextResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AnalyzeTextResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "text": "str", + "blocklistNames": [ + "str" + ], + "categories": [ + "str" + ], + "haltOnBlocklistHit": bool, + "outputType": "str" + } + + # response body for status code(s): 200 + response == { + "categoriesAnalysis": [ + { + "category": "str", + "severity": 0 + } + ], + "blocklistsMatch": [ + { + "blocklistItemId": "str", + "blocklistItemText": "str", + "blocklistName": "str" + } + ] + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -166,7 +475,7 @@ async def analyze_text( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -179,7 +488,10 @@ async def analyze_text( 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) @@ -194,90 +506,352 @@ async def analyze_text( return deserialized # type: ignore @overload - async def analyze_image( - self, options: _models.AnalyzeImageOptions, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + async def detect_text_protected_material( + self, + options: _models.DetectTextProtectedMaterialOptions, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + A synchronous API for detecting protected material in the given text. - :param options: The image analysis request. Required. - :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions + :param options: The request body to be detected, which may contain protected material. + Required. + :type options: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialOptions :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "text": "str" + } + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } """ @overload - async def analyze_image( + async def detect_text_protected_material( self, options: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + A synchronous API for detecting protected material in the given text. - :param options: The image analysis request. Required. + :param options: The request body to be detected, which may contain protected material. + Required. :type options: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } """ @overload - async def analyze_image( + async def detect_text_protected_material( self, options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + A synchronous API for detecting protected material in the given text. - :param options: The image analysis request. Required. + :param options: The request body to be detected, which may contain protected material. + Required. :type options: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } """ @distributed_trace_async - async def analyze_image( - self, options: Union[_models.AnalyzeImageOptions, JSON, IO[bytes]], **kwargs: Any - ) -> _models.AnalyzeImageResult: - """Analyze Image. + @api_version_validation( + method_added_on="2024-09-01", + params_added_on={"2024-09-01": ["api_version", "content_type", "accept"]}, + ) + async def detect_text_protected_material( + self, options: Union[_models.DetectTextProtectedMaterialOptions, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DetectTextProtectedMaterialResult: + """Detect Protected Material for Text. + + A synchronous API for detecting protected material in the given text. + + :param options: The request body to be detected, which may contain protected material. Is one + of the following types: DetectTextProtectedMaterialOptions, JSON, IO[bytes] Required. + :type options: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialOptions or JSON or + IO[bytes] + :return: DetectTextProtectedMaterialResult. The DetectTextProtectedMaterialResult is compatible + with MutableMapping + :rtype: ~azure.ai.contentsafety.models.DetectTextProtectedMaterialResult + :raises ~azure.core.exceptions.HttpResponseError: - A synchronous API for the analysis of potentially harmful image content. Currently, it supports - four categories: Hate, SelfHarm, Sexual, and Violence. + Example: + .. code-block:: python - :param options: The image analysis request. Is one of the following types: AnalyzeImageOptions, - JSON, IO[bytes] Required. - :type options: ~azure.ai.contentsafety.models.AnalyzeImageOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. + # JSON input template you can fill out and use as your body input. + options = { + "text": "str" + } + + # response body for status code(s): 200 + response == { + "protectedMaterialAnalysis": { + "detected": bool + } + } + """ + error_map: MutableMapping[int, Type[HttpResponseError]] = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DetectTextProtectedMaterialResult] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(options, (IOBase, bytes)): + _content = options + else: + _content = json.dumps(options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_content_safety_detect_text_protected_material_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + 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) + + if _stream: + deserialized = response.iter_bytes() + else: + deserialized = _deserialize(_models.DetectTextProtectedMaterialResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + async def shield_prompt( + self, options: _models.ShieldPromptOptions, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Required. + :type options: ~azure.ai.contentsafety.models.ShieldPromptOptions + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. - :return: AnalyzeImageResult. The AnalyzeImageResult is compatible with MutableMapping - :rtype: ~azure.ai.contentsafety.models.AnalyzeImageResult + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "documents": [ + "str" + ], + "userPrompt": "str" + } + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } """ - error_map = { + + @overload + async def shield_prompt( + self, options: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Required. + :type options: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } + """ + + @overload + async def shield_prompt( + self, options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Required. + :type options: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } + """ + + @distributed_trace_async + @api_version_validation( + method_added_on="2024-09-01", + params_added_on={"2024-09-01": ["api_version", "content_type", "accept"]}, + ) + async def shield_prompt( + self, options: Union[_models.ShieldPromptOptions, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ShieldPromptResult: + """Shield Prompt. + + A synchronous API for shielding prompt from direct and indirect injection attacks. + + :param options: The request body to be detected, which may contain direct or indirect injection + attacks. Is one of the following types: ShieldPromptOptions, JSON, IO[bytes] Required. + :type options: ~azure.ai.contentsafety.models.ShieldPromptOptions or JSON or IO[bytes] + :return: ShieldPromptResult. The ShieldPromptResult is compatible with MutableMapping + :rtype: ~azure.ai.contentsafety.models.ShieldPromptResult + :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "documents": [ + "str" + ], + "userPrompt": "str" + } + + # response body for status code(s): 200 + response == { + "documentsAnalysis": [ + { + "attackDetected": bool + } + ], + "userPromptAnalysis": { + "attackDetected": bool + } + } + """ + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -289,7 +863,7 @@ async def analyze_image( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.AnalyzeImageResult] = kwargs.pop("cls", None) + cls: ClsType[_models.ShieldPromptResult] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None @@ -298,7 +872,7 @@ async def analyze_image( else: _content = json.dumps(options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_content_safety_analyze_image_request( + _request = build_content_safety_shield_prompt_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -306,7 +880,7 @@ async def analyze_image( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -319,14 +893,17 @@ async def analyze_image( 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) if _stream: deserialized = response.iter_bytes() else: - deserialized = _deserialize(_models.AnalyzeImageResult, response.json()) + deserialized = _deserialize(_models.ShieldPromptResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -335,6 +912,7 @@ async def analyze_image( class BlocklistClientOperationsMixin(BlocklistClientMixinABC): + @overload async def add_or_update_blocklist_items( self, @@ -356,12 +934,37 @@ async def add_or_update_blocklist_items( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ @overload @@ -380,12 +983,25 @@ async def add_or_update_blocklist_items( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ @overload @@ -404,12 +1020,25 @@ async def add_or_update_blocklist_items( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ @distributed_trace_async @@ -430,17 +1059,39 @@ async def add_or_update_blocklist_items( AddOrUpdateTextBlocklistItemsOptions, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. - :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: AddOrUpdateTextBlocklistItemsResult. The AddOrUpdateTextBlocklistItemsResult is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.AddOrUpdateTextBlocklistItemsResult :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } + + # response body for status code(s): 200 + response == { + "blocklistItems": [ + { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } + ] + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -470,7 +1121,7 @@ async def add_or_update_blocklist_items( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -483,7 +1134,10 @@ async def add_or_update_blocklist_items( 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) @@ -517,11 +1171,24 @@ async def create_or_update_text_blocklist( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistName": "str", + "description": "str" + } + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ @overload @@ -539,11 +1206,18 @@ async def create_or_update_text_blocklist( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ @overload @@ -566,11 +1240,18 @@ async def create_or_update_text_blocklist( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ @distributed_trace_async @@ -586,15 +1267,26 @@ async def create_or_update_text_blocklist( :param options: The resource instance. Is one of the following types: TextBlocklist, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.TextBlocklist or JSON or IO[bytes] - :keyword content_type: This request has a JSON Merge Patch body. Default value is None. - :paramtype content_type: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistName": "str", + "description": "str" + } + + # response body for status code(s): 201, 200 + response == { + "blocklistName": "str", + "description": "str" + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -624,7 +1316,7 @@ async def create_or_update_text_blocklist( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -637,21 +1329,17 @@ async def create_or_update_text_blocklist( if response.status_code not in [200, 201]: 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) - if response.status_code == 200: - if _stream: - deserialized = response.iter_bytes() - else: - deserialized = _deserialize(_models.TextBlocklist, response.json()) - - if response.status_code == 201: - if _stream: - deserialized = response.iter_bytes() - else: - deserialized = _deserialize(_models.TextBlocklist, response.json()) + if _stream: + deserialized = response.iter_bytes() + else: + deserialized = _deserialize(_models.TextBlocklist, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -672,7 +1360,7 @@ async def delete_text_blocklist( # pylint: disable=inconsistent-return-statemen :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -692,7 +1380,7 @@ async def delete_text_blocklist( # pylint: disable=inconsistent-return-statemen params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -704,8 +1392,6 @@ async def delete_text_blocklist( # pylint: disable=inconsistent-return-statemen response = pipeline_response.http_response if response.status_code not in [204]: - if _stream: - await response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -720,13 +1406,20 @@ async def get_text_blocklist(self, blocklist_name: str, **kwargs: Any) -> _model :param blocklist_name: Text blocklist name. Required. :type blocklist_name: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklist. The TextBlocklist is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklist :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistName": "str", + "description": "str" + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -746,7 +1439,7 @@ async def get_text_blocklist(self, blocklist_name: str, **kwargs: Any) -> _model params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -759,7 +1452,10 @@ async def get_text_blocklist(self, blocklist_name: str, **kwargs: Any) -> _model 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) @@ -786,13 +1482,22 @@ async def get_text_blocklist_item( :param blocklist_item_id: The service will generate a BlocklistItemId, which will be a UUID. Required. :type blocklist_item_id: str - :keyword bool stream: Whether to stream the response of this operation. Defaults to False. You - will have to context manage the returned stream. :return: TextBlocklistItem. The TextBlocklistItem is compatible with MutableMapping :rtype: ~azure.ai.contentsafety.models.TextBlocklistItem :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -813,7 +1518,7 @@ async def get_text_blocklist_item( params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -826,7 +1531,10 @@ async def get_text_blocklist_item( 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) @@ -858,6 +1566,17 @@ def list_text_blocklist_items( :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.contentsafety.models.TextBlocklistItem] :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistItemId": "str", + "text": "str", + "description": "str", + "isRegex": bool + } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} @@ -865,7 +1584,7 @@ def list_text_blocklist_items( maxpagesize = kwargs.pop("maxpagesize", None) cls: ClsType[List[_models.TextBlocklistItem]] = kwargs.pop("cls", None) - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -886,9 +1605,7 @@ def prepare_request(next_link=None): params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -906,9 +1623,7 @@ def prepare_request(next_link=None): "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -931,8 +1646,6 @@ async def get_next(next_link=None): response = pipeline_response.http_response if response.status_code not in [200]: - if _stream: - await response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -949,13 +1662,22 @@ def list_text_blocklists(self, **kwargs: Any) -> AsyncIterable["_models.TextBloc :return: An iterator like instance of TextBlocklist :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.contentsafety.models.TextBlocklist] :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # response body for status code(s): 200 + response == { + "blocklistName": "str", + "description": "str" + } """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} cls: ClsType[List[_models.TextBlocklist]] = kwargs.pop("cls", None) - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -972,9 +1694,7 @@ def prepare_request(next_link=None): params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -992,9 +1712,7 @@ def prepare_request(next_link=None): "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1017,8 +1735,6 @@ async def get_next(next_link=None): response = pipeline_response.http_response if response.status_code not in [200]: - if _stream: - await response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) @@ -1050,6 +1766,16 @@ async def remove_blocklist_items( # pylint: disable=inconsistent-return-stateme :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItemIds": [ + "str" + ] + } """ @overload @@ -1112,14 +1838,21 @@ async def remove_blocklist_items( # pylint: disable=inconsistent-return-stateme RemoveTextBlocklistItemsOptions, JSON, IO[bytes] Required. :type options: ~azure.ai.contentsafety.models.RemoveTextBlocklistItemsOptions or JSON or IO[bytes] - :keyword content_type: Body parameter Content-Type. Known values are: application/json. Default - value is None. - :paramtype content_type: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: + + Example: + .. code-block:: python + + # JSON input template you can fill out and use as your body input. + options = { + "blocklistItemIds": [ + "str" + ] + } """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1149,7 +1882,7 @@ async def remove_blocklist_items( # pylint: disable=inconsistent-return-stateme params=_params, ) path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"), } _request.url = self._client.format_url(_request.url, **path_format_arguments) @@ -1161,8 +1894,6 @@ async def remove_blocklist_items( # pylint: disable=inconsistent-return-stateme response = pipeline_response.http_response if response.status_code not in [204]: - if _stream: - await response.read() # Load the body in memory and close the socket map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/__init__.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/__init__.py index a4cd06fb66cf..9c6480cedfbe 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/__init__.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/__init__.py @@ -12,13 +12,20 @@ from ._models import AnalyzeImageResult from ._models import AnalyzeTextOptions from ._models import AnalyzeTextResult +from ._models import DetectTextProtectedMaterialOptions +from ._models import DetectTextProtectedMaterialResult +from ._models import DocumentInjectionAnalysisResult from ._models import ImageCategoriesAnalysis from ._models import ImageData from ._models import RemoveTextBlocklistItemsOptions +from ._models import ShieldPromptOptions +from ._models import ShieldPromptResult from ._models import TextBlocklist from ._models import TextBlocklistItem from ._models import TextBlocklistMatch from ._models import TextCategoriesAnalysis +from ._models import TextProtectedMaterialAnalysisResult +from ._models import UserPromptInjectionAnalysisResult from ._enums import AnalyzeImageOutputType from ._enums import AnalyzeTextOutputType @@ -35,13 +42,20 @@ "AnalyzeImageResult", "AnalyzeTextOptions", "AnalyzeTextResult", + "DetectTextProtectedMaterialOptions", + "DetectTextProtectedMaterialResult", + "DocumentInjectionAnalysisResult", "ImageCategoriesAnalysis", "ImageData", "RemoveTextBlocklistItemsOptions", + "ShieldPromptOptions", + "ShieldPromptResult", "TextBlocklist", "TextBlocklistItem", "TextBlocklistMatch", "TextCategoriesAnalysis", + "TextProtectedMaterialAnalysisResult", + "UserPromptInjectionAnalysisResult", "AnalyzeImageOutputType", "AnalyzeTextOutputType", "ImageCategory", diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_enums.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_enums.py index 6e91fad1a406..c8f1dbdb7d4b 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_enums.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_enums.py @@ -27,18 +27,26 @@ class AnalyzeTextOutputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): class ImageCategory(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Image analyze category.""" + """The harm category supported in Image content analysis.""" HATE = "Hate" + """The harm category for Image - Hate.""" SELF_HARM = "SelfHarm" + """The harm category for Image - SelfHarm.""" SEXUAL = "Sexual" + """The harm category for Image - Sexual.""" VIOLENCE = "Violence" + """The harm category for Image - Violence.""" class TextCategory(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Text analyze category.""" + """The harm category supported in Text content analysis.""" HATE = "Hate" + """The harm category for Text - Hate.""" SELF_HARM = "SelfHarm" + """The harm category for Text - SelfHarm.""" SEXUAL = "Sexual" + """The harm category for Text - Sexual.""" VIOLENCE = "Violence" + """The harm category for Text - Violence.""" diff --git a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_models.py b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_models.py index cf0403b1cd4c..37491dff8efa 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_models.py +++ b/sdk/contentsafety/azure-ai-contentsafety/azure/ai/contentsafety/models/_models.py @@ -34,8 +34,7 @@ def __init__( self, *, blocklist_items: List["_models.TextBlocklistItem"], - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -51,7 +50,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class AddOrUpdateTextBlocklistItemsResult(_model_base.Model): """The response of adding blocklistItems to the text blocklist. - All required parameters must be populated in order to send to server. :ivar blocklist_items: Array of blocklistItems have been added. Required. :vartype blocklist_items: list[~azure.ai.contentsafety.models.TextBlocklistItem] @@ -65,8 +63,7 @@ def __init__( self, *, blocklist_items: List["_models.TextBlocklistItem"], - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -84,7 +81,7 @@ class AnalyzeImageOptions(_model_base.Model): All required parameters must be populated in order to send to server. - :ivar image: The image needs to be analyzed. Required. + :ivar image: The image to be analyzed. Required. :vartype image: ~azure.ai.contentsafety.models.ImageData :ivar categories: The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. @@ -95,7 +92,7 @@ class AnalyzeImageOptions(_model_base.Model): """ image: "_models.ImageData" = rest_field() - """The image needs to be analyzed. Required.""" + """The image to be analyzed. Required.""" categories: Optional[List[Union[str, "_models.ImageCategory"]]] = rest_field() """The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned.""" @@ -110,8 +107,7 @@ def __init__( image: "_models.ImageData", categories: Optional[List[Union[str, "_models.ImageCategory"]]] = None, output_type: Optional[Union[str, "_models.AnalyzeImageOutputType"]] = None, - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -127,7 +123,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class AnalyzeImageResult(_model_base.Model): """The image analysis response. - All required parameters must be populated in order to send to server. :ivar categories_analysis: Analysis result for categories. Required. :vartype categories_analysis: list[~azure.ai.contentsafety.models.ImageCategoriesAnalysis] @@ -141,8 +136,7 @@ def __init__( self, *, categories_analysis: List["_models.ImageCategoriesAnalysis"], - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -160,8 +154,8 @@ class AnalyzeTextOptions(_model_base.Model): All required parameters must be populated in order to send to server. - :ivar text: The text needs to be analyzed. We support a maximum of 10k Unicode characters - (Unicode code points) in the text of one request. Required. + :ivar text: The text to be analyzed. We support a maximum of 10k Unicode characters (Unicode + code points) in the text of one request. Required. :vartype text: str :ivar categories: The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. @@ -179,8 +173,8 @@ class AnalyzeTextOptions(_model_base.Model): """ text: str = rest_field() - """The text needs to be analyzed. We support a maximum of 10k Unicode characters (Unicode code - points) in the text of one request. Required.""" + """The text to be analyzed. We support a maximum of 10k Unicode characters (Unicode code points) + in the text of one request. Required.""" categories: Optional[List[Union[str, "_models.TextCategory"]]] = rest_field() """The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned.""" @@ -204,8 +198,7 @@ def __init__( blocklist_names: Optional[List[str]] = None, halt_on_blocklist_hit: Optional[bool] = None, output_type: Optional[Union[str, "_models.AnalyzeTextOutputType"]] = None, - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -221,7 +214,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class AnalyzeTextResult(_model_base.Model): """The text analysis response. - All required parameters must be populated in order to send to server. :ivar blocklists_match: The blocklist match details. :vartype blocklists_match: list[~azure.ai.contentsafety.models.TextBlocklistMatch] @@ -240,8 +232,100 @@ def __init__( *, categories_analysis: List["_models.TextCategoriesAnalysis"], blocklists_match: Optional[List["_models.TextBlocklistMatch"]] = None, - ): - ... + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class DetectTextProtectedMaterialOptions(_model_base.Model): + """The request of detecting potential protected material present in the given text. + + All required parameters must be populated in order to send to server. + + :ivar text: The text to be analyzed, which may contain protected material. The characters will + be counted in Unicode code points. Required. + :vartype text: str + """ + + text: str = rest_field() + """The text to be analyzed, which may contain protected material. The characters will be counted + in Unicode code points. Required.""" + + @overload + def __init__( + self, + *, + text: str, + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class DetectTextProtectedMaterialResult(_model_base.Model): + """The combined detection results of potential protected material. + + + :ivar protected_material_analysis: Analysis result for the given text. Required. + :vartype protected_material_analysis: + ~azure.ai.contentsafety.models.TextProtectedMaterialAnalysisResult + """ + + protected_material_analysis: "_models.TextProtectedMaterialAnalysisResult" = rest_field( + name="protectedMaterialAnalysis" + ) + """Analysis result for the given text. Required.""" + + @overload + def __init__( + self, + *, + protected_material_analysis: "_models.TextProtectedMaterialAnalysisResult", + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class DocumentInjectionAnalysisResult(_model_base.Model): + """The individual analysis result of potential injection attacks in the given documents. + + + :ivar attack_detected: Whether a potential injection attack is detected or not. Required. + :vartype attack_detected: bool + """ + + attack_detected: bool = rest_field(name="attackDetected") + """Whether a potential injection attack is detected or not. Required.""" + + @overload + def __init__( + self, + *, + attack_detected: bool, + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -257,7 +341,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class ImageCategoriesAnalysis(_model_base.Model): """Image analysis result. - All required parameters must be populated in order to send to server. :ivar category: The image analysis category. Required. Known values are: "Hate", "SelfHarm", "Sexual", and "Violence". @@ -282,8 +365,7 @@ def __init__( *, category: Union[str, "_models.ImageCategory"], severity: Optional[int] = None, - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -318,8 +400,7 @@ def __init__( *, content: Optional[bytes] = None, blob_url: Optional[str] = None, - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -349,8 +430,76 @@ def __init__( self, *, blocklist_item_ids: List[str], - ): - ... + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class ShieldPromptOptions(_model_base.Model): + """The request of analyzing potential direct or indirect injection attacks. + + :ivar user_prompt: The user prompt to be analyzed, which may contain direct injection attacks. + :vartype user_prompt: str + :ivar documents: The documents to be analyzed, which may contain direct or indirect injection + attacks. + :vartype documents: list[str] + """ + + user_prompt: Optional[str] = rest_field(name="userPrompt") + """The user prompt to be analyzed, which may contain direct injection attacks.""" + documents: Optional[List[str]] = rest_field() + """The documents to be analyzed, which may contain direct or indirect injection attacks.""" + + @overload + def __init__( + self, + *, + user_prompt: Optional[str] = None, + documents: Optional[List[str]] = None, + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class ShieldPromptResult(_model_base.Model): + """The combined analysis results of potential direct or indirect injection attacks. + + :ivar user_prompt_analysis: Direct injection attacks analysis result for the given user prompt. + :vartype user_prompt_analysis: ~azure.ai.contentsafety.models.UserPromptInjectionAnalysisResult + :ivar documents_analysis: Direct and indirect injection attacks analysis result for the given + documents. + :vartype documents_analysis: + list[~azure.ai.contentsafety.models.DocumentInjectionAnalysisResult] + """ + + user_prompt_analysis: Optional["_models.UserPromptInjectionAnalysisResult"] = rest_field(name="userPromptAnalysis") + """Direct injection attacks analysis result for the given user prompt.""" + documents_analysis: Optional[List["_models.DocumentInjectionAnalysisResult"]] = rest_field(name="documentsAnalysis") + """Direct and indirect injection attacks analysis result for the given documents.""" + + @overload + def __init__( + self, + *, + user_prompt_analysis: Optional["_models.UserPromptInjectionAnalysisResult"] = None, + documents_analysis: Optional[List["_models.DocumentInjectionAnalysisResult"]] = None, + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -366,7 +515,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class TextBlocklist(_model_base.Model): """Text Blocklist. - All required parameters must be populated in order to send to server. :ivar blocklist_name: Text blocklist name. Required. :vartype blocklist_name: str @@ -385,8 +533,7 @@ def __init__( *, blocklist_name: str, description: Optional[str] = None, - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -404,15 +551,17 @@ class TextBlocklistItem(_model_base.Model): Readonly variables are only populated by the server, and will be ignored when sending a request. - All required parameters must be populated in order to send to server. :ivar blocklist_item_id: The service will generate a BlocklistItemId, which will be a UUID. Required. :vartype blocklist_item_id: str :ivar description: BlocklistItem description. :vartype description: str - :ivar text: BlocklistItem content. Required. + :ivar text: BlocklistItem content. The length is counted using Unicode code point. Required. :vartype text: str + :ivar is_regex: An optional properties indicating whether this item is to be matched as a + regular expression. + :vartype is_regex: bool """ blocklist_item_id: str = rest_field(name="blocklistItemId", visibility=["read"]) @@ -420,7 +569,9 @@ class TextBlocklistItem(_model_base.Model): description: Optional[str] = rest_field() """BlocklistItem description.""" text: str = rest_field() - """BlocklistItem content. Required.""" + """BlocklistItem content. The length is counted using Unicode code point. Required.""" + is_regex: Optional[bool] = rest_field(name="isRegex") + """An optional properties indicating whether this item is to be matched as a regular expression.""" @overload def __init__( @@ -428,8 +579,8 @@ def __init__( *, text: str, description: Optional[str] = None, - ): - ... + is_regex: Optional[bool] = None, + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -445,7 +596,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class TextBlocklistMatch(_model_base.Model): """The result of blocklist match. - All required parameters must be populated in order to send to server. :ivar blocklist_name: The name of the matched blocklist. Required. :vartype blocklist_name: str @@ -469,8 +619,7 @@ def __init__( blocklist_name: str, blocklist_item_id: str, blocklist_item_text: str, - ): - ... + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): @@ -486,7 +635,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # pylint: disable=useles class TextCategoriesAnalysis(_model_base.Model): """Text analysis result. - All required parameters must be populated in order to send to server. :ivar category: The text analysis category. Required. Known values are: "Hate", "SelfHarm", "Sexual", and "Violence". @@ -513,8 +661,65 @@ def __init__( *, category: Union[str, "_models.TextCategory"], severity: Optional[int] = None, - ): - ... + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class TextProtectedMaterialAnalysisResult(_model_base.Model): + """The individual detection result of potential protected material. + + + :ivar detected: Whether potential protected material is detected or not. Required. + :vartype detected: bool + """ + + detected: bool = rest_field() + """Whether potential protected material is detected or not. Required.""" + + @overload + def __init__( + self, + *, + detected: bool, + ): ... + + @overload + def __init__(self, mapping: Mapping[str, Any]): + """ + :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 + super().__init__(*args, **kwargs) + + +class UserPromptInjectionAnalysisResult(_model_base.Model): + """The individual analysis result of potential injection attacks in the given user prompt. + + + :ivar attack_detected: Whether a potential injection attack is detected or not. Required. + :vartype attack_detected: bool + """ + + attack_detected: bool = rest_field(name="attackDetected") + """Whether a potential injection attack is detected or not. Required.""" + + @overload + def __init__( + self, + *, + attack_detected: bool, + ): ... @overload def __init__(self, mapping: Mapping[str, Any]): diff --git a/sdk/contentsafety/azure-ai-contentsafety/setup.py b/sdk/contentsafety/azure-ai-contentsafety/setup.py index b4e939ee2c66..bf8076d76021 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/setup.py +++ b/sdk/contentsafety/azure-ai-contentsafety/setup.py @@ -42,11 +42,11 @@ "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "License :: OSI Approved :: MIT License", ], zip_safe=False, @@ -63,9 +63,9 @@ "azure.ai.contentsafety": ["py.typed"], }, install_requires=[ - "isodate<1.0.0,>=0.6.1", - "azure-core<2.0.0,>=1.28.0", - "typing-extensions>=4.3.0; python_version<'3.8.0'", + "isodate>=0.6.1", + "azure-core>=1.30.0", + "typing-extensions>=4.6.0", ], - python_requires=">=3.7", + python_requires=">=3.8", ) diff --git a/sdk/contentsafety/azure-ai-contentsafety/tests/conftest.py b/sdk/contentsafety/azure-ai-contentsafety/tests/conftest.py index eabe5360b66b..1ca14ff35bdf 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/tests/conftest.py +++ b/sdk/contentsafety/azure-ai-contentsafety/tests/conftest.py @@ -9,6 +9,7 @@ from devtools_testutils import test_proxy, add_general_string_sanitizer import os + # autouse=True will trigger this fixture on each pytest run, even if it's not explicitly used by a test method @pytest.fixture(scope="session", autouse=True) def start_proxy(test_proxy): diff --git a/sdk/contentsafety/azure-ai-contentsafety/tsp-location.yaml b/sdk/contentsafety/azure-ai-contentsafety/tsp-location.yaml index 6b117195f5d3..5c077612c03f 100644 --- a/sdk/contentsafety/azure-ai-contentsafety/tsp-location.yaml +++ b/sdk/contentsafety/azure-ai-contentsafety/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/cognitiveservices/ContentSafety -commit: fb39d9813934567c594ca253efff7c5c01a474e8 +commit: 274e6bec630de1762940d0f33adf105db3e42ebe repo: Azure/azure-rest-api-specs -additionalDirectories: [] \ No newline at end of file +additionalDirectories: \ No newline at end of file