ipulse-shared-core-ftredge 26.1.1__tar.gz → 27.2.0__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 (63) hide show
  1. {ipulse_shared_core_ftredge-26.1.1/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-27.2.0}/PKG-INFO +2 -2
  2. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/setup.py +2 -2
  3. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +27 -20
  4. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +2 -2
  5. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/catalog/usertype.py +2 -2
  6. ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py +43 -0
  7. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/user_subscription.py +2 -2
  8. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/userprofile.py +2 -2
  9. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/userstatus.py +2 -2
  10. ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py +0 -0
  11. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +2 -2
  12. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +2 -0
  13. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +1 -1
  14. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/LICENCE +0 -0
  15. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/README.md +0 -0
  16. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/pyproject.toml +0 -0
  17. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/setup.cfg +0 -0
  18. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/__init__.py +0 -0
  19. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/cache/__init__.py +0 -0
  20. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/cache/shared_cache.py +0 -0
  21. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/__init__.py +0 -0
  22. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +0 -0
  23. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/auth_protected_router.py +0 -0
  24. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/authz_credit_extraction.py +0 -0
  25. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/dependencies/firestore_client.py +0 -0
  26. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/exceptions/__init__.py +0 -0
  27. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/exceptions/base_exceptions.py +0 -0
  28. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/exceptions/user_exceptions.py +0 -0
  29. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
  30. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/base_api_response.py +0 -0
  31. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/base_data_model.py +0 -0
  32. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/catalog/__init__.py +0 -0
  33. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/credit_api_response.py +0 -0
  34. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/custom_json_response.py +0 -0
  35. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/__init__.py +0 -0
  36. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/user_permissions.py +0 -0
  37. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/models/user/userauth.py +0 -0
  38. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/monitoring/__init__.py +0 -0
  39. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/monitoring/tracemon.py +0 -0
  40. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/__init__.py +0 -0
  41. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/base/__init__.py +0 -0
  42. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/base/base_firestore_service.py +0 -0
  43. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py +0 -0
  44. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/catalog/__init__.py +0 -0
  45. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +0 -0
  46. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +0 -0
  47. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/charging_processors.py +0 -0
  48. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/__init__.py +0 -0
  49. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_charging_operations.py +0 -0
  50. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_core_service.py +0 -0
  51. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +0 -0
  52. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +0 -0
  53. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +0 -0
  54. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/userauth_operations.py +0 -0
  55. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py +0 -0
  56. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py +0 -0
  57. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/services/user_charging_service.py +0 -0
  58. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/utils/__init__.py +0 -0
  59. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py +0 -0
  60. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge/utils/json_encoder.py +0 -0
  61. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
  62. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
  63. {ipulse_shared_core_ftredge-26.1.1 → ipulse_shared_core_ftredge-27.2.0}/tests/test_shared_cache.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 26.1.1
3
+ Version: 27.2.0
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
@@ -12,7 +12,7 @@ License-File: LICENCE
12
12
  Requires-Dist: pydantic[email]~=2.5
13
13
  Requires-Dist: python-dateutil~=2.8
14
14
  Requires-Dist: fastapi~=0.115.8
15
- Requires-Dist: ipulse_shared_base_ftredge==11.1.1
15
+ Requires-Dist: ipulse_shared_base_ftredge~=12.2.0
16
16
  Dynamic: author
17
17
  Dynamic: classifier
18
18
  Dynamic: home-page
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name='ipulse_shared_core_ftredge',
6
- version='26.1.1',
6
+ version='27.2.0',
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=[
@@ -11,7 +11,7 @@ setup(
11
11
  'pydantic[email]~=2.5',
12
12
  'python-dateutil~=2.8',
13
13
  'fastapi~=0.115.8',
14
- 'ipulse_shared_base_ftredge==11.1.1',
14
+ 'ipulse_shared_base_ftredge~=12.2.0',
15
15
  ],
16
16
  author='Russlan Ramdowar',
17
17
  description='Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.',
@@ -1,14 +1,13 @@
1
1
  import os
2
2
  import logging
3
- import asyncio
4
3
  from typing import Optional, Iterable, Dict, Any, List
5
4
  from datetime import datetime, timedelta, timezone
6
5
  import httpx
7
6
  from fastapi import HTTPException, Request
7
+ from ipulse_shared_base_ftredge import ApprovalStatus
8
8
  from ipulse_shared_core_ftredge.exceptions import ServiceError, ResourceNotFoundError
9
9
  from ipulse_shared_core_ftredge.models import UserStatus
10
10
  from ipulse_shared_core_ftredge.services import UserCoreService
11
- from ipulse_shared_base_ftredge import ApprovalStatus
12
11
 
13
12
  # Cache TTL constant
14
13
  USERSTATUS_CACHE_TTL = 60 # 60 seconds
@@ -63,12 +62,13 @@ class UserStatusCache:
63
62
  userstatus_cache = UserStatusCache()
64
63
 
65
64
  # Replace the logger dependency with a standard logger
66
- logger = logging.getLogger(__name__)
65
+ _module_logger = logging.getLogger(__name__)
67
66
 
68
67
  async def get_userstatus(
69
68
  user_uid: str,
70
69
  user_core_service: UserCoreService,
71
- force_fresh: bool = False
70
+ force_fresh: bool = False,
71
+ logger: Optional[logging.Logger] = None
72
72
  ) -> tuple[UserStatus, bool]:
73
73
  """
74
74
  Lightweight fetch of user status with caching.
@@ -78,10 +78,12 @@ async def get_userstatus(
78
78
  user_uid: User ID to fetch status for
79
79
  user_core_service: UserCoreService for data retrieval
80
80
  force_fresh: Whether to bypass cache
81
+ logger: Optional logger instance to use.
81
82
 
82
83
  Returns:
83
84
  Tuple of (UserStatus object, whether cache was used)
84
85
  """
86
+ log = logger if logger else _module_logger
85
87
  cache_used = False
86
88
 
87
89
  # Check cache first unless forced fresh
@@ -109,7 +111,7 @@ async def get_userstatus(
109
111
  raise ValueError(f"Expected UserStatus object or dict, got {type(status_obj)}")
110
112
 
111
113
  except Exception as e:
112
- logger.error(f"Error fetching user status via UserCoreService: {str(e)}")
114
+ log.error(f"Error fetching user status via UserCoreService: {str(e)}")
113
115
  raise ServiceError(
114
116
  operation="fetching user status for authz via UserCoreService",
115
117
  error=e,
@@ -134,11 +136,12 @@ def _validate_resource_fields(fields: Dict[str, Any]) -> List[str]:
134
136
  }
135
137
  return list(valid_fields.keys())
136
138
 
137
- async def extract_request_fields(request: Request) -> Optional[List[str]]:
139
+ async def extract_request_fields(request: Request, logger: Optional[logging.Logger] = None) -> Optional[List[str]]:
138
140
  """
139
141
  Extract fields from request body for both PATCH and POST methods.
140
142
  For GET and DELETE methods, return None as they typically don't have a body.
141
143
  """
144
+ log = logger if logger else _module_logger
142
145
  # Skip body extraction for GET and DELETE requests
143
146
  if request.method.upper() in ["GET", "DELETE", "HEAD", "OPTIONS"]:
144
147
  return None
@@ -161,7 +164,7 @@ async def extract_request_fields(request: Request) -> Optional[List[str]]:
161
164
  return None
162
165
 
163
166
  except Exception as e:
164
- logger.warning(f"Could not extract fields from request body: {str(e)}")
167
+ log.warning(f"Could not extract fields from request body: {str(e)}")
165
168
  return None # Return None instead of raising an error
166
169
 
167
170
  # Main authorization function with configurable timeout
@@ -169,6 +172,7 @@ async def authorizeAPIRequest(
169
172
  request: Request,
170
173
  user_core_service: UserCoreService, # UserCoreService instance for better integration
171
174
  request_resource_fields: Optional[Iterable[str]] = None,
175
+ logger: Optional[logging.Logger] = None
172
176
 
173
177
  ) -> Dict[str, Any]:
174
178
  """
@@ -179,6 +183,7 @@ async def authorizeAPIRequest(
179
183
  request: The incoming request
180
184
  user_core_service: UserCoreService instance for better integration
181
185
  request_resource_fields: Fields being accessed/modified in the request
186
+ logger: Optional logger instance to use.
182
187
 
183
188
  Returns:
184
189
  Authorization result containing decision details
@@ -186,18 +191,19 @@ async def authorizeAPIRequest(
186
191
  Raises:
187
192
  HTTPException: For authorization failures (403) or service errors (500)
188
193
  """
194
+ log = logger if logger else _module_logger
189
195
  opa_decision = None
190
196
  try:
191
197
  # Extract fields for both PATCH and POST if not provided
192
198
  if not request_resource_fields:
193
- request_resource_fields = await extract_request_fields(request)
199
+ request_resource_fields = await extract_request_fields(request, logger=log)
194
200
 
195
201
  # Extract request context and Firebase user claims
196
202
  firebase_user = request.state.user
197
- logger.debug(f"Firebase user: {firebase_user}")
203
+ log.debug(f"Firebase user: {firebase_user}")
198
204
  user_uid = firebase_user.get('uid')
199
205
  if not user_uid:
200
- logger.debug(f"Authorization denied for {request.method} {request.url.path}: No user UID found")
206
+ log.debug(f"Authorization denied for {request.method} {request.url.path}: No user UID found")
201
207
  raise HTTPException(
202
208
  status_code=403,
203
209
  detail="Not authorized to access this resource"
@@ -214,10 +220,11 @@ async def authorizeAPIRequest(
214
220
  user_uid=user_uid,
215
221
  user_core_service=user_core_service,
216
222
  force_fresh=force_fresh,
223
+ logger=log
217
224
  )
218
225
 
219
226
  # Perform comprehensive review and cleanup synchronously to ensure accurate auth data
220
- logger.debug(f"Comprehensive review for userstatus : {user_status_obj} during authz")
227
+ log.debug(f"Comprehensive review for userstatus : {user_status_obj} during authz")
221
228
  if user_core_service:
222
229
  try:
223
230
  review_result = await user_core_service.review_and_clean_active_subscription_credits_and_permissions(
@@ -228,10 +235,10 @@ async def authorizeAPIRequest(
228
235
  clean_expired_permissions=True,
229
236
  review_credits=True
230
237
  )
231
- logger.debug(f"Review result for userstatus : {review_result} during authz")
238
+ log.debug(f"Review result for userstatus : {review_result} during authz")
232
239
  # Refresh user status after comprehensive review if any actions were taken
233
240
  if review_result.get('actions_taken'):
234
- logger.info(f"Auth middleware performed comprehensive review for user {user_uid}: {review_result['actions_taken']}")
241
+ log.info(f"Authz middleware performed comprehensive review for user {user_uid}: {review_result['actions_taken']}")
235
242
  # Use the updated UserStatus returned from the review function
236
243
  if 'updated_userstatus' in review_result:
237
244
  user_status_obj = review_result['updated_userstatus']
@@ -241,7 +248,7 @@ async def authorizeAPIRequest(
241
248
  userstatus_cache.set(user_uid, user_status_obj)
242
249
 
243
250
  except Exception as e:
244
- logger.warning(f"Comprehensive review failed for user {user_uid} during auth: {str(e)}")
251
+ log.warning(f"Comprehensive review failed for user {user_uid} during auth: {str(e)}")
245
252
  # Continue with existing status if review fails
246
253
 
247
254
  # Get valid permissions after comprehensive review
@@ -299,17 +306,17 @@ async def authorizeAPIRequest(
299
306
  )
300
307
 
301
308
  if response.status_code != 200:
302
- logger.error(f"OPA authorization failed: {response.text}")
309
+ log.error(f"OPA authorization failed: {response.text}")
303
310
  raise HTTPException(
304
311
  status_code=500,
305
312
  detail="Authorization service error"
306
313
  )
307
314
 
308
315
  result = response.json()
309
-
316
+ log.debug(f"OPA response: {result}")
310
317
  # Handle OPA response format
311
318
  if "result" not in result:
312
- logger.warning("OPA response missing 'result' field")
319
+ log.warning("OPA response missing 'result' field")
313
320
  raise HTTPException(
314
321
  status_code=500,
315
322
  detail="Authorization service error: OPA response format unexpected"
@@ -320,14 +327,14 @@ async def authorizeAPIRequest(
320
327
 
321
328
  # Handle authorization denial
322
329
  if not allow:
323
- logger.debug(f"Authorization denied for {request.method} {request.url.path}")
330
+ log.debug(f"Authorization denied for {request.method} {request.url.path}")
324
331
  raise HTTPException(
325
332
  status_code=403,
326
333
  detail=f"Not authorized to {request.method} {request.url.path}"
327
334
  )
328
335
 
329
336
  except httpx.RequestError as e:
330
- logger.error(f"Failed to connect to OPA: {str(e)}")
337
+ log.error(f"Failed to connect to OPA: {str(e)}")
331
338
  raise HTTPException(
332
339
  status_code=500,
333
340
  detail="Authorization service temporarily unavailable"
@@ -346,7 +353,7 @@ async def authorizeAPIRequest(
346
353
  raise
347
354
  except Exception as e:
348
355
  # Only log unexpected errors at ERROR level
349
- logger.error(f"Unexpected error during authorization for {request.method} {request.url.path}: {str(e)}")
356
+ log.error(f"Unexpected error during authorization for {request.method} {request.url.path}: {str(e)}")
350
357
  raise HTTPException(
351
358
  status_code=500,
352
359
  detail="Internal authorization error"
@@ -10,7 +10,7 @@ from enum import StrEnum
10
10
  from datetime import datetime, timezone, timedelta
11
11
  from pydantic import Field, ConfigDict, field_validator,model_validator, BaseModel
12
12
  from ipulse_shared_base_ftredge import (Layer, Module, list_enums_as_lower_strings,
13
- Subject, SubscriptionPlanName,ObjectOverallStatus,
13
+ SystemSubject, SubscriptionPlanName,ObjectOverallStatus,
14
14
  SubscriptionStatus, TimeUnit)
15
15
  from ..base_data_model import BaseDataModel
16
16
  from ..user.user_permissions import UserPermission
@@ -60,7 +60,7 @@ class SubscriptionPlan(BaseDataModel):
60
60
  model_config = ConfigDict(extra="forbid")
61
61
 
62
62
  VERSION: ClassVar[float] = 1.0
63
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.CATALOG))
63
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.CATALOG))
64
64
  OBJ_REF: ClassVar[str] = "subscriptionplan"
65
65
 
66
66
  # System-managed fields
@@ -9,7 +9,7 @@ based on their user type (superadmin, admin, internal, authenticated, anonymous)
9
9
  from typing import Dict, Any, Optional, ClassVar, List
10
10
  from datetime import datetime
11
11
  from pydantic import Field, ConfigDict, field_validator, model_validator
12
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, ObjectOverallStatus
12
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, ObjectOverallStatus
13
13
  from ipulse_shared_base_ftredge.enums.enums_iam import IAMUserType
14
14
  from ipulse_shared_core_ftredge.models.base_data_model import BaseDataModel
15
15
  from ipulse_shared_core_ftredge.models.user.user_permissions import UserPermission
@@ -28,7 +28,7 @@ class UserType(BaseDataModel):
28
28
  model_config = ConfigDict(extra="forbid")
29
29
 
30
30
  VERSION: ClassVar[float] = 1.0
31
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE.name, Subject.CATALOG.name))
31
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE.name, SystemSubject.CATALOG.name))
32
32
  OBJ_REF: ClassVar[str] = "usertype"
33
33
 
34
34
  # System-managed fields
@@ -0,0 +1,43 @@
1
+ # pylint: disable=missing-module-docstring, missing-class-docstring
2
+ from typing import List, Optional, TypeVar, Generic
3
+ from datetime import datetime
4
+ from pydantic import Field, BaseModel
5
+ from ipulse_shared_core_ftredge.models.base_data_model import BaseDataModel
6
+ from ipulse_shared_base_ftredge.enums import DatasetLineage, DatasetScope
7
+
8
+ # Generic type for the records within the dataset
9
+ RecordsSamplingType = TypeVar('RecordsSamplingType', bound=BaseModel)
10
+
11
+ class TimeSeriesPackagedDatasetModel(BaseDataModel, Generic[RecordsSamplingType]):
12
+ """
13
+ An intermediary model for time series datasets that holds aggregated records.
14
+ It provides a generic way to handle different types of time series records.
15
+ """
16
+ dataset_id: str = Field(..., description="The unique identifier for this dataset, often matching the asset ID.")
17
+
18
+ dataset_modality: str = Field(..., description="The modality of the dataset, e.g., 'time_series', 'cross_sectional'.")
19
+ dataset_lineage: DatasetLineage = Field(..., description="The lineage of the data, indicating its origin and transformations.")
20
+ dataset_partition: DatasetScope = Field(..., description="The partition type of the dataset, e.g., full, subsampled.")
21
+
22
+ # Generic lists for different temporal buckets of records
23
+ max_bulk_records: List[RecordsSamplingType] = Field(default_factory=list)
24
+ latest_bulk_records: Optional[List[RecordsSamplingType]] = Field(default_factory=list)
25
+ latest_intraday_records: Optional[List[RecordsSamplingType]] = Field(default_factory=list)
26
+
27
+ # Metadata fields
28
+ max_bulk_updated_at: Optional[datetime] = None
29
+ max_bulk_updated_by: Optional[str] = None
30
+ max_bulk_recent_date_id: Optional[datetime] = None
31
+ max_bulk_oldest_date_id: Optional[datetime] = None
32
+ latest_bulk_recent_date_id: Optional[datetime] = None
33
+ latest_bulk_oldest_date_id: Optional[datetime] = None
34
+ latest_record_updated_at: Optional[datetime] = None
35
+ latest_record_updated_by: Optional[str] = None
36
+ latest_record_change_id: Optional[str] = None
37
+ latest_intraday_bulk_updated_at: Optional[datetime] = None
38
+ latest_intraday_bulk_updated_by: Optional[str] = None
39
+
40
+ @property
41
+ def id(self) -> str:
42
+ """Return dataset_id for backward compatibility and consistency."""
43
+ return self.dataset_id
@@ -3,7 +3,7 @@ from dateutil.relativedelta import relativedelta
3
3
  import uuid
4
4
  from typing import Optional, ClassVar, Dict, Any, List
5
5
  from pydantic import Field, ConfigDict, model_validator
6
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, SubscriptionPlanName, SubscriptionStatus, TimeUnit
6
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, SubscriptionPlanName, SubscriptionStatus, TimeUnit
7
7
  from ..base_data_model import BaseDataModel
8
8
  from .user_permissions import UserPermission
9
9
  # ORIGINAL AUTHOR ="russlan.ramdowar;russlan@ftredge.com"
@@ -22,7 +22,7 @@ class UserSubscription(BaseDataModel):
22
22
  model_config = ConfigDict(frozen=True, extra="forbid")
23
23
 
24
24
  VERSION: ClassVar[float] = 3.0 # Incremented version for direct fields instead of computed
25
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.SUBSCRIPTION))
25
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.SUBSCRIPTION))
26
26
  OBJ_REF: ClassVar[str] = "subscription"
27
27
 
28
28
  # System-managed fields (read-only)
@@ -3,7 +3,7 @@ from datetime import date, datetime
3
3
  import re # Add re import
4
4
  from typing import Set, Optional, ClassVar, Dict, Any, List
5
5
  from pydantic import EmailStr, Field, ConfigDict, model_validator, field_validator
6
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, IAMUserType
6
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, IAMUserType
7
7
  from ..base_data_model import BaseDataModel
8
8
  # ORIGINAL AUTHOR ="Russlan Ramdowar;russlan@ftredge.com"
9
9
  # CLASS_ORGIN_DATE=datetime(2024, 2, 12, 20, 5)
@@ -17,7 +17,7 @@ class UserProfile(BaseDataModel):
17
17
 
18
18
  # Class constants
19
19
  VERSION: ClassVar[float] = 5.0 # Incremented version for primary_usertype addition
20
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.USER))
20
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.USER))
21
21
  OBJ_REF: ClassVar[str] = "userprofile"
22
22
 
23
23
  schema_version: float = Field(
@@ -2,7 +2,7 @@
2
2
  from datetime import datetime, timezone, timedelta
3
3
  from typing import Set, Optional, Dict, List, ClassVar, Any
4
4
  from pydantic import Field, ConfigDict, model_validator, field_validator
5
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, TimeUnit
5
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, TimeUnit
6
6
  from ipulse_shared_base_ftredge.enums.enums_iam import IAMUnit
7
7
  from .user_subscription import UserSubscription
8
8
  from ..base_data_model import BaseDataModel
@@ -20,7 +20,7 @@ class UserStatus(BaseDataModel):
20
20
 
21
21
  # Class constants
22
22
  VERSION: ClassVar[float] = 7.0 # Major version bump for flattened IAM permissions structure
23
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.USER))
23
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.USER))
24
24
  OBJ_REF: ClassVar[str] = "userstatus"
25
25
 
26
26
  # Centralized collection name and document ID prefix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 26.1.1
3
+ Version: 27.2.0
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
@@ -12,7 +12,7 @@ License-File: LICENCE
12
12
  Requires-Dist: pydantic[email]~=2.5
13
13
  Requires-Dist: python-dateutil~=2.8
14
14
  Requires-Dist: fastapi~=0.115.8
15
- Requires-Dist: ipulse_shared_base_ftredge==11.1.1
15
+ Requires-Dist: ipulse_shared_base_ftredge~=12.2.0
16
16
  Dynamic: author
17
17
  Dynamic: classifier
18
18
  Dynamic: home-page
@@ -24,6 +24,7 @@ src/ipulse_shared_core_ftredge/models/base_api_response.py
24
24
  src/ipulse_shared_core_ftredge/models/base_data_model.py
25
25
  src/ipulse_shared_core_ftredge/models/credit_api_response.py
26
26
  src/ipulse_shared_core_ftredge/models/custom_json_response.py
27
+ src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py
27
28
  src/ipulse_shared_core_ftredge/models/catalog/__init__.py
28
29
  src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py
29
30
  src/ipulse_shared_core_ftredge/models/catalog/usertype.py
@@ -54,6 +55,7 @@ src/ipulse_shared_core_ftredge/services/user/userauth_operations.py
54
55
  src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py
55
56
  src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py
56
57
  src/ipulse_shared_core_ftredge/utils/__init__.py
58
+ src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py
57
59
  src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py
58
60
  src/ipulse_shared_core_ftredge/utils/json_encoder.py
59
61
  tests/test_shared_cache.py
@@ -1,4 +1,4 @@
1
1
  pydantic[email]~=2.5
2
2
  python-dateutil~=2.8
3
3
  fastapi~=0.115.8
4
- ipulse_shared_base_ftredge==11.1.1
4
+ ipulse_shared_base_ftredge~=12.2.0