Skip to content

Commit fb69b17

Browse files
committed
[req-changes] Added docstrings, fixed imports, pinned deps
1 parent 00ea476 commit fb69b17

8 files changed

Lines changed: 73 additions & 15 deletions

File tree

pyatlan/client/aio/client.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from pyatlan.client.aio.file import AsyncFileClient
4242
from pyatlan.client.aio.group import AsyncGroupClient
4343
from pyatlan.client.aio.impersonate import AsyncImpersonationClient
44+
from pyatlan.client.aio.oauth import AsyncOAuthTokenManager
4445
from pyatlan.client.aio.open_lineage import AsyncOpenLineageClient
4546
from pyatlan.client.aio.query import AsyncQueryClient
4647
from pyatlan.client.aio.role import AsyncRoleClient
@@ -134,13 +135,10 @@ class AsyncAtlanClient(AtlanClient):
134135
def __init__(self, **kwargs):
135136
# Initialize sync client (handles all validation, env vars, etc.)
136137
super().__init__(**kwargs)
137-
138138
if self.oauth_client_id and self.oauth_client_secret and self.api_key is None:
139139
LOGGER.debug(
140140
"API Key not provided. Using Async OAuth flow for authentication"
141141
)
142-
from pyatlan.client.aio.oauth import AsyncOAuthTokenManager
143-
144142
if self._oauth_token_manager:
145143
LOGGER.debug("Sync oauth flow open. Closing it for Async oauth flow")
146144
self._oauth_token_manager.close()

pyatlan/client/aio/oauth.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import time
55
from typing import Optional
6+
from urllib.parse import urljoin
67

78
import httpx
89
from authlib.oauth2.rfc6749 import OAuth2Token
@@ -12,6 +13,19 @@
1213

1314

