|
1 | 1 | # 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 |
5 | 7 |
|
6 |
| -from pyatlan.client.role import RoleClient |
7 | 8 | from pyatlan.model.role import AtlanRole
|
8 | 9 |
|
| 10 | +if TYPE_CHECKING: |
| 11 | + from pyatlan.client.atlan import AtlanClient |
| 12 | + |
9 | 13 | lock: Lock = Lock()
|
| 14 | +role_cache_tls = local() # Thread-local storage (TLS) |
10 | 15 |
|
11 | 16 |
|
12 | 17 | class RoleCache:
|
13 | 18 | """
|
14 | 19 | Lazily-loaded cache for translating Atlan-internal roles into their various IDs.
|
15 | 20 | """
|
16 | 21 |
|
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() |
18 | 28 |
|
19 | 29 | @classmethod
|
20 |
| - def get_cache(cls) -> "RoleCache": |
| 30 | + def get_cache(cls, client: Optional[AtlanClient] = None) -> RoleCache: |
21 | 31 | from pyatlan.client.atlan import AtlanClient
|
22 | 32 |
|
23 | 33 | with lock:
|
24 |
| - client = AtlanClient.get_default_client() |
| 34 | + client = client or AtlanClient.get_default_client() |
25 | 35 | 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] |
29 | 46 |
|
30 | 47 | @classmethod
|
31 | 48 | def get_id_for_name(cls, name: str) -> Optional[str]:
|
@@ -56,28 +73,22 @@ def validate_idstrs(cls, idstrs: Iterable[str]):
|
56 | 73 | """
|
57 | 74 | return cls.get_cache()._validate_idstrs(idstrs=idstrs)
|
58 | 75 |
|
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 |
| - |
66 | 76 | def _refresh_cache(self) -> None:
|
67 | 77 | with self.lock:
|
68 |
| - response = self.role_client.get( |
| 78 | + response = self.client.role.get( |
69 | 79 | limit=100, post_filter='{"name":{"$ilike":"$%"}}'
|
70 | 80 | )
|
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 |
81 | 92 |
|
82 | 93 | def _get_id_for_name(self, name: str) -> Optional[str]:
|
83 | 94 | """
|
|
0 commit comments