Skip to content

Commit 4427d21

Browse files
feat: add delete and delete_latest_version methods to ContractClient (DQ-665)
Adds SDK support for DataContract deletion — both delete-all (cascade) and delete-latest-only modes — across sync/async and legacy/v9 clients. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d5109e7 commit 4427d21

9 files changed

Lines changed: 212 additions & 4 deletions

File tree

pyatlan/client/aio/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ async def _call_api(
501501
request_obj=None,
502502
exclude_unset: bool = True,
503503
text_response=False,
504+
extra_headers=None,
504505
):
505506
"""
506507
Async version of _call_api - mirrors sync client structure.
@@ -509,6 +510,8 @@ async def _call_api(
509510
params = await self._create_params(
510511
api, query_params, request_obj, exclude_unset
511512
)
513+
if extra_headers:
514+
params["headers"].update(extra_headers)
512515
if LOGGER.isEnabledFor(logging.DEBUG):
513516
self._api_logger(api, path)
514517
return await self._call_api_internal(

pyatlan/client/aio/contract.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
from pydantic.v1 import validate_arguments
88

99
from pyatlan.client.common import AsyncApiCaller, ContractInit
10-
from pyatlan.client.constants import CONTRACT_INIT_API
10+
from pyatlan.client.constants import CONTRACT_INIT_API, DELETE_ENTITIES_BY_GUIDS
1111
from pyatlan.errors import ErrorCode
1212
from pyatlan.model.assets import Asset
13+
from pyatlan.model.enums import AtlanDeleteType
14+
from pyatlan.model.response import AssetMutationResponse
15+
16+
CONTRACT_DELETE_SCOPE_HEADER = "x-atlan-contract-delete-scope"
1317

1418

1519
class AsyncContractClient:
@@ -49,3 +53,47 @@ async def generate_initial_spec(
4953

5054
# Process response using shared logic
5155
return ContractInit.process_response(response)
56+
57+
@validate_arguments
58+
async def delete(self, guid: str) -> AssetMutationResponse:
59+
"""
60+
Hard-delete (purge) a data contract and all its versions (async version).
61+
This deletes every version of the contract associated with the same asset
62+
and cleans up the asset's contract attributes (hasContract, dataContractLatest,
63+
dataContractLatestCertified).
64+
65+
:param guid: unique identifier (GUID) of any version of the contract to delete
66+
:returns: details of the deleted contract version(s)
67+
:raises AtlanError: on any API communication issue
68+
69+
.. warning::
70+
This is an irreversible operation. All versions of the contract will be permanently removed.
71+
"""
72+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
73+
raw_json = await self._client._call_api(
74+
DELETE_ENTITIES_BY_GUIDS, query_params=query_params
75+
)
76+
return AssetMutationResponse(**raw_json)
77+
78+
@validate_arguments
79+
async def delete_latest_version(self, guid: str) -> AssetMutationResponse:
80+
"""
81+
Hard-delete (purge) only the latest version of a data contract (async version).
82+
The previous version (if any) becomes the new latest, and the asset's
83+
contract pointers are updated accordingly.
84+
85+
:param guid: unique identifier (GUID) of the latest contract version to delete
86+
:returns: details of the deleted contract version
87+
:raises AtlanError: on any API communication issue
88+
:raises ApiError: if the specified GUID is not the latest version
89+
90+
.. warning::
91+
This is an irreversible operation. Only the latest version will be removed.
92+
"""
93+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
94+
raw_json = await self._client._call_api(
95+
DELETE_ENTITIES_BY_GUIDS,
96+
query_params=query_params,
97+
extra_headers={CONTRACT_DELETE_SCOPE_HEADER: "single"},
98+
)
99+
return AssetMutationResponse(**raw_json)

pyatlan/client/atlan.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,9 +792,12 @@ def _call_api(
792792
request_obj=None,
793793
exclude_unset: bool = True,
794794
text_response=False,
795+
extra_headers=None,
795796
):
796797
path = self._create_path(api)
797798
params = self._create_params(api, query_params, request_obj, exclude_unset)
799+
if extra_headers:
800+
params["headers"].update(extra_headers)
798801
if LOGGER.isEnabledFor(logging.DEBUG):
799802
self._api_logger(api, path)
800803
return self._call_api_internal(api, path, params, text_response=text_response)

pyatlan/client/contract.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
from pydantic.v1 import validate_arguments
66

77
from pyatlan.client.common import ApiCaller, ContractInit
8-
from pyatlan.client.constants import CONTRACT_INIT_API
8+
from pyatlan.client.constants import CONTRACT_INIT_API, DELETE_ENTITIES_BY_GUIDS
99
from pyatlan.errors import ErrorCode
1010
from pyatlan.model.assets import Asset
11+
from pyatlan.model.enums import AtlanDeleteType
12+
from pyatlan.model.response import AssetMutationResponse
13+
14+
CONTRACT_DELETE_SCOPE_HEADER = "x-atlan-contract-delete-scope"
1115

1216

1317
class ContractClient:
@@ -44,3 +48,47 @@ def generate_initial_spec(
4448

4549
# Process response using shared logic
4650
return ContractInit.process_response(response)
51+
52+
@validate_arguments
53+
def delete(self, guid: str) -> AssetMutationResponse:
54+
"""
55+
Hard-delete (purge) a data contract and all its versions.
56+
This deletes every version of the contract associated with the same asset
57+
and cleans up the asset's contract attributes (hasContract, dataContractLatest,
58+
dataContractLatestCertified).
59+
60+
:param guid: unique identifier (GUID) of any version of the contract to delete
61+
:returns: details of the deleted contract version(s)
62+
:raises AtlanError: on any API communication issue
63+
64+
.. warning::
65+
This is an irreversible operation. All versions of the contract will be permanently removed.
66+
"""
67+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
68+
raw_json = self._client._call_api(
69+
DELETE_ENTITIES_BY_GUIDS, query_params=query_params
70+
)
71+
return AssetMutationResponse(**raw_json)
72+
73+
@validate_arguments
74+
def delete_latest_version(self, guid: str) -> AssetMutationResponse:
75+
"""
76+
Hard-delete (purge) only the latest version of a data contract.
77+
The previous version (if any) becomes the new latest, and the asset's
78+
contract pointers are updated accordingly.
79+
80+
:param guid: unique identifier (GUID) of the latest contract version to delete
81+
:returns: details of the deleted contract version
82+
:raises AtlanError: on any API communication issue
83+
:raises ApiError: if the specified GUID is not the latest version
84+
85+
.. warning::
86+
This is an irreversible operation. Only the latest version will be removed.
87+
"""
88+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
89+
raw_json = self._client._call_api(
90+
DELETE_ENTITIES_BY_GUIDS,
91+
query_params=query_params,
92+
extra_headers={CONTRACT_DELETE_SCOPE_HEADER: "single"},
93+
)
94+
return AssetMutationResponse(**raw_json)

pyatlan/client/protocol.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def _call_api(
2626
request_obj=None,
2727
exclude_unset: bool = True,
2828
text_response: bool = False,
29+
extra_headers=None,
2930
):
3031
pass
3132

@@ -56,6 +57,7 @@ async def _call_api(
5657
request_obj=None,
5758
exclude_unset: bool = True,
5859
text_response: bool = False,
60+
extra_headers=None,
5961
) -> Any:
6062
pass
6163

pyatlan_v9/client/aio/atlan.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,12 @@ async def _call_api(
418418
query_params=None,
419419
request_obj=None,
420420
text_response=False,
421+
extra_headers=None,
421422
):
422423
path = self._create_path(api)
423424
params = await self._create_params(api, query_params, request_obj)
425+
if extra_headers:
426+
params["headers"].update(extra_headers)
424427
if LOGGER.isEnabledFor(logging.DEBUG):
425428
self._api_logger(api, path)
426429
return await self._call_api_internal(

pyatlan_v9/client/aio/contract.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55
from typing import Optional
66

77
from pyatlan.client.common import AsyncApiCaller
8-
from pyatlan.client.constants import CONTRACT_INIT_API
8+
from pyatlan.client.constants import CONTRACT_INIT_API, DELETE_ENTITIES_BY_GUIDS
99
from pyatlan.errors import ErrorCode
10+
from pyatlan_v9.client.asset import _parse_mutation_response
1011
from pyatlan_v9.model.assets import Asset
1112
from pyatlan_v9.model.contract import InitRequest
13+
from pyatlan_v9.model.enums import AtlanDeleteType
14+
from pyatlan_v9.model.response import AssetMutationResponse
1215
from pyatlan_v9.validate import validate_arguments
1316

17+
CONTRACT_DELETE_SCOPE_HEADER = "x-atlan-contract-delete-scope"
18+
1419

1520
class V9AsyncContractClient:
1621
"""
@@ -48,3 +53,47 @@ async def generate_initial_spec(
4853
CONTRACT_INIT_API, request_obj=request_obj
4954
)
5055
return response.get("contract")
56+
57+
@validate_arguments
58+
async def delete(self, guid: str) -> AssetMutationResponse:
59+
"""
60+
Hard-delete (purge) a data contract and all its versions (async version).
61+
This deletes every version of the contract associated with the same asset
62+
and cleans up the asset's contract attributes (hasContract, dataContractLatest,
63+
dataContractLatestCertified).
64+
65+
:param guid: unique identifier (GUID) of any version of the contract to delete
66+
:returns: details of the deleted contract version(s)
67+
:raises AtlanError: on any API communication issue
68+
69+
.. warning::
70+
This is an irreversible operation. All versions of the contract will be permanently removed.
71+
"""
72+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
73+
raw_json = await self._client._call_api(
74+
DELETE_ENTITIES_BY_GUIDS, query_params=query_params
75+
)
76+
return _parse_mutation_response(raw_json)
77+
78+
@validate_arguments
79+
async def delete_latest_version(self, guid: str) -> AssetMutationResponse:
80+
"""
81+
Hard-delete (purge) only the latest version of a data contract (async version).
82+
The previous version (if any) becomes the new latest, and the asset's
83+
contract pointers are updated accordingly.
84+
85+
:param guid: unique identifier (GUID) of the latest contract version to delete
86+
:returns: details of the deleted contract version
87+
:raises AtlanError: on any API communication issue
88+
:raises ApiError: if the specified GUID is not the latest version
89+
90+
.. warning::
91+
This is an irreversible operation. Only the latest version will be removed.
92+
"""
93+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
94+
raw_json = await self._client._call_api(
95+
DELETE_ENTITIES_BY_GUIDS,
96+
query_params=query_params,
97+
extra_headers={CONTRACT_DELETE_SCOPE_HEADER: "single"},
98+
)
99+
return _parse_mutation_response(raw_json)