1415
class AsyncOAuthTokenManager:
16+
"""
17+
Manages OAuth tokens for asynchronous HTTP clients.
18+
19+
:param base_url: Base URL of the Atlan tenant.
20+
:param client_id: OAuth client ID.
21+
:param client_secret: OAuth client secret.
22+
:param http_client: Optional asynchronous HTTP client to use.
23+
:param connect_timeout: Timeout for establishing connections.
24+
:param read_timeout: Timeout for reading data.
25+
:param write_timeout: Timeout for writing data.
26+
:param pool_timeout: Timeout for acquiring a connection from the pool.
27+
"""
28+
1529
def __init__(
1630
self,
1731
base_url: str,
@@ -20,6 +34,8 @@ def __init__(
2034
http_client: Optional[httpx.AsyncClient] = None,
2135
connect_timeout: float = 30.0,
2236
read_timeout: float = 900.0,
37+
write_timeout: float = 30.0,
38+
pool_timeout: float = 30.0,
2339
):
2440
self.base_url = base_url
2541
self.client_id = client_id
@@ -28,13 +44,19 @@ def __init__(
2844
self._lock = asyncio.Lock()
2945
self._http_client = http_client or httpx.AsyncClient(
3046
timeout=httpx.Timeout(
31-
connect=connect_timeout, read=read_timeout, write=30.0, pool=30.0
47+
connect=connect_timeout,
48+
read=read_timeout,
49+
write=write_timeout,
50+
pool=pool_timeout,
3251
)
3352
)
3453
self._token: Optional[OAuth2Token] = None
3554
self._owns_client = http_client is None
3655

3756
async def get_token(self) -> str:
57+
"""
58+
Retrieves a valid OAuth token, refreshing it if necessary.
59+
"""
3860
async with self._lock:
3961
if self._token and not self._token.is_expired():
4062
return str(self._token["access_token"])
@@ -73,18 +95,25 @@ async def get_token(self) -> str:
7395
return access_token
7496

7597
async def invalidate_token(self):
98+
"""
99+
Invalidates the current OAuth token.
100+
"""
76101
async with self._lock:
77102
self._token = None
78103

79104
def _create_path(self, api: API):
80-
from urllib.parse import urljoin
81-
105+
"""
106+
Creates the full URL for the given API endpoint.
107+
"""
82108
if self.base_url == "INTERNAL":
83109
return urljoin(api.endpoint.service, api.path)
84110
else:
85111
base_with_prefix = urljoin(self.base_url, api.endpoint.prefix)
86112
return urljoin(base_with_prefix, api.path)
87113

88114
async def aclose(self):
115+
"""
116+
Closes the underlying HTTP client if owned by this manager.
117+
"""
89118
if self._owns_client:
90119
await self._http_client.aclose()

pyatlan/client/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
WHOAMI_API, HTTPMethod.GET, HTTPStatus.OK, endpoint=EndPoint.HERACLES
9090
)
9191

92-
# oauth client authentinatication
92+
# oauth client authentication
9393
GET_OAUTH_CLIENT = API(
9494
"oauth-clients/token",
9595
HTTPMethod.POST,

pyatlan/client/oauth.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import threading
44
import time
55
from typing import Optional
6+
from urllib.parse import urljoin
67

78
import httpx
89
from authlib.oauth2.rfc6749 import OAuth2Token
@@ -12,6 +13,18 @@
1213

1314

1415
class OAuthTokenManager:
16+
"""
17+
Manages OAuth tokens for HTTP clients.
18+
:param base_url: Base URL of the Atlan tenant.
19+
:param client_id: OAuth client ID.
20+
:param client_secret: OAuth client secret.
21+
:param http_client: Optional HTTP client to use.
22+
:param connect_timeout: Timeout for establishing connections.
23+
:param read_timeout: Timeout for reading data.
24+
:param write_timeout: Timeout for writing data.
25+
:param pool_timeout: Timeout for acquiring a connection from the pool.
26+
"""
27+
1528
def __init__(
1629
self,
1730
base_url: str,
@@ -20,6 +33,8 @@ def __init__(
2033
http_client: Optional[httpx.Client] = None,
2134
connect_timeout: float = 30.0,
2235
read_timeout: float = 900.0,
36+
write_timeout: float = 30.0,
37+
pool_timeout: float = 30.0,
2338
):
2439
self.base_url = base_url
2540
self.client_id = client_id
@@ -28,13 +43,19 @@ def __init__(
2843
self._lock = threading.Lock()
2944
self._http_client = http_client or httpx.Client(
3045
timeout=httpx.Timeout(
31-
connect=connect_timeout, read=read_timeout, write=30.0, pool=30.0
46+
connect=connect_timeout,
47+
read=read_timeout,
48+
write=write_timeout,
49+
pool=pool_timeout,
3250
)
3351
)
3452
self._token: Optional[OAuth2Token] = None
3553
self._owns_client = http_client is None
3654

3755
def get_token(self) -> str:
56+
"""
57+
Retrieves a valid OAuth token, refreshing it if necessary.
58+
"""
3859
with self._lock:
3960
if self._token and not self._token.is_expired():
4061
return str(self._token["access_token"])
@@ -73,18 +94,25 @@ def get_token(self) -> str:
7394
return access_token
7495

7596
def invalidate_token(self):
97+
"""
98+
Invalidates the current OAuth token.
99+
"""
76100
with self._lock:
77101
self._token = None
78102

79103
def _create_path(self, api: API):
80-
from urllib.parse import urljoin
81-
104+
"""
105+
Creates the full URL for the given API endpoint.
106+
"""
82107
if self.base_url == "INTERNAL":
83108
return urljoin(api.endpoint.service, api.path)
84109
else:
85110
base_with_prefix = urljoin(self.base_url, api.endpoint.prefix)
86111
return urljoin(base_with_prefix, api.path)
87112

88113
def close(self):
114+
"""
115+
Closes the underlying HTTP client if owned by this manager.
116+
"""
89117
if self._owns_client:
90118
self._http_client.close()

pyatlan/pkg/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def get_client(
7676
This will use an API token if found in ATLAN_API_KEY, and will fallback to attempting to impersonate a user if
7777
ATLAN_API_KEY is empty.
7878
79-
:param impersonate_user_id: unique identifier (GUID) of a user or API token to impersonate
79+
:param impersonate_user_id: unique identifier (GUID) of a user or API token to impersonate (default is None)
8080
:param set_pkg_headers: whether to set package headers on the client (default is False)
8181
:returns: an initialized client
8282
"""
@@ -131,7 +131,7 @@ async def get_client_async(
131131
This will use an API token if found in ATLAN_API_KEY, and will fallback to attempting to impersonate a user if
132132
ATLAN_API_KEY is empty.
133133
134-
:param impersonate_user_id: unique identifier (GUID) of a user or API token to impersonate
134+
:param impersonate_user_id: unique identifier (GUID) of a user or API token to impersonate (default is None)
135135
:param set_pkg_headers: whether to set package headers on the client (default is False)
136136
:returns: an initialized async client
137137
"""

pyatlan/test_utils/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ def create_connection(
107107
) -> Connection:
108108
admin_role_guid = str(client.role_cache.get_id_for_name("$admin"))
109109
to_create = Connection.create(
110-
client=client, name=name, connector_type=connector_type, admin_roles=[admin_role_guid]
110+
client=client,
111+
name=name,
112+
connector_type=connector_type,
113+
admin_roles=[admin_role_guid],
111114
)
112115
response = client.asset.save(to_create)
113116
result = response.assets_created(asset_type=Connection)[0]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ dev = [
5151
"mypy~=1.18.0",
5252
"ruff~=0.14.5",
5353
"types-setuptools~=80.9.0.20250822",
54-
"types-Authlib",
54+
"types-Authlib~=1.6.5.20251005",
5555
"pytest~=8.4.2",
5656
"pytest-vcr~=1.0.2",
5757
"vcrpy~=7.0.0",

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)