Skip to content

Commit 745e6ac

Browse files
committed
[change] Bound RoleCache to AtlanClient, moved class var to TLS
1 parent 575d729 commit 745e6ac

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

pyatlan/cache/role_cache.py

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
11
# SPDX-License-Identifier: Apache-2.0
2-
# Copyright 2022 Atlan Pte. Ltd.
3-
from threading import Lock
4-
from typing import Dict, Iterable, 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, Iterable, Optional
57

6-
from pyatlan.client.role import RoleClient
78
from pyatlan.model.role import AtlanRole
89

10+
if TYPE_CHECKING:
11+
from pyatlan.client.atlan import AtlanClient
12+
913
lock: Lock = Lock()
14+
role_cache_tls = local() # Thread-local storage (TLS)
1015

1116

1217
class RoleCache:
1318
"""
1419
Lazily-loaded cache for translating Atlan-internal roles into their various IDs.
1520
"""
1621

17-
caches: Dict[int, "RoleCache"] = {}
22+
def __init__(self, client: AtlanClient):
23+
self.client: AtlanClient = client
24+
self.cache_by_id: Dict[str, AtlanRole] = {}
25+
self.map_id_to_name: Dict[str, str] = {}
26+
self.map_name_to_id: Dict[str, str] = {}
27+
self.lock: Lock = Lock()
1828

1929
@classmethod
20-
def get_cache(cls) -> "RoleCache":
30+
def get_cache(cls, client: Optional[AtlanClient] = None) -> RoleCache:
2131
from pyatlan.client.atlan import AtlanClient
2232

2333
with lock:
24-
client = AtlanClient.get_default_client()
34+
client = client or AtlanClient.get_default_client()
2535
cache_key = client.cache_key
26-
if cache_key not in cls.caches:
27-
cls.caches[cache_key] = RoleCache(role_client=client.role)
28-
return cls.caches[cache_key]
36+
37+
if not hasattr(role_cache_tls, "caches"):
38+
role_cache_tls.caches = {}
39+
40+
if cache_key not in role_cache_tls.caches:
41+
cache_instance = RoleCache(client=client)
42+
cache_instance._refresh_cache() # Refresh on new cache instance
43+
role_cache_tls.caches[cache_key] = cache_instance
44+
45+
return role_cache_tls.caches[cache_key]
2946

3047
@classmethod
3148
def get_id_for_name(cls, name: str) -> Optional[str]:
@@ -56,28 +73,22 @@ def validate_idstrs(cls, idstrs: Iterable[str]):
5673
"""
5774
return cls.get_cache()._validate_idstrs(idstrs=idstrs)
5875

59-
def __init__(self, role_client: RoleClient):
60-
self.role_client: RoleClient = role_client
61-
self.cache_by_id: Dict[str, AtlanRole] = {}
62-
self.map_id_to_name: Dict[str, str] = {}
63-
self.map_name_to_id: Dict[str, str] = {}
64-
self.lock: Lock = Lock()
65-
6676
def _refresh_cache(self) -> None:
6777
with self.lock:
68-
response = self.role_client.get(
78+
response = self.client.role.get(
6979
limit=100, post_filter='{"name":{"$ilike":"$%"}}'
7080
)
71-
if response is not None:
72-
self.cache_by_id = {}
73-
self.map_id_to_name = {}
74-
self.map_name_to_id = {}
75-
for role in response.records:
76-
role_id = role.id
77-
role_name = role.name
78-
self.cache_by_id[role_id] = role
79-
self.map_id_to_name[role_id] = role_name
80-
self.map_name_to_id[role_name] = role_id
81+
if not response:
82+
return
83+
self.cache_by_id = {}
84+
self.map_id_to_name = {}
85+
self.map_name_to_id = {}
86+
for role in response.records:
87+
role_id = role.id
88+
role_name = role.name
89+
self.cache_by_id[role_id] = role
90+
self.map_id_to_name[role_id] = role_name
91+
self.map_name_to_id[role_name] = role_id
8192

8293
def _get_id_for_name(self, name: str) -> Optional[str]:
8394
"""

pyatlan/client/atlan.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from pyatlan.cache.custom_metadata_cache import CustomMetadataCache
4646
from pyatlan.cache.enum_cache import EnumCache
4747
from pyatlan.cache.group_cache import GroupCache
48+
from pyatlan.cache.role_cache import RoleCache
4849
from pyatlan.client.admin import AdminClient
4950
from pyatlan.client.asset import A, AssetClient, IndexSearchResults, LineageListResults
5051
from pyatlan.client.audit import AuditClient
@@ -177,6 +178,7 @@ class AtlanClient(BaseSettings):
177178
_atlan_tag_cache: Optional[AtlanTagCache] = PrivateAttr(default=None)
178179
_enum_cache: Optional[EnumCache] = PrivateAttr(default=None)
179180
_group_cache: Optional[GroupCache] = PrivateAttr(default=None)
181+
_role_cache: Optional[RoleCache] = PrivateAttr(default=None)
180182
_custom_metadata_cache: Optional[CustomMetadataCache] = PrivateAttr(default=None)
181183

182184
class Config:
@@ -345,6 +347,12 @@ def group_cache(self) -> GroupCache:
345347
self._group_cache = GroupCache.get_cache(client=self)
346348
return self._group_cache
347349

350+
@property
351+
def role_cache(self) -> RoleCache:
352+
if self._role_cache is None:
353+
self._role_cache = RoleCache.get_cache(client=self)
354+
return self._role_cache
355+
348356
@property
349357
def custom_metadata_cache(self) -> CustomMetadataCache:
350358
if self._custom_metadata_cache is None:

0 commit comments

Comments
 (0)