ipulse-shared-core-ftredge 27.3.0__tar.gz → 27.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-27.4.1}/PKG-INFO +1 -1
  2. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/setup.py +1 -1
  3. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/base_api_response.py +4 -0
  4. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py +65 -4
  5. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/charging_processors.py +2 -2
  6. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +1 -1
  7. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +1 -3
  8. ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py +0 -0
  9. ipulse_shared_core_ftredge-27.3.0/tests/test_shared_cache.py +0 -147
  10. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/LICENCE +0 -0
  11. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/README.md +0 -0
  12. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/pyproject.toml +0 -0
  13. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/setup.cfg +0 -0
  14. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/__init__.py +0 -0
  15. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/cache/__init__.py +0 -0
  16. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/cache/shared_cache.py +0 -0
  17. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/__init__.py +0 -0
  18. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +0 -0
  19. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/auth_protected_router.py +0 -0
  20. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/authz_credit_extraction.py +0 -0
  21. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +0 -0
  22. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/dependencies/firestore_client.py +0 -0
  23. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/exceptions/__init__.py +0 -0
  24. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/exceptions/base_exceptions.py +0 -0
  25. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/exceptions/user_exceptions.py +0 -0
  26. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
  27. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/base_data_model.py +0 -0
  28. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/catalog/__init__.py +0 -0
  29. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +0 -0
  30. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/catalog/usertype.py +0 -0
  31. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/credit_api_response.py +0 -0
  32. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/custom_json_response.py +0 -0
  33. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py +0 -0
  34. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/__init__.py +0 -0
  35. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/user_permissions.py +0 -0
  36. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/user_subscription.py +0 -0
  37. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/userauth.py +0 -0
  38. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/userprofile.py +0 -0
  39. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/models/user/userstatus.py +0 -0
  40. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/monitoring/__init__.py +0 -0
  41. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/monitoring/tracemon.py +0 -0
  42. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/__init__.py +0 -0
  43. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/__init__.py +0 -0
  44. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/base_firestore_service.py +0 -0
  45. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/base/multi_collection_cache_aware_firestore_service.py +0 -0
  46. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/catalog/__init__.py +0 -0
  47. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +0 -0
  48. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +0 -0
  49. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/__init__.py +0 -0
  50. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_charging_operations.py +0 -0
  51. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_core_service.py +0 -0
  52. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +0 -0
  53. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +0 -0
  54. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +0 -0
  55. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/userauth_operations.py +0 -0
  56. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py +0 -0
  57. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py +0 -0
  58. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/services/user_charging_service.py +0 -0
  59. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/utils/__init__.py +0 -0
  60. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py +0 -0
  61. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge/utils/json_encoder.py +0 -0
  62. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
  63. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +0 -0
  64. {ipulse_shared_core_ftredge-27.3.0 → ipulse_shared_core_ftredge-27.4.1}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 27.3.0
3
+ Version: 27.4.1
4
4
  Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
5
5
  Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
6
6
  Author: Russlan Ramdowar
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name='ipulse_shared_core_ftredge',
6
- version='27.3.0',
6
+ version='27.4.1',
7
7
  package_dir={'': 'src'}, # Specify the source directory
8
8
  packages=find_packages(where='src'), # Look for packages in 'src'
