Skip to content

Commit 8199787

Browse files
committed
[change] Bound EnumCache to AtlanClient, moved class var to TLS
1 parent 5f946f1 commit 8199787

File tree

2 files changed

+38
-20
lines changed

2 files changed

+38
-20
lines changed

pyatlan/cache/enum_cache.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,48 @@
11
# SPDX-License-Identifier: Apache-2.0
2-
# Copyright 2023 Atlan Pte. Ltd.
3-
from threading import Lock
4-
from typing import Dict, Optional
2+
# Copyright 2025 Atlan Pte. Ltd.
3+
from __future__ import annotations
4+
5+
from threading import Lock, local
6+
from typing import TYPE_CHECKING, Dict, Optional
57

6-
from pyatlan.client.typedef import TypeDefClient
78
from pyatlan.errors import ErrorCode
89
from pyatlan.model.enums import AtlanTypeCategory
910
from pyatlan.model.typedef import EnumDef
1011

12+
if TYPE_CHECKING:
13+
from pyatlan.client.atlan import AtlanClient
14+
1115
lock: Lock = Lock()
16+
enum_cache_tls = local() # Thread-local storage (TLS)
1217

1318

1419
class EnumCache:
1520
"""
1621
Lazily-loaded cache for accessing details of an enumeration.
1722
"""
1823

19-
caches: Dict[int, "EnumCache"] = {}
24+
def __init__(self, client: AtlanClient):
25+
self.client: AtlanClient = client
26+
self.cache_by_name: Dict[str, EnumDef] = {}
27+
self.lock: Lock = Lock()
2028

2129
@classmethod
22-
def get_cache(cls) -> "EnumCache":
30+
def get_cache(cls, client: Optional[AtlanClient] = None) -> EnumCache:
2331
from pyatlan.client.atlan import AtlanClient
2432

2533
with lock:
26-
client = AtlanClient.get_default_client()
34+
client = client or AtlanClient.get_default_client()
2735
cache_key = client.cache_key
28-
if cache_key not in cls.caches:
29-
cls.caches[cache_key] = EnumCache(typedef_client=client.typedef)
30-
return cls.caches[cache_key]
36+
37+
if not hasattr(enum_cache_tls, "caches"):
38+
enum_cache_tls.caches = {}
39+
40+
if cache_key not in enum_cache_tls.caches:
41+
cache_instance = EnumCache(client=client)
42+
cache_instance._refresh_cache() # Refresh on new cache instance
43+
enum_cache_tls.caches[cache_key] = cache_instance
44+
45+
return enum_cache_tls.caches[cache_key]
3146

3247
@classmethod
3348
def refresh_cache(cls) -> None:
@@ -49,17 +64,12 @@ def get_by_name(cls, name: str) -> EnumDef:
4964
raise ErrorCode.ENUM_NOT_FOUND.exception_with_parameters(name)
5065
return enum
5166

52-
def __init__(self, typedef_client: TypeDefClient):
53-
self.typedef_client: TypeDefClient = typedef_client
54-
self.cache_by_name: Dict[str, EnumDef] = {}
55-
self.lock: Lock = Lock()
56-
5767
def _refresh_cache(self) -> None:
5868
"""
5969
Refreshes the cache of enumerations by requesting the full set of enumerations from Atlan.
6070
"""
6171
with self.lock:
62-
response = self.typedef_client.get(type_category=AtlanTypeCategory.ENUM)
72+
response = self.client.typedef.get(type_category=AtlanTypeCategory.ENUM)
6373
if not response or not response.enum_defs:
6474
raise ErrorCode.EXPIRED_API_TOKEN.exception_with_parameters()
6575
self.cache_by_name = {}

pyatlan/client/atlan.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
from pyatlan.cache.atlan_tag_cache import AtlanTagCache
4545
from pyatlan.cache.custom_metadata_cache import CustomMetadataCache
46+
from pyatlan.cache.enum_cache import EnumCache
4647
from pyatlan.client.admin import AdminClient
4748
from pyatlan.client.asset import A, AssetClient, IndexSearchResults, LineageListResults
4849
from pyatlan.client.audit import AuditClient
@@ -144,7 +145,7 @@ def get_session():
144145

145146

146147
class AtlanClient(BaseSettings):
147-
_default_client_storage: ClassVar[local] = local() # Thread-local storage
148+
_default_client_tls: ClassVar[local] = local() # Thread-local storage (TLS)
148149
base_url: Union[Literal["INTERNAL"], HttpUrl]
149150
api_key: str
150151
connect_timeout: float = 30.0 # 30 secs
@@ -173,6 +174,7 @@ class AtlanClient(BaseSettings):
173174
_contract_client: Optional[ContractClient] = PrivateAttr(default=None)
174175
_open_lineage_client: Optional[OpenLineageClient] = PrivateAttr(default=None)
175176
_atlan_tag_cache: Optional[AtlanTagCache] = PrivateAttr(default=None)
177+
_enum_cache: Optional[EnumCache] = PrivateAttr(default=None)
176178
_custom_metadata_cache: Optional[CustomMetadataCache] = PrivateAttr(default=None)
177179

178180
class Config:
@@ -185,7 +187,7 @@ def set_default_client(cls, client: "AtlanClient"):
185187
"""
186188
if not isinstance(client, AtlanClient):
187189
raise ErrorCode.MISSING_ATLAN_CLIENT.exception_with_parameters()
188-
cls._default_client_storage.client = client
190+
cls._default_client_tls.client = client
189191

190192
@classmethod
191193
def get_default_client(cls) -> AtlanClient:
@@ -194,9 +196,9 @@ def get_default_client(cls) -> AtlanClient:
194196
195197
:returns: the default client
196198
"""
197-
if not hasattr(cls._default_client_storage, "client"):
199+
if not hasattr(cls._default_client_tls, "client"):
198200
raise ErrorCode.NO_ATLAN_CLIENT_AVAILABLE.exception_with_parameters()
199-
return cls._default_client_storage.client
201+
return cls._default_client_tls.client
200202

201203
def __init__(self, **data):
202204
super().__init__(**data)
@@ -329,6 +331,12 @@ def atlan_tag_cache(self) -> AtlanTagCache:
329331
self._atlan_tag_cache = AtlanTagCache.get_cache(client=self)
330332
return self._atlan_tag_cache
331333

334+
@property
335+
def enum_cache(self) -> EnumCache:
336+
if self._enum_cache is None:
337+
self._enum_cache = EnumCache.get_cache(client=self)
338+
return self._enum_cache
339+
332340
@property
333341
def custom_metadata_cache(self) -> CustomMetadataCache:
334342
if self._custom_metadata_cache is None:

0 commit comments

Comments
 (0)