Skip to content

Commit e3a521f

Browse files
committed
[refactor] Migrate v9 client layer and enforce proper sync/async model separation
- Add dedicated v9 sync and async client sub-clients (user, group, typedef, token, workflow, asset, admin, audit, credential, file, oauth_client, open_lineage, query, role, search_log, sso, task, contract, impersonate) - Remove Pydantic remnants from v9 client layer: eliminate AtlanObject imports, exclude_unset parameter, and .json(by_alias=True) serialization - Use creator/updater naming convention for v9 client CRUD methods; keep create_connection/create_sso_group compound names unchanged - Remove unnecessary create=creator backward-compat aliases from v9 models (query, user, open_lineage event/job/input_dataset/output_dataset) - Separate async models into pyatlan_v9/model/aio/ matching legacy structure: AsyncUserResponse, AsyncGroupResponse, AsyncOAuthClientListResponse, AsyncCustomMetadataDict/Proxy/Request - Remove mixed async code (_get_next_page_async, __aiter__) from sync UserResponse and GroupResponse - Fix entity.py to import AsyncCustomMetadataProxy from v9 instead of legacy - Update all v9 unit tests for client naming, model changes, and async separation Made-with: Cursor
1 parent b47a712 commit e3a521f

237 files changed

Lines changed: 51215 additions & 661 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pyatlan_v9/client/admin.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright 2025 Atlan Pte. Ltd.
3+
4+
from __future__ import annotations
5+
6+
import msgspec
7+
8+
from pyatlan.client.common import AdminGetAdminEvents, AdminGetKeycloakEvents, ApiCaller
9+
from pyatlan.errors import ErrorCode
10+
from pyatlan.validate import validate_arguments
11+
from pyatlan_v9.model.keycloak_events import (
12+
AdminEvent,
13+
AdminEventRequest,
14+
AdminEventResponse,
15+
KeycloakEvent,
16+
KeycloakEventRequest,
17+
KeycloakEventResponse,
18+
)
19+
20+
21+
class V9AdminClient:
22+
"""
23+
This class can be used to retrieve keycloak and admin events. This class does not need to be instantiated
24+
directly but can be obtained through the admin property of AtlanClient.
25+
"""
26+
27+
def __init__(self, client: ApiCaller):
28+
if not isinstance(client, ApiCaller):
29+
raise ErrorCode.INVALID_PARAMETER_TYPE.exception_with_parameters(
30+
"client", "ApiCaller"
31+
)
32+
self._client = client
33+
34+
@validate_arguments
35+
def get_keycloak_events(
36+
self, keycloak_request: KeycloakEventRequest
37+
) -> KeycloakEventResponse:
38+
"""
39+
Retrieve all events, based on the supplied filters.
40+
41+
:param keycloak_request: details of the filters to apply when retrieving events
42+
:returns: the events that match the supplied filters
43+
:raises AtlanError: on any API communication issue
44+
"""
45+
endpoint, query_params = AdminGetKeycloakEvents.prepare_request(
46+
keycloak_request
47+
)
48+
raw_json = self._client._call_api(
49+
endpoint,
50+
query_params=query_params,
51+
)
52+
if raw_json:
53+
events = msgspec.convert(raw_json, list[KeycloakEvent], strict=False)
54+
else:
55+
events = []
56+
57+
return KeycloakEventResponse(
58+
client=self._client,
59+
criteria=keycloak_request,
60+
start=keycloak_request.offset or 0,
61+
size=keycloak_request.size or 100,
62+
events=events,
63+
)
64+
65+
@validate_arguments
66+
def get_admin_events(self, admin_request: AdminEventRequest) -> AdminEventResponse:
67+
"""
68+
Retrieve admin events based on the supplied filters.
69+
70+
:param admin_request: details of the filters to apply when retrieving admin events
71+
:returns: the admin events that match the supplied filters
72+
:raises AtlanError: on any API communication issue
73+
"""
74+
endpoint, query_params = AdminGetAdminEvents.prepare_request(admin_request)
75+
raw_json = self._client._call_api(
76+
endpoint, query_params=query_params
77+
)
78+
if raw_json:
79+
events = msgspec.convert(raw_json, list[AdminEvent], strict=False)
80+
else:
81+
events = []
82+
83+
return AdminEventResponse(
84+
client=self._client,
85+
criteria=admin_request,
86+
start=admin_request.offset or 0,
87+
size=admin_request.size or 100,
88+
events=events,
89+
)