pyatlan_v9/client/atlan.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,9 +650,12 @@ def _call_api(
650650
query_params=None,
651651
request_obj=None,
652652
text_response=False,
653+
extra_headers=None,
653654
):
654655
path = self._create_path(api)
655656
params = self._create_params(api, query_params, request_obj)
657+
if extra_headers:
658+
params["headers"].update(extra_headers)
656659
if LOGGER.isEnabledFor(logging.DEBUG):
657660
self._api_logger(api, path)
658661
return self._call_api_internal(api, path, params, text_response=text_response)

pyatlan_v9/client/contract.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33
from typing import Optional
44

55
from pyatlan.client.common import ApiCaller
6-
from pyatlan.client.constants import CONTRACT_INIT_API
6+
from pyatlan.client.constants import CONTRACT_INIT_API, DELETE_ENTITIES_BY_GUIDS
77
from pyatlan.errors import ErrorCode
8+
from pyatlan_v9.client.asset import _parse_mutation_response
89
from pyatlan_v9.model.assets import Asset
910
from pyatlan_v9.model.contract import InitRequest
11+
from pyatlan_v9.model.enums import AtlanDeleteType
12+
from pyatlan_v9.model.response import AssetMutationResponse
1013
from pyatlan_v9.validate import validate_arguments
1114

