Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyatlan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
except ImportError:
# Fallback for older Python versions
try:
import pkg_resources
import pkg_resources # type: ignore[import-not-found]

__version__ = pkg_resources.get_distribution("pyatlan").version
except Exception:
Expand Down
71 changes: 43 additions & 28 deletions pyatlan/client/aio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import json
import logging
import os
from contextlib import _AsyncGeneratorContextManager
from http import HTTPStatus
from types import SimpleNamespace
from typing import Optional
Expand Down Expand Up @@ -233,126 +234,126 @@ async def from_token_guid( # type: ignore[override]
def admin(self) -> AsyncAdminClient: # type: ignore[override]
"""Get async admin client with same API as sync"""
if self._async_admin_client is None:
self._async_admin_client = AsyncAdminClient(self)
self._async_admin_client = AsyncAdminClient(self) # type: ignore[arg-type]
return self._async_admin_client

@property
def asset(self) -> AsyncAssetClient: # type: ignore[override]
"""Get async asset client with same API as sync"""
if self._async_asset_client is None:
self._async_asset_client = AsyncAssetClient(self)
self._async_asset_client = AsyncAssetClient(self) # type: ignore[arg-type]
return self._async_asset_client

@property
def audit(self) -> AsyncAuditClient: # type: ignore[override]
"""Get async audit client with same API as sync"""
if self._async_audit_client is None:
self._async_audit_client = AsyncAuditClient(self)
self._async_audit_client = AsyncAuditClient(self) # type: ignore[arg-type]
return self._async_audit_client

@property
def contracts(self) -> AsyncContractClient: # type: ignore[override]
"""Get async contract client with same API as sync"""
if self._async_contract_client is None:
self._async_contract_client = AsyncContractClient(self)
self._async_contract_client = AsyncContractClient(self) # type: ignore[arg-type]
return self._async_contract_client

@property
def credentials(self) -> AsyncCredentialClient: # type: ignore[override]
"""Get async credential client with same API as sync"""
if self._async_credential_client is None:
self._async_credential_client = AsyncCredentialClient(self)
self._async_credential_client = AsyncCredentialClient(self) # type: ignore[arg-type]
return self._async_credential_client

@property
def files(self) -> AsyncFileClient: # type: ignore[override]
"""Get async file client with same API as sync"""
if self._async_file_client is None:
self._async_file_client = AsyncFileClient(self)
self._async_file_client = AsyncFileClient(self) # type: ignore[arg-type]
return self._async_file_client

@property
def group(self) -> AsyncGroupClient: # type: ignore[override]
"""Get async group client with same API as sync"""
if self._async_group_client is None:
self._async_group_client = AsyncGroupClient(self)
self._async_group_client = AsyncGroupClient(self) # type: ignore[arg-type]
return self._async_group_client

@property
def impersonate(self) -> AsyncImpersonationClient: # type: ignore[override]
"""Get async impersonate client with same API as sync"""
if self._async_impersonate_client is None:
self._async_impersonate_client = AsyncImpersonationClient(self)
self._async_impersonate_client = AsyncImpersonationClient(self) # type: ignore[arg-type]
return self._async_impersonate_client

@property
def open_lineage(self) -> AsyncOpenLineageClient: # type: ignore[override]
"""Get async open lineage client with same API as sync"""
if self._async_open_lineage_client is None:
self._async_open_lineage_client = AsyncOpenLineageClient(self)
self._async_open_lineage_client = AsyncOpenLineageClient(self) # type: ignore[arg-type]
return self._async_open_lineage_client

@property
def queries(self) -> AsyncQueryClient: # type: ignore[override]
"""Get async query client with same API as sync"""
if self._async_query_client is None:
self._async_query_client = AsyncQueryClient(self)
self._async_query_client = AsyncQueryClient(self) # type: ignore[arg-type]
return self._async_query_client

@property
def role(self) -> AsyncRoleClient: # type: ignore[override]
"""Get async role client with same API as sync"""
if self._async_role_client is None:
self._async_role_client = AsyncRoleClient(self)
self._async_role_client = AsyncRoleClient(self) # type: ignore[arg-type]
return self._async_role_client

@property
def search_log(self) -> AsyncSearchLogClient: # type: ignore[override]
"""Get async search log client with same API as sync"""
if self._async_search_log_client is None:
self._async_search_log_client = AsyncSearchLogClient(self)
self._async_search_log_client = AsyncSearchLogClient(self) # type: ignore[arg-type]
return self._async_search_log_client

@property
def sso(self) -> AsyncSSOClient: # type: ignore[override]
"""Get async SSO client with same API as sync"""
if self._async_sso_client is None:
self._async_sso_client = AsyncSSOClient(self)
self._async_sso_client = AsyncSSOClient(self) # type: ignore[arg-type]
return self._async_sso_client

@property
def tasks(self) -> AsyncTaskClient: # type: ignore[override]
"""Get the task client."""
if self._async_task_client is None:
self._async_task_client = AsyncTaskClient(client=self)
self._async_task_client = AsyncTaskClient(client=self) # type: ignore[arg-type]
return self._async_task_client

@property
def token(self) -> AsyncTokenClient: # type: ignore[override]
"""Get async token client with same API as sync"""
if self._async_token_client is None:
self._async_token_client = AsyncTokenClient(self)
self._async_token_client = AsyncTokenClient(self) # type: ignore[arg-type]
return self._async_token_client

@property
def typedef(self) -> AsyncTypeDefClient: # type: ignore[override]
"""Get async typedef client with same API as sync"""
if self._async_typedef_client is None:
self._async_typedef_client = AsyncTypeDefClient(self)
self._async_typedef_client = AsyncTypeDefClient(self) # type: ignore[arg-type]
return self._async_typedef_client

@property
def user(self) -> AsyncUserClient: # type: ignore[override]
"""Get async user client with same API as sync"""
if self._async_user_client is None:
self._async_user_client = AsyncUserClient(self)
self._async_user_client = AsyncUserClient(self) # type: ignore[arg-type]
return self._async_user_client

@property
def workflow(self) -> AsyncWorkflowClient: # type: ignore[override]
"""Get async workflow client with same API as sync"""
if self._async_workflow_client is None:
self._async_workflow_client = AsyncWorkflowClient(self)
self._async_workflow_client = AsyncWorkflowClient(self) # type: ignore[arg-type]
return self._async_workflow_client

@property
Expand Down Expand Up @@ -884,17 +885,31 @@ async def aclose(self):
if self._async_session:
await self._async_session.aclose()
self._async_session = None
if self._async_asset_client:
self._async_asset_client = None
if self._async_file_client:
self._async_file_client = None
if self._async_group_client:
self._async_group_client = None

@contextlib.asynccontextmanager
async def max_retries( # type: ignore[override]

# Clean up all client references
self._async_admin_client = None
self._async_asset_client = None
self._async_audit_client = None
self._async_contract_client = None
self._async_credential_client = None
self._async_file_client = None
self._async_group_client = None
self._async_impersonate_client = None
self._async_open_lineage_client = None
self._async_query_client = None
self._async_role_client = None
self._async_search_log_client = None
self._async_sso_client = None
self._async_task_client = None
self._async_token_client = None
self._async_typedef_client = None
self._async_user_client = None
self._async_workflow_client = None

@contextlib.asynccontextmanager # type: ignore[arg-type]
async def max_retries( # type: ignore[override,misc]
self, max_retries: Retry = CONNECTION_RETRY
):
) -> _AsyncGeneratorContextManager[None]:
"""Creates an async context manager that can be used to temporarily change parameters used for retrying connections.
The original Retry information will be restored when the context is exited."""
# Store current transport and create new one with updated retries
Expand Down
7 changes: 4 additions & 3 deletions pyatlan/client/atlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import logging
import os
import uuid
from contextlib import _GeneratorContextManager
from contextvars import ContextVar
from http import HTTPStatus
from importlib.resources import read_text
Expand Down Expand Up @@ -1936,10 +1937,10 @@ def find_term_by_name(
name=name, glossary_name=glossary_name, attributes=attributes
)

@contextlib.contextmanager
def max_retries(
@contextlib.contextmanager # type: ignore[misc,arg-type]
def max_retries( # type: ignore[misc]
self, max_retries: Retry = CONNECTION_RETRY
) -> Generator[None, None, None]:
) -> _GeneratorContextManager[None]:
"""Creates a context manger that can used to temporarily change parameters used for retrying connnections.
The original Retry information will be restored when the context is exited."""
# Store current transport and create new one with updated retries
Expand Down
9 changes: 6 additions & 3 deletions pyatlan/client/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# Copyright 2025 Atlan Pte. Ltd.
from __future__ import annotations

from typing import Any, Generator, Protocol, runtime_checkable
from contextlib import _AsyncGeneratorContextManager, _GeneratorContextManager
from typing import Any, Protocol, runtime_checkable

from httpx_retries import Retry

Expand Down Expand Up @@ -30,7 +31,7 @@ def _call_api(

def max_retries(
self, max_retries: Retry = CONNECTION_RETRY
) -> Generator[None, None, None]:
) -> _GeneratorContextManager[None]:
pass

def _s3_presigned_url_file_upload(self, api, upload_file: Any):
Expand Down Expand Up @@ -58,7 +59,9 @@ async def _call_api(
) -> Any:
pass

async def max_retries(self, max_retries: Retry = CONNECTION_RETRY):
async def max_retries(
self, max_retries: Retry = CONNECTION_RETRY
) -> _AsyncGeneratorContextManager[None]:
pass

async def _s3_presigned_url_file_upload(self, api, upload_file: Any):
Expand Down
2 changes: 1 addition & 1 deletion pyatlan/model/aio/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def __init__(
bulk: bool = False,
):
super().__init__(
client,
client, # type: ignore[arg-type]
INDEX_SEARCH,
criteria,
start,
Expand Down
8 changes: 4 additions & 4 deletions pyatlan/model/suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ def get(self, client: AtlanClient) -> SuggestionResponse:
return suggestion_response

def _get_descriptions(self, result: Aggregations, field: AtlanField):
results = []
results = [] # type: ignore[var-annotated]
if isinstance(result, AggregationBucketResult):
for bucket in result.buckets:
count = bucket.doc_count
Expand All @@ -321,7 +321,7 @@ def _get_descriptions(self, result: Aggregations, field: AtlanField):
return results

def _get_terms(self, result: Aggregations):
results = []
results = [] # type: ignore[var-annotated]
if isinstance(result, AggregationBucketResult):
for bucket in result.buckets:
count = bucket.doc_count
Expand All @@ -335,7 +335,7 @@ def _get_terms(self, result: Aggregations):
return results

def _get_tags(self, client: AtlanClient, result: Aggregations):
results = []
results = [] # type: ignore[var-annotated]
if isinstance(result, AggregationBucketResult):
for bucket in result.buckets:
count = bucket.doc_count
Expand All @@ -348,7 +348,7 @@ def _get_tags(self, client: AtlanClient, result: Aggregations):
return results

def _get_others(self, result: Aggregations):
results = []
results = [] # type: ignore[var-annotated]
if isinstance(result, AggregationBucketResult):
for bucket in result.buckets:
count = bucket.doc_count
Expand Down
43 changes: 21 additions & 22 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,16 @@ classifiers = [
]
requires-python = ">=3.9"
dependencies = [
"pydantic~=2.11.7",
"pydantic~=2.12.3",
"jinja2~=3.1.6",
"tenacity~=9.1.2",
"lazy_loader~=0.4",
"lazy-loader~=0.4",
"nanoid~=2.0.0",
"pytz~=2025.2",
"python-dateutil~=2.9.0.post0",
"PyYAML~=6.0.2",
"PyYAML~=6.0.3",
"httpx~=0.28.1",
"httpx-retries~=0.4.0",
"pytest-asyncio~=1.1.0",
"httpx-retries~=0.4.5",
]

[project.urls]
Expand All @@ -48,33 +47,33 @@ Issues = "https://github.com/atlanhq/atlan-python/issues"

[dependency-groups]
dev = [
"mypy~=1.9.0",
"ruff~=0.12.8",
"types-requests~=2.31.0.6",
"types-setuptools~=75.8.0.20250110",
"pytest~=8.3.4",
"mypy~=1.18.0",
"ruff~=0.14.0",
"types-setuptools~=80.9.0.20250822",
"pytest~=8.4.2",
"pytest-vcr~=1.0.2",
"vcrpy~=6.0.2",
"vcrpy~=7.0.0",
"pytest-order~=1.3.0",
"pytest-timer[termcolor]~=1.0.0",
"pytest-sugar~=1.0.0",
"retry~=0.9.2",
"pre-commit~=3.5.0",
"deepdiff~=7.0.1",
"pytest-cov~=5.0.0",
"twine~=6.1.0",
"types-retry~=0.9.9.20241221",
"networkx~=3.1.0",
"pre-commit~=4.3.0",
"deepdiff~=8.6.1",
"pytest-cov~=7.0.0",
"twine~=6.2.0",
"types-retry~=0.9.9.20250322",
"networkx~=3.2.1",
"networkx-stubs~=0.0.1",
"pytest-asyncio~=1.2.0",
]

docs = [
"sphinx~=7.2.6",
"furo~=2024.8.6",
"requests~=2.32.4",
"pydantic~=2.11.7",
"sphinx~=7.4.7",
"furo~=2025.9.25",
"requests~=2.32.5",
"pydantic~=2.12.3",
"jinja2~=3.1.6",
"networkx~=3.1.0",
"networkx~=3.2.1",
"tenacity~=9.1.2",
]

Expand Down
Loading
Loading