pyatlan_v9/client/aio/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright 2025 Atlan Pte. Ltd.
3+
"""v9 async client wrappers."""
4+
5+
from pyatlan_v9.client.aio.asset import V9AsyncAssetClient
6+
from pyatlan_v9.client.aio.atlan import AsyncAtlanClient
7+
from pyatlan_v9.client.aio.group import V9AsyncGroupClient
8+
9+
__all__ = ["AsyncAtlanClient", "V9AsyncAssetClient", "V9AsyncGroupClient"]

pyatlan_v9/client/aio/admin.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright 2025 Atlan Pte. Ltd.
3+
4+
from __future__ import annotations
5+
6+
import msgspec
7+
8+
from pyatlan.client.common import (
9+
AdminGetAdminEvents,
10+
AdminGetKeycloakEvents,
11+
AsyncApiCaller,
12+
)
13+
from pyatlan.errors import ErrorCode
14+
from pyatlan.validate import validate_arguments
15+
from pyatlan_v9.model.aio.keycloak_events import (
16+
AsyncAdminEventResponse,
17+
AsyncKeycloakEventResponse,
18+
)
19+
from pyatlan_v9.model.keycloak_events import (
20+
AdminEvent,
21+
AdminEventRequest,
22+
KeycloakEvent,
23+
KeycloakEventRequest,
24+
)
25+
26+
27+
class V9AsyncAdminClient:
28+
"""
29+
Async version of AdminClient for retrieving keycloak and admin events. This class does not need to be instantiated
30+
directly but can be obtained through the admin property of the async Atlan client.
31+
"""
32+
33+
def __init__(self, client: AsyncApiCaller):
34+
if not isinstance(client, AsyncApiCaller):
35+
raise ErrorCode.INVALID_PARAMETER_TYPE.exception_with_parameters(
36+
"client", "AsyncApiCaller"
37+
)
38+
self._client = client
39+
40+
@validate_arguments
41+
async def get_keycloak_events(
42+
self, keycloak_request: KeycloakEventRequest
43+
) -> AsyncKeycloakEventResponse:
44+
"""
45+
Retrieve all events, based on the supplied filters.
46+
47+
:param keycloak_request: details of the filters to apply when retrieving events
48+
:returns: the events that match the supplied filters
49+
:raises AtlanError: on any API communication issue
50+
"""
51+
endpoint, query_params = AdminGetKeycloakEvents.prepare_request(
52+
keycloak_request
53+
)
54+
raw_json = await self._client._call_api(
55+
endpoint,
56+
query_params=query_params,
57+
)
58+
if raw_json:
59+
events = msgspec.convert(raw_json, list[KeycloakEvent], strict=False)
60+
else:
61+
events = []
62+
63+
return AsyncKeycloakEventResponse(
64+
client=self._client,
65+
criteria=keycloak_request,
66+
start=keycloak_request.offset or 0,
67+
size=keycloak_request.size or 100,
68+
events=events,
69+
)
70+
71+
@validate_arguments
72+
async def get_admin_events(
73+
self, admin_request: AdminEventRequest
74+
) -> AsyncAdminEventResponse:
75+
"""
76+
Retrieve admin events based on the supplied filters.
77+
78+
:param admin_request: details of the filters to apply when retrieving admin events
79+
:returns: the admin events that match the supplied filters
80+
:raises AtlanError: on any API communication issue
81+
"""
82+
endpoint, query_params = AdminGetAdminEvents.prepare_request(admin_request)
83+
raw_json = await self._client._call_api(
84+
endpoint, query_params=query_params
85+
)
86+
if raw_json:
87+
events = msgspec.convert(raw_json, list[AdminEvent], strict=False)
88+
else:
89+
events = []
90+
91+
return AsyncAdminEventResponse(
92+
client=self._client,
93+
criteria=admin_request,
94+
start=admin_request.offset or 0,
95+
size=admin_request.size or 100,
96+
events=events,
97+
)

0 commit comments

Comments
 (0)