15+
CONTRACT_DELETE_SCOPE_HEADER = "x-atlan-contract-delete-scope"
16+
1217

1318
class V9ContractClient:
1419
"""
@@ -42,3 +47,47 @@ def generate_initial_spec(
4247
)
4348
response = self._client._call_api(CONTRACT_INIT_API, request_obj=request_obj)
4449
return response.get("contract")
50+
51+
@validate_arguments
52+
def delete(self, guid: str) -> AssetMutationResponse:
53+
"""
54+
Hard-delete (purge) a data contract and all its versions.
55+
This deletes every version of the contract associated with the same asset
56+
and cleans up the asset's contract attributes (hasContract, dataContractLatest,
57+
dataContractLatestCertified).
58+
59+
:param guid: unique identifier (GUID) of any version of the contract to delete
60+
:returns: details of the deleted contract version(s)
61+
:raises AtlanError: on any API communication issue
62+
63+
.. warning::
64+
This is an irreversible operation. All versions of the contract will be permanently removed.
65+
"""
66+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
67+
raw_json = self._client._call_api(
68+
DELETE_ENTITIES_BY_GUIDS, query_params=query_params
69+
)
70+
return _parse_mutation_response(raw_json)
71+
72+
@validate_arguments
73+
def delete_latest_version(self, guid: str) -> AssetMutationResponse:
74+
"""
75+
Hard-delete (purge) only the latest version of a data contract.
76+
The previous version (if any) becomes the new latest, and the asset's
77+
contract pointers are updated accordingly.
78+
79+
:param guid: unique identifier (GUID) of the latest contract version to delete
80+
:returns: details of the deleted contract version
81+
:raises AtlanError: on any API communication issue
82+
:raises ApiError: if the specified GUID is not the latest version
83+
84+
.. warning::
85+
This is an irreversible operation. Only the latest version will be removed.
86+
"""
87+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
88+
raw_json = self._client._call_api(
89+
DELETE_ENTITIES_BY_GUIDS,
90+
query_params=query_params,
91+
extra_headers={CONTRACT_DELETE_SCOPE_HEADER: "single"},
92+
)
93+
return _parse_mutation_response(raw_json)

0 commit comments

Comments
 (0)