9
9
  install_requires=[
@@ -16,6 +16,10 @@ class BaseAPIResponse(BaseModel, Generic[T]):
16
16
  message: Optional[str] = None
17
17
  error: Optional[str] = None
18
18
 
19
+ # Optional fields for specific use cases
20
+ cache_hit: Optional[bool] = None # Whether data came from cache
21
+ charged: Optional[bool] = None # Whether credits were charged for this request
22
+
19
23
  metadata: Dict[str, Any] = {
20
24
  "timestamp": dt.datetime.now(dt.timezone.utc).isoformat()
21
25
  }
@@ -1,6 +1,6 @@
1
1
  """Cache-aware Firestore service base class."""
2
2
  import time
3
- from typing import TypeVar, Generic, Dict, Any, List, Optional, Union, Type
3
+ from typing import TypeVar, Generic, Dict, Any, List, Optional, Union, Type, Tuple
4
4
  from google.cloud import firestore
5
5
  from . import BaseFirestoreService
6
6
  from ...exceptions import ResourceNotFoundError, ServiceError
@@ -58,7 +58,9 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
58
58
  cache_check_time = (time.time() - start_time) * 1000
59
59
 
60
60
  if cached_doc is not None:
61
- self.logger.debug(f"Cache HIT for document {doc_id} in {cache_check_time:.2f}ms")
61
+ # SharedCache.get() already logs cache hit, only log timing if significant
62
+ if cache_check_time > 5.0: # Only log if cache check took >5ms
63
+ self.logger.debug(f"Cache HIT for document {doc_id} in {cache_check_time:.2f}ms")
62
64
  if convert_to_model and self.model_class:
63
65
  return self._convert_to_model(cached_doc, doc_id)
64
66
  else:
@@ -68,7 +70,66 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
68
70
  self.logger.debug(f"Cache MISS for document {doc_id} - checking Firestore")
69
71
 
70
72
  # Fetch from Firestore using parent method
71
- return await super().get_document(doc_id, convert_to_model)
73
+ result = await super().get_document(doc_id, convert_to_model)
74
+
75
+ # Cache the result if we have a cache and got valid data
76
+ if self.document_cache and result is not None:
77
+ if convert_to_model and isinstance(result, BaseDataModel):
78
+ # Cache the model's dict representation
79
+ self._cache_document_data(doc_id, result.model_dump())
80
+ elif isinstance(result, dict):
81
+ # Cache the dict directly
82
+ self._cache_document_data(doc_id, result)
83
+
84
+ return result
85
+
86
+ async def get_document_with_cache_info(self, doc_id: str, convert_to_model: bool = True) -> Tuple[Union[T, Dict[str, Any], None], bool]:
87
+ """
88
+ Get a document with cache hit information.
89
+
90
+ Args:
91
+ doc_id: Document ID to fetch
92
+ convert_to_model: Whether to convert to Pydantic model
93
+
94
+ Returns:
95
+ Tuple of (document, cache_hit) where cache_hit indicates if from cache
96
+
97
+ Raises:
98
+ ResourceNotFoundError: If document doesn't exist
99
+ """
100
+ cache_hit = False
101
+
102
+ # Check cache first
103
+ if self.document_cache:
104
+ cached_doc = self.document_cache.get(doc_id)
105
+ if cached_doc is not None:
106
+ cache_hit = True
107
+ # Note: SharedCache.get() already logs cache hit at DEBUG level
108
+ if convert_to_model and self.model_class:
109
+ return self._convert_to_model(cached_doc, doc_id), cache_hit
110
+ else:
111
+ cached_doc['id'] = doc_id
112
+ return cached_doc, cache_hit
113
+
114
+ # Cache miss - fetch from Firestore
115
+ self.logger.debug(f"Cache MISS for document {doc_id} - checking Firestore")
116
+
117
+ try:
118
+ result = await super().get_document(doc_id, convert_to_model)
119
+
120
+ # Cache the result if we have a cache and got valid data
121
+ if self.document_cache and result is not None:
122
+ if convert_to_model and isinstance(result, BaseDataModel):
123
+ # Cache the model's dict representation
124
+ self._cache_document_data(doc_id, result.model_dump())
125
+ elif isinstance(result, dict):
126
+ # Cache the dict directly
127
+ self._cache_document_data(doc_id, result)
128
+
129
+ return result, cache_hit
130
+
131
+ except ResourceNotFoundError:
132
+ return None, cache_hit
72
133
 
73
134
  async def get_all_documents(self, cache_key: Optional[str] = None, as_models: bool = True) -> Union[List[T], List[Dict[str, Any]]]:
74
135
  """
@@ -151,7 +212,7 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
151
212
  """Helper to cache document data if document_cache is available."""
152
213
  if self.document_cache:
153
214
  self.document_cache.set(doc_id, data)
154
- self.logger.debug(f"Cached item {doc_id} in {self.document_cache.name}")
215
+ # Note: SharedCache.set() already logs at DEBUG level
155
216
 
156
217
  async def create_document(self, doc_id: str, data: Union[T, Dict[str, Any]], creator_uid: str, merge: bool = False) -> Dict[str, Any]:
157
218
  """Create document and invalidate cache."""
@@ -56,7 +56,7 @@ class ChargingProcessor:
56
56
  updated_user_credits = pre_fetched_credits
57
57
  elif self.user_charging_service: # Attempt to get current credits if not pre-fetched
58
58
  try:
59
- _, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid, 0, None)
59
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid=user_uid, required_credits_for_resource=0, pre_fetched_user_credits=None)
60
60
  updated_user_credits = current_user_credits_from_verify
61
61
  except Exception: # pylint: disable=broad-except
62
62
  self.logger.warning(f"Could not fetch current credits for user {user_uid} for free item.")
@@ -77,7 +77,7 @@ class ChargingProcessor:
77
77
  updated_user_credits = pre_fetched_credits
78
78
  elif self.user_charging_service:
79
79
  try:
80
- _, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid, 0, None)
80
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_enough_credits(user_uid=user_uid, required_credits_for_resource=0, pre_fetched_user_credits=None)
81
81
  updated_user_credits = current_user_credits_from_verify
82
82
  except Exception: # pylint: disable=broad-except
83
83
  self.logger.warning(f"Could not fetch current credits for user {user_uid} during debug bypass.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 27.3.0
3
+ Version: 27.4.1
4
4
  Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
5
5
  Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
6
6
  Author: Russlan Ramdowar
@@ -56,7 +56,5 @@ src/ipulse_shared_core_ftredge/services/user/userauth_operations.py
56
56
  src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py
57
57
  src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py
58
58
  src/ipulse_shared_core_ftredge/utils/__init__.py
59
- src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py
60
59
  src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py
61
- src/ipulse_shared_core_ftredge/utils/json_encoder.py
62
- tests/test_shared_cache.py
60
+ src/ipulse_shared_core_ftredge/utils/json_encoder.py
@@ -1,147 +0,0 @@
1
- """Tests for the SharedCache implementation."""
2
-
3
- import time
4
- import unittest
5
- import logging
6
- from ipulse_shared_core_ftredge.cache.shared_cache import SharedCache
7
-
8
- # Configure logging for tests
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
-
12
-
13
- class TestSharedCache(unittest.TestCase):
14
- """Test cases for SharedCache."""
15
-
16
- def setUp(self):
17
- """Set up test fixtures."""
18
- self.cache = SharedCache[str](
19
- name="TestCache",
20
- ttl=0.5, # Short TTL for faster testing
21
- enabled=True,
22
- logger=logger
23
- )
24
-
25
- def test_cache_set_get(self):
26
- """Test basic cache set and get operations."""
27
- # Set a value
28
- self.cache.set("test_key", "test_value")
29
-
30
- # Get the value
31
- cached_value = self.cache.get("test_key")
32
-
33
- # Verify value was cached
34
- self.assertEqual(cached_value, "test_value")
35
-
36
- def test_cache_ttl_expiration(self):
37
- """Test cache TTL expiration."""
38
- # Set a value
39
- self.cache.set("expiring_key", "expiring_value")
40
-
41
- # Verify it's initially cached
42
- self.assertEqual(self.cache.get("expiring_key"), "expiring_value")
43
-
44
- # Wait for TTL to expire
45
- time.sleep(0.6) # Slightly longer than TTL (0.5s)
46
-
47
- # Verify value is no longer cached
48
- self.assertIsNone(self.cache.get("expiring_key"))
49
-
50
- def test_cache_invalidate(self):
51
- """Test cache invalidation."""
52
- # Set multiple values
53
- self.cache.set("key1", "value1")
54
- self.cache.set("key2", "value2")
55
-
56
- # Invalidate specific key
57
- self.cache.invalidate("key1")
58
-
59
- # Verify key1 is gone but key2 remains
60
- self.assertIsNone(self.cache.get("key1"))
61
- self.assertEqual(self.cache.get("key2"), "value2")
62
-
63
- def test_cache_invalidate_all(self):
64
- """Test invalidating all cache entries."""
65
- # Set multiple values
66
- self.cache.set("key1", "value1")
67
- self.cache.set("key2", "value2")
68
-
69
- # Invalidate all
70
- self.cache.invalidate_all()
71
-
72
- # Verify both keys are gone
73
- self.assertIsNone(self.cache.get("key1"))
74
- self.assertIsNone(self.cache.get("key2"))
75
-
76
- def test_cache_get_or_set(self):
77
- """Test get_or_set functionality."""
78
- # Define a counter to verify how many times the loader is called
79
- counter = [0]
80
-
81
- def data_loader():
82
- counter[0] += 1
83
- return f"loaded_value_{counter[0]}"
84
-
85
- # First call should use data_loader
86
- value1, was_cached1 = self.cache.get_or_set("loader_key", data_loader)
87
-
88
- # Second call should use cached value
89
- value2, was_cached2 = self.cache.get_or_set("loader_key", data_loader)
90
-
91
- # Verify results
92
- self.assertEqual(value1, "loaded_value_1")
93
- self.assertEqual(value2, "loaded_value_1") # Same value from cache
94
- self.assertFalse(was_cached1) # First call was not cached
95
- self.assertTrue(was_cached2) # Second call was cached
96
- self.assertEqual(counter[0], 1) # Loader called exactly once
97
-
98
- def test_cache_disabled(self):
99
- """Test cache behavior when disabled."""
100
- # Create disabled cache
101
- disabled_cache = SharedCache[str](
102
- name="DisabledCache",
103
- ttl=1.0,
104
- enabled=False,
105
- logger=logger
106
- )
107
-
108
- # Set a value
109
- disabled_cache.set("disabled_key", "disabled_value")
110
-
111
- # Attempt to get - should return None since cache is disabled
112
- cached_value = disabled_cache.get("disabled_key")
113
- self.assertIsNone(cached_value)
114
-
115
- def test_cache_generic_typing(self):
116
- """Test cache with different data types."""
117
- # Integer cache
118
- int_cache = SharedCache[int](name="IntCache", ttl=1.0, enabled=True)
119
- int_cache.set("int_key", 123)
120
- self.assertEqual(int_cache.get("int_key"), 123)
121
-
122
- # Dictionary cache
123
- dict_cache = SharedCache[dict](name="DictCache", ttl=1.0, enabled=True)
124
- dict_cache.set("dict_key", {"a": 1, "b": 2})
125
- self.assertEqual(dict_cache.get("dict_key"), {"a": 1, "b": 2})
126
-
127
- def test_cache_stats(self):
128
- """Test cache statistics."""
129
- # Add some data
130
- self.cache.set("stats_key1", "stats_value1")
131
- self.cache.set("stats_key2", "stats_value2")
132
-
133
- # Get stats
134
- stats = self.cache.get_stats()
135
-
136
- # Verify stats
137
- self.assertEqual(stats["name"], "TestCache")
138
- self.assertEqual(stats["enabled"], True)
139
- self.assertEqual(stats["ttl_seconds"], 0.5)
140
- self.assertEqual(stats["item_count"], 2)
141
- self.assertIn("stats_key1", stats["first_20_keys"])
142
- self.assertIn("stats_key2", stats["first_20_keys"])
143
- self.assertEqual(stats["total_keys"], 2)
144
-
145
-
146
- if __name__ == "__main__":
147
- unittest.main()