ipulse-shared-core-ftredge 6.7.1__tar.gz → 6.9.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.

Potentially problematic release.


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

Files changed (34) hide show
  1. {ipulse_shared_core_ftredge-6.7.1/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-6.9.1}/PKG-INFO +2 -2
  2. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/setup.py +2 -2
  3. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/__init__.py +4 -1
  4. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/dependencies/authorization_api.py +55 -39
  5. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/__init__.py +1 -1
  6. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/base_api_response.py +5 -2
  7. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/services/__init__.py +1 -1
  8. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/services/base_firestore_service.py +16 -16
  9. ipulse_shared_core_ftredge-6.7.1/src/ipulse_shared_core_ftredge/services/base_exceptions.py → ipulse_shared_core_ftredge-6.9.1/src/ipulse_shared_core_ftredge/services/base_service_exceptions.py +5 -5
  10. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +2 -2
  11. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +1 -1
  12. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +1 -1
  13. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/LICENCE +0 -0
  14. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/README.md +0 -0
  15. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/pyproject.toml +0 -0
  16. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/setup.cfg +0 -0
  17. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/dependencies/__init__.py +0 -0
  18. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/dependencies/auth_router.py +0 -0
  19. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/dependencies/database.py +0 -0
  20. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/dependencies/token_validation.py +0 -0
  21. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/base_data_model.py +0 -0
  22. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/organization_profile.py +0 -0
  23. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/resource_catalog_item.py +0 -0
  24. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/subscription.py +0 -0
  25. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/user_auth.py +0 -0
  26. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/user_profile.py +0 -0
  27. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/user_profile_update.py +0 -0
  28. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/models/user_status.py +0 -0
  29. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/services/fastapiservicemon.py +0 -0
  30. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/services/servicemon.py +0 -0
  31. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/utils/__init__.py +0 -0
  32. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge/utils/json_encoder.py +0 -0
  33. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
  34. {ipulse_shared_core_ftredge-6.7.1 → ipulse_shared_core_ftredge-6.9.1}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 6.7.1
3
+ Version: 6.9.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
@@ -9,7 +9,7 @@ Requires-Dist: pydantic[email]~=2.5
9
9
  Requires-Dist: python-dateutil~=2.8
10
10
  Requires-Dist: fastapi~=0.115.8
11
11
  Requires-Dist: pytest~=7.1
12
- Requires-Dist: ipulse_shared_base_ftredge>=5.6.1
12
+ Requires-Dist: ipulse_shared_base_ftredge>=5.7.1
13
13
  Dynamic: author
14
14
  Dynamic: home-page
15
15
  Dynamic: requires-dist
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name='ipulse_shared_core_ftredge',
6
- version='6.7.1',
6
+ version='6.9.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=[
@@ -12,7 +12,7 @@ setup(
12
12
  'python-dateutil~=2.8',
13
13
  'fastapi~=0.115.8',
14
14
  'pytest~=7.1',
15
- 'ipulse_shared_base_ftredge>=5.6.1',
15
+ 'ipulse_shared_base_ftredge>=5.7.1',
16
16
  ],
17
17
  author='Russlan Ramdowar',
18
18
  description='Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.',
@@ -1,9 +1,12 @@
1
1
  # pylint: disable=missing-module-docstring
2
2
  from .models import ( UserAuth, UserProfile,Subscription,
3
3
  UserStatus, UserProfileUpdate,
4
- OrganizationProfile, BaseAPIResponse, CustomJSONResponse )
4
+ OrganizationProfile, BaseAPIResponse,
5
+ CustomJSONResponse )
5
6
 
6
7
 
7
8
 
8
9
  from .services import (BaseFirestoreService,BaseServiceException, ResourceNotFoundError, AuthorizationError,
9
10
  ValidationError)
11
+
12
+ from .utils import (CustomJSONEncoder)
@@ -6,24 +6,25 @@ import httpx
6
6
  from fastapi import HTTPException, Request
7
7
  from google.cloud import firestore
8
8
  from ipulse_shared_core_ftredge.services import ServiceError, AuthorizationError, ResourceNotFoundError
9
+ from ipulse_shared_core_ftredge.models import UserStatus
9
10
 
10
11
  # Constants
11
- USERS_STATUS_COLLECTION_NAME = "user-statuses"
12
- USERS_STATUS_DOC_REF = "userusrsttus_"
12
+ USERS_STATUS_COLLECTION_NAME = UserStatus.get_collection_name()
13
+ USERS_STATUS_DOC_REF = "userstatus_"
13
14
  CACHE_TTL = 60 # 60 seconds
14
15
  class UserStatusCache:
