diff --git a/packages/typespec-python/src/emitter.ts b/packages/typespec-python/src/emitter.ts index 3df4012d88f..eb126f6c016 100644 --- a/packages/typespec-python/src/emitter.ts +++ b/packages/typespec-python/src/emitter.ts @@ -53,6 +53,7 @@ import { getLibraryName, getAllModels, isInternal, + isInclude, getSdkSimpleType, getSdkListOrDict, getSdkUnion, @@ -836,7 +837,7 @@ function emitModel(context: SdkContext, type: Model): Record { addedOn: getAddedOnVersion(context, type), snakeCaseName: modelName ? camelToSnakeCase(modelName) : modelName, base: modelName === "" ? "json" : "dpg", - internal: isInternal(context, type), + internal: isInternal(context, type) && !isInclude(context, type), }; } diff --git a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/aio/operations/_operations.py b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/aio/operations/_operations.py index 421f0234dc4..492a81ac84d 100644 --- a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/aio/operations/_operations.py +++ b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/aio/operations/_operations.py @@ -6,7 +6,10 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, Callable, Dict, Optional, TypeVar +from io import IOBase +import json +import sys +from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload from azure.core.exceptions import ( ClientAuthenticationError, @@ -19,19 +22,26 @@ from azure.core.pipeline import PipelineResponse from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import _deserialize +from ..._model_base import AzureJSONEncoder, _deserialize from ...operations._operations import ( build_internal_internal_only_request, + build_internal_internal_with_include_model_request, build_internal_public_only_request, build_shared_internal_request, build_shared_public_request, ) from .._vendor import InternalClientMixinABC +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] +JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object class SharedOperations: @@ -268,3 +278,89 @@ async def _internal_only( # pylint: disable=protected-access return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + + @overload + async def _internal_with_include_model( + self, body: _models.InternalIncludeModel, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.InternalIncludeModel: + ... + + @overload + async def _internal_with_include_model( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.InternalIncludeModel: + ... + + @overload + async def _internal_with_include_model( + self, body: IO, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.InternalIncludeModel: + ... + + @distributed_trace_async + async def _internal_with_include_model( + self, body: Union[_models.InternalIncludeModel, JSON, IO], **kwargs: Any + ) -> _models.InternalIncludeModel: + """internal_with_include_model. + + :param body: Is one of the following types: InternalIncludeModel, JSON, IO Required. + :type body: ~_specs_.azure.clientgenerator.core.internal.models.InternalIncludeModel or JSON or + IO + :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: InternalIncludeModel. The InternalIncludeModel is compatible with MutableMapping + :rtype: ~_specs_.azure.clientgenerator.core.internal.models.InternalIncludeModel + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 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.InternalIncludeModel] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=AzureJSONEncoder) # type: ignore + + request = build_internal_internal_with_include_model_request( + content_type=content_type, + content=_content, + headers=_headers, + params=_params, + ) + request.url = self._client.format_url(request.url) + + _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]: + 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.InternalIncludeModel, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore diff --git a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/__init__.py b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/__init__.py index 6d6cc6cdca1..936ce8fadd2 100644 --- a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/__init__.py +++ b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/__init__.py @@ -6,6 +6,7 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +from ._models import InternalIncludeModel from ._models import PublicModel from ._models import SharedModel from ._patch import __all__ as _patch_all @@ -13,6 +14,7 @@ from ._patch import patch_sdk as _patch_sdk __all__ = [ + "InternalIncludeModel", "PublicModel", "SharedModel", ] diff --git a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/_models.py b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/_models.py index d321ee59645..01118c9d9b4 100644 --- a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/_models.py +++ b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/models/_models.py @@ -7,11 +7,52 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, Mapping, overload +from typing import Any, Mapping, TYPE_CHECKING, overload from .. import _model_base from .._model_base import rest_field +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from .. import models as _models + + +class InternalIncludeModel(_model_base.Model): + """This is a model only used by internal operation. Also, it is decorated with @include. It should + be generated and exported. + + All required parameters must be populated in order to send to Azure. + + :ivar name: Required. + :vartype name: str + :ivar nested: Required. + :vartype nested: ~_specs_.azure.clientgenerator.core.internal.models.NestedIncludeModel + """ + + name: str = rest_field() + """Required.""" + nested: "_models._models.NestedIncludeModel" = rest_field() + """Required.""" + + @overload + def __init__( + self, + *, + name: str, + nested: "_models._models.NestedIncludeModel", + ): + ... + + @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 InternalModel(_model_base.Model): """This is a model only used by internal operation. It should be generated but not exported. @@ -26,6 +67,19 @@ class InternalModel(_model_base.Model): """Required.""" +class NestedIncludeModel(_model_base.Model): + """This is a model referred by model decorated with @include. It should be generated and exported. + + All required parameters must be populated in order to send to Azure. + + :ivar comment: Required. + :vartype comment: str + """ + + comment: str = rest_field() + """Required.""" + + class PublicModel(_model_base.Model): """This is a model only used by public operation. It should be generated and exported. diff --git a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/operations/_operations.py b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/operations/_operations.py index ae970ce56c0..fbb4fcff45c 100644 --- a/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/operations/_operations.py +++ b/packages/typespec-python/test/generated/azure-client-generator-core-internal/_specs_/azure/clientgenerator/core/internal/operations/_operations.py @@ -6,7 +6,10 @@ # Code generated by Microsoft (R) Python Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, Callable, Dict, Optional, TypeVar +from io import IOBase +import json +import sys +from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload from azure.core.exceptions import ( ClientAuthenticationError, @@ -22,12 +25,17 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _deserialize +from .._model_base import AzureJSONEncoder, _deserialize from .._serialization import Serializer from .._vendor import InternalClientMixinABC +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] +JSON = MutableMapping[str, Any] # pylint: disable=unsubscriptable-object _SERIALIZER = Serializer() _SERIALIZER.client_side_validation = False @@ -105,6 +113,23 @@ def build_internal_internal_only_request(*, name: str, **kwargs: Any) -> HttpReq return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) +def build_internal_internal_with_include_model_request(**kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/azure/client-generator-core/internal/internal" + + # 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") + + return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) + + class SharedOperations: """ .. warning:: @@ -339,3 +364,89 @@ def _internal_only( # pylint: disable=protected-access return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + + @overload + def _internal_with_include_model( + self, body: _models.InternalIncludeModel, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.InternalIncludeModel: + ... + + @overload + def _internal_with_include_model( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.InternalIncludeModel: + ... + + @overload + def _internal_with_include_model( + self, body: IO, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.InternalIncludeModel: + ... + + @distributed_trace + def _internal_with_include_model( + self, body: Union[_models.InternalIncludeModel, JSON, IO], **kwargs: Any + ) -> _models.InternalIncludeModel: + """internal_with_include_model. + + :param body: Is one of the following types: InternalIncludeModel, JSON, IO Required. + :type body: ~_specs_.azure.clientgenerator.core.internal.models.InternalIncludeModel or JSON or + IO + :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: InternalIncludeModel. The InternalIncludeModel is compatible with MutableMapping + :rtype: ~_specs_.azure.clientgenerator.core.internal.models.InternalIncludeModel + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map = { + 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.InternalIncludeModel] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=AzureJSONEncoder) # type: ignore + + request = build_internal_internal_with_include_model_request( + content_type=content_type, + content=_content, + headers=_headers, + params=_params, + ) + request.url = self._client.format_url(request.url) + + _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]: + 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.InternalIncludeModel, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore diff --git a/packages/typespec-python/test/mock_api_tests/asynctests/test_azure_client_generator_core_internal_async.py b/packages/typespec-python/test/mock_api_tests/asynctests/test_azure_client_generator_core_internal_async.py index bd6d13012eb..2f2dd216d0e 100644 --- a/packages/typespec-python/test/mock_api_tests/asynctests/test_azure_client_generator_core_internal_async.py +++ b/packages/typespec-python/test/mock_api_tests/asynctests/test_azure_client_generator_core_internal_async.py @@ -5,6 +5,7 @@ # -------------------------------------------------------------------------- import pytest from _specs_.azure.clientgenerator.core.internal.aio import InternalClient +from _specs_.azure.clientgenerator.core.internal.models import InternalIncludeModel @pytest.fixture @@ -37,11 +38,19 @@ async def test_shared_internal(client: InternalClient): assert result.name == "test" +@pytest.mark.asyncio +async def test_shared_internal(client: InternalClient): + result = await client._internal_with_include_model(InternalIncludeModel(name="test")) + assert result.name == "test" + + @pytest.mark.asyncio async def test_visibility(client: InternalClient): from _specs_.azure.clientgenerator.core.internal.models import ( PublicModel, SharedModel, + InternalIncludeModel, + # NestedIncludeModel ) with pytest.raises(ImportError): diff --git a/packages/typespec-python/test/mock_api_tests/test_azure_client_generator_core_internal.py b/packages/typespec-python/test/mock_api_tests/test_azure_client_generator_core_internal.py index 352d1458f82..8d5e148ef46 100644 --- a/packages/typespec-python/test/mock_api_tests/test_azure_client_generator_core_internal.py +++ b/packages/typespec-python/test/mock_api_tests/test_azure_client_generator_core_internal.py @@ -5,6 +5,7 @@ # -------------------------------------------------------------------------- import pytest from _specs_.azure.clientgenerator.core.internal import InternalClient +from _specs_.azure.clientgenerator.core.internal.models import InternalIncludeModel @pytest.fixture @@ -33,10 +34,17 @@ def test_shared_internal(client: InternalClient): assert result.name == "test" +def test_shared_internal(client: InternalClient): + result = client._internal_with_include_model(InternalIncludeModel(name="test")) + assert result.name == "test" + + def test_visibility(client: InternalClient): from _specs_.azure.clientgenerator.core.internal.models import ( PublicModel, SharedModel, + InternalIncludeModel, + # NestedIncludeModel ) with pytest.raises(ImportError):