ipulse-shared-core-ftredge 27.3.0__py3-none-any.whl → 27.4.1__py3-none-any.whl

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.

Potentially problematic release.


This version of ipulse-shared-core-ftredge might be problematic. Click here for more details.

@@ -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
@@ -11,7 +11,7 @@ ipulse_shared_core_ftredge/exceptions/__init__.py,sha256=Cb_RsIie4DbT_NLwFVwjw4r
11
11
  ipulse_shared_core_ftredge/exceptions/base_exceptions.py,sha256=117YsiCbYLLBu_D0IffYFVSX2yh-pisALMtoSMwj6xI,5338
12
12
  ipulse_shared_core_ftredge/exceptions/user_exceptions.py,sha256=I-nm21MKrUYEoybpRODeYNzc184HfgHvRZQm_xux4VY,6824
13
13
  ipulse_shared_core_ftredge/models/__init__.py,sha256=jhaVbOzJiFUf24saV1-a4GeKUaPif3jqAnIr4wgiUVs,455
14
- ipulse_shared_core_ftredge/models/base_api_response.py,sha256=g7f1jH3VkEyMuW-d_j3ex2zk8LO2EMlkYRJQqYic_KU,792
14
+ ipulse_shared_core_ftredge/models/base_api_response.py,sha256=vEcy5BDXcuJFldWq8FgadSAiq0kbVFA8BYVIpY3n9aE,993
15
15
  ipulse_shared_core_ftredge/models/base_data_model.py,sha256=GZ7KTT5FanHTgvmaHHTxawzAJtuixkbyb-SuL-mjWys,2193
16
16
  ipulse_shared_core_ftredge/models/credit_api_response.py,sha256=gavsJeuIsQJmY1t8DPzRZP5da68DT6IknE_oAeoapTc,797
17
17
  ipulse_shared_core_ftredge/models/custom_json_response.py,sha256=5WCqpb6YEzZQitXE9DdnPv3x-me_0iV_qmd6laeiPWA,1396
@@ -28,11 +28,11 @@ ipulse_shared_core_ftredge/models/user/userstatus.py,sha256=4uXa41NJqH27--yHN8o2
28
28
  ipulse_shared_core_ftredge/monitoring/__init__.py,sha256=gUoJjT0wj-cQYnMWheWbh1mmRHmaeojmnBZTj7KPNus,61
29
29
  ipulse_shared_core_ftredge/monitoring/tracemon.py,sha256=Trku0qrwWvEcvKsBWiYokd_G3fcH-5uP2wRVgcgIz_k,11596
30
30
  ipulse_shared_core_ftredge/services/__init__.py,sha256=w02WgdTyTaRn54XPpCxLXzyTobVeUP5SHRjpbLH54_0,608
31
- ipulse_shared_core_ftredge/services/charging_processors.py,sha256=Ynt8nQZprdsny9FaCB1ifrEIXPP6V7r_MxWID1BrRug,16391
31
+ ipulse_shared_core_ftredge/services/charging_processors.py,sha256=JrOfuNHbdfjeGoPDBfgMHw58rcvYgUaM036_G47Tv6E,16519
32
32
  ipulse_shared_core_ftredge/services/user_charging_service.py,sha256=WNVGn77Rcy_Al3M9wF0VZPYQVWL__E2baVRDQeA37I4,14609
33
33
  ipulse_shared_core_ftredge/services/base/__init__.py,sha256=hP2x_F07nycNj6_WCIQE7-8o84cIRj-tZlGwrA1yIcI,491
34
34
  ipulse_shared_core_ftredge/services/base/base_firestore_service.py,sha256=leZFwxb1ruheypqudpKnuNtRQXtO4KNeoJk6ZACozHc,19512
35
- ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py,sha256=ya5Asff9BQodYnJVAw6M_Pm8WtVRPpEK7izFlZ2MyjA,10016
35
+ ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py,sha256=rwyaHWrqXqOYXQWAnVqhA9qokZjjBLmaJ1WF9ZZDV-w,12560
36
36
  ipulse_shared_core_ftredge/services/base/multi_collection_cache_aware_firestore_service.py,sha256=Z-L20YkGhArTlwabPsqRXew-o87oL_9B5WOEh5zF0A4,10739
37
37
  ipulse_shared_core_ftredge/services/catalog/__init__.py,sha256=ctc2nDGwsW_Ji4lk9pys3oyNwR_V-gHSbSHawym5fKQ,385
38
38
  ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py,sha256=X5xAi9sOk_F1ky0ECwPVlwIPPsN2PrZC6bN_pASGDjQ,9702
@@ -47,11 +47,10 @@ ipulse_shared_core_ftredge/services/user/userauth_operations.py,sha256=QY_ueDei4
47
47
  ipulse_shared_core_ftredge/services/user/userprofile_operations.py,sha256=_qyIEAQYCTV-subgP-5naMs_26apCpauomE6qmCCVWs,7333
48
48
  ipulse_shared_core_ftredge/services/user/userstatus_operations.py,sha256=Om9d94cM4uOdTmCNXECU0hFtsUZ-o-OLMEiLAG74YUQ,22730
49
49
  ipulse_shared_core_ftredge/utils/__init__.py,sha256=JnxUb8I2MRjJC7rBPXSrpwBIQDEOku5O9JsiTi3oun8,56
50
- ipulse_shared_core_ftredge/utils/authz_credit_extraction.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
50
  ipulse_shared_core_ftredge/utils/custom_json_encoder.py,sha256=DblQLD0KOSNDyQ58wQRogBrShIXzPIZUw_oGOBATnJY,1366
52
51
  ipulse_shared_core_ftredge/utils/json_encoder.py,sha256=QkcaFneVv3-q-s__Dz4OiUWYnM6jgHDJrDMdPv09RCA,2093
53
- ipulse_shared_core_ftredge-27.3.0.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
54
- ipulse_shared_core_ftredge-27.3.0.dist-info/METADATA,sha256=9kTpPalCVGts8D7cxf5LFMCzSpcP-C_nVlfZRZeZWu0,782
55
- ipulse_shared_core_ftredge-27.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
56
- ipulse_shared_core_ftredge-27.3.0.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
57
- ipulse_shared_core_ftredge-27.3.0.dist-info/RECORD,,
52
+ ipulse_shared_core_ftredge-27.4.1.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
53
+ ipulse_shared_core_ftredge-27.4.1.dist-info/METADATA,sha256=3NfRSOG2vmcn-S-5k7a1rjc8mGYWCD-RfBCWri6c4NI,782
54
+ ipulse_shared_core_ftredge-27.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
+ ipulse_shared_core_ftredge-27.4.1.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
56
+ ipulse_shared_core_ftredge-27.4.1.dist-info/RECORD,,