Skip to content

Commit a34d753

Browse files
authored
Merge pull request #903 from atlanhq/dq-665-contract-delete-sdk
feat: add contract delete SDK methods (DQ-665)
2 parents dbbddb0 + 5b093b3 commit a34d753

16 files changed

Lines changed: 1716 additions & 9 deletions

File tree

pyatlan/client/aio/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from contextlib import _AsyncGeneratorContextManager
1717
from http import HTTPStatus
1818
from types import SimpleNamespace
19-
from typing import Any, Optional
19+
from typing import Any, Dict, Optional
2020

2121
import httpx
2222
from httpx_retries.retry import Retry
@@ -501,6 +501,7 @@ async def _call_api(
501501
request_obj=None,
502502
exclude_unset: bool = True,
503503
text_response=False,
504+
extra_headers: Optional[Dict[str, str]] = 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: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@
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 (
11+
CONTRACT_DELETE_SCOPE_HEADER,
12+
CONTRACT_INIT_API,
13+
DELETE_ENTITIES_BY_GUIDS,
14+
)
1115
from pyatlan.errors import ErrorCode
1216
from pyatlan.model.assets import Asset
17+
from pyatlan.model.enums import AtlanDeleteType
18+
from pyatlan.model.response import AssetMutationResponse
1319

1420

1521
class AsyncContractClient:
@@ -49,3 +55,47 @@ async def generate_initial_spec(
4955

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,3 +704,5 @@
704704
HTTPStatus.ACCEPTED,
705705
endpoint=EndPoint.CHRONOS,
706706
)
707+
708+
CONTRACT_DELETE_SCOPE_HEADER = "x-atlan-contract-delete-scope"

pyatlan/client/contract.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
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 (
9+
CONTRACT_DELETE_SCOPE_HEADER,
10+
CONTRACT_INIT_API,
11+
DELETE_ENTITIES_BY_GUIDS,
12+
)
913
from pyatlan.errors import ErrorCode
1014
from pyatlan.model.assets import Asset
15+
from pyatlan.model.enums import AtlanDeleteType
16+
from pyatlan.model.response import AssetMutationResponse
1117

1218

1319
class ContractClient:
@@ -44,3 +50,47 @@ def generate_initial_spec(
4450

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

pyatlan/client/protocol.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from contextlib import _AsyncGeneratorContextManager, _GeneratorContextManager
6-
from typing import Any, Protocol, runtime_checkable
6+
from typing import Any, Dict, Optional, Protocol, runtime_checkable
77

88
from httpx_retries import Retry
99

@@ -26,6 +26,7 @@ def _call_api(
2626
request_obj=None,
2727
exclude_unset: bool = True,
2828
text_response: bool = False,
29+
extra_headers: Optional[Dict[str, str]] = 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: Optional[Dict[str, str]] = 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: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +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 (
9+
CONTRACT_DELETE_SCOPE_HEADER,
10+
CONTRACT_INIT_API,
11+
DELETE_ENTITIES_BY_GUIDS,
12+
)
913
from pyatlan.errors import ErrorCode
14+
from pyatlan_v9.client.asset import _parse_mutation_response
1015
from pyatlan_v9.model.assets import Asset
1116
from pyatlan_v9.model.contract import InitRequest
17+
from pyatlan_v9.model.enums import AtlanDeleteType
18+
from pyatlan_v9.model.response import AssetMutationResponse
1219
from pyatlan_v9.validate import validate_arguments
1320

1421

@@ -48,3 +55,47 @@ async def generate_initial_spec(
4855
CONTRACT_INIT_API, request_obj=request_obj
4956
)
5057
return response.get("contract")
58+
59+
@validate_arguments
60+
async def delete(self, guid: str) -> AssetMutationResponse:
61+
"""
62+
Hard-delete (purge) a data contract and all its versions (async version).
63+
This deletes every version of the contract associated with the same asset
64+
and cleans up the asset's contract attributes (hasContract, dataContractLatest,
65+
dataContractLatestCertified).
66+
67+
:param guid: unique identifier (GUID) of any version of the contract to delete
68+
:returns: details of the deleted contract version(s)
69+
:raises AtlanError: on any API communication issue
70+
71+
.. warning::
72+
This is an irreversible operation. All versions of the contract will be permanently removed.
73+
"""
74+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
75+
raw_json = await self._client._call_api(
76+
DELETE_ENTITIES_BY_GUIDS, query_params=query_params
77+
)
78+
return _parse_mutation_response(raw_json)
79+
80+
@validate_arguments
81+
async def delete_latest_version(self, guid: str) -> AssetMutationResponse:
82+
"""
83+
Hard-delete (purge) only the latest version of a data contract (async version).
84+
The previous version (if any) becomes the new latest, and the asset's
85+
contract pointers are updated accordingly.
86+
87+
:param guid: unique identifier (GUID) of the latest contract version to delete
88+
:returns: details of the deleted contract version
89+
:raises AtlanError: on any API communication issue
90+
:raises ApiError: if the specified GUID is not the latest version
91+
92+
.. warning::
93+
This is an irreversible operation. Only the latest version will be removed.
94+
"""
95+
query_params = {"deleteType": AtlanDeleteType.PURGE.value, "guid": [guid]}
96+
raw_json = await self._client._call_api(
97+
DELETE_ENTITIES_BY_GUIDS,
98+
query_params=query_params,
99+
extra_headers={CONTRACT_DELETE_SCOPE_HEADER: "single"},
100+
)
101+
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: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +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 (
7+
CONTRACT_DELETE_SCOPE_HEADER,
8+
CONTRACT_INIT_API,
9+
DELETE_ENTITIES_BY_GUIDS,
10+
)
711
from pyatlan.errors import ErrorCode
12+
from pyatlan_v9.client.asset import _parse_mutation_response
813
from pyatlan_v9.model.assets import Asset
914
from pyatlan_v9.model.contract import InitRequest
15+
from pyatlan_v9.model.enums import AtlanDeleteType
16+
from pyatlan_v9.model.response import AssetMutationResponse
1017
from pyatlan_v9.validate import validate_arguments
1118

1219

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

0 commit comments

Comments
 (0)