15
16
  """Manages user status caching with dynamic invalidation"""
16
17
  def __init__(self):
17
18
  self._cache: Dict[str, Dict[str, Any]] = {}
18
19
  self._timestamps: Dict[str, datetime] = {}
19
-
20
+
20
21
  def get(self, user_uid: str) -> Optional[Dict[str, Any]]:
21
22
  """
22
23
  Retrieves user status from cache if available and valid.
23
24
 
24
25
  Args:
25
26
  user_uid (str): The user ID.
26
-
27
+
27
28
  """
28
29
  if user_uid in self._cache:
29
30
  status_data = self._cache[user_uid]
@@ -33,7 +34,7 @@ class UserStatusCache:
33
34
  return status_data
34
35
  self.invalidate(user_uid)
35
36
  return None
36
-
37
+
37
38
  def set(self, user_uid: str, data: Dict[str, Any]) -> None:
38
39
  """
39
40
  Sets user status data in the cache.
@@ -44,7 +45,7 @@ class UserStatusCache:
44
45
  """
45
46
  self._cache[user_uid] = data
46
47
  self._timestamps[user_uid] = datetime.now()
47
-
48
+
48
49
  def invalidate(self, user_uid: str) -> None:
49
50
  """
50
51
  Invalidates (removes) user status from the cache.
@@ -56,13 +57,13 @@ class UserStatusCache:
56
57
  self._timestamps.pop(user_uid, None)
57
58
 
58
59
  # Global cache instance
59
- user_status_cache = UserStatusCache()
60
+ userstatus_cache = UserStatusCache()
60
61
 
61
62
  # Replace the logger dependency with a standard logger
62
63
  logger = logging.getLogger(__name__)
63
64
 
64
- async def get_user_status(
65
- user_uid: str,
65
+ async def get_userstatus(
66
+ user_uid: str,
66
67
  db: firestore.Client, # Note: This expects the actual client, not a Depends
67
68
  force_fresh: bool = False
68
69
  ) -> tuple[Dict[str, Any], bool]:
@@ -71,39 +72,39 @@ async def get_user_status(
71
72
  """
72
73
  cache_used = False
73
74
  if not force_fresh:
74
- cached_status = user_status_cache.get(user_uid)
75
+ cached_status = userstatus_cache.get(user_uid)
75
76
  if cached_status:
76
77
  cache_used = True
77
78
  return cached_status, cache_used
78
79
 
79
80
  try:
80
81
  # Get reference to the document
81
- user_status_id = USERS_STATUS_DOC_REF + user_uid
82
- user_ref = db.collection(USERS_STATUS_COLLECTION_NAME).document(user_status_id)
83
-
82
+ userstatus_id = USERS_STATUS_DOC_REF + user_uid
83
+ user_ref = db.collection(USERS_STATUS_COLLECTION_NAME).document(userstatus_id)
84
+
84
85
  # Get the document
85
86
  snapshot = user_ref.get()
86
87
  if not snapshot.exists:
87
88
  raise ResourceNotFoundError(
88
- resource_type="user_status",
89
- resource_id=user_status_id,
89
+ resource_type="authorization userstatus",
90
+ resource_id=userstatus_id,
90
91
  additional_info={"user_uid": user_uid}
91
92
  )
92
-
93
+
93
94
  status_data = snapshot.to_dict()
94
-
95
+
95
96
  # Only cache if not forced fresh
96
97
  if not force_fresh:
97
- user_status_cache.set(user_uid, status_data)
98
+ userstatus_cache.set(user_uid, status_data)
98
99
  return status_data, cache_used
99
-
100
+
100
101
  except ResourceNotFoundError:
101
102
  raise
102
103
  except Exception as e:
103
104
  raise ServiceError(
104
105
  operation=f"fetching user status",
105
106
  error=e,
106
- resource_type="user_status",
107
+ resource_type="userstatus",
107
108
  resource_id=user_uid,
108
109
  additional_info={
109
110
  "force_fresh": force_fresh,
@@ -131,18 +132,18 @@ async def extract_request_fields(request: Request) -> Optional[List[str]]:
131
132
  if isinstance(body, dict):
132
133
  if request.method == "PATCH":
133
134
  return _validate_resource_fields(body)
134
- elif request.method == "POST":
135
+ if request.method == "POST":
135
136
  # For POST, we want to include all fields being set
136
137
  return list(body.keys())
137
138
  elif hasattr(body, 'model_dump'):
138
139
  data = body.model_dump(exclude_unset=True)
139
140
  if request.method == "PATCH":
140
141
  return _validate_resource_fields(data)
141
- elif request.method == "POST":
142
+ if request.method == "POST":
142
143
  return list(data.keys())
143
-
144
+
144
145
  return None
145
-
146
+
146
147
  except Exception as e:
147
148
  logger.error(f"Error extracting fields from request body: {str(e)}")
148
149
  return None
@@ -172,8 +173,8 @@ async def authorizeAPIRequest(
172
173
 
173
174
  # Determine if we need fresh status
174
175
  force_fresh = _should_force_fresh_status(request)
175
- user_status, cache_used = await get_user_status(user_uid, db, force_fresh=force_fresh)
176
-
176
+ userstatus, cache_used = await get_userstatus(user_uid, db, force_fresh=force_fresh)
177
+
177
178
  # Prepare authorization input
178
179
  auth_input = {
179
180
  "api_url": request.url.path,
@@ -181,10 +182,10 @@ async def authorizeAPIRequest(
181
182
  "uid": user_uid,
182
183
  "usertypes": request.state.user.get("usertypes"),
183
184
  "email_verified": request.state.user.get("email_verified"),
184
- "iam_groups": user_status.get("iam_groups"),
185
- "subscriptions": user_status.get("subscriptions"),
186
- "sbscrptn_based_insight_credits": user_status.get("sbscrptn_based_insight_credits"),
187
- "extra_insight_credits": user_status.get("extra_insight_credits")
185
+ "iam_groups": userstatus.get("iam_groups"),
186
+ "subscriptions": userstatus.get("subscriptions"),
187
+ "sbscrptn_based_insight_credits": userstatus.get("sbscrptn_based_insight_credits"),
188
+ "extra_insight_credits": userstatus.get("extra_insight_credits")
188
189
  },
189
190
  "method": request.method.lower(),
190
191
  "request_resource_fields": request_resource_fields
@@ -192,13 +193,28 @@ async def authorizeAPIRequest(
192
193
 
193
194
  # Query OPA
194
195
  opa_url = f"{os.getenv('OPA_SERVER_URL', 'http://localhost:8181')}{os.getenv('OPA_DECISION_PATH', '/v1/data/http/authz/ingress/decision')}"
196
+ logger.debug(f"Attempting to connect to OPA at: {opa_url}")
197
+ logger.debug(f"Authorization input: {auth_input}")
195
198
  async with httpx.AsyncClient() as client:
196
- response = await client.post(
197
- opa_url,
198
- json={"input": auth_input},
199
- timeout=5.0 # 5 seconds timeout
200
- )
201
-
199
+ try:
200
+ response = await client.post(
201
+ opa_url,
202
+ json={"input": auth_input},
203
+ timeout=5.0 # 5 seconds timeout
204
+ )
205
+ logger.debug(f"OPA Response Status: {response.status_code}")
206
+ logger.debug(f"OPA Response Body: {response.text}")
207
+ except httpx.RequestError as e:
208
+ logger.error(f"Failed to connect to OPA: {str(e)}")
209
+ raise ServiceError(
210
+ operation="API authorization",
211
+ error=e,
212
+ resource_type="authorization",
213
+ additional_info={
214
+ "opa_url": opa_url,
215
+ "connection_error": str(e)
216
+ }
217
+ ) from e
202
218
  if response.status_code != 200:
203
219
  logger.error(f"OPA authorization failed: {response.text}")
204
220
  raise HTTPException(
@@ -236,7 +252,7 @@ async def authorizeAPIRequest(
236
252
  "user_uid": request.state.user.get('uid'),
237
253
  "resource_fields": request_resource_fields
238
254
  }
239
- )
255
+ ) from e
240
256
 
241
257
  def _should_force_fresh_status(request: Request) -> bool:
242
258
  """
@@ -250,10 +266,10 @@ def _should_force_fresh_status(request: Request) -> bool:
250
266
  ]
251
267
  # Methods that require fresh status
252
268
  sensitive_methods = {'post', 'patch', 'put', 'delete'}
253
-
269
+
254
270
  path = request.url.path.lower()
255
271
  method = request.method.lower()
256
-
272
+
257
273
  return (
258
274
  any(pattern in path for pattern in credit_sensitive_patterns) or
259
275
  method in sensitive_methods
@@ -4,7 +4,7 @@ from .user_status import UserStatus
4
4
  from .user_profile_update import UserProfileUpdate
5
5
  from .user_auth import UserAuth
6
6
  from .organization_profile import OrganizationProfile
7
- from .base_api_response import BaseAPIResponse, CustomJSONResponse
7
+ from .base_api_response import BaseAPIResponse , CustomJSONResponse
8
8
 
9
9
 
10
10
 
@@ -1,9 +1,12 @@
1
1
  from typing import Generic, TypeVar, Optional, Any, Dict, List
2
- from pydantic import BaseModel, ConfigDict
3
2
  import datetime as dt
3
+ import json
4
+ from pydantic import BaseModel, ConfigDict
4
5
  from fastapi.responses import JSONResponse
5
6
  from ipulse_shared_core_ftredge.utils import CustomJSONEncoder
6
- import json
7
+
8
+
9
+
7
10
 
8
11
 
9
12
  T = TypeVar('T')
@@ -1,6 +1,6 @@
1
1
  from .base_firestore_service import BaseFirestoreService
2
2
 
3
- from .base_exceptions import (BaseServiceException, ResourceNotFoundError, AuthorizationError,
3
+ from .base_service_exceptions import (BaseServiceException, ResourceNotFoundError, AuthorizationError,
4
4
  ValidationError ,ServiceError)
5
5
  from .servicemon import Servicemon
6
6
  from .fastapiservicemon import FastAPIServiceMon
@@ -4,13 +4,13 @@ import logging
4
4
  from datetime import datetime, timezone
5
5
  from pydantic import BaseModel
6
6
  from google.cloud import firestore
7
- from .base_exceptions import ResourceNotFoundError, ValidationError, ServiceError
7
+ from .base_service_exceptions import ResourceNotFoundError, ValidationError, ServiceError
8
8
 
9
9
  T = TypeVar('T', bound=BaseModel)
10
10
 
11
11
  class BaseFirestoreService(Generic[T]):
12
12
  """Base class for Firestore services with common CRUD operations"""
13
-
13
+
14
14
  def __init__(self, db: firestore.Client, collection_name: str, resource_type: str, logger: logging.Logger):
15
15
  self.db = db
16
16
  self.collection_name = collection_name
@@ -22,7 +22,7 @@ class BaseFirestoreService(Generic[T]):
22
22
  try:
23
23
  current_time = datetime.now(timezone.utc)
24
24
  doc_data = data.model_dump(mode='json')
25
-
25
+
26
26
  # Add audit fields
27
27
  doc_data.update({
28
28
  'creat_date': current_time.isoformat(),
@@ -33,7 +33,7 @@ class BaseFirestoreService(Generic[T]):
33
33
 
34
34
  doc_ref = self.db.collection(self.collection_name).document(doc_id)
35
35
  doc_ref.set(doc_data)
36
-
36
+
37
37
  self.logger.info(f"Created {self.resource_type}: {doc_id}")
38
38
  return doc_data
39
39
 
@@ -61,7 +61,7 @@ class BaseFirestoreService(Generic[T]):
61
61
  'updt_date': current_time.isoformat(),
62
62
  'updt_by_user': creator_uid
63
63
  })
64
-
64
+
65
65
  doc_ref = self.db.collection(self.collection_name).document(doc_data.get('id'))
66
66
  batch.set(doc_ref, doc_data)
67
67
  created_docs.append(doc_data)
@@ -83,39 +83,39 @@ class BaseFirestoreService(Generic[T]):
83
83
  """Get a document by ID with standardized error handling"""
84
84
  doc_ref = self.db.collection(self.collection_name).document(doc_id)
85
85
  doc = doc_ref.get()
86
-
86
+
87
87
  if not doc.exists:
88
88
  raise ResourceNotFoundError(
89
89
  resource_type=self.resource_type,
90
90
  resource_id=doc_id,
91
91
  additional_info={"collection": self.collection_name}
92
92
  )
93
-
93
+
94
94
  return doc.to_dict()
95
95
 
96
96
  async def update_document(self, doc_id: str, update_data: Dict[str, Any], updater_uid: str) -> Dict[str, Any]:
97
97
  """Standard update method with validation and audit fields"""
98
98
  try:
99
99
  doc_ref = self.db.collection(self.collection_name).document(doc_id)
100
-
100
+
101
101
  if not doc_ref.get().exists:
102
102
  raise ResourceNotFoundError(
103
103
  resource_type=self.resource_type,
104
104
  resource_id=doc_id,
105
105
  additional_info={"collection": self.collection_name}
106
106
  )
107
-
107
+
108
108
  valid_fields = self._validate_update_fields(update_data)
109
-
109
+
110
110
  # Add audit fields
111
111
  valid_fields.update({
112
112
  'updt_date': datetime.now(timezone.utc).isoformat(),
113
113
  'updt_by_user': updater_uid
114
114
  })
115
-
115
+
116
116
  doc_ref.update(valid_fields)
117
117
  return doc_ref.get().to_dict()
118
-
118
+
119
119
  except (ResourceNotFoundError, ValidationError):
120
120
  raise
121
121
  except Exception as e:
@@ -136,7 +136,7 @@ class BaseFirestoreService(Generic[T]):
136
136
  resource_type=self.resource_type,
137
137
  resource_id=doc_id
138
138
  )
139
-
139
+
140
140
  doc_ref.delete()
141
141
  self.logger.info(f"Deleted {self.resource_type}: {doc_id}")
142
142
 
@@ -155,17 +155,17 @@ class BaseFirestoreService(Generic[T]):
155
155
  """Centralized update fields validation"""
156
156
  if not isinstance(update_data, dict):
157
157
  update_data = update_data.model_dump(exclude_unset=True)
158
-
158
+
159
159
  valid_fields = {
160
160
  k: v for k, v in update_data.items()
161
161
  if v is not None and not (isinstance(v, (list, dict, set)) and len(v) == 0)
162
162
  }
163
-
163
+
164
164
  if not valid_fields:
165
165
  raise ValidationError(
166
166
  resource_type=self.resource_type,
167
167
  detail="No valid fields to update",
168
168
  resource_id=None
169
169
  )
170
-
170
+
171
171
  return valid_fields
@@ -19,7 +19,7 @@ class BaseServiceException(HTTPException):
19
19
  self.resource_id = resource_id
20
20
  self.additional_info = additional_info or {}
21
21
  self.original_error = original_error
22
-
22
+
23
23
  # Get full traceback if there's an original error
24
24
  if original_error:
25
25
  self.traceback = ''.join(traceback.format_exception(
@@ -29,14 +29,14 @@ class BaseServiceException(HTTPException):
29
29
  ))
30
30
  else:
31
31
  self.traceback = ''.join(traceback.format_stack())
32
-
32
+
33
33
  # Build detailed message
34
34
  detail_msg = f"{detail}"
35
35
  if resource_type:
36
36
  detail_msg += f" [Resource Type: {resource_type}]"
37
37
  if resource_id:
38
38
  detail_msg += f" [ID: {resource_id}]"
39
-
39
+
40
40
  super().__init__(status_code=status_code, detail=detail_msg)
41
41
 
42
42
  def log_error(self, logger: logging.Logger):
@@ -48,7 +48,7 @@ class BaseServiceException(HTTPException):
48
48
  "detail": self.detail,
49
49
  **self.additional_info
50
50
  }
51
-
51
+
52
52
  log_message = f"""
53
53
  Service Error Occurred:
54
54
  Status Code: {self.status_code}
@@ -60,7 +60,7 @@ class BaseServiceException(HTTPException):
60
60
  Traceback:
61
61
  {self.traceback}
62
62
  """
63
-
63
+
64
64
  logger.error(log_message, extra=error_context)
65
65
 
66
66
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 6.7.1
3
+ Version: 6.9.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
@@ -9,7 +9,7 @@ Requires-Dist: pydantic[email]~=2.5
9
9
  Requires-Dist: python-dateutil~=2.8
10
10
  Requires-Dist: fastapi~=0.115.8
11
11
  Requires-Dist: pytest~=7.1
12
- Requires-Dist: ipulse_shared_base_ftredge>=5.6.1
12
+ Requires-Dist: ipulse_shared_base_ftredge>=5.7.1
13
13
  Dynamic: author
14
14
  Dynamic: home-page
15
15
  Dynamic: requires-dist
@@ -24,8 +24,8 @@ src/ipulse_shared_core_ftredge/models/user_profile.py
24
24
  src/ipulse_shared_core_ftredge/models/user_profile_update.py
25
25
  src/ipulse_shared_core_ftredge/models/user_status.py
26
26
  src/ipulse_shared_core_ftredge/services/__init__.py
27
- src/ipulse_shared_core_ftredge/services/base_exceptions.py
28
27
  src/ipulse_shared_core_ftredge/services/base_firestore_service.py
28
+ src/ipulse_shared_core_ftredge/services/base_service_exceptions.py
29
29
  src/ipulse_shared_core_ftredge/services/fastapiservicemon.py
30
30
  src/ipulse_shared_core_ftredge/services/servicemon.py
31
31
  src/ipulse_shared_core_ftredge/utils/__init__.py
@@ -2,4 +2,4 @@ pydantic[email]~=2.5
2
2
  python-dateutil~=2.8
3
3
  fastapi~=0.115.8
4
4
  pytest~=7.1
5
- ipulse_shared_base_ftredge>=5.6.1
5
+ ipulse_shared_base_ftredge>=5.7.1