ipulse-shared-core-ftredge 3.2.3__tar.gz → 4.1.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 (25) hide show
  1. {ipulse_shared_core_ftredge-3.2.3/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-4.1.1}/PKG-INFO +1 -1
  2. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/setup.py +1 -1
  3. ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/__init__.py +9 -0
  4. ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/exceptions.py +71 -0
  5. ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/models/api_response.py +22 -0
  6. ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/services/__init__.py +1 -0
  7. ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge/services/base_service.py +75 -0
  8. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +1 -1
  9. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +4 -0
  10. ipulse_shared_core_ftredge-3.2.3/src/ipulse_shared_core_ftredge/__init__.py +0 -4
  11. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/LICENCE +0 -0
  12. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/README.md +0 -0
  13. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/pyproject.toml +0 -0
  14. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/setup.cfg +0 -0
  15. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
  16. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/organisation.py +0 -0
  17. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/resource_catalog_item.py +0 -0
  18. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_auth.py +0 -0
  19. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_profile.py +0 -0
  20. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_profile_update.py +0 -0
  21. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge/models/user_status.py +0 -0
  22. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
  23. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +0 -0
  24. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
  25. {ipulse_shared_core_ftredge-3.2.3 → ipulse_shared_core_ftredge-4.1.1}/tests/test_utils_gcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 3.2.3
3
+ Version: 4.1.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='3.2.3',
6
+ version='4.1.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=[
@@ -0,0 +1,9 @@
1
+ # pylint: disable=missing-module-docstring
2
+ from .models import ( UserAuth, UserProfile,
3
+ UserStatus, UserProfileUpdate,
4
+ Organisation)
5
+
6
+ from .exceptions import (BaseServiceException, ResourceNotFoundError, AuthorizationError,
7
+ ValidationError )
8
+
9
+ from .services import (BaseFirestoreService)
@@ -0,0 +1,71 @@
1
+ from fastapi import HTTPException
2
+ from typing import Optional, Any, Dict
3
+
4
+ class BaseServiceException(HTTPException):
5
+ def __init__(
6
+ self,
7
+ status_code: int,
8
+ detail: str,
9
+ resource_type: str,
10
+ resource_id: Optional[str] = None,
11
+ additional_info: Optional[Dict[str, Any]] = None
12
+ ):
13
+ self.resource_type = resource_type
14
+ self.resource_id = resource_id
15
+ self.additional_info = additional_info or {}
16
+
17
+ # Build detailed message
18
+ detail_msg = f"{detail}"
19
+ if resource_type:
20
+ detail_msg += f" [Resource Type: {resource_type}]"
21
+ if resource_id:
22
+ detail_msg += f" [ID: {resource_id}]"
23
+
24
+ super().__init__(status_code=status_code, detail=detail_msg)
25
+
26
+ class ResourceNotFoundError(BaseServiceException):
27
+ def __init__(
28
+ self,
29
+ resource_type: str,
30
+ resource_id: str,
31
+ additional_info: Optional[Dict[str, Any]] = None
32
+ ):
33
+ super().__init__(
34
+ status_code=404,
35
+ detail="Resource not found",
36
+ resource_type=resource_type,
37
+ resource_id=resource_id,
38
+ additional_info=additional_info
39
+ )
40
+
41
+ class AuthorizationError(BaseServiceException):
42
+ def __init__(
43
+ self,
44
+ resource_type: str,
45
+ action: str,
46
+ resource_id: Optional[str] = None,
47
+ additional_info: Optional[Dict[str, Any]] = None
48
+ ):
49
+ super().__init__(
50
+ status_code=403,
51
+ detail=f"Not authorized to {action}",
52
+ resource_type=resource_type,
53
+ resource_id=resource_id,
54
+ additional_info=additional_info
55
+ )
56
+
57
+ class ValidationError(BaseServiceException):
58
+ def __init__(
59
+ self,
60
+ resource_type: str,
61
+ detail: str,
62
+ resource_id: Optional[str] = None,
63
+ additional_info: Optional[Dict[str, Any]] = None
64
+ ):
65
+ super().__init__(
66
+ status_code=422,
67
+ detail=detail,
68
+ resource_type=resource_type,
69
+ resource_id=resource_id,
70
+ additional_info=additional_info
71
+ )
@@ -0,0 +1,22 @@
1
+ from typing import Generic, TypeVar, Optional, Any, Dict, List
2
+ from pydantic import BaseModel, ConfigDict
3
+ import datetime as dt
4
+
5
+ T = TypeVar('T')
6
+
7
+ class StandardResponse(BaseModel, Generic[T]):
8
+ model_config = ConfigDict(arbitrary_types_allowed=True)
9
+ success: bool
10
+ data: Optional[T] = None
11
+ message: Optional[str] = None
12
+ error: Optional[str] = None
13
+
14
+ metadata: Dict[str, Any] = {
15
+ "timestamp": dt.datetime.now(dt.timezone.utc).isoformat()
16
+ }
17
+
18
+ class PaginatedResponse(StandardResponse, Generic[T]):
19
+ total_count: int
20
+ page: int
21
+ page_size: int
22
+ items: List[T]
@@ -0,0 +1 @@
1
+ from .base_service import BaseFirestoreService
@@ -0,0 +1,75 @@
1
+ from typing import Dict, Any, Optional
2
+ from datetime import datetime,timezone
3
+ from fastapi import HTTPException
4
+ from google.cloud import firestore
5
+ from ..exceptions import ResourceNotFoundError, ValidationError
6
+
7
+ class BaseFirestoreService:
8
+ def __init__(self, db: firestore.Client, collection_name: str, resource_type: str):
9
+ self.db = db
10
+ self.collection_name = collection_name
11
+ self.resource_type = resource_type
12
+
13
+ def _validate_update_fields(self, update_data: Dict[str, Any]) -> Dict[str, Any]:
14
+ """Centralized update fields validation"""
15
+ if not isinstance(update_data, dict):
16
+ update_data = update_data.model_dump(exclude_unset=True)
17
+
18
+ valid_fields = {
19
+ k: v for k, v in update_data.items()
20
+ if v is not None and not (isinstance(v, (list, dict, set)) and len(v) == 0)
21
+ }
22
+
23
+ if not valid_fields:
24
+ raise ValidationError(
25
+ resource_type=self.resource_type,
26
+ detail="No valid fields to update",
27
+ resource_id=None
28
+ )
29
+
30
+ return valid_fields
31
+
32
+ async def get_document(self, doc_id: str) -> Dict[str, Any]:
33
+ """Get a document by ID with standardized error handling"""
34
+ doc_ref = self.db.collection(self.collection_name).document(doc_id)
35
+ doc = doc_ref.get()
36
+
37
+ if not doc.exists:
38
+ raise ResourceNotFoundError(
39
+ resource_type=self.resource_type,
40
+ resource_id=doc_id,
41
+ additional_info={"collection": self.collection_name}
42
+ )
43
+
44
+ return doc.to_dict()
45
+
46
+ async def update_document(self, doc_id: str, update_data: Dict[str, Any], user_uid: Optional[str] = None) -> Dict[str, Any]:
47
+ """Standard update method with validation and audit fields"""
48
+ try:
49
+ doc_ref = self.db.collection(self.collection_name).document(doc_id)
50
+
51
+ if not doc_ref.get().exists:
52
+ raise ResourceNotFoundError(
53
+ resource_type=self.resource_type,
54
+ resource_id=doc_id,
55
+ additional_info={"collection": self.collection_name}
56
+ )
57
+
58
+ valid_fields = self._validate_update_fields(update_data)
59
+
60
+ # Add audit fields
61
+ valid_fields.update({
62
+ 'updt_date': datetime.now(timezone.utc).isoformat(),
63
+ 'updt_by_user': user_uid if user_uid else None
64
+ })
65
+
66
+ doc_ref.update(valid_fields)
67
+ return doc_ref.get().to_dict()
68
+
69
+ except (ResourceNotFoundError, ValidationError):
70
+ raise
71
+ except Exception as e:
72
+ raise HTTPException(
73
+ status_code=500,
74
+ detail=f"Failed to update {self.resource_type}: {str(e)}"
75
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 3.2.3
3
+ Version: 4.1.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,16 +3,20 @@ README.md
3
3
  pyproject.toml
4
4
  setup.py
5
5
  src/ipulse_shared_core_ftredge/__init__.py
6
+ src/ipulse_shared_core_ftredge/exceptions.py
6
7
  src/ipulse_shared_core_ftredge.egg-info/PKG-INFO
7
8
  src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt
8
9
  src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt
9
10
  src/ipulse_shared_core_ftredge.egg-info/requires.txt
10
11
  src/ipulse_shared_core_ftredge.egg-info/top_level.txt
11
12
  src/ipulse_shared_core_ftredge/models/__init__.py
13
+ src/ipulse_shared_core_ftredge/models/api_response.py
12
14
  src/ipulse_shared_core_ftredge/models/organisation.py
13
15
  src/ipulse_shared_core_ftredge/models/resource_catalog_item.py
14
16
  src/ipulse_shared_core_ftredge/models/user_auth.py
15
17
  src/ipulse_shared_core_ftredge/models/user_profile.py
16
18
  src/ipulse_shared_core_ftredge/models/user_profile_update.py
17
19
  src/ipulse_shared_core_ftredge/models/user_status.py
20
+ src/ipulse_shared_core_ftredge/services/__init__.py
21
+ src/ipulse_shared_core_ftredge/services/base_service.py
18
22
  tests/test_utils_gcp.py
@@ -1,4 +0,0 @@
1
- # pylint: disable=missing-module-docstring
2
- from .models import ( UserAuth, UserProfile,
3
- UserStatus, UserProfileUpdate,
4
- Organisation)