diff --git a/.vscode/cspell.json b/.vscode/cspell.json index 2d7349a88660..9bb929939da5 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -1859,6 +1859,7 @@ { "filename": "sdk/confidentialledger/azure-confidentialledger/**", "words": [ + "deser", "mrenclave", "MRENCLAVE", "oeverify" diff --git a/sdk/confidentialledger/azure-confidentialledger/CHANGELOG.md b/sdk/confidentialledger/azure-confidentialledger/CHANGELOG.md index 645885090a54..a887af3bcb5f 100644 --- a/sdk/confidentialledger/azure-confidentialledger/CHANGELOG.md +++ b/sdk/confidentialledger/azure-confidentialledger/CHANGELOG.md @@ -1,5 +1,21 @@ # Release History +## 2.0.0 (2026-06-15) + +### Features Added + +- Stable release of the Azure Confidential Ledger client library based on API version `2026-02-23`. +- Added user-defined functions support including `create_user_defined_endpoint`, `get_user_defined_endpoint`, and related operations. +- Added user-defined roles support including `create_user_defined_role`, `update_user_defined_role`, `get_user_defined_role`, and `delete_user_defined_role`. +- Added `create_or_update_ledger_user`, `delete_ledger_user`, `get_ledger_user`, and `list_ledger_users` operations. +- Added redirect URL caching for write operations to reduce latency. + +### Breaking Changes + +- Removed the `azure.confidentialledger.certificate` namespace and the `ConfidentialLedgerCertificateClient`. Use the `azure-confidentialledger-certificate` package to access this client. +- Changed the input parameter on `create_user_defined_role` and `update_user_defined_role` from a list of roles to a `Roles` model. +- `get_user_defined_role()` returns a `Roles` model instead of a list of roles. + ## 2.0.0b3 (2026-06-05) ### Features Added diff --git a/sdk/confidentialledger/azure-confidentialledger/_metadata.json b/sdk/confidentialledger/azure-confidentialledger/_metadata.json index 9b574d2c1b24..44deafa90967 100644 --- a/sdk/confidentialledger/azure-confidentialledger/_metadata.json +++ b/sdk/confidentialledger/azure-confidentialledger/_metadata.json @@ -1,3 +1,11 @@ { - "apiVersion": "2024-12-09-preview" + "apiVersion": "2026-02-23", + "apiVersions": { + "ConfidentialLedger": "2026-02-23" + }, + "commit": "8a3262d0e5c399e19b4e489368643a0e5b7f16e3", + "repository_url": "https://github.com/Azure/azure-rest-api-specs", + "typespec_src": "specification/confidentialledger/data-plane/ConfidentialLedger", + "emitterVersion": "0.63.1", + "httpClientPythonVersion": "^0.31.1" } \ No newline at end of file diff --git a/sdk/confidentialledger/azure-confidentialledger/api.md b/sdk/confidentialledger/azure-confidentialledger/api.md new file mode 100644 index 000000000000..80d9a5e51cb2 --- /dev/null +++ b/sdk/confidentialledger/azure-confidentialledger/api.md @@ -0,0 +1,1535 @@ +```py +namespace azure.confidentialledger + + class azure.confidentialledger.ConfidentialLedgerCertificateCredential: + property certificate_path: Union[bytes, str, PathLike] # Read-only + + def __init__(self, certificate_path: Union[bytes, str, PathLike]): ... + + + class azure.confidentialledger.ConfidentialLedgerClient(GeneratedClient): implements ContextManager + + def __init__( + self, + endpoint: str, + credential: Union[ConfidentialLedgerCertificateCredential, TokenCredential], + *, + api_version: str = ..., + ledger_certificate_path: Union[bytes, str, PathLike], + **kwargs: Any + ) -> None: ... + + def begin_create_ledger_entry( + self, + entry: Union[LedgerEntry, JSON, IO[bytes]], + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[TransactionStatus]: ... + + def begin_get_ledger_entry( + self, + transaction_id: str, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LROPoller[LedgerQueryResult]: ... + + def begin_get_receipt( + self, + transaction_id: str, + **kwargs: Any + ) -> LROPoller[TransactionReceipt]: ... + + def begin_wait_for_commit( + self, + transaction_id: str, + **kwargs + ) -> LROPoller[TransactionStatus]: ... + + def close(self) -> None: ... + + def create_ledger_entry( + self, + entry: Union[LedgerEntry, JSON, IO[bytes]], + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LedgerWriteResult: ... + + @overload + def create_or_update_ledger_user( + self, + user_id: str, + user_multiple_roles: LedgerUserMultipleRoles, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @overload + def create_or_update_ledger_user( + self, + user_id: str, + user_multiple_roles: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @overload + def create_or_update_ledger_user( + self, + user_id: str, + user_multiple_roles: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @overload + def create_or_update_user( + self, + user_id: str, + user_details: LedgerUser, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUser: ... + + @overload + def create_or_update_user( + self, + user_id: str, + user_details: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUser: ... + + @overload + def create_or_update_user( + self, + user_id: str, + user_details: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUser: ... + + @overload + def create_user_defined_endpoint( + self, + bundle: Bundle, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: ... + + @overload + def create_user_defined_endpoint( + self, + bundle: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: ... + + @overload + def create_user_defined_endpoint( + self, + bundle: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: ... + + @overload + def create_user_defined_function( + self, + function_id: str, + user_defined_function: UserDefinedFunction, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunction: ... + + @overload + def create_user_defined_function( + self, + function_id: str, + user_defined_function: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunction: ... + + @overload + def create_user_defined_function( + self, + function_id: str, + user_defined_function: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunction: ... + + @overload + def create_user_defined_role_stable( + self, + body: UserDefinedRoles, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + def create_user_defined_role_stable( + self, + body: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + def create_user_defined_role_stable( + self, + body: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @distributed_trace + def delete_ledger_user( + self, + user_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace + def delete_user( + self, + user_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace + def delete_user_defined_function( + self, + function_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace + @api_version_validation(method_added_on='2026-02-23', params_added_on={'2026-02-23': ['api_version', 'role_name']}, api_versions_list=['2026-02-23']) + def delete_user_defined_role_stable( + self, + *, + role_name: str, + **kwargs: Any + ) -> None: ... + + @overload + def execute_user_defined_function( + self, + function_id: str, + user_defined_function_execution_properties: Optional[UserDefinedFunctionExecutionProperties] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunctionExecutionResponse: ... + + @overload + def execute_user_defined_function( + self, + function_id: str, + user_defined_function_execution_properties: Optional[JSON] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunctionExecutionResponse: ... + + @overload + def execute_user_defined_function( + self, + function_id: str, + user_defined_function_execution_properties: Optional[IO[bytes]] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunctionExecutionResponse: ... + + @distributed_trace + def get_constitution(self, **kwargs: Any) -> Constitution: ... + + @distributed_trace + def get_current_ledger_entry( + self, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LedgerEntry: ... + + @distributed_trace + def get_enclave_quotes(self, **kwargs: Any) -> ConfidentialLedgerEnclaves: ... + + @distributed_trace + def get_ledger_entry( + self, + transaction_id: str, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LedgerQueryResult: ... + + @distributed_trace + def get_ledger_user( + self, + user_id: str, + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @distributed_trace + def get_receipt( + self, + transaction_id: str, + **kwargs: Any + ) -> TransactionReceipt: ... + + @distributed_trace + def get_runtime_options(self, **kwargs: Any) -> JsRuntimeOptions: ... + + @distributed_trace + def get_transaction_status( + self, + transaction_id: str, + **kwargs: Any + ) -> TransactionStatus: ... + + @distributed_trace + def get_user( + self, + user_id: str, + **kwargs: Any + ) -> LedgerUser: ... + + @distributed_trace + def get_user_defined_endpoint(self, **kwargs: Any) -> Bundle: ... + + @distributed_trace + def get_user_defined_endpoints_module( + self, + *, + module_name: str, + **kwargs: Any + ) -> ModuleDef: ... + + @distributed_trace + def get_user_defined_function( + self, + function_id: str, + **kwargs: Any + ) -> UserDefinedFunction: ... + + @distributed_trace + def get_user_defined_role( + self, + *, + role_name: str, + **kwargs: Any + ) -> UserDefinedRole: ... + + @distributed_trace + def list_collections(self, **kwargs: Any) -> ItemPaged[Collection]: ... + + @distributed_trace + def list_consortium_members(self, **kwargs: Any) -> ItemPaged[ConsortiumMember]: ... + + @distributed_trace + def list_ledger_entries( + self, + *, + collection_id: Optional[str] = ..., + from_transaction_id: Optional[str] = ..., + tag: Optional[str] = ..., + to_transaction_id: Optional[str] = ..., + **kwargs: Any + ) -> ItemPaged[LedgerEntry]: ... + + @distributed_trace + def list_ledger_users(self, **kwargs: Any) -> ItemPaged[LedgerUserMultipleRoles]: ... + + @distributed_trace + @api_version_validation(method_added_on='2026-02-23', params_added_on={'2026-02-23': ['api_version', 'collection_id', 'accept']}, api_versions_list=['2026-02-23']) + def list_tags( + self, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> ItemPaged[str]: ... + + @distributed_trace + def list_user_defined_functions(self, **kwargs: Any) -> ItemPaged[UserDefinedFunction]: ... + + @distributed_trace + def list_users(self, **kwargs: Any) -> ItemPaged[LedgerUser]: ... + + def send_request( + self, + request: HttpRequest, + *, + stream: bool = False, + **kwargs: Any + ) -> HttpResponse: ... + + @overload + def update_runtime_options_stable( + self, + js_runtime_options: JsRuntimeOptions, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> JsRuntimeOptions: ... + + @overload + def update_runtime_options_stable( + self, + js_runtime_options: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> JsRuntimeOptions: ... + + @overload + def update_runtime_options_stable( + self, + js_runtime_options: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> JsRuntimeOptions: ... + + @overload + def update_user_defined_role_stable( + self, + body: UserDefinedRoles, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + def update_user_defined_role_stable( + self, + body: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + def update_user_defined_role_stable( + self, + body: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + +namespace azure.confidentialledger.aio + + class azure.confidentialledger.aio.ConfidentialLedgerClient(GeneratedClient): implements AsyncContextManager + + def __init__( + self, + endpoint: str, + credential: Union[ConfidentialLedgerCertificateCredential, AsyncTokenCredential], + *, + api_version: str = ..., + ledger_certificate_path: Union[bytes, str, PathLike], + **kwargs: Any + ) -> None: ... + + async def begin_create_ledger_entry( + self, + entry: Union[LedgerEntry, JSON, IO[bytes]], + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[TransactionStatus]: ... + + async def begin_get_ledger_entry( + self, + transaction_id: str, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncLROPoller[LedgerQueryResult]: ... + + async def begin_get_receipt( + self, + transaction_id: str, + **kwargs: Any + ) -> AsyncLROPoller[TransactionReceipt]: ... + + async def begin_wait_for_commit( + self, + transaction_id: str, + **kwargs: Any + ) -> AsyncLROPoller[TransactionStatus]: ... + + async def close(self) -> None: ... + + async def create_ledger_entry( + self, + entry: Union[LedgerEntry, JSON, IO[bytes]], + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LedgerWriteResult: ... + + @overload + async def create_or_update_ledger_user( + self, + user_id: str, + user_multiple_roles: LedgerUserMultipleRoles, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @overload + async def create_or_update_ledger_user( + self, + user_id: str, + user_multiple_roles: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @overload + async def create_or_update_ledger_user( + self, + user_id: str, + user_multiple_roles: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @overload + async def create_or_update_user( + self, + user_id: str, + user_details: LedgerUser, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUser: ... + + @overload + async def create_or_update_user( + self, + user_id: str, + user_details: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUser: ... + + @overload + async def create_or_update_user( + self, + user_id: str, + user_details: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> LedgerUser: ... + + @overload + async def create_user_defined_endpoint( + self, + bundle: Bundle, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: ... + + @overload + async def create_user_defined_endpoint( + self, + bundle: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: ... + + @overload + async def create_user_defined_endpoint( + self, + bundle: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: ... + + @overload + async def create_user_defined_function( + self, + function_id: str, + user_defined_function: UserDefinedFunction, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunction: ... + + @overload + async def create_user_defined_function( + self, + function_id: str, + user_defined_function: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunction: ... + + @overload + async def create_user_defined_function( + self, + function_id: str, + user_defined_function: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunction: ... + + @overload + async def create_user_defined_role_stable( + self, + body: UserDefinedRoles, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + async def create_user_defined_role_stable( + self, + body: JSON, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + async def create_user_defined_role_stable( + self, + body: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @distributed_trace_async + async def delete_ledger_user( + self, + user_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace_async + async def delete_user( + self, + user_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace_async + async def delete_user_defined_function( + self, + function_id: str, + **kwargs: Any + ) -> None: ... + + @distributed_trace_async + @api_version_validation(method_added_on='2026-02-23', params_added_on={'2026-02-23': ['api_version', 'role_name']}, api_versions_list=['2026-02-23']) + async def delete_user_defined_role_stable( + self, + *, + role_name: str, + **kwargs: Any + ) -> None: ... + + @overload + async def execute_user_defined_function( + self, + function_id: str, + user_defined_function_execution_properties: Optional[UserDefinedFunctionExecutionProperties] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunctionExecutionResponse: ... + + @overload + async def execute_user_defined_function( + self, + function_id: str, + user_defined_function_execution_properties: Optional[JSON] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunctionExecutionResponse: ... + + @overload + async def execute_user_defined_function( + self, + function_id: str, + user_defined_function_execution_properties: Optional[IO[bytes]] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> UserDefinedFunctionExecutionResponse: ... + + @distributed_trace_async + async def get_constitution(self, **kwargs: Any) -> Constitution: ... + + @distributed_trace_async + async def get_current_ledger_entry( + self, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LedgerEntry: ... + + @distributed_trace_async + async def get_enclave_quotes(self, **kwargs: Any) -> ConfidentialLedgerEnclaves: ... + + @distributed_trace_async + async def get_ledger_entry( + self, + transaction_id: str, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> LedgerQueryResult: ... + + @distributed_trace_async + async def get_ledger_user( + self, + user_id: str, + **kwargs: Any + ) -> LedgerUserMultipleRoles: ... + + @distributed_trace_async + async def get_receipt( + self, + transaction_id: str, + **kwargs: Any + ) -> TransactionReceipt: ... + + @distributed_trace_async + async def get_runtime_options(self, **kwargs: Any) -> JsRuntimeOptions: ... + + @distributed_trace_async + async def get_transaction_status( + self, + transaction_id: str, + **kwargs: Any + ) -> TransactionStatus: ... + + @distributed_trace_async + async def get_user( + self, + user_id: str, + **kwargs: Any + ) -> LedgerUser: ... + + @distributed_trace_async + async def get_user_defined_endpoint(self, **kwargs: Any) -> Bundle: ... + + @distributed_trace_async + async def get_user_defined_endpoints_module( + self, + *, + module_name: str, + **kwargs: Any + ) -> ModuleDef: ... + + @distributed_trace_async + async def get_user_defined_function( + self, + function_id: str, + **kwargs: Any + ) -> UserDefinedFunction: ... + + @distributed_trace_async + async def get_user_defined_role( + self, + *, + role_name: str, + **kwargs: Any + ) -> UserDefinedRole: ... + + @distributed_trace + def list_collections(self, **kwargs: Any) -> AsyncItemPaged[Collection]: ... + + @distributed_trace + def list_consortium_members(self, **kwargs: Any) -> AsyncItemPaged[ConsortiumMember]: ... + + @distributed_trace + def list_ledger_entries( + self, + *, + collection_id: Optional[str] = ..., + from_transaction_id: Optional[str] = ..., + tag: Optional[str] = ..., + to_transaction_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncItemPaged[LedgerEntry]: ... + + @distributed_trace + def list_ledger_users(self, **kwargs: Any) -> AsyncItemPaged[LedgerUserMultipleRoles]: ... + + @distributed_trace + @api_version_validation(method_added_on='2026-02-23', params_added_on={'2026-02-23': ['api_version', 'collection_id', 'accept']}, api_versions_list=['2026-02-23']) + def list_tags( + self, + *, + collection_id: Optional[str] = ..., + **kwargs: Any + ) -> AsyncItemPaged[str]: ... + + @distributed_trace + def list_user_defined_functions(self, **kwargs: Any) -> AsyncItemPaged[UserDefinedFunction]: ... + + @distributed_trace + def list_users(self, **kwargs: Any) -> AsyncItemPaged[LedgerUser]: ... + + def send_request( + self, + request: HttpRequest, + *, + stream: bool = False, + **kwargs: Any + ) -> Awaitable[AsyncHttpResponse]: ... + + @overload + async def update_runtime_options_stable( + self, + js_runtime_options: JsRuntimeOptions, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> JsRuntimeOptions: ... + + @overload + async def update_runtime_options_stable( + self, + js_runtime_options: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> JsRuntimeOptions: ... + + @overload + async def update_runtime_options_stable( + self, + js_runtime_options: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> JsRuntimeOptions: ... + + @overload + async def update_user_defined_role_stable( + self, + body: UserDefinedRoles, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + async def update_user_defined_role_stable( + self, + body: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + @overload + async def update_user_defined_role_stable( + self, + body: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> UserDefinedRoles: ... + + +namespace azure.confidentialledger.models + + class azure.confidentialledger.models.ApplicationClaim(_Model): + digest: Optional[ClaimDigest] + kind: Union[str, ApplicationClaimKind] + ledger_entry: Optional[LedgerEntryClaim] + + @overload + def __init__( + self, + *, + digest: Optional[ClaimDigest] = ..., + kind: Union[str, ApplicationClaimKind], + ledger_entry: Optional[LedgerEntryClaim] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ApplicationClaimKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): + CLAIM_DIGEST = "ClaimDigest" + LEDGER_ENTRY = "LedgerEntry" + + + class azure.confidentialledger.models.ApplicationClaimProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LEDGER_ENTRY_V1 = "LedgerEntryV1" + + + class azure.confidentialledger.models.Bundle(_Model): + metadata: Metadata + modules: list[ModuleDef] + + @overload + def __init__( + self, + *, + metadata: Metadata, + modules: list[ModuleDef] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ClaimDigest(_Model): + protocol: Union[str, ApplicationClaimProtocol] + value: Optional[str] + + @overload + def __init__( + self, + *, + protocol: Union[str, ApplicationClaimProtocol], + value: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.Collection(_Model): + collection_id: str + + @overload + def __init__( + self, + *, + collection_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ConfidentialLedgerEnclaves(_Model): + current_node_id: str + enclave_quotes: dict[str, EnclaveQuote] + + @overload + def __init__( + self, + *, + current_node_id: str, + enclave_quotes: dict[str, EnclaveQuote] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ConfidentialLedgerError(_Model): + error: Optional[ConfidentialLedgerErrorBody] + + + class azure.confidentialledger.models.ConfidentialLedgerErrorBody(_Model): + code: Optional[str] + message: Optional[str] + + + class azure.confidentialledger.models.ConfidentialLedgerQueryState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + LOADING = "Loading" + READY = "Ready" + + + class azure.confidentialledger.models.ConfidentialLedgerUserRoleName(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ADMINISTRATOR = "Administrator" + CONTRIBUTOR = "Contributor" + READER = "Reader" + + + class azure.confidentialledger.models.ConsortiumMember(_Model): + certificate: str + id: str + + @overload + def __init__( + self, + *, + certificate: str, + id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.Constitution(_Model): + digest: str + script: str + + @overload + def __init__( + self, + *, + digest: str, + script: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.EnclaveQuote(_Model): + mrenclave: Optional[str] + node_id: str + quote_version: str + raw: str + + @overload + def __init__( + self, + *, + mrenclave: Optional[str] = ..., + node_id: str, + quote_version: str, + raw: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.EndpointProperties(_Model): + authn_policies: list[dict[str, Any]] + forwarding_required: Union[str, ForwardingRequired] + interpreter_reuse: Optional[InterpreterReusePolicy] + js_function: Optional[str] + js_module: Optional[str] + mode: Optional[Union[str, Mode]] + openapi: Optional[dict[str, Any]] + openapi_hidden: Optional[bool] + redirection_strategy: Optional[Union[str, RedirectionStrategy]] + + @overload + def __init__( + self, + *, + authn_policies: list[dict[str, Any]], + forwarding_required: Union[str, ForwardingRequired], + interpreter_reuse: Optional[InterpreterReusePolicy] = ..., + js_function: Optional[str] = ..., + js_module: Optional[str] = ..., + mode: Optional[Union[str, Mode]] = ..., + openapi: Optional[dict[str, Any]] = ..., + openapi_hidden: Optional[bool] = ..., + redirection_strategy: Optional[Union[str, RedirectionStrategy]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ForwardingRequired(str, Enum, metaclass=CaseInsensitiveEnumMeta): + ALWAYS = "always" + NEVER = "never" + SOMETIMES = "sometimes" + + + class azure.confidentialledger.models.InterpreterReusePolicy(_Model): + key: str + + @overload + def __init__( + self, + *, + key: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.JsRuntimeOptions(_Model): + log_exception_details: Optional[bool] + max_cached_interpreters: Optional[int] + max_execution_time_ms: Optional[int] + max_heap_bytes: Optional[int] + max_stack_bytes: Optional[int] + return_exception_details: Optional[bool] + + @overload + def __init__( + self, + *, + log_exception_details: Optional[bool] = ..., + max_cached_interpreters: Optional[int] = ..., + max_execution_time_ms: Optional[int] = ..., + max_heap_bytes: Optional[int] = ..., + max_stack_bytes: Optional[int] = ..., + return_exception_details: Optional[bool] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.LedgerEntry(_Model): + collection_id: Optional[str] + contents: str + post_hooks: Optional[list[UserDefinedFunctionHook]] + pre_hooks: Optional[list[UserDefinedFunctionHook]] + transaction_id: Optional[str] + + @overload + def __init__( + self, + *, + contents: str, + post_hooks: Optional[list[UserDefinedFunctionHook]] = ..., + pre_hooks: Optional[list[UserDefinedFunctionHook]] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.LedgerEntryClaim(_Model): + collection_id: Optional[str] + contents: Optional[str] + protocol: Union[str, ApplicationClaimProtocol] + secret_key: Optional[str] + + @overload + def __init__( + self, + *, + collection_id: Optional[str] = ..., + contents: Optional[str] = ..., + protocol: Union[str, ApplicationClaimProtocol], + secret_key: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.LedgerQueryResult(_Model): + entry: Optional[LedgerEntry] + state: Union[str, ConfidentialLedgerQueryState] + + @overload + def __init__( + self, + *, + entry: Optional[LedgerEntry] = ..., + state: Union[str, ConfidentialLedgerQueryState] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.LedgerUser(_Model): + assigned_role: Union[str, ConfidentialLedgerUserRoleName] + user_id: Optional[str] + + @overload + def __init__( + self, + *, + assigned_role: Union[str, ConfidentialLedgerUserRoleName] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.LedgerUserMultipleRoles(_Model): + assigned_roles: list[Union[str, ConfidentialLedgerUserRoleName]] + user_id: Optional[str] + + @overload + def __init__( + self, + *, + assigned_roles: list[Union[str, ConfidentialLedgerUserRoleName]] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.LedgerWriteResult(_Model): + collection_id: str + + @overload + def __init__( + self, + *, + collection_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.Metadata(_Model): + endpoints: dict[str, MethodToEndpointProperties] + + @overload + def __init__( + self, + *, + endpoints: dict[str, MethodToEndpointProperties] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.MethodToEndpointProperties(_Model): + delete: Optional[EndpointProperties] + get_property: Optional[EndpointProperties] + patch: Optional[EndpointProperties] + put: Optional[EndpointProperties] + + @overload + def __init__( + self, + *, + delete: Optional[EndpointProperties] = ..., + get_property: Optional[EndpointProperties] = ..., + patch: Optional[EndpointProperties] = ..., + put: Optional[EndpointProperties] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.Mode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + HISTORICAL = "historical" + READONLY = "readonly" + READWRITE = "readwrite" + + + class azure.confidentialledger.models.ModuleDef(_Model): + module: str + name: str + + @overload + def __init__( + self, + *, + module: str, + name: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ReceiptContents(_Model): + cert: Optional[str] + leaf: Optional[str] + leaf_components: Optional[ReceiptLeafComponents] + node_id: str + proof: list[ReceiptElement] + root: Optional[str] + service_endorsements: Optional[list[str]] + signature: str + + @overload + def __init__( + self, + *, + cert: Optional[str] = ..., + leaf: Optional[str] = ..., + leaf_components: Optional[ReceiptLeafComponents] = ..., + node_id: str, + proof: list[ReceiptElement], + root: Optional[str] = ..., + service_endorsements: Optional[list[str]] = ..., + signature: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ReceiptElement(_Model): + left: Optional[str] + right: Optional[str] + + @overload + def __init__( + self, + *, + left: Optional[str] = ..., + right: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.ReceiptLeafComponents(_Model): + claims_digest: Optional[str] + commit_evidence: Optional[str] + write_set_digest: Optional[str] + + @overload + def __init__( + self, + *, + claims_digest: Optional[str] = ..., + commit_evidence: Optional[str] = ..., + write_set_digest: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.RedirectionStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): + NONE = "none" + TO_BACKUP = "to_backup" + TO_PRIMARY = "to_primary" + + + class azure.confidentialledger.models.Role(_Model): + role_actions: Optional[list[str]] + role_name: Optional[str] + + @overload + def __init__( + self, + *, + role_actions: Optional[list[str]] = ..., + role_name: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.TransactionReceipt(_Model): + application_claims: Optional[list[ApplicationClaim]] + receipt: Optional[ReceiptContents] + state: Union[str, ConfidentialLedgerQueryState] + transaction_id: str + + @overload + def __init__( + self, + *, + application_claims: Optional[list[ApplicationClaim]] = ..., + receipt: Optional[ReceiptContents] = ..., + state: Union[str, ConfidentialLedgerQueryState], + transaction_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.TransactionState(str, Enum, metaclass=CaseInsensitiveEnumMeta): + COMMITTED = "Committed" + PENDING = "Pending" + + + class azure.confidentialledger.models.TransactionStatus(_Model): + state: Union[str, TransactionState] + transaction_id: str + + @overload + def __init__( + self, + *, + state: Union[str, TransactionState], + transaction_id: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedFunction(_Model): + code: str + id: Optional[str] + + @overload + def __init__( + self, + *, + code: str + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedFunctionExecutionError(_Model): + message: Optional[str] + + @overload + def __init__( + self, + *, + message: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedFunctionExecutionProperties(_Model): + arguments: Optional[list[str]] + exported_function_name: Optional[str] + runtime_options: Optional[JsRuntimeOptions] + + @overload + def __init__( + self, + *, + arguments: Optional[list[str]] = ..., + exported_function_name: Optional[str] = ..., + runtime_options: Optional[JsRuntimeOptions] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedFunctionExecutionResponse(_Model): + error: Optional[UserDefinedFunctionExecutionError] + result: Optional[UserDefinedFunctionExecutionResult] + status: Union[str, UserDefinedFunctionExecutionStatus] + + @overload + def __init__( + self, + *, + error: Optional[UserDefinedFunctionExecutionError] = ..., + result: Optional[UserDefinedFunctionExecutionResult] = ..., + status: Union[str, UserDefinedFunctionExecutionStatus] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedFunctionExecutionResult(_Model): + return_value: Optional[str] + + @overload + def __init__( + self, + *, + return_value: Optional[str] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedFunctionExecutionStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): + FAILED = "Failed" + SUCCEEDED = "Succeeded" + + + class azure.confidentialledger.models.UserDefinedFunctionHook(_Model): + function_id: str + properties: Optional[UserDefinedFunctionExecutionProperties] + + @overload + def __init__( + self, + *, + function_id: str, + properties: Optional[UserDefinedFunctionExecutionProperties] = ... + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedRole(_Model): + role: list[Role] + + @overload + def __init__( + self, + *, + role: list[Role] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + + class azure.confidentialledger.models.UserDefinedRoles(_Model): + roles: list[Role] + + @overload + def __init__( + self, + *, + roles: list[Role] + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: ... + + +namespace azure.confidentialledger.receipt + + def azure.confidentialledger.receipt.compute_claims_digest(application_claims: List[Dict[str, Any]]) -> str: ... + + + def azure.confidentialledger.receipt.verify_receipt( + receipt: Dict[str, Any], + service_cert: str, + *, + application_claims: Optional[List[Dict[str, Any]]] = ... + ) -> None: ... + + +``` \ No newline at end of file diff --git a/sdk/confidentialledger/azure-confidentialledger/api.metadata.yml b/sdk/confidentialledger/azure-confidentialledger/api.metadata.yml new file mode 100644 index 000000000000..990d1dffc04b --- /dev/null +++ b/sdk/confidentialledger/azure-confidentialledger/api.metadata.yml @@ -0,0 +1,3 @@ +apiMdSha256: f7460a0f8a55563ffde7696b77d30bf660b4ec25299d66af89755ab09357dce5 +parserVersion: 0.3.28 +pythonVersion: 3.12.10 diff --git a/sdk/confidentialledger/azure-confidentialledger/apiview-properties.json b/sdk/confidentialledger/azure-confidentialledger/apiview-properties.json index afeb37d478db..51e247dd9ef8 100644 --- a/sdk/confidentialledger/azure-confidentialledger/apiview-properties.json +++ b/sdk/confidentialledger/azure-confidentialledger/apiview-properties.json @@ -27,7 +27,6 @@ "azure.confidentialledger.models.ReceiptElement": "ConfidentialLedger.ReceiptElement", "azure.confidentialledger.models.ReceiptLeafComponents": "ConfidentialLedger.ReceiptLeafComponents", "azure.confidentialledger.models.Role": "ConfidentialLedger.Role", - "azure.confidentialledger.models.Roles": "ConfidentialLedger.Roles", "azure.confidentialledger.models.TransactionReceipt": "ConfidentialLedger.TransactionReceipt", "azure.confidentialledger.models.TransactionStatus": "ConfidentialLedger.TransactionStatus", "azure.confidentialledger.models.UserDefinedFunction": "ConfidentialLedger.UserDefinedFunction", @@ -36,6 +35,8 @@ "azure.confidentialledger.models.UserDefinedFunctionExecutionResponse": "ConfidentialLedger.UserDefinedFunctionExecutionResponse", "azure.confidentialledger.models.UserDefinedFunctionExecutionResult": "ConfidentialLedger.UserDefinedFunctionExecutionResult", "azure.confidentialledger.models.UserDefinedFunctionHook": "ConfidentialLedger.UserDefinedFunctionHook", + "azure.confidentialledger.models.UserDefinedRole": "ConfidentialLedger.UserDefinedRole", + "azure.confidentialledger.models.UserDefinedRoles": "ConfidentialLedger.UserDefinedRoles", "azure.confidentialledger.models.ConfidentialLedgerQueryState": "ConfidentialLedger.ConfidentialLedgerQueryState", "azure.confidentialledger.models.ApplicationClaimProtocol": "ConfidentialLedger.ApplicationClaimProtocol", "azure.confidentialledger.models.ApplicationClaimKind": "ConfidentialLedger.ApplicationClaimKind", @@ -53,6 +54,8 @@ "azure.confidentialledger.aio.ConfidentialLedgerClient.get_enclave_quotes": "ConfidentialLedger.getEnclaveQuotes", "azure.confidentialledger.ConfidentialLedgerClient.list_collections": "ConfidentialLedger.listCollections", "azure.confidentialledger.aio.ConfidentialLedgerClient.list_collections": "ConfidentialLedger.listCollections", + "azure.confidentialledger.ConfidentialLedgerClient.list_tags": "ConfidentialLedger.listTags", + "azure.confidentialledger.aio.ConfidentialLedgerClient.list_tags": "ConfidentialLedger.listTags", "azure.confidentialledger.ConfidentialLedgerClient.list_ledger_entries": "ConfidentialLedger.listLedgerEntries", "azure.confidentialledger.aio.ConfidentialLedgerClient.list_ledger_entries": "ConfidentialLedger.listLedgerEntries", "azure.confidentialledger.ConfidentialLedgerClient.create_ledger_entry": "ConfidentialLedger.createLedgerEntry", @@ -87,8 +90,8 @@ "azure.confidentialledger.aio.ConfidentialLedgerClient.create_user_defined_endpoint": "ConfidentialLedger.createUserDefinedEndpoint", "azure.confidentialledger.ConfidentialLedgerClient.get_runtime_options": "ConfidentialLedger.getRuntimeOptions", "azure.confidentialledger.aio.ConfidentialLedgerClient.get_runtime_options": "ConfidentialLedger.getRuntimeOptions", - "azure.confidentialledger.ConfidentialLedgerClient.update_runtime_options": "ConfidentialLedger.updateRuntimeOptions", - "azure.confidentialledger.aio.ConfidentialLedgerClient.update_runtime_options": "ConfidentialLedger.updateRuntimeOptions", + "azure.confidentialledger.ConfidentialLedgerClient.update_runtime_options_stable": "ConfidentialLedger.updateRuntimeOptionsStable", + "azure.confidentialledger.aio.ConfidentialLedgerClient.update_runtime_options_stable": "ConfidentialLedger.updateRuntimeOptionsStable", "azure.confidentialledger.ConfidentialLedgerClient.get_user_defined_endpoints_module": "ConfidentialLedger.getUserDefinedEndpointsModule", "azure.confidentialledger.aio.ConfidentialLedgerClient.get_user_defined_endpoints_module": "ConfidentialLedger.getUserDefinedEndpointsModule", "azure.confidentialledger.ConfidentialLedgerClient.list_user_defined_functions": "ConfidentialLedger.listUserDefinedFunctions", @@ -103,11 +106,12 @@ "azure.confidentialledger.aio.ConfidentialLedgerClient.execute_user_defined_function": "ConfidentialLedger.executeUserDefinedFunction", "azure.confidentialledger.ConfidentialLedgerClient.get_user_defined_role": "ConfidentialLedger.getUserDefinedRole", "azure.confidentialledger.aio.ConfidentialLedgerClient.get_user_defined_role": "ConfidentialLedger.getUserDefinedRole", - "azure.confidentialledger.ConfidentialLedgerClient.create_user_defined_role": "ConfidentialLedger.createUserDefinedRole", - "azure.confidentialledger.aio.ConfidentialLedgerClient.create_user_defined_role": "ConfidentialLedger.createUserDefinedRole", - "azure.confidentialledger.ConfidentialLedgerClient.update_user_defined_role": "ConfidentialLedger.updateUserDefinedRole", - "azure.confidentialledger.aio.ConfidentialLedgerClient.update_user_defined_role": "ConfidentialLedger.updateUserDefinedRole", - "azure.confidentialledger.ConfidentialLedgerClient.delete_user_defined_role": "ConfidentialLedger.deleteUserDefinedRole", - "azure.confidentialledger.aio.ConfidentialLedgerClient.delete_user_defined_role": "ConfidentialLedger.deleteUserDefinedRole" - } + "azure.confidentialledger.ConfidentialLedgerClient.create_user_defined_role_stable": "ConfidentialLedger.createUserDefinedRoleStable", + "azure.confidentialledger.aio.ConfidentialLedgerClient.create_user_defined_role_stable": "ConfidentialLedger.createUserDefinedRoleStable", + "azure.confidentialledger.ConfidentialLedgerClient.update_user_defined_role_stable": "ConfidentialLedger.updateUserDefinedRoleStable", + "azure.confidentialledger.aio.ConfidentialLedgerClient.update_user_defined_role_stable": "ConfidentialLedger.updateUserDefinedRoleStable", + "azure.confidentialledger.ConfidentialLedgerClient.delete_user_defined_role_stable": "ConfidentialLedger.deleteUserDefinedRoleStable", + "azure.confidentialledger.aio.ConfidentialLedgerClient.delete_user_defined_role_stable": "ConfidentialLedger.deleteUserDefinedRoleStable" + }, + "CrossLanguageVersion": "4c5f007c40fa" } \ No newline at end of file diff --git a/sdk/confidentialledger/azure-confidentialledger/assets.json b/sdk/confidentialledger/azure-confidentialledger/assets.json index 50415ce26c34..35c6ee4cdef8 100644 --- a/sdk/confidentialledger/azure-confidentialledger/assets.json +++ b/sdk/confidentialledger/azure-confidentialledger/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/confidentialledger/azure-confidentialledger", - "Tag": "python/confidentialledger/azure-confidentialledger_30ab71ea9a" + "Tag": "python/confidentialledger/azure-confidentialledger_3b255b1a8e" } diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_client.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_client.py index fa11e8b73f11..fee3a653c7f4 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_client.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_client.py @@ -7,8 +7,8 @@ # -------------------------------------------------------------------------- from copy import deepcopy +import sys from typing import Any -from typing_extensions import Self from azure.core import PipelineClient from azure.core.pipeline import policies @@ -16,9 +16,13 @@ from ._configuration import ConfidentialLedgerClientConfiguration from ._operations import _ConfidentialLedgerClientOperationsMixin -from ._redirect_caching_policy import RedirectCachingPolicy from ._utils.serialization import Deserializer, Serializer +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # type: ignore + class ConfidentialLedgerClient(_ConfidentialLedgerClientOperationsMixin): """Write and retrieve ledger entries against the Confidential Ledger service. @@ -27,9 +31,9 @@ class ConfidentialLedgerClient(_ConfidentialLedgerClientOperationsMixin): `https://contoso.confidentialledger.azure.com `_. Required. :type ledger_endpoint: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-12-09-preview". Note that overriding this default value may result in unsupported - behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-02-23" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -47,19 +51,13 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential self._config.user_agent_policy, self._config.proxy_policy, policies.ContentDecodePolicy(**kwargs), - kwargs.get("redirect_policy") or RedirectCachingPolicy(**kwargs), + self._config.redirect_policy, self._config.retry_policy, self._config.authentication_policy, self._config.custom_hook_policy, self._config.logging_policy, policies.DistributedTracingPolicy(**kwargs), - # Redirect cleanup is disabled to preserve authentication and ledger-specific headers - # on service-managed redirects. Confidential Ledger redirects are expected to stay within - # the same trusted ledger endpoint, so forwarding these sensitive headers is required - # for correct authentication behavior. - policies.SensitiveHeaderCleanupPolicy( - disable_redirect_cleanup=True, **kwargs - ) if self._config.redirect_policy else None, + policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, self._config.http_logging_policy, ] self._client: PipelineClient = PipelineClient(base_url=_endpoint, policies=_policies, **kwargs) diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_configuration.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_configuration.py index 9042692d9795..936ca23d6a4e 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_configuration.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_configuration.py @@ -23,14 +23,14 @@ class ConfidentialLedgerClientConfiguration: # pylint: disable=too-many-instanc `https://contoso.confidentialledger.azure.com `_. Required. :type ledger_endpoint: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-12-09-preview". Note that overriding this default value may result in unsupported - behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-02-23" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ def __init__(self, ledger_endpoint: str, **kwargs: Any) -> None: - api_version: str = kwargs.pop("api_version", "2024-12-09-preview") + api_version: str = kwargs.pop("api_version", "2026-02-23") if ledger_endpoint is None: raise ValueError("Parameter 'ledger_endpoint' must not be None.") diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_operations/_operations.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_operations/_operations.py index 77da3c99ebaf..7ababd67fcad 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_operations/_operations.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_operations/_operations.py @@ -34,6 +34,7 @@ from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize from .._utils.serialization import Serializer from .._utils.utils import ClientMixinABC +from .._validation import api_version_validation JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -47,7 +48,7 @@ def build_confidential_ledger_get_constitution_request(**kwargs: Any) -> HttpReq _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -68,7 +69,7 @@ def build_confidential_ledger_list_consortium_members_request( # pylint: disabl _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -87,7 +88,7 @@ def build_confidential_ledger_get_enclave_quotes_request(**kwargs: Any) -> HttpR _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -106,7 +107,7 @@ def build_confidential_ledger_list_collections_request(**kwargs: Any) -> HttpReq _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -121,6 +122,29 @@ def build_confidential_ledger_list_collections_request(**kwargs: Any) -> HttpReq return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) +def build_confidential_ledger_list_tags_request( # pylint: disable=name-too-long + *, collection_id: Optional[str] = None, **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", "2026-02-23")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/app/collections/tags" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + if collection_id is not None: + _params["collectionId"] = _SERIALIZER.query("collection_id", collection_id, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + def build_confidential_ledger_list_ledger_entries_request( # pylint: disable=name-too-long *, collection_id: Optional[str] = None, @@ -132,7 +156,7 @@ def build_confidential_ledger_list_ledger_entries_request( # pylint: disable=na _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -162,7 +186,7 @@ def build_confidential_ledger_create_ledger_entry_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -189,7 +213,7 @@ def build_confidential_ledger_get_ledger_entry_request( # pylint: disable=name- _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -217,7 +241,7 @@ def build_confidential_ledger_get_receipt_request( # pylint: disable=name-too-l _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -243,7 +267,7 @@ def build_confidential_ledger_get_transaction_status_request( # pylint: disable _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -269,7 +293,7 @@ def build_confidential_ledger_get_current_ledger_entry_request( # pylint: disab _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -290,7 +314,7 @@ def build_confidential_ledger_list_users_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -309,7 +333,7 @@ def build_confidential_ledger_list_ledger_users_request(**kwargs: Any) -> HttpRe _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -329,7 +353,7 @@ def build_confidential_ledger_delete_user_request( # pylint: disable=name-too-l ) -> HttpRequest: _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) # Construct URL _url = "/app/users/{userId}" path_format_arguments = { @@ -350,7 +374,7 @@ def build_confidential_ledger_get_user_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -377,7 +401,7 @@ def build_confidential_ledger_create_or_update_user_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -404,7 +428,7 @@ def build_confidential_ledger_delete_ledger_user_request( # pylint: disable=nam ) -> HttpRequest: _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) # Construct URL _url = "/app/ledgerUsers/{userId}" path_format_arguments = { @@ -425,7 +449,7 @@ def build_confidential_ledger_get_ledger_user_request( # pylint: disable=name-t _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -452,7 +476,7 @@ def build_confidential_ledger_create_or_update_ledger_user_request( # pylint: d _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-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -480,7 +504,7 @@ def build_confidential_ledger_get_user_defined_endpoint_request( # pylint: disa _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -502,7 +526,7 @@ def build_confidential_ledger_create_user_defined_endpoint_request( # pylint: d _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-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) # Construct URL _url = "/app/userDefinedEndpoints" @@ -522,7 +546,7 @@ def build_confidential_ledger_get_runtime_options_request( # pylint: disable=na _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -537,14 +561,14 @@ def build_confidential_ledger_get_runtime_options_request( # pylint: disable=na return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_confidential_ledger_update_runtime_options_request( # pylint: disable=name-too-long +def build_confidential_ledger_update_runtime_options_stable_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -567,7 +591,7 @@ def build_confidential_ledger_get_user_defined_endpoints_module_request( # pyli _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -589,7 +613,7 @@ def build_confidential_ledger_list_user_defined_functions_request( # pylint: di _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -609,7 +633,7 @@ def build_confidential_ledger_delete_user_defined_function_request( # pylint: d ) -> HttpRequest: _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) # Construct URL _url = "/app/userDefinedFunctions/{functionId}" path_format_arguments = { @@ -630,7 +654,7 @@ def build_confidential_ledger_get_user_defined_function_request( # pylint: disa _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -657,7 +681,7 @@ def build_confidential_ledger_create_user_defined_function_request( # pylint: d _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-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -686,7 +710,7 @@ def build_confidential_ledger_execute_user_defined_function_request( # pylint: _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-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -714,7 +738,7 @@ def build_confidential_ledger_get_user_defined_role_request( # pylint: disable= _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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) accept = _headers.pop("Accept", "application/json") # Construct URL @@ -730,14 +754,16 @@ def build_confidential_ledger_get_user_defined_role_request( # pylint: disable= return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_confidential_ledger_create_user_defined_role_request( # pylint: disable=name-too-long +def build_confidential_ledger_create_user_defined_role_stable_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) + accept = _headers.pop("Accept", "application/json") + # Construct URL _url = "/app/roles" @@ -747,18 +773,21 @@ def build_confidential_ledger_create_user_defined_role_request( # pylint: disab # 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="PUT", url=_url, params=_params, headers=_headers, **kwargs) -def build_confidential_ledger_update_user_defined_role_request( # pylint: disable=name-too-long +def build_confidential_ledger_update_user_defined_role_stable_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", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) + accept = _headers.pop("Accept", "application/json") + # Construct URL _url = "/app/roles" @@ -768,16 +797,17 @@ def build_confidential_ledger_update_user_defined_role_request( # pylint: disab # 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="PATCH", url=_url, params=_params, headers=_headers, **kwargs) -def build_confidential_ledger_delete_user_defined_role_request( # pylint: disable=name-too-long +def build_confidential_ledger_delete_user_defined_role_stable_request( # pylint: disable=name-too-long *, role_name: str, **kwargs: Any ) -> HttpRequest: _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2024-12-09-preview")) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-02-23")) # Construct URL _url = "/app/roles" @@ -796,8 +826,7 @@ class _ConfidentialLedgerClientOperationsMixin( # pylint: disable=too-many-publ def get_constitution(self, **kwargs: Any) -> _models.Constitution: """Gets the constitution used for governance. - The constitution is a script that assesses and applies proposals from - consortium members. + The constitution is a script that assesses and applies proposals from consortium members. :return: Constitution. The Constitution is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.Constitution @@ -828,6 +857,7 @@ def get_constitution(self, **kwargs: Any) -> _models.Constitution: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -842,11 +872,14 @@ def get_constitution(self, **kwargs: Any) -> _models.Constitution: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.Constitution, response.json()) @@ -904,7 +937,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -917,7 +953,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.ConsortiumMember], deserialized.get("members", [])) + list_of_elem = _deserialize( + list[_models.ConsortiumMember], + deserialized.get("members", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -933,7 +972,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -944,8 +986,8 @@ def get_next(next_link=None): def get_enclave_quotes(self, **kwargs: Any) -> _models.ConfidentialLedgerEnclaves: """Gets quotes for all nodes of the Confidential Ledger. - A quote is an SGX enclave measurement that can be used to verify the validity - of a node and its enclave. + A quote is an SGX enclave measurement that can be used to verify the validity of a node and its + enclave. :return: ConfidentialLedgerEnclaves. The ConfidentialLedgerEnclaves is compatible with MutableMapping @@ -977,6 +1019,7 @@ def get_enclave_quotes(self, **kwargs: Any) -> _models.ConfidentialLedgerEnclave } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -991,11 +1034,14 @@ def get_enclave_quotes(self, **kwargs: Any) -> _models.ConfidentialLedgerEnclave except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ConfidentialLedgerEnclaves, response.json()) @@ -1053,7 +1099,112 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) + path_format_arguments = { + "ledgerEndpoint": self._serialize.url( + "self._config.ledger_endpoint", self._config.ledger_endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + list[_models.Collection], + deserialized.get("collections", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _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) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "collection_id", "accept"]}, + api_versions_list=["2026-02-23"], + ) + def list_tags(self, *, collection_id: Optional[str] = None, **kwargs: Any) -> ItemPaged[str]: + """Gets a list of tags for a collection. + + Retrieves the tags associated with a collection. + + :keyword collection_id: The collection id. Default value is None. + :paramtype collection_id: str + :return: An iterator like instance of str + :rtype: ~azure.core.paging.ItemPaged[str] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[list[str]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(next_link=None): + if not next_link: + + _request = build_confidential_ledger_list_tags_request( + collection_id=collection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "ledgerEndpoint": self._serialize.url( + "self._config.ledger_endpoint", self._config.ledger_endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -1066,7 +1217,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.Collection], deserialized.get("collections", [])) + list_of_elem = _deserialize( + list[str], + deserialized.get("tags", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -1082,7 +1236,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1101,8 +1258,8 @@ def list_ledger_entries( ) -> ItemPaged["_models.LedgerEntry"]: """Gets ledger entries from a collection corresponding to a range. - A collection id may optionally be specified. Only entries in the specified (or - default) collection will be returned. + A collection id may optionally be specified. Only entries in the specified (or default) + collection will be returned. :keyword collection_id: The collection id. Default value is None. :paramtype collection_id: str @@ -1160,7 +1317,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -1173,7 +1333,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.LedgerEntry], deserialized.get("entries", [])) + list_of_elem = _deserialize( + list[_models.LedgerEntry], + deserialized.get("entries", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -1189,7 +1352,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1341,6 +1507,7 @@ def create_ledger_entry( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1355,7 +1522,10 @@ def create_ledger_entry( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) response_headers = {} @@ -1364,7 +1534,7 @@ def create_ledger_entry( ) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerWriteResult, response.json()) @@ -1377,14 +1547,12 @@ def create_ledger_entry( def get_ledger_entry( self, transaction_id: str, *, collection_id: Optional[str] = None, **kwargs: Any ) -> _models.LedgerQueryResult: - """Gets the ledger entry at the specified transaction id. A collection id may - optionally be specified to indicate the collection from which to fetch the - value. + """Gets the ledger entry at the specified transaction id. A collection id may optionally be + specified to indicate the collection from which to fetch the value. - To return older ledger entries, the relevant sections of the ledger must be - read from disk and validated. To prevent blocking within the enclave, the - response will indicate whether the entry is ready and part of the response, or - if the loading is still ongoing. + To return older ledger entries, the relevant sections of the ledger must be read from disk and + validated. To prevent blocking within the enclave, the response will indicate whether the entry + is ready and part of the response, or if the loading is still ongoing. :param transaction_id: Identifies a write transaction. Required. :type transaction_id: str @@ -1421,6 +1589,7 @@ def get_ledger_entry( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1435,11 +1604,14 @@ def get_ledger_entry( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerQueryResult, response.json()) @@ -1486,6 +1658,7 @@ def get_receipt(self, transaction_id: str, **kwargs: Any) -> _models.Transaction } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1500,11 +1673,14 @@ def get_receipt(self, transaction_id: str, **kwargs: Any) -> _models.Transaction except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.TransactionReceipt, response.json()) @@ -1551,6 +1727,7 @@ def get_transaction_status(self, transaction_id: str, **kwargs: Any) -> _models. } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1565,11 +1742,14 @@ def get_transaction_status(self, transaction_id: str, **kwargs: Any) -> _models. except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.TransactionStatus, response.json()) @@ -1616,6 +1796,7 @@ def get_current_ledger_entry(self, *, collection_id: Optional[str] = None, **kwa } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1630,11 +1811,14 @@ def get_current_ledger_entry(self, *, collection_id: Optional[str] = None, **kwa except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerEntry, response.json()) @@ -1692,7 +1876,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -1705,7 +1892,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.LedgerUser], deserialized.get("ledgerUsers", [])) + list_of_elem = _deserialize( + list[_models.LedgerUser], + deserialized.get("ledgerUsers", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -1721,7 +1911,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1777,7 +1970,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -1790,7 +1986,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.LedgerUserMultipleRoles], deserialized.get("ledgerUsers", [])) + list_of_elem = _deserialize( + list[_models.LedgerUserMultipleRoles], + deserialized.get("ledgerUsers", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -1806,7 +2005,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1860,7 +2062,10 @@ def delete_user(self, user_id: str, **kwargs: Any) -> None: # pylint: disable=i if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -1904,6 +2109,7 @@ def get_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUser: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1918,11 +2124,14 @@ def get_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUser: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUser, response.json()) @@ -2054,6 +2263,7 @@ def create_or_update_user( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2068,11 +2278,14 @@ def create_or_update_user( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUser, response.json()) @@ -2128,7 +2341,10 @@ def delete_ledger_user(self, user_id: str, **kwargs: Any) -> None: # pylint: di if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -2172,6 +2388,7 @@ def get_ledger_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUserMult } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2186,11 +2403,14 @@ def get_ledger_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUserMult except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUserMultipleRoles, response.json()) @@ -2331,6 +2551,7 @@ def create_or_update_ledger_user( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2345,11 +2566,14 @@ def create_or_update_ledger_user( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUserMultipleRoles, response.json()) @@ -2393,6 +2617,7 @@ def get_user_defined_endpoint(self, **kwargs: Any) -> _models.Bundle: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2407,11 +2632,14 @@ def get_user_defined_endpoint(self, **kwargs: Any) -> _models.Bundle: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.Bundle, response.json()) @@ -2533,7 +2761,10 @@ def create_user_defined_endpoint( # pylint: disable=inconsistent-return-stateme if response.status_code not in [201]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -2574,6 +2805,7 @@ def get_runtime_options(self, **kwargs: Any) -> _models.JsRuntimeOptions: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2588,11 +2820,14 @@ def get_runtime_options(self, **kwargs: Any) -> _models.JsRuntimeOptions: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.JsRuntimeOptions, response.json()) @@ -2602,8 +2837,12 @@ def get_runtime_options(self, **kwargs: Any) -> _models.JsRuntimeOptions: return deserialized # type: ignore @overload - def update_runtime_options( - self, js_runtime_options: _models.JsRuntimeOptions, *, content_type: str = "application/json", **kwargs: Any + def update_runtime_options_stable( + self, + js_runtime_options: _models.JsRuntimeOptions, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any, ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -2612,7 +2851,7 @@ def update_runtime_options( :param js_runtime_options: JS Runtime options. Required. :type js_runtime_options: ~azure.confidentialledger.models.JsRuntimeOptions :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str :return: JsRuntimeOptions. The JsRuntimeOptions is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.JsRuntimeOptions @@ -2620,8 +2859,8 @@ def update_runtime_options( """ @overload - def update_runtime_options( - self, js_runtime_options: JSON, *, content_type: str = "application/json", **kwargs: Any + def update_runtime_options_stable( + self, js_runtime_options: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -2630,7 +2869,7 @@ def update_runtime_options( :param js_runtime_options: JS Runtime options. Required. :type js_runtime_options: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str :return: JsRuntimeOptions. The JsRuntimeOptions is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.JsRuntimeOptions @@ -2638,8 +2877,8 @@ def update_runtime_options( """ @overload - def update_runtime_options( - self, js_runtime_options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + def update_runtime_options_stable( + self, js_runtime_options: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -2648,7 +2887,7 @@ def update_runtime_options( :param js_runtime_options: JS Runtime options. Required. :type js_runtime_options: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str :return: JsRuntimeOptions. The JsRuntimeOptions is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.JsRuntimeOptions @@ -2656,7 +2895,12 @@ def update_runtime_options( """ @distributed_trace - def update_runtime_options( + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "content_type", "accept"]}, + api_versions_list=["2026-02-23"], + ) + def update_runtime_options_stable( self, js_runtime_options: Union[_models.JsRuntimeOptions, JSON, IO[bytes]], **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -2685,14 +2929,14 @@ def update_runtime_options( content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) cls: ClsType[_models.JsRuntimeOptions] = kwargs.pop("cls", None) - content_type = content_type or "application/json" + content_type = content_type or "application/merge-patch+json" _content = None if isinstance(js_runtime_options, (IOBase, bytes)): _content = js_runtime_options else: _content = json.dumps(js_runtime_options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_confidential_ledger_update_runtime_options_request( + _request = build_confidential_ledger_update_runtime_options_stable_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -2706,6 +2950,7 @@ def update_runtime_options( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2720,11 +2965,14 @@ def update_runtime_options( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.JsRuntimeOptions, response.json()) @@ -2771,6 +3019,7 @@ def get_user_defined_endpoints_module(self, *, module_name: str, **kwargs: Any) } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2785,11 +3034,14 @@ def get_user_defined_endpoints_module(self, *, module_name: str, **kwargs: Any) except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ModuleDef, response.json()) @@ -2847,7 +3099,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -2860,7 +3115,10 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.UserDefinedFunction], deserialized.get("functions", [])) + list_of_elem = _deserialize( + list[_models.UserDefinedFunction], + deserialized.get("functions", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, iter(list_of_elem) @@ -2876,7 +3134,10 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -2932,7 +3193,10 @@ def delete_user_defined_function( # pylint: disable=inconsistent-return-stateme if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -2976,6 +3240,7 @@ def get_user_defined_function(self, function_id: str, **kwargs: Any) -> _models. } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2990,11 +3255,14 @@ def get_user_defined_function(self, function_id: str, **kwargs: Any) -> _models. except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.UserDefinedFunction, response.json()) @@ -3133,6 +3401,7 @@ def create_user_defined_function( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -3147,7 +3416,10 @@ def create_user_defined_function( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) response_headers = {} @@ -3156,7 +3428,7 @@ def create_user_defined_function( ) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.UserDefinedFunction, response.json()) @@ -3312,6 +3584,7 @@ def execute_user_defined_function( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -3326,11 +3599,14 @@ def execute_user_defined_function( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.UserDefinedFunctionExecutionResponse, response.json()) @@ -3340,15 +3616,15 @@ def execute_user_defined_function( return deserialized # type: ignore @distributed_trace - def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.Roles: + def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.UserDefinedRole: """Gets role actions for user defined roles. user defined roles allow users to define and manage app specific AuthZ policy. :keyword role_name: user defined role name. Required. :paramtype role_name: str - :return: Roles. The Roles is compatible with MutableMapping - :rtype: ~azure.confidentialledger.models.Roles + :return: UserDefinedRole. The UserDefinedRole is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRole :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3362,7 +3638,7 @@ def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.Rol _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Roles] = kwargs.pop("cls", None) + cls: ClsType[_models.UserDefinedRole] = kwargs.pop("cls", None) _request = build_confidential_ledger_get_user_defined_role_request( role_name=role_name, @@ -3377,6 +3653,7 @@ def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.Rol } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -3391,13 +3668,16 @@ def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.Rol except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Roles, response.json()) + deserialized = _deserialize(_models.UserDefinedRole, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3405,25 +3685,27 @@ def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.Rol return deserialized # type: ignore @overload - def create_user_defined_role( - self, body: _models.Roles, *, content_type: str = "application/json", **kwargs: Any - ) -> None: + def create_user_defined_role_stable( + self, body: _models.UserDefinedRoles, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. - :type body: ~azure.confidentialledger.models.Roles + :type body: ~azure.confidentialledger.models.UserDefinedRoles :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_user_defined_role(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> None: + def create_user_defined_role_stable( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. @@ -3433,15 +3715,15 @@ def create_user_defined_role(self, body: JSON, *, content_type: str = "applicati :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_user_defined_role( + def create_user_defined_role_stable( self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> None: + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. @@ -3451,23 +3733,29 @@ def create_user_defined_role( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_user_defined_role( # pylint: disable=inconsistent-return-statements - self, body: Union[_models.Roles, JSON, IO[bytes]], **kwargs: Any - ) -> None: + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "content_type", "accept"]}, + api_versions_list=["2026-02-23"], + ) + def create_user_defined_role_stable( + self, body: Union[_models.UserDefinedRoles, JSON, IO[bytes]], **kwargs: Any + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. - :param body: Request body. Is one of the following types: Roles, JSON, IO[bytes] Required. - :type body: ~azure.confidentialledger.models.Roles or JSON or IO[bytes] - :return: None - :rtype: None + :param body: Request body. Is one of the following types: UserDefinedRoles, JSON, IO[bytes] + Required. + :type body: ~azure.confidentialledger.models.UserDefinedRoles or JSON or IO[bytes] + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3482,7 +3770,7 @@ def create_user_defined_role( # pylint: disable=inconsistent-return-statements _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.UserDefinedRoles] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None @@ -3491,7 +3779,7 @@ def create_user_defined_role( # pylint: disable=inconsistent-return-statements else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_confidential_ledger_create_user_defined_role_request( + _request = build_confidential_ledger_create_user_defined_role_stable_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -3505,7 +3793,8 @@ def create_user_defined_role( # pylint: disable=inconsistent-return-statements } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -3513,81 +3802,104 @@ def create_user_defined_role( # pylint: disable=inconsistent-return-statements 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) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.UserDefinedRoles, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @overload - def update_user_defined_role( - self, body: _models.Roles, *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + def update_user_defined_role_stable( + self, body: _models.UserDefinedRoles, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. - :type body: ~azure.confidentialledger.models.Roles + :type body: ~azure.confidentialledger.models.UserDefinedRoles :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update_user_defined_role(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + def update_user_defined_role_stable( + self, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update_user_defined_role( - self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + def update_user_defined_role_stable( + self, body: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update_user_defined_role( # pylint: disable=inconsistent-return-statements - self, body: Union[_models.Roles, JSON, IO[bytes]], **kwargs: Any - ) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "content_type", "accept"]}, + api_versions_list=["2026-02-23"], + ) + def update_user_defined_role_stable( + self, body: Union[_models.UserDefinedRoles, JSON, IO[bytes]], **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. - :param body: Request body. Is one of the following types: Roles, JSON, IO[bytes] Required. - :type body: ~azure.confidentialledger.models.Roles or JSON or IO[bytes] - :return: None - :rtype: None + :param body: Request body. Is one of the following types: UserDefinedRoles, JSON, IO[bytes] + Required. + :type body: ~azure.confidentialledger.models.UserDefinedRoles or JSON or IO[bytes] + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3602,16 +3914,16 @@ def update_user_defined_role( # pylint: disable=inconsistent-return-statements _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.UserDefinedRoles] = kwargs.pop("cls", None) - content_type = content_type or "application/json" + content_type = content_type or "application/merge-patch+json" _content = None if isinstance(body, (IOBase, bytes)): _content = body else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_confidential_ledger_update_user_defined_role_request( + _request = build_confidential_ledger_update_user_defined_role_stable_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -3625,7 +3937,8 @@ def update_user_defined_role( # pylint: disable=inconsistent-return-statements } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -3633,21 +3946,40 @@ def update_user_defined_role( # pylint: disable=inconsistent-return-statements 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) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.UserDefinedRoles, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace - def delete_user_defined_role( # pylint: disable=inconsistent-return-statements + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "role_name"]}, + api_versions_list=["2026-02-23"], + ) + def delete_user_defined_role_stable( # pylint: disable=inconsistent-return-statements self, *, role_name: str, **kwargs: Any ) -> None: """Deletes user defined roles. - A user defined role allows the users to create and manage their own role - actions using the API. + A user defined role allows the users to create and manage their own role actions using the API. :keyword role_name: user defined role name. Required. :paramtype role_name: str @@ -3668,7 +4000,7 @@ def delete_user_defined_role( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_confidential_ledger_delete_user_defined_role_request( + _request = build_confidential_ledger_delete_user_defined_role_stable_request( role_name=role_name, api_version=self._config.api_version, headers=_headers, @@ -3688,9 +4020,12 @@ def delete_user_defined_role( # pylint: disable=inconsistent-return-statements response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_patch.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_patch.py index 59473e6e901b..cbce74bd6ca5 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_patch.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_patch.py @@ -14,6 +14,7 @@ from azure.core.pipeline import policies from azure.confidentialledger._client import ConfidentialLedgerClient as GeneratedClient +from azure.confidentialledger._redirect_caching_policy import RedirectCachingPolicy from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient # pylint: disable=import-error,no-name-in-module __all__: List[str] = [ @@ -117,4 +118,10 @@ def __init__( kwargs["connection_verify"] = kwargs.get("connection_verify", ledger_certificate_path) + # Inject the redirect-caching policy so that write requests skip the + # load-balancer after the first redirect, and preserve sensitive headers + # on service-managed redirects within the trusted ledger endpoint. + kwargs.setdefault("redirect_policy", RedirectCachingPolicy(**kwargs)) + kwargs.setdefault("disable_redirect_cleanup", True) + super().__init__(endpoint, **kwargs) diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/model_base.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/model_base.py index 3cd9cb9ceabf..bd5b9caf1022 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/model_base.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/model_base.py @@ -23,20 +23,26 @@ from json import JSONEncoder import xml.etree.ElementTree as ET from collections.abc import MutableMapping -from typing_extensions import Self import isodate from azure.core.exceptions import DeserializationError from azure.core import CaseInsensitiveEnumMeta from azure.core.pipeline import PipelineResponse from azure.core.serialization import _Null + from azure.core.rest import HttpResponse +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + _LOGGER = logging.getLogger(__name__) __all__ = ["SdkJSONEncoder", "Model", "rest_field", "rest_discriminator"] TZ_UTC = timezone.utc _T = typing.TypeVar("_T") +_NONE_TYPE = type(None) def _timedelta_as_isostr(td: timedelta) -> str: @@ -171,6 +177,21 @@ def default(self, o): # pylint: disable=too-many-return-statements r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT" ) +_ARRAY_ENCODE_MAPPING = { + "pipeDelimited": "|", + "spaceDelimited": " ", + "commaDelimited": ",", + "newlineDelimited": "\n", +} + + +def _deserialize_array_encoded(delimit: str, attr): + if isinstance(attr, str): + if attr == "": + return [] + return attr.split(delimit) + return attr + def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: """Deserialize ISO-8601 formatted string into Datetime object. @@ -202,7 +223,7 @@ def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: test_utc = date_obj.utctimetuple() if test_utc.tm_year > 9999 or test_utc.tm_year < 1: raise OverflowError("Hit max or min date") - return date_obj + return date_obj # type: ignore[no-any-return] def _deserialize_datetime_rfc7231(attr: typing.Union[str, datetime]) -> datetime: @@ -256,7 +277,7 @@ def _deserialize_time(attr: typing.Union[str, time]) -> time: """ if isinstance(attr, time): return attr - return isodate.parse_time(attr) + return isodate.parse_time(attr) # type: ignore[no-any-return] def _deserialize_bytes(attr): @@ -315,6 +336,8 @@ def _deserialize_int_as_str(attr): def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): if annotation is int and rf and rf._format == "str": return _deserialize_int_as_str + if annotation is str and rf and rf._format in _ARRAY_ENCODE_MAPPING: + return functools.partial(_deserialize_array_encoded, _ARRAY_ENCODE_MAPPING[rf._format]) if rf and rf._format: return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore @@ -353,9 +376,39 @@ def __contains__(self, key: typing.Any) -> bool: return key in self._data def __getitem__(self, key: str) -> typing.Any: + # If this key has been deserialized (for mutable types), we need to handle serialization + if hasattr(self, "_attr_to_rest_field"): + cache_attr = f"_deserialized_{key}" + if hasattr(self, cache_attr): + rf = _get_rest_field(getattr(self, "_attr_to_rest_field"), key) + if rf: + value = self._data.get(key) + if isinstance(value, (dict, list, set)): + # For mutable types, serialize and return + # But also update _data with serialized form and clear flag + # so mutations via this returned value affect _data + serialized = _serialize(value, rf._format) + # If serialized form is same type (no transformation needed), + # return _data directly so mutations work + if isinstance(serialized, type(value)) and serialized == value: + return self._data.get(key) + # Otherwise return serialized copy and clear flag + try: + object.__delattr__(self, cache_attr) + except AttributeError: + pass + # Store serialized form back + self._data[key] = serialized + return serialized return self._data.__getitem__(key) def __setitem__(self, key: str, value: typing.Any) -> None: + # Clear any cached deserialized value when setting through dictionary access + cache_attr = f"_deserialized_{key}" + try: + object.__delattr__(self, cache_attr) + except AttributeError: + pass self._data.__setitem__(key, value) def __delitem__(self, key: str) -> None: @@ -467,6 +520,8 @@ def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: return self._data.setdefault(key, default) def __eq__(self, other: typing.Any) -> bool: + if isinstance(other, _MyMutableMapping): + return self._data == other._data try: other_model = self.__class__(other) except Exception: @@ -483,6 +538,8 @@ def _is_model(obj: typing.Any) -> bool: def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements if isinstance(o, list): + if format in _ARRAY_ENCODE_MAPPING and all(isinstance(x, str) for x in o): + return _ARRAY_ENCODE_MAPPING[format].join(o) return [_serialize(x, format) for x in o] if isinstance(o, dict): return {k: _serialize(v, format) for k, v in o.items()} @@ -533,6 +590,239 @@ def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typin return _serialize(value, rf._format) +# ============================================================================ +# Fast-path scalar deserializer functions for rest_field(deserializer=...) +# These are referenced from rest_field declarations to bypass the generic +# _deserialize -> _deserialize_with_callable chain. +# Only simple/primitive types — no models or container types. +# ============================================================================ + + +def _xml_deser_str(value): + if isinstance(value, ET.Element): + return value.text or "" + return str(value) if value is not None else None + + +def _xml_deser_int(value): + if isinstance(value, ET.Element): + return int(value.text) if value.text else None + return int(value) if value is not None else None + + +def _xml_deser_float(value): + if isinstance(value, ET.Element): + return float(value.text) if value.text else None + return float(value) if value is not None else None + + +def _xml_deser_bool(value): + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + if text in (True, False): + return text + return text.lower() == "true" + + +# pylint: disable=docstring-missing-param +def _xml_deser_bytes(value): + """Deserialize bytes from XML (base64).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_bytes(text) + + +def _xml_deser_bytes_base64url(value): + """Deserialize bytes from XML (base64url).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_bytes_base64(text) + + +def _xml_deser_datetime(value): + """Deserialize a datetime from XML (ISO 8601 / rfc3339).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime(text) + + +def _xml_deser_datetime_rfc7231(value): + """Deserialize a datetime from XML (RFC7231 format).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime_rfc7231(text) + + +def _xml_deser_datetime_unix_timestamp(value): + """Deserialize a datetime from XML (Unix timestamp).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_datetime_unix_timestamp(float(text)) + + +def _xml_deser_date(value): + """Deserialize a date from XML (ISO 8601).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_date(text) + + +def _xml_deser_time(value): + """Deserialize a time from XML (ISO 8601).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_time(text) + + +def _xml_deser_duration(value): + """Deserialize a timedelta from XML (ISO 8601 duration).""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_duration(text) + + +def _xml_deser_decimal(value): + """Deserialize a Decimal from XML.""" + if isinstance(value, ET.Element): + text = value.text + else: + text = value + if text is None: + return None + return _deserialize_decimal(text) + + +def _xml_deser_enum_or_str(enum_cls, value): + """Deserialize a Union[EnumType, str] from XML.""" + text = value.text if isinstance(value, ET.Element) else value + if text is None: + return None + try: + return enum_cls(text) + except ValueError: + return text + + +def _extract_xml_model_type(rf_type): + """Extract the concrete Model class from a resolved rf._type partial chain. + + Unwraps ``Optional[Model]`` and ``_deserialize_model(Model, ...)`` + wrappers. Only handles Model and Optional[Model] — other composite + types (List, Dict, Union, etc.) return None and fall through to the + generic ``_deserialize`` path at runtime. + """ + if rf_type is None: + return None + if isinstance(rf_type, type) and _is_model(rf_type): + return rf_type + if not isinstance(rf_type, functools.partial): + return None + func = rf_type.func + args = rf_type.args + if func is _deserialize_with_optional and args: + return _extract_xml_model_type(args[0]) + if func is _deserialize_model and args: + cls = args[0] + return cls if isinstance(cls, type) and _is_model(cls) else None + return None + + +def _build_xml_field_plan( # pylint: disable=docstring-missing-return, docstring-missing-rtype, unused-variable + cls, attr_to_rest_field: dict +) -> list: + """Build a precomputed XML field plan for fast _init_from_xml iteration. + + Called once per model class in __new__. Returns a list of tuples: + (rest_name, xml_name, kind, deser, rf_type, is_optional, items_name) + + kind: 0=wrapped, 1=attribute, 2=unwrapped, 3=text + + For Model and Optional[Model] fields that lack a scalar + ``_deserializer``, this function precomputes the Model class as the + deserializer so ``_init_from_xml`` can call ``ModelClass(element)`` + directly instead of going through the expensive + ``_get_deserialize_callable_from_annotation`` chain at runtime. + """ + model_meta = getattr(cls, "_xml", {}) + model_ns = model_meta.get("ns") or model_meta.get("namespace") + plan = [] + + for rf in attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + deser = rf._deserializer + + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + is_optional = rf._is_optional + + # For Model / Optional[Model] fields without a scalar deserializer, + # precompute the Model class as the deserializer. + if deser is None and rf._type is not None: + model_cls = _extract_xml_model_type(rf._type) + if model_cls is not None: + deser = model_cls + + if prop_meta.get("attribute", False): + plan.append((rf._rest_name, xml_name, 1, deser, rf._type, is_optional, None)) + elif prop_meta.get("unwrapped", False): + items_name = prop_meta.get("itemsName") + if items_name: + items_ns = prop_meta.get("itemsNs") + if items_ns is not None: + xml_ns = items_ns + if xml_ns: + items_name = "{" + xml_ns + "}" + items_name + else: + items_name = xml_name + plan.append((rf._rest_name, xml_name, 2, deser, rf._type, is_optional, items_name)) + elif prop_meta.get("text", False): + plan.append((rf._rest_name, xml_name, 3, deser, rf._type, is_optional, None)) + else: + plan.append((rf._rest_name, xml_name, 0, deser, rf._type, is_optional, None)) + + return plan + + +# pylint: enable=docstring-missing-param class Model(_MyMutableMapping): _is_model = True # label whether current class's _attr_to_rest_field has been calculated @@ -543,59 +833,10 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: class_name = self.__class__.__name__ if len(args) > 1: raise TypeError(f"{class_name}.__init__() takes 2 positional arguments but {len(args) + 1} were given") - dict_to_pass = { - rest_field._rest_name: rest_field._default - for rest_field in self._attr_to_rest_field.values() - if rest_field._default is not _UNSET - } - if args: # pylint: disable=too-many-nested-blocks + dict_to_pass: dict[str, typing.Any] = {} + if args: if isinstance(args[0], ET.Element): - existed_attr_keys = [] - model_meta = getattr(self, "_xml", {}) - - for rf in self._attr_to_rest_field.values(): - prop_meta = getattr(rf, "_xml", {}) - xml_name = prop_meta.get("name", rf._rest_name) - xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) - if xml_ns: - xml_name = "{" + xml_ns + "}" + xml_name - - # attribute - if prop_meta.get("attribute", False) and args[0].get(xml_name) is not None: - existed_attr_keys.append(xml_name) - dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].get(xml_name)) - continue - - # unwrapped element is array - if prop_meta.get("unwrapped", False): - # unwrapped array could either use prop items meta/prop meta - if prop_meta.get("itemsName"): - xml_name = prop_meta.get("itemsName") - xml_ns = prop_meta.get("itemNs") - if xml_ns: - xml_name = "{" + xml_ns + "}" + xml_name - items = args[0].findall(xml_name) # pyright: ignore - if len(items) > 0: - existed_attr_keys.append(xml_name) - dict_to_pass[rf._rest_name] = _deserialize(rf._type, items) - continue - - # text element is primitive type - if prop_meta.get("text", False): - if args[0].text is not None: - dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].text) - continue - - # wrapped element could be normal property or array, it should only have one element - item = args[0].find(xml_name) - if item is not None: - existed_attr_keys.append(xml_name) - dict_to_pass[rf._rest_name] = _deserialize(rf._type, item) - - # rest thing is additional properties - for e in args[0]: - if e.tag not in existed_attr_keys: - dict_to_pass[e.tag] = _convert_element(e) + dict_to_pass.update(self._init_from_xml(args[0])) else: dict_to_pass.update( {k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()} @@ -612,8 +853,117 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: if v is not None } ) + # Apply client default values for fields the caller didn't set so that + # defaults are part of `_data` and therefore included during serialization. + for rf in self._attr_to_rest_field.values(): + if rf._default is _UNSET: + continue + if rf._rest_name in dict_to_pass: + continue + dict_to_pass[rf._rest_name] = _create_value(rf, rf._default) super().__init__(dict_to_pass) + def _init_from_xml( # pylint: disable=too-many-branches, too-many-statements + self, element: ET.Element + ) -> dict[str, typing.Any]: + """Deserialize an XML element into a dict mapping rest field names to values. + + :param ET.Element element: The XML element to deserialize from. + :returns: A dictionary of rest_name to deserialized value pairs. + :rtype: dict + """ + result: dict[str, typing.Any] = {} + existed_attr_keys: list[str] = [] + + field_plan = getattr(self, "_xml_field_plan", None) + if field_plan: + for rest_name, xml_name, kind, deser, rf_type, is_optional, items_name in field_plan: + if kind == 0: # wrapped element (most common) + item = element.find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + if deser: + result[rest_name] = deser(item) + else: + result[rest_name] = _deserialize(rf_type, item) + elif kind == 1: # attribute + attr_val = element.get(xml_name) + if attr_val is not None: + existed_attr_keys.append(xml_name) + if deser: + result[rest_name] = deser(attr_val) + else: + result[rest_name] = attr_val + elif kind == 2: # unwrapped array + items = element.findall(items_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(items_name) + if deser: + result[rest_name] = deser(items) + else: + result[rest_name] = _deserialize(rf_type, items) + elif not is_optional: + existed_attr_keys.append(items_name) + result[rest_name] = [] + elif kind == 3: # text + if element.text is not None: + if deser: + result[rest_name] = deser(element.text) + else: + result[rest_name] = element.text + else: + model_meta = getattr(self, "_xml", {}) + for rf in self._attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + # attribute + if prop_meta.get("attribute", False) and element.get(xml_name) is not None: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, element.get(xml_name)) + continue + + # unwrapped element is array + if prop_meta.get("unwrapped", False): + _items_name = prop_meta.get("itemsName") + if _items_name: + xml_name = _items_name + _items_ns = prop_meta.get("itemsNs") + if _items_ns is not None: + xml_ns = _items_ns + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + items = element.findall(xml_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, items) + elif not rf._is_optional: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = [] + continue + + # text element is primitive type + if prop_meta.get("text", False): + if element.text is not None: + result[rf._rest_name] = _deserialize(rf._type, element.text) + continue + + # wrapped element could be normal property or array + item = element.find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + result[rf._rest_name] = _deserialize(rf._type, item) + + # rest thing is additional properties + for e in element: + if e.tag not in existed_attr_keys: + result[e.tag] = _convert_element(e) + + return result + def copy(self) -> "Model": return Model(self.__dict__) @@ -638,6 +988,13 @@ def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: if not rf._rest_name_input: rf._rest_name_input = attr cls._attr_to_rest_field: dict[str, _RestField] = dict(attr_to_rest_field.items()) + cls._backcompat_attr_to_rest_field: dict[str, _RestField] = { + Model._get_backcompat_attribute_name(cls._attr_to_rest_field, attr): rf + for attr, rf in cls._attr_to_rest_field.items() + } + # Build XML field plan for fast _init_from_xml (only for XML models) + if getattr(cls, "_xml", None): + cls._xml_field_plan = _build_xml_field_plan(cls, attr_to_rest_field) cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}") return super().__new__(cls) @@ -647,6 +1004,16 @@ def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None: if hasattr(base, "__mapping__"): base.__mapping__[discriminator or cls.__name__] = cls # type: ignore + @classmethod + def _get_backcompat_attribute_name(cls, attr_to_rest_field: dict[str, "_RestField"], attr_name: str) -> str: + rest_field_obj = attr_to_rest_field.get(attr_name) # pylint: disable=protected-access + if rest_field_obj is None: + return attr_name + original_tsp_name = getattr(rest_field_obj, "_original_tsp_name", None) # pylint: disable=protected-access + if original_tsp_name: + return original_tsp_name + return attr_name + @classmethod def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField"]: for v in cls.__dict__.values(): @@ -666,7 +1033,7 @@ def _deserialize(cls, data, exist_discriminators): model_meta = getattr(cls, "_xml", {}) prop_meta = getattr(discriminator, "_xml", {}) xml_name = prop_meta.get("name", discriminator._rest_name) - xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) + xml_ns = _resolve_xml_ns(prop_meta, model_meta) if xml_ns: xml_name = "{" + xml_ns + "}" + xml_name @@ -758,6 +1125,14 @@ def _deserialize_multiple_sequence( return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers)) +def _is_array_encoded_deserializer(deserializer: functools.partial) -> bool: + return ( + isinstance(deserializer, functools.partial) + and isinstance(deserializer.args[0], functools.partial) + and deserializer.args[0].func == _deserialize_array_encoded # pylint: disable=comparison-with-callable + ) + + def _deserialize_sequence( deserializer: typing.Optional[typing.Callable], module: typing.Optional[str], @@ -767,6 +1142,19 @@ def _deserialize_sequence( return obj if isinstance(obj, ET.Element): obj = list(obj) + + # encoded string may be deserialized to sequence + if isinstance(obj, str) and isinstance(deserializer, functools.partial): + # for list[str] + if _is_array_encoded_deserializer(deserializer): + return deserializer(obj) + + # for list[Union[...]] + if isinstance(deserializer.args[0], list): + for sub_deserializer in deserializer.args[0]: + if _is_array_encoded_deserializer(sub_deserializer): + return sub_deserializer(obj) + return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) @@ -817,16 +1205,18 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur # is it optional? try: - if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore # pylint: disable=unidiomatic-typecheck + if any(a is _NONE_TYPE for a in annotation.__args__): # pyright: ignore + if rf: + rf._is_optional = True 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 # pylint: disable=unidiomatic-typecheck + next(a for a in annotation.__args__ if a is not _NONE_TYPE), 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 # pylint: disable=unidiomatic-typecheck + annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a is not _NONE_TYPE] # pyright: ignore return _get_deserialize_callable_from_annotation(annotation_copy, module, rf) except AttributeError: pass @@ -910,16 +1300,20 @@ def _deserialize_with_callable( return float(value.text) if value.text else None if deserializer is bool: return value.text == "true" if value.text else None + if deserializer and deserializer in _DESERIALIZE_MAPPING.values(): + return deserializer(value.text) if value.text else None + if deserializer and deserializer in _DESERIALIZE_MAPPING_WITHFORMAT.values(): + return deserializer(value.text) if value.text else None if deserializer is None: return value if deserializer in [int, float, bool]: return deserializer(value) if isinstance(deserializer, CaseInsensitiveEnumMeta): try: - return deserializer(value) + return deserializer(value.text if isinstance(value, ET.Element) else value) except ValueError: # for unknown value, return raw value - return value + return value.text if isinstance(value, ET.Element) else value if isinstance(deserializer, type) and issubclass(deserializer, Model): return deserializer._deserialize(value, []) return typing.cast(typing.Callable[[typing.Any], typing.Any], deserializer)(value) @@ -952,7 +1346,7 @@ def _failsafe_deserialize( ) -> typing.Any: try: return _deserialize(deserializer, response.json(), module, rf, format) - except DeserializationError: + except Exception: # pylint: disable=broad-except _LOGGER.warning( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True ) @@ -965,13 +1359,14 @@ def _failsafe_deserialize_xml( ) -> typing.Any: try: return _deserialize_xml(deserializer, response.text()) - except DeserializationError: + except Exception: # pylint: disable=broad-except _LOGGER.warning( "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True ) return None +# pylint: disable=too-many-instance-attributes class _RestField: def __init__( self, @@ -984,6 +1379,8 @@ def __init__( format: typing.Optional[str] = None, is_multipart_file_input: bool = False, xml: typing.Optional[dict[str, typing.Any]] = None, + deserializer: typing.Optional[typing.Callable] = None, + original_tsp_name: typing.Optional[str] = None, ): self._type = type self._rest_name_input = name @@ -991,14 +1388,21 @@ def __init__( self._is_discriminator = is_discriminator self._visibility = visibility self._is_model = False + self._is_optional = False self._default = default self._format = format self._is_multipart_file_input = is_multipart_file_input self._xml = xml if xml is not None else {} + self._deserializer = deserializer + self._original_tsp_name = original_tsp_name @property def _class_type(self) -> typing.Any: - return getattr(self._type, "args", [None])[0] + result = getattr(self._type, "args", [None])[0] + # type may be wrapped by nested functools.partial so we need to check for that + if isinstance(result, functools.partial): + return getattr(result, "args", [None])[0] + return result @property def _rest_name(self) -> str: @@ -1009,14 +1413,44 @@ def _rest_name(self) -> str: def __get__(self, obj: Model, type=None): # pylint: disable=redefined-builtin # by this point, type and rest_name will have a value bc we default # them in __new__ of the Model class - item = obj.get(self._rest_name) + # Use _data.get() directly to avoid triggering __getitem__ which clears the cache + item = obj._data.get(self._rest_name, _UNSET) + if item is _UNSET: + # Field not set by user; return the client default if one exists, otherwise None + return self._default if self._default is not _UNSET else None if item is None: return item if self._is_model: return item - return _deserialize(self._type, _serialize(item, self._format), rf=self) + + # For mutable types, we want mutations to directly affect _data + # Check if we've already deserialized this value + cache_attr = f"_deserialized_{self._rest_name}" + if hasattr(obj, cache_attr): + # Return the value from _data directly (it's been deserialized in place) + return obj._data.get(self._rest_name) + + # Fast path: use _deserializer directly (avoids _serialize/_deserialize chain) + if self._deserializer: + deserialized = self._deserializer(item) + else: + deserialized = _deserialize(self._type, _serialize(item, self._format), rf=self) + + # For mutable types, store the deserialized value back in _data + # so mutations directly affect _data + if isinstance(deserialized, (dict, list, set)): + obj._data[self._rest_name] = deserialized + object.__setattr__(obj, cache_attr, True) # Mark as deserialized + return deserialized + + return deserialized def __set__(self, obj: Model, value) -> None: + # Clear the cached deserialized object when setting a new value + cache_attr = f"_deserialized_{self._rest_name}" + if hasattr(obj, cache_attr): + object.__delattr__(obj, cache_attr) + if value is None: # we want to wipe out entries if users set attr to None try: @@ -1046,6 +1480,8 @@ def rest_field( format: typing.Optional[str] = None, is_multipart_file_input: bool = False, xml: typing.Optional[dict[str, typing.Any]] = None, + deserializer: typing.Optional[typing.Callable] = None, + original_tsp_name: typing.Optional[str] = None, ) -> typing.Any: return _RestField( name=name, @@ -1055,6 +1491,8 @@ def rest_field( format=format, is_multipart_file_input=is_multipart_file_input, xml=xml, + deserializer=deserializer, + original_tsp_name=original_tsp_name, ) @@ -1079,6 +1517,56 @@ def serialize_xml(model: Model, exclude_readonly: bool = False) -> str: return ET.tostring(_get_element(model, exclude_readonly), encoding="unicode") # type: ignore +def _get_xml_ns(meta: dict[str, typing.Any]) -> typing.Optional[str]: + """Return the XML namespace from a metadata dict, checking both 'ns' (old-style) and 'namespace' (DPG) keys. + + :param dict meta: The metadata dictionary to extract namespace from. + :returns: The namespace string if 'ns' or 'namespace' key is present, None otherwise. + :rtype: str or None + """ + ns = meta.get("ns") + if ns is None: + ns = meta.get("namespace") + return ns + + +def _resolve_xml_ns( + prop_meta: dict[str, typing.Any], model_meta: typing.Optional[dict[str, typing.Any]] = None +) -> typing.Optional[str]: + """Resolve XML namespace for a property, falling back to model namespace when appropriate. + + Checks the property metadata first; if no namespace is found and the model does not declare + an explicit prefix, falls back to the model-level namespace. + + :param dict prop_meta: The property metadata dictionary. + :param dict model_meta: The model metadata dictionary, used as fallback. + :returns: The resolved namespace string, or None. + :rtype: str or None + """ + ns = _get_xml_ns(prop_meta) + if ns is None and model_meta is not None and not model_meta.get("prefix"): + ns = _get_xml_ns(model_meta) + return ns + + +def _set_xml_attribute(element: ET.Element, name: str, value: typing.Any, prop_meta: dict[str, typing.Any]) -> None: + """Set an XML attribute on an element, handling namespace prefix registration. + + :param ET.Element element: The element to set the attribute on. + :param str name: The default attribute name (wire name). + :param any value: The attribute value. + :param dict prop_meta: The property metadata dictionary. + """ + xml_name = prop_meta.get("name", name) + _attr_ns = _get_xml_ns(prop_meta) + if _attr_ns: + _attr_prefix = prop_meta.get("prefix") + if _attr_prefix: + _safe_register_namespace(_attr_prefix, _attr_ns) + xml_name = "{" + _attr_ns + "}" + xml_name + element.set(xml_name, _get_primitive_type_value(value)) + + def _get_element( o: typing.Any, exclude_readonly: bool = False, @@ -1090,10 +1578,16 @@ def _get_element( # if prop is a model, then use the prop element directly, else generate a wrapper of model if wrapped_element is None: + # When serializing as an array item (parent_meta is set), check if the parent has an + # explicit itemsName. This ensures correct element names for unwrapped arrays (where + # the element tag is the property/items name, not the model type name). + _items_name = parent_meta.get("itemsName") if parent_meta is not None else None + element_name = _items_name if _items_name else (model_meta.get("name") or o.__class__.__name__) + _model_ns = _get_xml_ns(model_meta) wrapped_element = _create_xml_element( - model_meta.get("name", o.__class__.__name__), + element_name, model_meta.get("prefix"), - model_meta.get("ns"), + _model_ns, ) readonly_props = [] @@ -1115,7 +1609,9 @@ def _get_element( # additional properties will not have rest field, use the wire name as xml name prop_meta = {"name": k} - # if no ns for prop, use model's + # Propagate model namespace to properties only for old-style "ns"-keyed models. + # DPG-generated models use the "namespace" key and explicitly declare namespace on + # each property that needs it, so propagation is intentionally skipped for them. if prop_meta.get("ns") is None and model_meta.get("ns"): prop_meta["ns"] = model_meta.get("ns") prop_meta["prefix"] = model_meta.get("prefix") @@ -1127,12 +1623,7 @@ def _get_element( # text could only set on primitive type wrapped_element.text = _get_primitive_type_value(v) elif prop_meta.get("attribute", False): - xml_name = prop_meta.get("name", k) - if prop_meta.get("ns"): - ET.register_namespace(prop_meta.get("prefix"), prop_meta.get("ns")) # pyright: ignore - xml_name = "{" + prop_meta.get("ns") + "}" + xml_name # pyright: ignore - # attribute should be primitive type - wrapped_element.set(xml_name, _get_primitive_type_value(v)) + _set_xml_attribute(wrapped_element, k, v, prop_meta) else: # other wrapped prop element wrapped_element.append(_get_wrapped_element(v, exclude_readonly, prop_meta)) @@ -1141,6 +1632,7 @@ def _get_element( return [_get_element(x, exclude_readonly, parent_meta) for x in o] # type: ignore if isinstance(o, dict): result = [] + _dict_ns = _get_xml_ns(parent_meta) if parent_meta else None for k, v in o.items(): result.append( _get_wrapped_element( @@ -1148,7 +1640,7 @@ def _get_element( exclude_readonly, { "name": k, - "ns": parent_meta.get("ns") if parent_meta else None, + "ns": _dict_ns, "prefix": parent_meta.get("prefix") if parent_meta else None, }, ) @@ -1157,13 +1649,16 @@ def _get_element( # primitive case need to create element based on parent_meta if parent_meta: + _items_ns = parent_meta.get("itemsNs") + if _items_ns is None: + _items_ns = _get_xml_ns(parent_meta) return _get_wrapped_element( o, exclude_readonly, { "name": parent_meta.get("itemsName", parent_meta.get("name")), "prefix": parent_meta.get("itemsPrefix", parent_meta.get("prefix")), - "ns": parent_meta.get("itemsNs", parent_meta.get("ns")), + "ns": _items_ns, }, ) @@ -1175,8 +1670,9 @@ def _get_wrapped_element( exclude_readonly: bool, meta: typing.Optional[dict[str, typing.Any]], ) -> ET.Element: + _meta_ns = _get_xml_ns(meta) if meta else None wrapped_element = _create_xml_element( - meta.get("name") if meta else None, meta.get("prefix") if meta else None, meta.get("ns") if meta else None + meta.get("name") if meta else None, meta.get("prefix") if meta else None, _meta_ns ) if isinstance(v, (dict, list)): wrapped_element.extend(_get_element(v, exclude_readonly, meta)) @@ -1184,7 +1680,7 @@ def _get_wrapped_element( _get_element(v, exclude_readonly, meta, wrapped_element) else: wrapped_element.text = _get_primitive_type_value(v) - return wrapped_element + return wrapped_element # type: ignore[no-any-return] def _get_primitive_type_value(v) -> str: @@ -1197,9 +1693,29 @@ def _get_primitive_type_value(v) -> str: return str(v) -def _create_xml_element(tag, prefix=None, ns=None): - if prefix and ns: +def _safe_register_namespace(prefix: str, ns: str) -> None: + """Register an XML namespace prefix, handling reserved prefix patterns. + + Some prefixes (e.g. 'ns2') match Python's reserved 'ns\\d+' pattern used for + auto-generated prefixes, causing register_namespace to raise ValueError. + Falls back to directly registering in the internal namespace map. + + :param str prefix: The namespace prefix to register. + :param str ns: The namespace URI. + """ + try: ET.register_namespace(prefix, ns) + except ValueError: + _ns_map = getattr(ET, "_namespace_map", None) + if _ns_map is not None: + _ns_map[ns] = prefix + + +def _create_xml_element( + tag: typing.Any, prefix: typing.Optional[str] = None, ns: typing.Optional[str] = None +) -> ET.Element: + if prefix and ns: + _safe_register_namespace(prefix, ns) if ns: return ET.Element("{" + ns + "}" + tag) return ET.Element(tag) @@ -1210,6 +1726,8 @@ def _deserialize_xml( value: str, ) -> typing.Any: element = ET.fromstring(value) # nosec + if _is_model(deserializer): + return deserializer._deserialize(element, []) return _deserialize(deserializer, element) diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/serialization.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/serialization.py index 45a3e44e45cb..a088671e9c51 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/serialization.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_utils/serialization.py @@ -39,11 +39,15 @@ import xml.etree.ElementTree as ET import isodate # type: ignore -from typing_extensions import Self from azure.core.exceptions import DeserializationError, SerializationError from azure.core.serialization import NULL as CoreNull +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + _BOM = codecs.BOM_UTF8.decode(encoding="utf-8") JSON = MutableMapping[str, Any] @@ -821,13 +825,20 @@ def serialize_basic(cls, data, data_type, **kwargs): :param str data_type: Type of object in the iterable. :rtype: str, int, float, bool :return: serialized object + :raises TypeError: raise if data_type is not one of str, int, float, bool. """ custom_serializer = cls._get_custom_serializers(data_type, **kwargs) if custom_serializer: return custom_serializer(data) if data_type == "str": return cls.serialize_unicode(data) - return eval(data_type)(data) # nosec # pylint: disable=eval-used + if data_type == "int": + return int(data) + if data_type == "float": + return float(data) + if data_type == "bool": + return bool(data) + raise TypeError("Unknown basic data type: {}".format(data_type)) @classmethod def serialize_unicode(cls, data): @@ -1394,7 +1405,7 @@ def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: # Otherwise, result are unexpected self.additional_properties_detection = True - def __call__(self, target_obj, response_data, content_type=None): + def __call__(self, target_obj, response_data, content_type=None): # pylint: disable=too-many-return-statements """Call the deserializer to process a REST response. :param str target_obj: Target data type to deserialize to. @@ -1404,6 +1415,27 @@ def __call__(self, target_obj, response_data, content_type=None): :return: Deserialized object. :rtype: object """ + # Fast path for header deserialization: response_data is a plain str or None + # and target_obj is a simple scalar type. This avoids the expensive + # _unpack_content → _deserialize → _classify_target → deserialize_data chain. + if response_data is None: + return None + if target_obj == "str" and isinstance(response_data, str): + return response_data + if isinstance(response_data, str): + if target_obj == "int": + return int(response_data) + if target_obj == "bool": + if response_data in ("true", "1", "True"): + return True + if response_data in ("false", "0", "False"): + return False + return bool(response_data) + if target_obj == "rfc-1123": + return Deserializer.deserialize_rfc(response_data) + if target_obj == "bytearray": + return Deserializer.deserialize_bytearray(response_data) + data = self._unpack_content(response_data, content_type) return self._deserialize(target_obj, data) @@ -1757,7 +1789,7 @@ def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return :param str data_type: deserialization data type. :return: Deserialized basic type. :rtype: str, int, float or bool - :raises TypeError: if string format is not valid. + :raises TypeError: if string format is not valid or data_type is not one of str, int, float, bool. """ # If we're here, data is supposed to be a basic type. # If it's still an XML node, take the text @@ -1783,7 +1815,11 @@ def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return if data_type == "str": return self.deserialize_unicode(attr) - return eval(data_type)(attr) # nosec # pylint: disable=eval-used + if data_type == "int": + return int(attr) + if data_type == "float": + return float(attr) + raise TypeError("Unknown basic data type: {}".format(data_type)) @staticmethod def deserialize_unicode(data): diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_validation.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_validation.py new file mode 100644 index 000000000000..f5af3a4eb8a2 --- /dev/null +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_validation.py @@ -0,0 +1,66 @@ +# -------------------------------------------------------------------------- +# 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", "") + api_versions_list = kwargs.pop("api_versions_list", []) + + def _index_with_default(value: str, default: int = -1) -> int: + """Get the index of value in lst, or return default if not found. + + :param value: The value to search for in the api_versions_list. + :type value: str + :param default: The default value to return if the value is not found. + :type default: int + :return: The index of the value in the list, or the default value if not found. + :rtype: int + """ + try: + return api_versions_list.index(value) + except ValueError: + return default + + 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 _index_with_default(method_added_on) > _index_with_default(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 _index_with_default(api_version) > _index_with_default(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/confidentialledger/azure-confidentialledger/azure/confidentialledger/_version.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_version.py index 2e7efc3e2e20..8f2350dd3b0c 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_version.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/_version.py @@ -6,4 +6,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "2.0.0b3" +VERSION = "2.0.0" diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_client.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_client.py index 7e465fb3869c..f0e9e03db253 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_client.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_client.py @@ -7,18 +7,22 @@ # -------------------------------------------------------------------------- from copy import deepcopy +import sys from typing import Any, Awaitable -from typing_extensions import Self from azure.core import AsyncPipelineClient from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._redirect_caching_policy import AsyncRedirectCachingPolicy from .._utils.serialization import Deserializer, Serializer from ._configuration import ConfidentialLedgerClientConfiguration from ._operations import _ConfidentialLedgerClientOperationsMixin +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # type: ignore + class ConfidentialLedgerClient(_ConfidentialLedgerClientOperationsMixin): """Write and retrieve ledger entries against the Confidential Ledger service. @@ -27,9 +31,9 @@ class ConfidentialLedgerClient(_ConfidentialLedgerClientOperationsMixin): `https://contoso.confidentialledger.azure.com `_. Required. :type ledger_endpoint: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-12-09-preview". Note that overriding this default value may result in unsupported - behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-02-23" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ @@ -47,15 +51,13 @@ def __init__( # pylint: disable=missing-client-constructor-parameter-credential self._config.user_agent_policy, self._config.proxy_policy, policies.ContentDecodePolicy(**kwargs), - kwargs.get("redirect_policy") or AsyncRedirectCachingPolicy(**kwargs), + self._config.redirect_policy, self._config.retry_policy, self._config.authentication_policy, self._config.custom_hook_policy, self._config.logging_policy, policies.DistributedTracingPolicy(**kwargs), - policies.SensitiveHeaderCleanupPolicy( - disable_redirect_cleanup=True, **kwargs - ) if self._config.redirect_policy else None, + policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, self._config.http_logging_policy, ] self._client: AsyncPipelineClient = AsyncPipelineClient(base_url=_endpoint, policies=_policies, **kwargs) diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_configuration.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_configuration.py index 19fde80839b2..ceef61606532 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_configuration.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_configuration.py @@ -23,14 +23,14 @@ class ConfidentialLedgerClientConfiguration: # pylint: disable=too-many-instanc `https://contoso.confidentialledger.azure.com `_. Required. :type ledger_endpoint: str - :keyword api_version: The API version to use for this operation. Default value is - "2024-12-09-preview". Note that overriding this default value may result in unsupported - behavior. + :keyword api_version: The API version to use for this operation. Known values are "2026-02-23" + and None. Default value is None. If not set, the operation's default API version will be used. + Note that overriding this default value may result in unsupported behavior. :paramtype api_version: str """ def __init__(self, ledger_endpoint: str, **kwargs: Any) -> None: - api_version: str = kwargs.pop("api_version", "2024-12-09-preview") + api_version: str = kwargs.pop("api_version", "2026-02-23") if ledger_endpoint is None: raise ValueError("Parameter 'ledger_endpoint' must not be None.") diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_operations/_operations.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_operations/_operations.py index 92a2e38e0703..50f2155730d9 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_operations/_operations.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_operations/_operations.py @@ -37,10 +37,10 @@ build_confidential_ledger_create_or_update_user_request, build_confidential_ledger_create_user_defined_endpoint_request, build_confidential_ledger_create_user_defined_function_request, - build_confidential_ledger_create_user_defined_role_request, + build_confidential_ledger_create_user_defined_role_stable_request, build_confidential_ledger_delete_ledger_user_request, build_confidential_ledger_delete_user_defined_function_request, - build_confidential_ledger_delete_user_defined_role_request, + build_confidential_ledger_delete_user_defined_role_stable_request, build_confidential_ledger_delete_user_request, build_confidential_ledger_execute_user_defined_function_request, build_confidential_ledger_get_constitution_request, @@ -60,13 +60,15 @@ build_confidential_ledger_list_consortium_members_request, build_confidential_ledger_list_ledger_entries_request, build_confidential_ledger_list_ledger_users_request, + build_confidential_ledger_list_tags_request, build_confidential_ledger_list_user_defined_functions_request, build_confidential_ledger_list_users_request, - build_confidential_ledger_update_runtime_options_request, - build_confidential_ledger_update_user_defined_role_request, + build_confidential_ledger_update_runtime_options_stable_request, + build_confidential_ledger_update_user_defined_role_stable_request, ) from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize from ..._utils.utils import ClientMixinABC +from ..._validation import api_version_validation from .._configuration import ConfidentialLedgerClientConfiguration JSON = MutableMapping[str, Any] @@ -82,8 +84,7 @@ class _ConfidentialLedgerClientOperationsMixin( # pylint: disable=too-many-publ async def get_constitution(self, **kwargs: Any) -> _models.Constitution: """Gets the constitution used for governance. - The constitution is a script that assesses and applies proposals from - consortium members. + The constitution is a script that assesses and applies proposals from consortium members. :return: Constitution. The Constitution is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.Constitution @@ -114,6 +115,7 @@ async def get_constitution(self, **kwargs: Any) -> _models.Constitution: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -128,11 +130,14 @@ async def get_constitution(self, **kwargs: Any) -> _models.Constitution: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.Constitution, response.json()) @@ -191,7 +196,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -204,7 +212,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.ConsortiumMember], deserialized.get("members", [])) + list_of_elem = _deserialize( + list[_models.ConsortiumMember], + deserialized.get("members", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -220,7 +231,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -231,8 +245,8 @@ async def get_next(next_link=None): async def get_enclave_quotes(self, **kwargs: Any) -> _models.ConfidentialLedgerEnclaves: """Gets quotes for all nodes of the Confidential Ledger. - A quote is an SGX enclave measurement that can be used to verify the validity - of a node and its enclave. + A quote is an SGX enclave measurement that can be used to verify the validity of a node and its + enclave. :return: ConfidentialLedgerEnclaves. The ConfidentialLedgerEnclaves is compatible with MutableMapping @@ -264,6 +278,7 @@ async def get_enclave_quotes(self, **kwargs: Any) -> _models.ConfidentialLedgerE } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -278,11 +293,14 @@ async def get_enclave_quotes(self, **kwargs: Any) -> _models.ConfidentialLedgerE except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ConfidentialLedgerEnclaves, response.json()) @@ -340,7 +358,112 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, + ) + path_format_arguments = { + "ledgerEndpoint": self._serialize.url( + "self._config.ledger_endpoint", self._config.ledger_endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + list[_models.Collection], + deserialized.get("collections", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + _request = prepare_request(next_link) + + _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) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + @distributed_trace + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "collection_id", "accept"]}, + api_versions_list=["2026-02-23"], + ) + def list_tags(self, *, collection_id: Optional[str] = None, **kwargs: Any) -> AsyncItemPaged[str]: + """Gets a list of tags for a collection. + + Retrieves the tags associated with a collection. + + :keyword collection_id: The collection id. Default value is None. + :paramtype collection_id: str + :return: An iterator like instance of str + :rtype: ~azure.core.async_paging.AsyncItemPaged[str] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[list[str]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(next_link=None): + if not next_link: + + _request = build_confidential_ledger_list_tags_request( + collection_id=collection_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "ledgerEndpoint": self._serialize.url( + "self._config.ledger_endpoint", self._config.ledger_endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -353,7 +476,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.Collection], deserialized.get("collections", [])) + list_of_elem = _deserialize( + list[str], + deserialized.get("tags", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -369,7 +495,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -388,8 +517,8 @@ def list_ledger_entries( ) -> AsyncItemPaged["_models.LedgerEntry"]: """Gets ledger entries from a collection corresponding to a range. - A collection id may optionally be specified. Only entries in the specified (or - default) collection will be returned. + A collection id may optionally be specified. Only entries in the specified (or default) + collection will be returned. :keyword collection_id: The collection id. Default value is None. :paramtype collection_id: str @@ -447,7 +576,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -460,7 +592,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.LedgerEntry], deserialized.get("entries", [])) + list_of_elem = _deserialize( + list[_models.LedgerEntry], + deserialized.get("entries", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -476,7 +611,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -628,6 +766,7 @@ async def create_ledger_entry( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -642,7 +781,10 @@ async def create_ledger_entry( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) response_headers = {} @@ -651,7 +793,7 @@ async def create_ledger_entry( ) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerWriteResult, response.json()) @@ -664,14 +806,12 @@ async def create_ledger_entry( async def get_ledger_entry( self, transaction_id: str, *, collection_id: Optional[str] = None, **kwargs: Any ) -> _models.LedgerQueryResult: - """Gets the ledger entry at the specified transaction id. A collection id may - optionally be specified to indicate the collection from which to fetch the - value. + """Gets the ledger entry at the specified transaction id. A collection id may optionally be + specified to indicate the collection from which to fetch the value. - To return older ledger entries, the relevant sections of the ledger must be - read from disk and validated. To prevent blocking within the enclave, the - response will indicate whether the entry is ready and part of the response, or - if the loading is still ongoing. + To return older ledger entries, the relevant sections of the ledger must be read from disk and + validated. To prevent blocking within the enclave, the response will indicate whether the entry + is ready and part of the response, or if the loading is still ongoing. :param transaction_id: Identifies a write transaction. Required. :type transaction_id: str @@ -708,6 +848,7 @@ async def get_ledger_entry( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -722,11 +863,14 @@ async def get_ledger_entry( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerQueryResult, response.json()) @@ -773,6 +917,7 @@ async def get_receipt(self, transaction_id: str, **kwargs: Any) -> _models.Trans } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -787,11 +932,14 @@ async def get_receipt(self, transaction_id: str, **kwargs: Any) -> _models.Trans except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.TransactionReceipt, response.json()) @@ -838,6 +986,7 @@ async def get_transaction_status(self, transaction_id: str, **kwargs: Any) -> _m } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -852,11 +1001,14 @@ async def get_transaction_status(self, transaction_id: str, **kwargs: Any) -> _m except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.TransactionStatus, response.json()) @@ -905,6 +1057,7 @@ async def get_current_ledger_entry( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -919,11 +1072,14 @@ async def get_current_ledger_entry( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerEntry, response.json()) @@ -981,7 +1137,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -994,7 +1153,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.LedgerUser], deserialized.get("ledgerUsers", [])) + list_of_elem = _deserialize( + list[_models.LedgerUser], + deserialized.get("ledgerUsers", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -1010,7 +1172,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1067,7 +1232,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -1080,7 +1248,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.LedgerUserMultipleRoles], deserialized.get("ledgerUsers", [])) + list_of_elem = _deserialize( + list[_models.LedgerUserMultipleRoles], + deserialized.get("ledgerUsers", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -1096,7 +1267,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -1150,7 +1324,10 @@ async def delete_user(self, user_id: str, **kwargs: Any) -> None: if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -1194,6 +1371,7 @@ async def get_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUser: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1208,11 +1386,14 @@ async def get_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUser: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUser, response.json()) @@ -1344,6 +1525,7 @@ async def create_or_update_user( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1358,11 +1540,14 @@ async def create_or_update_user( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUser, response.json()) @@ -1418,7 +1603,10 @@ async def delete_ledger_user(self, user_id: str, **kwargs: Any) -> None: if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -1462,6 +1650,7 @@ async def get_ledger_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUs } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1476,11 +1665,14 @@ async def get_ledger_user(self, user_id: str, **kwargs: Any) -> _models.LedgerUs except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUserMultipleRoles, response.json()) @@ -1621,6 +1813,7 @@ async def create_or_update_ledger_user( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1635,11 +1828,14 @@ async def create_or_update_ledger_user( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.LedgerUserMultipleRoles, response.json()) @@ -1683,6 +1879,7 @@ async def get_user_defined_endpoint(self, **kwargs: Any) -> _models.Bundle: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1697,11 +1894,14 @@ async def get_user_defined_endpoint(self, **kwargs: Any) -> _models.Bundle: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.Bundle, response.json()) @@ -1821,7 +2021,10 @@ async def create_user_defined_endpoint(self, bundle: Union[_models.Bundle, JSON, if response.status_code not in [201]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -1862,6 +2065,7 @@ async def get_runtime_options(self, **kwargs: Any) -> _models.JsRuntimeOptions: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -1876,11 +2080,14 @@ async def get_runtime_options(self, **kwargs: Any) -> _models.JsRuntimeOptions: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.JsRuntimeOptions, response.json()) @@ -1890,8 +2097,12 @@ async def get_runtime_options(self, **kwargs: Any) -> _models.JsRuntimeOptions: return deserialized # type: ignore @overload - async def update_runtime_options( - self, js_runtime_options: _models.JsRuntimeOptions, *, content_type: str = "application/json", **kwargs: Any + async def update_runtime_options_stable( + self, + js_runtime_options: _models.JsRuntimeOptions, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -1900,7 +2111,7 @@ async def update_runtime_options( :param js_runtime_options: JS Runtime options. Required. :type js_runtime_options: ~azure.confidentialledger.models.JsRuntimeOptions :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str :return: JsRuntimeOptions. The JsRuntimeOptions is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.JsRuntimeOptions @@ -1908,8 +2119,8 @@ async def update_runtime_options( """ @overload - async def update_runtime_options( - self, js_runtime_options: JSON, *, content_type: str = "application/json", **kwargs: Any + async def update_runtime_options_stable( + self, js_runtime_options: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -1918,7 +2129,7 @@ async def update_runtime_options( :param js_runtime_options: JS Runtime options. Required. :type js_runtime_options: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str :return: JsRuntimeOptions. The JsRuntimeOptions is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.JsRuntimeOptions @@ -1926,8 +2137,8 @@ async def update_runtime_options( """ @overload - async def update_runtime_options( - self, js_runtime_options: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + async def update_runtime_options_stable( + self, js_runtime_options: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -1936,7 +2147,7 @@ async def update_runtime_options( :param js_runtime_options: JS Runtime options. Required. :type js_runtime_options: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str :return: JsRuntimeOptions. The JsRuntimeOptions is compatible with MutableMapping :rtype: ~azure.confidentialledger.models.JsRuntimeOptions @@ -1944,7 +2155,12 @@ async def update_runtime_options( """ @distributed_trace_async - async def update_runtime_options( + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "content_type", "accept"]}, + api_versions_list=["2026-02-23"], + ) + async def update_runtime_options_stable( self, js_runtime_options: Union[_models.JsRuntimeOptions, JSON, IO[bytes]], **kwargs: Any ) -> _models.JsRuntimeOptions: """Runtime options for user defined endpoints. @@ -1973,14 +2189,14 @@ async def update_runtime_options( content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) cls: ClsType[_models.JsRuntimeOptions] = kwargs.pop("cls", None) - content_type = content_type or "application/json" + content_type = content_type or "application/merge-patch+json" _content = None if isinstance(js_runtime_options, (IOBase, bytes)): _content = js_runtime_options else: _content = json.dumps(js_runtime_options, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_confidential_ledger_update_runtime_options_request( + _request = build_confidential_ledger_update_runtime_options_stable_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -1994,6 +2210,7 @@ async def update_runtime_options( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2008,11 +2225,14 @@ async def update_runtime_options( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.JsRuntimeOptions, response.json()) @@ -2059,6 +2279,7 @@ async def get_user_defined_endpoints_module(self, *, module_name: str, **kwargs: } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2073,11 +2294,14 @@ async def get_user_defined_endpoints_module(self, *, module_name: str, **kwargs: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.ModuleDef, response.json()) @@ -2136,7 +2360,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + headers=_headers, + params=_next_request_params, ) path_format_arguments = { "ledgerEndpoint": self._serialize.url( @@ -2149,7 +2376,10 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize(list[_models.UserDefinedFunction], deserialized.get("functions", [])) + list_of_elem = _deserialize( + list[_models.UserDefinedFunction], + deserialized.get("functions", []), + ) if cls: list_of_elem = cls(list_of_elem) # type: ignore return deserialized.get("nextLink") or None, AsyncList(list_of_elem) @@ -2165,7 +2395,10 @@ async def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) return pipeline_response @@ -2219,7 +2452,10 @@ async def delete_user_defined_function(self, function_id: str, **kwargs: Any) -> if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: @@ -2263,6 +2499,7 @@ async def get_user_defined_function(self, function_id: str, **kwargs: Any) -> _m } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2277,11 +2514,14 @@ async def get_user_defined_function(self, function_id: str, **kwargs: Any) -> _m except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.UserDefinedFunction, response.json()) @@ -2420,6 +2660,7 @@ async def create_user_defined_function( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2434,7 +2675,10 @@ async def create_user_defined_function( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) response_headers = {} @@ -2443,7 +2687,7 @@ async def create_user_defined_function( ) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.UserDefinedFunction, response.json()) @@ -2599,6 +2843,7 @@ async def execute_user_defined_function( } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2613,11 +2858,14 @@ async def execute_user_defined_function( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: deserialized = _deserialize(_models.UserDefinedFunctionExecutionResponse, response.json()) @@ -2627,15 +2875,15 @@ async def execute_user_defined_function( return deserialized # type: ignore @distributed_trace_async - async def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.Roles: + async def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _models.UserDefinedRole: """Gets role actions for user defined roles. user defined roles allow users to define and manage app specific AuthZ policy. :keyword role_name: user defined role name. Required. :paramtype role_name: str - :return: Roles. The Roles is compatible with MutableMapping - :rtype: ~azure.confidentialledger.models.Roles + :return: UserDefinedRole. The UserDefinedRole is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRole :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -2649,7 +2897,7 @@ async def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _mode _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Roles] = kwargs.pop("cls", None) + cls: ClsType[_models.UserDefinedRole] = kwargs.pop("cls", None) _request = build_confidential_ledger_get_user_defined_role_request( role_name=role_name, @@ -2664,6 +2912,7 @@ async def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _mode } _request.url = self._client.format_url(_request.url, **path_format_arguments) + _decompress = kwargs.pop("decompress", True) _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs @@ -2678,13 +2927,16 @@ async def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _mode except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if _stream: - deserialized = response.iter_bytes() + deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Roles, response.json()) + deserialized = _deserialize(_models.UserDefinedRole, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -2692,27 +2944,27 @@ async def get_user_defined_role(self, *, role_name: str, **kwargs: Any) -> _mode return deserialized # type: ignore @overload - async def create_user_defined_role( - self, body: _models.Roles, *, content_type: str = "application/json", **kwargs: Any - ) -> None: + async def create_user_defined_role_stable( + self, body: _models.UserDefinedRoles, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. - :type body: ~azure.confidentialledger.models.Roles + :type body: ~azure.confidentialledger.models.UserDefinedRoles :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_user_defined_role( + async def create_user_defined_role_stable( self, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> None: + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. @@ -2722,15 +2974,15 @@ async def create_user_defined_role( :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_user_defined_role( + async def create_user_defined_role_stable( self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> None: + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. @@ -2740,21 +2992,29 @@ async def create_user_defined_role( :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_user_defined_role(self, body: Union[_models.Roles, JSON, IO[bytes]], **kwargs: Any) -> None: + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "content_type", "accept"]}, + api_versions_list=["2026-02-23"], + ) + async def create_user_defined_role_stable( + self, body: Union[_models.UserDefinedRoles, JSON, IO[bytes]], **kwargs: Any + ) -> _models.UserDefinedRoles: """Creates new roles and their actions. User defined roles allow users to define and manage app specific AuthZ policy. - :param body: Request body. Is one of the following types: Roles, JSON, IO[bytes] Required. - :type body: ~azure.confidentialledger.models.Roles or JSON or IO[bytes] - :return: None - :rtype: None + :param body: Request body. Is one of the following types: UserDefinedRoles, JSON, IO[bytes] + Required. + :type body: ~azure.confidentialledger.models.UserDefinedRoles or JSON or IO[bytes] + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -2769,7 +3029,7 @@ async def create_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.UserDefinedRoles] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None @@ -2778,7 +3038,7 @@ async def create_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_confidential_ledger_create_user_defined_role_request( + _request = build_confidential_ledger_create_user_defined_role_stable_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -2792,7 +3052,8 @@ async def create_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -2800,81 +3061,104 @@ async def create_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt 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) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.UserDefinedRoles, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @overload - async def update_user_defined_role( - self, body: _models.Roles, *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + async def update_user_defined_role_stable( + self, body: _models.UserDefinedRoles, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. - :type body: ~azure.confidentialledger.models.Roles + :type body: ~azure.confidentialledger.models.UserDefinedRoles :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update_user_defined_role( - self, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + async def update_user_defined_role_stable( + self, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update_user_defined_role( - self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + async def update_user_defined_role_stable( + self, body: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. :param body: Request body. Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: None - :rtype: None + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def update_user_defined_role(self, body: Union[_models.Roles, JSON, IO[bytes]], **kwargs: Any) -> None: - """Patch replaces the allowed action on existing roles,if the desire is to remove - an existing action, the role must be deleted and recreated. + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "content_type", "accept"]}, + api_versions_list=["2026-02-23"], + ) + async def update_user_defined_role_stable( + self, body: Union[_models.UserDefinedRoles, JSON, IO[bytes]], **kwargs: Any + ) -> _models.UserDefinedRoles: + """Patch replaces the allowed action on existing roles,if the desire is to remove an existing + action, the role must be deleted and recreated. User defined roles allow users to define and manage app specific AuthZ policy. - :param body: Request body. Is one of the following types: Roles, JSON, IO[bytes] Required. - :type body: ~azure.confidentialledger.models.Roles or JSON or IO[bytes] - :return: None - :rtype: None + :param body: Request body. Is one of the following types: UserDefinedRoles, JSON, IO[bytes] + Required. + :type body: ~azure.confidentialledger.models.UserDefinedRoles or JSON or IO[bytes] + :return: UserDefinedRoles. The UserDefinedRoles is compatible with MutableMapping + :rtype: ~azure.confidentialledger.models.UserDefinedRoles :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -2889,16 +3173,16 @@ async def update_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.UserDefinedRoles] = kwargs.pop("cls", None) - content_type = content_type or "application/json" + content_type = content_type or "application/merge-patch+json" _content = None if isinstance(body, (IOBase, bytes)): _content = body else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_confidential_ledger_update_user_defined_role_request( + _request = build_confidential_ledger_update_user_defined_role_stable_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -2912,7 +3196,8 @@ async def update_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # type: ignore # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -2920,19 +3205,38 @@ async def update_user_defined_role(self, body: Union[_models.Roles, JSON, IO[byt 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) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.UserDefinedRoles, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace_async - async def delete_user_defined_role(self, *, role_name: str, **kwargs: Any) -> None: + @api_version_validation( + method_added_on="2026-02-23", + params_added_on={"2026-02-23": ["api_version", "role_name"]}, + api_versions_list=["2026-02-23"], + ) + async def delete_user_defined_role_stable(self, *, role_name: str, **kwargs: Any) -> None: """Deletes user defined roles. - A user defined role allows the users to create and manage their own role - actions using the API. + A user defined role allows the users to create and manage their own role actions using the API. :keyword role_name: user defined role name. Required. :paramtype role_name: str @@ -2953,7 +3257,7 @@ async def delete_user_defined_role(self, *, role_name: str, **kwargs: Any) -> No cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_confidential_ledger_delete_user_defined_role_request( + _request = build_confidential_ledger_delete_user_defined_role_stable_request( role_name=role_name, api_version=self._config.api_version, headers=_headers, @@ -2973,9 +3277,12 @@ async def delete_user_defined_role(self, *, role_name: str, **kwargs: Any) -> No response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize(_models.ConfidentialLedgerError, response) + error = _failsafe_deserialize( + _models.ConfidentialLedgerError, + response, + ) raise HttpResponseError(response=response, model=error) if cls: diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_patch.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_patch.py index 0f494322eb1d..ce87ffcdd434 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_patch.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/aio/_patch.py @@ -20,6 +20,7 @@ # Since we can't `await` in __init__, use the sync client for the Identity Service. +from azure.confidentialledger._redirect_caching_policy import AsyncRedirectCachingPolicy from azure.confidentialledger.certificate import ConfidentialLedgerCertificateClient # pylint: disable=import-error,no-name-in-module from azure.confidentialledger._patch import ConfidentialLedgerCertificateCredential @@ -115,4 +116,10 @@ def __init__( kwargs["connection_verify"] = kwargs.get("connection_verify", ledger_certificate_path) + # Inject the redirect-caching policy so that write requests skip the + # load-balancer after the first redirect, and preserve sensitive headers + # on service-managed redirects within the trusted ledger endpoint. + kwargs.setdefault("redirect_policy", AsyncRedirectCachingPolicy(**kwargs)) + kwargs.setdefault("disable_redirect_cleanup", True) + super().__init__(endpoint, **kwargs) diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/__init__.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/__init__.py index 72c893bbc073..354dbbc29a03 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/__init__.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/__init__.py @@ -40,7 +40,6 @@ ReceiptElement, ReceiptLeafComponents, Role, - Roles, TransactionReceipt, TransactionStatus, UserDefinedFunction, @@ -49,6 +48,8 @@ UserDefinedFunctionExecutionResponse, UserDefinedFunctionExecutionResult, UserDefinedFunctionHook, + UserDefinedRole, + UserDefinedRoles, ) from ._enums import ( # type: ignore @@ -93,7 +94,6 @@ "ReceiptElement", "ReceiptLeafComponents", "Role", - "Roles", "TransactionReceipt", "TransactionStatus", "UserDefinedFunction", @@ -102,6 +102,8 @@ "UserDefinedFunctionExecutionResponse", "UserDefinedFunctionExecutionResult", "UserDefinedFunctionHook", + "UserDefinedRole", + "UserDefinedRoles", "ApplicationClaimKind", "ApplicationClaimProtocol", "ConfidentialLedgerQueryState", diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_enums.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_enums.py index 5e977f918559..a4ed197c44b0 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_enums.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_enums.py @@ -14,86 +14,84 @@ class ApplicationClaimKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents the kind of an application claim.""" LEDGER_ENTRY = "LedgerEntry" - """Claim derived from a ledger entry""" + """Claim derived from a ledger entry.""" CLAIM_DIGEST = "ClaimDigest" - """Claim in digested form""" + """Claim in digested form.""" class ApplicationClaimProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Represents the protocol to be used to compute the digest of a claim from the - given claim data. - """ + """Represents the protocol to be used to compute the digest of a claim from the given claim data.""" LEDGER_ENTRY_V1 = "LedgerEntryV1" - """Ledger Entry V1 protocol""" + """Ledger Entry V1 protocol.""" class ConfidentialLedgerQueryState(str, Enum, metaclass=CaseInsensitiveEnumMeta): """State of a ledger query.""" LOADING = "Loading" - """The query is still loading""" + """The query is still loading.""" READY = "Ready" - """The query is ready""" + """The query is ready.""" class ConfidentialLedgerUserRoleName(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents an assignable role.""" ADMINISTRATOR = "Administrator" - """Administrator role""" + """Administrator role.""" CONTRIBUTOR = "Contributor" - """Contributor role""" + """Contributor role.""" READER = "Reader" - """Reader role""" + """Reader role.""" class ForwardingRequired(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Indicates whether request forwarding is required for this operation.""" SOMETIMES = "sometimes" - """Forwarding is required sometimes""" + """Forwarding is required sometimes.""" ALWAYS = "always" - """Forwarding is always required""" + """Forwarding is always required.""" NEVER = "never" - """Forwarding is never required""" + """Forwarding is never required.""" class Mode(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents the operation mode of the endpoint.""" READWRITE = "readwrite" - """Read-write mode""" + """Read-write mode.""" READONLY = "readonly" - """Read-only mode""" + """Read-only mode.""" HISTORICAL = "historical" - """Historical mode""" + """Historical mode.""" class RedirectionStrategy(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents the redirection strategy for the endpoint.""" NONE = "none" - """No redirection strategy""" + """No redirection strategy.""" TO_PRIMARY = "to_primary" - """Redirect to primary""" + """Redirect to primary.""" TO_BACKUP = "to_backup" - """Redirect to backup""" + """Redirect to backup.""" class TransactionState(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents the state of the transaction.""" COMMITTED = "Committed" - """The transaction is committed""" + """The transaction is committed.""" PENDING = "Pending" - """The transaction is pending""" + """The transaction is pending.""" class UserDefinedFunctionExecutionStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Represents the status of a user defined function execution.""" SUCCEEDED = "Succeeded" - """The function execution completed successfully""" + """The function execution completed successfully.""" FAILED = "Failed" - """The function execution failed""" + """The function execution failed.""" diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_models.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_models.py index 3050c86fb133..851a38fe68fd 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_models.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_models.py @@ -108,8 +108,8 @@ class ClaimDigest(_Model): protocol: Union[str, "_models.ApplicationClaimProtocol"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Represents the protocol to be used to compute the digest of a claim from the - given claim data. Required. \"LedgerEntryV1\"""" + """Represents the protocol to be used to compute the digest of a claim from the given claim data. + Required. \"LedgerEntryV1\"""" @overload def __init__( @@ -511,18 +511,16 @@ class LedgerEntry(_Model): collection_id: Optional[str] = rest_field(name="collectionId", visibility=["read"]) """The collection identifier for this ledger entry.""" transaction_id: Optional[str] = rest_field(name="transactionId", visibility=["read"]) - """A unique identifier for the state of the ledger. If returned as part of a - LedgerEntry, it indicates the state from which the entry was read.""" + """A unique identifier for the state of the ledger. If returned as part of a LedgerEntry, it + indicates the state from which the entry was read.""" pre_hooks: Optional[list["_models.UserDefinedFunctionHook"]] = rest_field( name="preHooks", visibility=["read", "create", "update", "delete", "query"] ) - """List of user defined function hooks to be executed before the ledger entry is - written.""" + """List of user defined function hooks to be executed before the ledger entry is written.""" post_hooks: Optional[list["_models.UserDefinedFunctionHook"]] = rest_field( name="postHooks", visibility=["read", "create", "update", "delete", "query"] ) - """List of user defined function hooks to be executed after the ledger entry is - written.""" + """List of user defined function hooks to be executed after the ledger entry is written.""" @overload def __init__( @@ -569,8 +567,8 @@ class LedgerEntryClaim(_Model): protocol: Union[str, "_models.ApplicationClaimProtocol"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Represents the protocol to be used to compute the digest of a claim from the - given claim data. Required. \"LedgerEntryV1\"""" + """Represents the protocol to be used to compute the digest of a claim from the given claim data. + Required. \"LedgerEntryV1\"""" @overload def __init__( @@ -594,8 +592,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class LedgerQueryResult(_Model): - """The result of querying for a ledger entry from an older transaction id. The - ledger entry is available in the response only if the returned state is Ready. + """The result of querying for a ledger entry from an older transaction id. The ledger entry is + available in the response only if the returned state is Ready. :ivar state: State of a ledger query. Required. Known values are: "Loading" and "Ready". :vartype state: str or ~azure.confidentialledger.models.ConfidentialLedgerQueryState @@ -609,8 +607,8 @@ class LedgerQueryResult(_Model): ) """State of a ledger query. Required. Known values are: \"Loading\" and \"Ready\".""" entry: Optional["_models.LedgerEntry"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The ledger entry found as a result of the query. This is only available if the - query is in Ready state.""" + """The ledger entry found as a result of the query. This is only available if the query is in + Ready state.""" @overload def __init__( @@ -648,8 +646,7 @@ class LedgerUser(_Model): """Represents an assignable role. Required. Known values are: \"Administrator\", \"Contributor\", and \"Reader\".""" user_id: Optional[str] = rest_field(name="userId", visibility=["read"]) - """Identifier for the user. This must either be an AAD object id or a certificate - fingerprint.""" + """Identifier for the user. This must either be an AAD object id or a certificate fingerprint.""" @overload def __init__( @@ -685,8 +682,7 @@ class LedgerUserMultipleRoles(_Model): ) """Represents an assignable role. Required.""" user_id: Optional[str] = rest_field(name="userId", visibility=["read"]) - """Identifier for the user. This must either be an AAD object id or a certificate - fingerprint.""" + """Identifier for the user. This must either be an AAD object id or a certificate fingerprint.""" @overload def __init__( @@ -707,8 +703,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class LedgerWriteResult(_Model): - """Returned as a result of a write to the Confidential Ledger, the transaction id - in the response indicates when the write will become durable. + """Returned as a result of a write to the Confidential Ledger, the transaction id in the response + indicates when the write will become durable. :ivar collection_id: The collection identifier of the ledger entry. Required. :vartype collection_id: str @@ -779,7 +775,7 @@ class MethodToEndpointProperties(_Model): """ get_property: Optional["_models.EndpointProperties"] = rest_field( - name="get", visibility=["read", "create", "update", "delete", "query"] + name="get", visibility=["read", "create", "update", "delete", "query"], original_tsp_name="get" ) """Properties for GET method endpoint.""" put: Optional["_models.EndpointProperties"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -954,7 +950,7 @@ class ReceiptLeafComponents(_Model): :vartype claims_digest: str :ivar commit_evidence: Commit evidence. :vartype commit_evidence: str - :ivar write_set_digest: TWrite set digest. + :ivar write_set_digest: Write set digest. :vartype write_set_digest: str """ @@ -969,7 +965,7 @@ class ReceiptLeafComponents(_Model): write_set_digest: Optional[str] = rest_field( name="writeSetDigest", visibility=["read", "create", "update", "delete", "query"] ) - """TWrite set digest.""" + """Write set digest.""" @overload def __init__( @@ -1026,34 +1022,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Roles(_Model): - """Roles. - - :ivar roles: Roles. Required. - :vartype roles: list[~azure.confidentialledger.models.Role] - """ - - roles: list["_models.Role"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Roles. Required.""" - - @overload - def __init__( - self, - *, - roles: list["_models.Role"], - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - class TransactionReceipt(_Model): """A receipt certifying the transaction at the specified id. @@ -1081,8 +1049,8 @@ class TransactionReceipt(_Model): ) """State of a ledger query. Required. Known values are: \"Loading\" and \"Ready\".""" transaction_id: str = rest_field(name="transactionId", visibility=["read", "create", "update", "delete", "query"]) - """A unique identifier for the state of the ledger. If returned as part of a - LedgerEntry, it indicates the state from which the entry was read. Required.""" + """A unique identifier for the state of the ledger. If returned as part of a LedgerEntry, it + indicates the state from which the entry was read. Required.""" @overload def __init__( @@ -1122,8 +1090,8 @@ class TransactionStatus(_Model): """Represents the state of the transaction. Required. Known values are: \"Committed\" and \"Pending\".""" transaction_id: str = rest_field(name="transactionId", visibility=["read", "create", "update", "delete", "query"]) - """A unique identifier for the state of the ledger. If returned as part of a - LedgerEntry, it indicates the state from which the entry was read. Required.""" + """A unique identifier for the state of the ledger. If returned as part of a LedgerEntry, it + indicates the state from which the entry was read. Required.""" @overload def __init__( @@ -1177,8 +1145,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class UserDefinedFunctionExecutionError(_Model): - """The error object of a user defined function execution. This is returned only - when the user defined function execution throws an exception. + """The error object of a user defined function execution. This is returned only when the user + defined function execution throws an exception. :ivar message: Message indicating the error thrown when executing the function. :vartype message: str @@ -1211,8 +1179,7 @@ class UserDefinedFunctionExecutionProperties(_Model): :ivar arguments: Runtime arguments of the user defined function. Defaults to an empty list. :vartype arguments: list[str] :ivar exported_function_name: Name of the exported function to execute in the code of the user - defined - function. Defaults to main. + defined function. Defaults to main. :vartype exported_function_name: str :ivar runtime_options: JS runtime options for user defined endpoints and functions. :vartype runtime_options: ~azure.confidentialledger.models.JsRuntimeOptions @@ -1223,8 +1190,8 @@ class UserDefinedFunctionExecutionProperties(_Model): exported_function_name: Optional[str] = rest_field( name="exportedFunctionName", visibility=["read", "create", "update", "delete", "query"] ) - """Name of the exported function to execute in the code of the user defined - function. Defaults to main.""" + """Name of the exported function to execute in the code of the user defined function. Defaults to + main.""" runtime_options: Optional["_models.JsRuntimeOptions"] = rest_field( name="runtimeOptions", visibility=["read", "create", "update", "delete", "query"] ) @@ -1253,8 +1220,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class UserDefinedFunctionExecutionResponse(_Model): """The result of a user defined function execution. - :ivar error: The error object of a user defined function execution. This is returned only - when the user defined function execution throws an exception. + :ivar error: The error object of a user defined function execution. This is returned only when + the user defined function execution throws an exception. :vartype error: ~azure.confidentialledger.models.UserDefinedFunctionExecutionError :ivar result: The result object of a user defined function execution. This is returned only when the user defined function executes successfully. @@ -1267,13 +1234,13 @@ class UserDefinedFunctionExecutionResponse(_Model): error: Optional["_models.UserDefinedFunctionExecutionError"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The error object of a user defined function execution. This is returned only - when the user defined function execution throws an exception.""" + """The error object of a user defined function execution. This is returned only when the user + defined function execution throws an exception.""" result: Optional["_models.UserDefinedFunctionExecutionResult"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The result object of a user defined function execution. This is returned only - when the user defined function executes successfully.""" + """The result object of a user defined function execution. This is returned only when the user + defined function executes successfully.""" status: Union[str, "_models.UserDefinedFunctionExecutionStatus"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) @@ -1301,20 +1268,19 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class UserDefinedFunctionExecutionResult(_Model): - """The result object of a user defined function execution. This is returned only - when the user defined function executes successfully. + """The result object of a user defined function execution. This is returned only when the user + defined function executes successfully. :ivar return_value: String-encoded value returned by the user defined function execution. If - the - function does not return any value, this is set to an empty string. + the function does not return any value, this is set to an empty string. :vartype return_value: str """ return_value: Optional[str] = rest_field( name="returnValue", visibility=["read", "create", "update", "delete", "query"] ) - """String-encoded value returned by the user defined function execution. If the - function does not return any value, this is set to an empty string.""" + """String-encoded value returned by the user defined function execution. If the function does not + return any value, this is set to an empty string.""" @overload def __init__( @@ -1367,3 +1333,59 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + + +class UserDefinedRole(_Model): + """User defined role. + + :ivar role: User defined role. Required. + :vartype role: list[~azure.confidentialledger.models.Role] + """ + + role: list["_models.Role"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """User defined role. Required.""" + + @overload + def __init__( + self, + *, + role: list["_models.Role"], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class UserDefinedRoles(_Model): + """Roles. + + :ivar roles: Roles. Required. + :vartype roles: list[~azure.confidentialledger.models.Role] + """ + + roles: list["_models.Role"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Roles. Required.""" + + @overload + def __init__( + self, + *, + roles: list["_models.Role"], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) diff --git a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_patch.py b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_patch.py index 8bcb627aa475..87676c65a8f0 100644 --- a/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_patch.py +++ b/sdk/confidentialledger/azure-confidentialledger/azure/confidentialledger/models/_patch.py @@ -7,9 +7,9 @@ Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -from typing import List -__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + +__all__: list[str] = [] # Add all objects you want publicly available to users at this package level def patch_sdk(): diff --git a/sdk/confidentialledger/azure-confidentialledger/pyproject.toml b/sdk/confidentialledger/azure-confidentialledger/pyproject.toml index 90bafd3f2522..570346a8eb48 100644 --- a/sdk/confidentialledger/azure-confidentialledger/pyproject.toml +++ b/sdk/confidentialledger/azure-confidentialledger/pyproject.toml @@ -1,68 +1,84 @@ -# -------------------------------------------------------------------------- -# 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. -# -------------------------------------------------------------------------- - [build-system] -requires = ["setuptools>=77.0.3", "wheel"] +requires = [ + "setuptools>=77.0.3", + "wheel", +] build-backend = "setuptools.build_meta" [project] name = "azure-confidentialledger" authors = [ - { name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com" }, + { name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com" }, ] description = "Microsoft Corporation Azure Confidential Ledger Client Library for Python" license = "MIT" classifiers = [ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +requires-python = ">=3.10" +keywords = [ + "azure", + "azure sdk", ] -requires-python = ">=3.9" -keywords = ["azure", "azure sdk"] - dependencies = [ "isodate>=0.6.1", - "azure-core>=1.35.0", + "azure-core>=1.37.0", "typing-extensions>=4.6.0", "cryptography>=2.1.4", "azure-confidentialledger-certificate>=1.0.0b1", ] dynamic = [ -"version", "readme" + "version", + "readme", ] [project.urls] -Homepage = "https://github.com/Azure/azure-sdk-for-python" -"Bug Reports" = "https://github.com/Azure/azure-sdk-for-python/issues" -Source = "https://github.com/Azure/azure-sdk-for-python" +repository = "https://github.com/Azure/azure-sdk-for-python" -[tool.setuptools.dynamic] -version = {attr = "azure.confidentialledger._version.VERSION"} -readme = {file = ["README.md", "CHANGELOG.md"], content-type = "text/markdown"} +[tool.setuptools.dynamic.version] +attr = "azure.confidentialledger._version.VERSION" + +[tool.setuptools.dynamic.readme] +file = [ + "README.md", + "CHANGELOG.md", +] +content-type = "text/markdown" [tool.setuptools.packages.find] exclude = [ "tests*", + "generated_tests*", "samples*", + "generated_samples*", "doc*", "azure", ] [tool.setuptools.package-data] -pytyped = ["py.typed"] +pytyped = [ + "py.typed", +] [tool.azure-sdk-build] pyright = false [tool.azure-sdk-conda] in_bundle = false + +[packaging] +package_name = "azure-confidentialledger" +package_pprint_name = "Azure Confidential Ledger" +package_doc_id = "" +is_stable = true +is_arm = false +need_msrestazure = false +auto_update = false diff --git a/sdk/confidentialledger/azure-confidentialledger/sdk_packaging.toml b/sdk/confidentialledger/azure-confidentialledger/sdk_packaging.toml deleted file mode 100644 index 04b9b55da3e4..000000000000 --- a/sdk/confidentialledger/azure-confidentialledger/sdk_packaging.toml +++ /dev/null @@ -1,8 +0,0 @@ -[packaging] -package_name = "azure-confidentialledger" -package_pprint_name = "Azure Confidential Ledger" -package_doc_id = "" -is_stable = false -is_arm = false -need_msrestazure = false -auto_update = false \ No newline at end of file diff --git a/sdk/confidentialledger/azure-confidentialledger/tests/_shared/testcase.py b/sdk/confidentialledger/azure-confidentialledger/tests/_shared/testcase.py index 8291d327fa70..6db0d95b344b 100644 --- a/sdk/confidentialledger/azure-confidentialledger/tests/_shared/testcase.py +++ b/sdk/confidentialledger/azure-confidentialledger/tests/_shared/testcase.py @@ -68,6 +68,10 @@ def set_ledger_identity(self, confidentialledger_id: str) -> str: client = self.create_client_from_credential( ConfidentialLedgerCertificateClient, credential=None, + certificate_endpoint=os.environ.get( + "CONFIDENTIALLEDGER_IDENTITY_ENDPOINT", + "https://identity.confidential-ledger.core.azure.com", + ), ) network_identity = client.get_ledger_identity(ledger_id=confidentialledger_id) @@ -91,6 +95,10 @@ async def set_ledger_identity_async(self, confidentialledger_id: str) -> str: client = self.create_client_from_credential( ConfidentialLedgerCertificateClientAsync, credential=None, + certificate_endpoint=os.environ.get( + "CONFIDENTIALLEDGER_IDENTITY_ENDPOINT", + "https://identity.confidential-ledger.core.azure.com", + ), ) try: diff --git a/sdk/confidentialledger/azure-confidentialledger/tests/test_client_configuration.py b/sdk/confidentialledger/azure-confidentialledger/tests/test_client_configuration.py index 47459e6733dd..94041273a849 100644 --- a/sdk/confidentialledger/azure-confidentialledger/tests/test_client_configuration.py +++ b/sdk/confidentialledger/azure-confidentialledger/tests/test_client_configuration.py @@ -4,12 +4,14 @@ # ------------------------------------ """Unit tests for ConfidentialLedgerClient configuration.""" +import os +import tempfile + import pytest from unittest.mock import patch, MagicMock from azure.core.pipeline import policies -# Import the generated client directly to test its policy configuration -from azure.confidentialledger._client import ConfidentialLedgerClient as GeneratedClient +from azure.confidentialledger._redirect_caching_policy import RedirectCachingPolicy class TestClientConfiguration: @@ -22,77 +24,98 @@ def test_sensitive_header_cleanup_policy_disable_redirect_cleanup_enabled(self): on service-managed redirects, which is required for correct authentication behavior within the trusted Confidential Ledger endpoint. """ - # Mock the PipelineClient to capture the policies passed to it - with patch("azure.confidentialledger._client.PipelineClient") as mock_pipeline_client: + with ( + patch("azure.confidentialledger._client.PipelineClient") as mock_pipeline_client, + patch( + "azure.confidentialledger._patch.ConfidentialLedgerCertificateClient" + ) as mock_cert_client, + ): mock_pipeline_client.return_value = MagicMock() - - # Create the generated client directly - this will trigger policy creation - # The generated client only requires ledger_endpoint - client = GeneratedClient( - ledger_endpoint="https://test-ledger.confidentialledger.azure.com" - ) - - # Get the policies argument passed to PipelineClient - call_args = mock_pipeline_client.call_args - policies_arg = call_args.kwargs.get("policies") or call_args[1].get("policies") - - # Find the SensitiveHeaderCleanupPolicy in the policies list - sensitive_header_policy = None - for policy in policies_arg: - if isinstance(policy, policies.SensitiveHeaderCleanupPolicy): - sensitive_header_policy = policy - break - - # Assert the policy exists and has disable_redirect_cleanup=True - assert sensitive_header_policy is not None, ( - "SensitiveHeaderCleanupPolicy should be present in the client's policies" - ) - assert sensitive_header_policy._disable_redirect_cleanup is True, ( - "SensitiveHeaderCleanupPolicy should have disable_redirect_cleanup=True " - "to preserve authentication headers on Confidential Ledger redirects" - ) - - client.close() - - def test_sensitive_header_cleanup_policy_is_in_correct_position(self): - """Test that SensitiveHeaderCleanupPolicy is positioned after authentication_policy. - - The policy should be placed after the authentication policy so that it can - properly handle the redirect cleanup for authentication headers. - """ - with patch("azure.confidentialledger._client.PipelineClient") as mock_pipeline_client: + mock_cert_client.return_value.get_ledger_identity.return_value = { + "ledgerTlsCertificate": "fake-cert" + } + + with tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False) as f: + f.write("fake-cert") + cert_path = f.name + + try: + from azure.confidentialledger._patch import ( + ConfidentialLedgerClient, + ConfidentialLedgerCertificateCredential, + ) + + cred = ConfidentialLedgerCertificateCredential(cert_path) + client = ConfidentialLedgerClient( + "https://test-ledger.confidentialledger.azure.com", + cred, + ledger_certificate_path=cert_path, + ) + + call_args = mock_pipeline_client.call_args + policies_arg = call_args.kwargs.get("policies") or call_args[1].get("policies") + + sensitive_header_policy = None + for policy in policies_arg: + if isinstance(policy, policies.SensitiveHeaderCleanupPolicy): + sensitive_header_policy = policy + break + + assert ( + sensitive_header_policy is not None + ), "SensitiveHeaderCleanupPolicy should be present in the client's policies" + assert sensitive_header_policy._disable_redirect_cleanup is True, ( + "SensitiveHeaderCleanupPolicy should have disable_redirect_cleanup=True " + "to preserve authentication headers on Confidential Ledger redirects" + ) + + client.close() + finally: + os.unlink(cert_path) + + def test_redirect_caching_policy_is_used(self): + """Test that RedirectCachingPolicy is used as the redirect policy.""" + with ( + patch("azure.confidentialledger._client.PipelineClient") as mock_pipeline_client, + patch( + "azure.confidentialledger._patch.ConfidentialLedgerCertificateClient" + ) as mock_cert_client, + ): mock_pipeline_client.return_value = MagicMock() - - client = GeneratedClient( - ledger_endpoint="https://test-ledger.confidentialledger.azure.com" - ) - - # Get the policies argument passed to PipelineClient - call_args = mock_pipeline_client.call_args - policies_arg = call_args.kwargs.get("policies") or call_args[1].get("policies") - - # Filter out None values - non_none_policies = [p for p in policies_arg if p is not None] - - # Find positions of key policies - sensitive_header_idx = None - distributed_tracing_idx = None - - for idx, policy in enumerate(non_none_policies): - if isinstance(policy, policies.SensitiveHeaderCleanupPolicy): - sensitive_header_idx = idx - elif isinstance(policy, policies.DistributedTracingPolicy): - distributed_tracing_idx = idx - - # SensitiveHeaderCleanupPolicy should come after DistributedTracingPolicy - assert sensitive_header_idx is not None, ( - "SensitiveHeaderCleanupPolicy should be present in the policies" - ) - assert distributed_tracing_idx is not None, ( - "DistributedTracingPolicy should be present in the policies" - ) - assert sensitive_header_idx > distributed_tracing_idx, ( - "SensitiveHeaderCleanupPolicy should be positioned after DistributedTracingPolicy" - ) - - client.close() + mock_cert_client.return_value.get_ledger_identity.return_value = { + "ledgerTlsCertificate": "fake-cert" + } + + with tempfile.NamedTemporaryFile(mode="w", suffix=".pem", delete=False) as f: + f.write("fake-cert") + cert_path = f.name + + try: + from azure.confidentialledger._patch import ( + ConfidentialLedgerClient, + ConfidentialLedgerCertificateCredential, + ) + + cred = ConfidentialLedgerCertificateCredential(cert_path) + client = ConfidentialLedgerClient( + "https://test-ledger.confidentialledger.azure.com", + cred, + ledger_certificate_path=cert_path, + ) + + call_args = mock_pipeline_client.call_args + policies_arg = call_args.kwargs.get("policies") or call_args[1].get("policies") + + redirect_policy = None + for policy in policies_arg: + if isinstance(policy, RedirectCachingPolicy): + redirect_policy = policy + break + + assert redirect_policy is not None, ( + "RedirectCachingPolicy should be used as the redirect policy" + ) + + client.close() + finally: + os.unlink(cert_path) diff --git a/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client.py b/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client.py index 59f5d8d2b414..54ab6ba2f0e0 100644 --- a/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client.py +++ b/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client.py @@ -413,7 +413,7 @@ def user_management_actions(self, client): user = client.get_ledger_user(user_id) assert user["userId"] == user_id - assert user["assignedRoles"] == ["Contributor", "Reader"] + assert sorted(user["assignedRoles"]) == ["Contributor", "Reader"] client.delete_ledger_user(user_id) @@ -584,23 +584,30 @@ def test_user_defined_role(self, confidentialledger_endpoint, confidentialledger role_name = "modify" - client.create_user_defined_role({"roles": [{"role_name": role_name, "role_actions": ["/content/read"]}]}) + # Clean up in case role exists from a previous run + try: + client.delete_user_defined_role_stable(role_name=role_name) + time.sleep(3) + except exceptions.HttpResponseError: + pass + + client.create_user_defined_role_stable({"roles": [{"role_name": role_name, "role_actions": ["/content/read"]}]}) time.sleep(3) - roles = client.get_user_defined_role(role_name=role_name) - assert roles.roles[0]["role_name"] == role_name - assert roles.roles[0]["role_actions"] == ["/content/read"] + role_result = client.get_user_defined_role(role_name=role_name) + assert role_result["roles"][0]["role_name"] == role_name + assert role_result["roles"][0]["role_actions"] == ["/content/read"] - client.update_user_defined_role( + client.update_user_defined_role_stable( {"roles": [{"role_name": role_name, "role_actions": ["/content/write", "/content/read"]}]} ) time.sleep(3) - roles = client.get_user_defined_role(role_name=role_name) - assert roles.roles[0]["role_name"] == role_name - assert roles.roles[0]["role_actions"] == ["/content/read", "/content/write"] + role_result = client.get_user_defined_role(role_name=role_name) + assert role_result["roles"][0]["role_name"] == role_name + assert sorted(role_result["roles"][0]["role_actions"]) == ["/content/read", "/content/write"] - client.delete_user_defined_role(role_name=role_name) + client.delete_user_defined_role_stable(role_name=role_name) time.sleep(3) @ConfidentialLedgerPreparer() diff --git a/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client_async.py b/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client_async.py index 585c2df93760..f02a68638ffb 100644 --- a/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client_async.py +++ b/sdk/confidentialledger/azure-confidentialledger/tests/test_confidential_ledger_client_async.py @@ -395,7 +395,7 @@ async def user_management_actions(self, client): user = await client.get_ledger_user(user_id) assert user["userId"] == user_id - assert user["assignedRoles"] == ["Contributor", "Reader"] + assert sorted(user["assignedRoles"]) == ["Contributor", "Reader"] await client.delete_ledger_user(user_id) await asyncio.sleep(3) # Let the DELETE user operation be committed, just in case. diff --git a/sdk/confidentialledger/azure-confidentialledger/tests/test_redirect_caching_policy.py b/sdk/confidentialledger/azure-confidentialledger/tests/test_redirect_caching_policy.py index b62b6707980f..e4dad63b3b88 100644 --- a/sdk/confidentialledger/azure-confidentialledger/tests/test_redirect_caching_policy.py +++ b/sdk/confidentialledger/azure-confidentialledger/tests/test_redirect_caching_policy.py @@ -320,8 +320,7 @@ def test_disallowed_redirect_emits_warning_log(self, caplog): warnings = [r for r in caplog.records if r.levelno == logging.WARNING] assert any( - "Refusing to follow redirect to disallowed target" in r.message - and UNRELATED_URL in r.message + "Refusing to follow redirect to disallowed target" in r.message and UNRELATED_URL in r.message for r in warnings ), f"Expected a block warning for {UNRELATED_URL}, got: {[r.message for r in warnings]}" @@ -453,7 +452,6 @@ async def test_disallowed_redirect_emits_warning_log(self, caplog): warnings = [r for r in caplog.records if r.levelno == logging.WARNING] assert any( - "Refusing to follow redirect to disallowed target" in r.message - and UNRELATED_URL in r.message + "Refusing to follow redirect to disallowed target" in r.message and UNRELATED_URL in r.message for r in warnings ), f"Expected a block warning for {UNRELATED_URL}, got: {[r.message for r in warnings]}" diff --git a/sdk/confidentialledger/azure-confidentialledger/tsp-location.yaml b/sdk/confidentialledger/azure-confidentialledger/tsp-location.yaml index 1571c3088a86..85a542b9fdad 100644 --- a/sdk/confidentialledger/azure-confidentialledger/tsp-location.yaml +++ b/sdk/confidentialledger/azure-confidentialledger/tsp-location.yaml @@ -1,4 +1,4 @@ -directory: specification/confidentialledger/Microsoft.ConfidentialLedger/Ledger -commit: cccd9de9aa977d28bee3f8bfa028c8b34b3db78c +directory: specification/confidentialledger/data-plane/ConfidentialLedger +commit: 8a3262d0e5c399e19b4e489368643a0e5b7f16e3 repo: Azure/azure-rest-api-specs -additionalDirectories: [] +additionalDirectories: