bw-essentials-core 0.1.2__py3-none-any.whl → 0.1.4__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 bw-essentials-core might be problematic. Click here for more details.

@@ -18,3 +18,5 @@ class Services(Enum):
18
18
  PAYMENT = 'Payment'
19
19
  MODEL_PORTFOLIO = "Model_Portfolio"
20
20
  PROMETHEUS_USER_APP = "Prometheus_User_App"
21
+ PORTFOLIO_CATALOGUE = "Portfolio_Catalogue"
22
+ PORTFOLIO_CONTENT = "Portfolio_Content"
@@ -28,10 +28,11 @@ class NotificationService(ApiClient):
28
28
  self.name = Services.NOTIFICATION.value
29
29
  self.base_url = self.get_base_url(self.name)
30
30
  self.urls = {
31
- "whatsapp": "whatsapp"
31
+ "whatsapp": "whatsapp",
32
+ "email": "email"
32
33
  }
33
34
 
34
- def _whatsapp(self, title, template, platform, params, to, user_id):
35
+ def _whatsapp(self, title, template, platform, params, to, user_id) -> None:
35
36
  """
36
37
  Sends a WhatsApp notification.
37
38
 
@@ -66,12 +67,77 @@ class NotificationService(ApiClient):
66
67
  resp_data = self._post(url=self.base_url, endpoint=self.urls.get('whatsapp'), data=payload)
67
68
  logger.info(f"Whatsapp response {resp_data =}")
68
69
 
69
- def send_whatsapp(self, template, title, params, to, user_id):
70
- logger.info(f"In - send_whatsapp_notification {user_id =} {title = } {params = } {to = }")
70
+ def send_whatsapp(self, template, title, params, to, user_id) -> None:
71
+ """
72
+
73
+ Args:
74
+ template (str): Template for the WhatsApp message.
75
+ title (str): Title of the notification.
76
+ params: Parameters for the notification message.
77
+ to (str): Recipient's whatsapp number.
78
+ user_id (str): The ID of the user receiving the notification.
71
79
 
80
+ Returns:
81
+ None
82
+ """
83
+ logger.info(f"In - send_whatsapp_notification {user_id =} {title = } {params = } {to = }")
72
84
  self._whatsapp(title=title,
73
85
  template=template,
74
86
  platform=self._get_env_var(NotificationService.PLATFORM),
75
87
  params=params,
76
88
  to=to,
77
89
  user_id=user_id)
90
+
91
+ def _email(self, title: str, content: str, platform: str, to: str, user_id: str) -> None:
92
+ """
93
+ Sends an email notification using the internal notification service.
94
+
95
+ Args:
96
+ title (str): The subject or title of the email.
97
+ content (str): The HTML or plain text body of the email.
98
+ platform (str): The platform identifier from which the email is sent (e.g., 'prometheus').
99
+ to (str): Recipient's email address.
100
+ user_id (str): The ID of the user for tracking or logging purposes.
101
+
102
+ Returns:
103
+ None
104
+
105
+ """
106
+ logger.info(f"In - email {user_id =}, {to =}, {title =}, {platform =}, {content =}")
107
+ payload = {
108
+ "to": to,
109
+ "userId": user_id,
110
+ "platform": platform,
111
+ "title": title,
112
+ "content": content
113
+ }
114
+ logger.info(f"email {payload =}")
115
+ headers = {
116
+ 'api-key': self._get_env_var(NotificationService.NOTIFICATION_API_KEY),
117
+ 'Content-Type': 'application/json'
118
+ }
119
+ self.set_headers(headers)
120
+ resp_data = self._post(url=self.base_url, endpoint=self.urls.get('email'), json=payload)
121
+ logger.info(f"Email response {resp_data =}")
122
+
123
+ def send_email(self, title: str, content: str, to: str, user_id: str) -> None:
124
+ """
125
+ Sends an email notification to the specified recipient.
126
+
127
+ Args:
128
+ title (str): The subject or title of the email.
129
+ content (str): The HTML or plain text content of the email.
130
+ to (str): The recipient's email address.
131
+ user_id (str): The ID of the user associated with the notification.
132
+
133
+ Returns:
134
+ None
135
+ """
136
+ logger.info(f"In - send_email {user_id =}, {title =}, {to =}")
137
+ self._email(
138
+ title=title,
139
+ content=content,
140
+ platform=self._get_env_var(NotificationService.PLATFORM),
141
+ to=to,
142
+ user_id=user_id
143
+ )
@@ -0,0 +1,104 @@
1
+ """portfolio_catalogue.py
2
+
3
+ Client wrapper for interacting with the Portfolio-Catalogue Service API.
4
+
5
+ This module exposes `PortfolioCatalogue`, a thin abstraction over the
6
+ shared :class:`bw_essentials.services.api_client.ApiClient` that collates
7
+ all URL templates and common logic required to communicate with the
8
+ Portfolio-Catalogue micro-service responsible for portfolio construction
9
+ and rebalancing operations.
10
+
11
+ Features
12
+ --------
13
+ - Centralised mapping of service endpoints.
14
+ - Uniform request/response logging using the shared API client helper.
15
+ - Simple, type-hinted public interface that hides low-level HTTP calls.
16
+
17
+ Example
18
+ -------
19
+ >>> from bw_essentials.services.portfolio_catalogue import PortfolioCatalogue
20
+ >>> client = PortfolioCatalogue(service_user="system")
21
+ >>> data = {
22
+ "portfolioId": "BASKE_e3f7fc",
23
+ "startDate": "2025-07-01",
24
+ "endDate": "2025-07-10",
25
+ "status": "active",
26
+ "createdBy": "KP",
27
+ "constituents": [
28
+ {
29
+ "symbol": "EROSMEDIA",
30
+ "weight": 0.5,
31
+ "isin": "INE416L01017",
32
+ "status": "active",
33
+ "rationale": "Hello"
34
+ },
35
+ {
36
+ "symbol": "IDEA",
37
+ "weight": 0.5,
38
+ "isin": "INE669E01016",
39
+ "status": "active",
40
+ "rationale": "Hello"
41
+ }
42
+ ]
43
+ }
44
+ >>> response = client.create_rebalance(json=data)
45
+ >>> print(response)
46
+ """
47
+
48
+ import logging
49
+ from typing import Optional, Dict, Any
50
+
51
+ from bw_essentials.constants.services import Services
52
+ from bw_essentials.services.api_client import ApiClient
53
+
54
+ logger = logging.getLogger(__name__)
55
+
56
+
57
+ class PortfolioCatalogue(ApiClient):
58
+ """High-level client for the Portfolio-Catalogue Service.
59
+
60
+ This class bundles together the logic for generating fully-qualified
61
+ endpoint URLs and executing authenticated HTTP requests for
62
+ portfolio rebalancing workflows.
63
+
64
+ Attributes
65
+ ----------
66
+ base_url : str
67
+ Resolved base URL for the Portfolio-Catalogue service obtained
68
+ from configuration or environment variables.
69
+ name : str
70
+ Canonical service identifier used for logging and telemetry.
71
+ urls : dict[str, str]
72
+ Mapping of human-readable keys to relative endpoint paths.
73
+ """
74
+
75
+ def __init__(self, service_user: str):
76
+ super().__init__(user=service_user)
77
+ self.base_url = self.get_base_url(Services.PORTFOLIO_CATALOGUE.value)
78
+ self.name = Services.PORTFOLIO_CATALOGUE.value
79
+ self.urls = {
80
+ "rebalance": "rebalance",
81
+ }
82
+
83
+ def create_rebalance(self, json: Dict[str, Any]) -> Optional[Dict[str, Any]]:
84
+ """Submit a rebalance request.
85
+
86
+ Parameters
87
+ ----------
88
+ json : dict
89
+ Request payload describing the rebalance parameters and
90
+ portfolio metadata.
91
+
92
+ Returns
93
+ -------
94
+ dict
95
+ Parsed JSON response returned by the service.
96
+ """
97
+ logger.info("In - create_rebalance %s", json)
98
+ data = self._post(
99
+ url=self.base_url,
100
+ endpoint=self.urls["rebalance"],
101
+ json=json,
102
+ )
103
+ logger.info("%s", data)
104
+ return data
@@ -0,0 +1,69 @@
1
+ """portfolio_content.py
2
+
3
+ Client wrapper for the Portfolio-Content Service API.
4
+
5
+ This module exposes :class:`PortfolioContent`, a light-weight abstraction
6
+ around :class:`bw_essentials.services.api_client.ApiClient` that
7
+ centralises endpoint definitions and adds structured logging when
8
+ querying portfolio content (e.g. constituent list, metadata).
9
+
10
+ Example
11
+ -------
12
+ >>> from bw_essentials.services.portfolio_content import PortfolioContent
13
+ >>> client = PortfolioContent(service_user="system")
14
+ >>> details = client.get_portfolio_details("BASKE_e3f7fc")
15
+ >>> print(details)
16
+ """
17
+
18
+ import logging
19
+ from typing import Optional, Dict, Any
20
+
21
+ from bw_essentials.constants.services import Services
22
+ from bw_essentials.services.api_client import ApiClient
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class PortfolioContent(ApiClient):
28
+ """High-level client for the Portfolio-Content Service.
29
+
30
+ Attributes
31
+ ----------
32
+ base_url : str
33
+ Resolved base URL of the Portfolio-Content micro-service.
34
+ name : str
35
+ Canonical service identifier for logging/telemetry.
36
+ urls : dict[str, str]
37
+ Mapping of friendly names to relative endpoint paths.
38
+ """
39
+
40
+ def __init__(self, service_user: str):
41
+ super().__init__(user=service_user)
42
+ self.base_url = self.get_base_url(Services.PORTFOLIO_CONTENT.value)
43
+ self.name = Services.PORTFOLIO_CONTENT.value
44
+ self.urls = {
45
+ "portfolio": "portfolio",
46
+ }
47
+
48
+ def get_portfolio_details(self, portfolio_id: str) -> Optional[Dict[str, Any]]:
49
+ """Retrieve full details of a portfolio.
50
+
51
+ Parameters
52
+ ----------
53
+ portfolio_id : str
54
+ Unique identifier of the portfolio whose details should be
55
+ fetched.
56
+
57
+ Returns
58
+ -------
59
+ Optional[dict]
60
+ Parsed JSON response if the request succeeds, otherwise
61
+ ``None``.
62
+ """
63
+ logger.info("In - get_portfolio_details %s", portfolio_id)
64
+ data = self._get(
65
+ url=self.base_url,
66
+ endpoint=f"{self.urls['portfolio']}/{portfolio_id}"
67
+ )
68
+ logger.info("%s", data)
69
+ return data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bw-essentials-core
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Reusable utilities for S3, email, Data Loch, Microsoft Teams Notifications and more.
5
5
  Author: InvestorAI
6
6
  Author-email: support+tech@investorai.in
@@ -1,6 +1,6 @@
1
1
  bw_essentials/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  bw_essentials/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- bw_essentials/constants/services.py,sha256=ymvYcXjJpWQoGnnCnqURhQao61QJAMM-g9sJCx_Y8s4,561
3
+ bw_essentials/constants/services.py,sha256=IcJNd2w7bfEjvEvrkKg9te_71l4rntvU_g4gOMbmrDE,653
4
4
  bw_essentials/data_loch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  bw_essentials/data_loch/data_loch.py,sha256=iJO0oPhZyQjoUZOaeBP1nsbuc5iR9ZNWoAXj2pGEpT8,11716
6
6
  bw_essentials/email_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -16,12 +16,14 @@ bw_essentials/services/broker.py,sha256=As-VT1MxkCD9p-13dQJDwf0_aEJVA6H0wNqL-EYH
16
16
  bw_essentials/services/market_pricer.py,sha256=Qc9lxzAjhefAvjyEKsBPDu60bF6_61cnSpZNfjGMyDg,11755
17
17
  bw_essentials/services/master_data.py,sha256=2o_r2gdhIKBeTFgn5IIY-becgCEpYBymO4BKmixdV1g,11987
18
18
  bw_essentials/services/model_portfolio_reporting.py,sha256=iOtm4gyfU8P7C0R1gp6gUJI4ZRxJD5K2GLOalI_gToM,3249
19
- bw_essentials/services/notification.py,sha256=OQD-rB7FaqcoyjRgFyl2pgeXWIgtYcUhRs_4uT1Em9A,2634
19
+ bw_essentials/services/notification.py,sha256=q4jIZzIWIHvn-XaIIbkEjjhkYUV8ZGQWUXaY4NNRFgI,5078
20
+ bw_essentials/services/portfolio_catalogue.py,sha256=sLS7tYW7AkCEXYt8oWdXhmzgzvHCH9nKKFl47y8-c9c,3070
21
+ bw_essentials/services/portfolio_content.py,sha256=rdFTTsUUIt-AgFfA1SAItqg2njakVOm4dUKU0FHZQ2E,2148
20
22
  bw_essentials/services/trade_placement.py,sha256=PrzeU2XXC9HF1IQ1dMDM_ZHxmC491sOl-JbA6GWPwII,20772
21
23
  bw_essentials/services/user_app.py,sha256=_Y2NgDq6kEoco7ZRJ3-MMYJ-K2HGStJoFoeGOH_HotQ,11107
22
24
  bw_essentials/services/user_portfolio.py,sha256=_5M6yPfQt4MXedINBawEoPkb_o7IGzxPeHkvZkoQm8k,16191
23
25
  bw_essentials/services/user_portfolio_reporting.py,sha256=QaZzcw912Uos5ZafEaxLXDmCyetTFiVX3at3cTAv6MA,6003
24
- bw_essentials_core-0.1.2.dist-info/METADATA,sha256=Bpm1zfFijl-hOhODELxsMOlhbuQXR8YwQ77kniBeSnI,7501
25
- bw_essentials_core-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
- bw_essentials_core-0.1.2.dist-info/top_level.txt,sha256=gDc5T_y5snwKGXDQUusEus-FEt0RFwG644Yn_58wQOQ,14
27
- bw_essentials_core-0.1.2.dist-info/RECORD,,
26
+ bw_essentials_core-0.1.4.dist-info/METADATA,sha256=H8GOOZwwtDbXU-DtWLK1LCMFOlyuXAeX9KD9X8Wmt0c,7501
27
+ bw_essentials_core-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ bw_essentials_core-0.1.4.dist-info/top_level.txt,sha256=gDc5T_y5snwKGXDQUusEus-FEt0RFwG644Yn_58wQOQ,14
29
+ bw_essentials_core-0.1.4.dist-info/RECORD,,