bw-essentials-core 0.0.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 bw-essentials-core might be problematic. Click here for more details.
- bw_essentials/__init__.py +0 -0
- bw_essentials/constants/__init__.py +0 -0
- bw_essentials/constants/services.py +19 -0
- bw_essentials/data_loch/__init__.py +0 -0
- bw_essentials/data_loch/data_loch.py +282 -0
- bw_essentials/email_client/__init__.py +0 -0
- bw_essentials/email_client/email_client.py +243 -0
- bw_essentials/notifications/__init__.py +0 -0
- bw_essentials/notifications/teams_notification_schemas.py +173 -0
- bw_essentials/notifications/teams_notifications.py +189 -0
- bw_essentials/s3_utils/__init__.py +0 -0
- bw_essentials/s3_utils/s3_utils.py +361 -0
- bw_essentials/services/__init__.py +0 -0
- bw_essentials/services/api_client.py +229 -0
- bw_essentials/services/broker.py +250 -0
- bw_essentials/services/market_pricer.py +233 -0
- bw_essentials/services/master_data.py +257 -0
- bw_essentials/services/model_portfolio_reporting.py +81 -0
- bw_essentials/services/trade_placement.py +499 -0
- bw_essentials/services/user_portfolio.py +406 -0
- bw_essentials/services/user_portfolio_reporting.py +153 -0
- bw_essentials_core-0.0.1.dist-info/METADATA +213 -0
- bw_essentials_core-0.0.1.dist-info/RECORD +25 -0
- bw_essentials_core-0.0.1.dist-info/WHEEL +5 -0
- bw_essentials_core-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module to store schemas for teams workflows.
|
|
3
|
+
"""
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_error_schema(service_url, message, summary, error_trace=None, request_id=None):
|
|
8
|
+
"""
|
|
9
|
+
Returns the schema for an error message to be sent to Microsoft Teams.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
service_url (str): The URL of the service.
|
|
13
|
+
message (str): The error message.
|
|
14
|
+
summary (str): A summary of the error.
|
|
15
|
+
error_trace (str, optional): The error trace details. Defaults to None.
|
|
16
|
+
request_id (str, optional): The ID of the request. Defaults to None.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
dict: The schema for the error message.
|
|
20
|
+
"""
|
|
21
|
+
return {
|
|
22
|
+
"type": "message",
|
|
23
|
+
"attachments": [
|
|
24
|
+
{
|
|
25
|
+
"contentType": "application/vnd.microsoft.card.adaptive",
|
|
26
|
+
"content": {
|
|
27
|
+
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
|
28
|
+
"type": "AdaptiveCard",
|
|
29
|
+
"version": "1.0",
|
|
30
|
+
"body": [
|
|
31
|
+
{
|
|
32
|
+
"type": "Container",
|
|
33
|
+
"items": [
|
|
34
|
+
{
|
|
35
|
+
"type": "TextBlock",
|
|
36
|
+
"text": "ERROR",
|
|
37
|
+
"color": "attention",
|
|
38
|
+
"weight": "bolder",
|
|
39
|
+
"size": "large"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"style": "attention"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"type": "TextBlock",
|
|
46
|
+
"text": f"Service: {service_url}",
|
|
47
|
+
"weight": "bolder",
|
|
48
|
+
"wrap": True
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "TextBlock",
|
|
52
|
+
"text": f"{message}",
|
|
53
|
+
"weight": "bolder",
|
|
54
|
+
"wrap": True,
|
|
55
|
+
"isSubtle": True
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "TextBlock",
|
|
59
|
+
"text": "Summary:",
|
|
60
|
+
"weight": "bolder",
|
|
61
|
+
"wrap": True
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"type": "TextBlock",
|
|
65
|
+
"text": f"{summary}",
|
|
66
|
+
"wrap": True,
|
|
67
|
+
"fontType": "monospace"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"type": "TextBlock",
|
|
71
|
+
"text": "Error Trace:",
|
|
72
|
+
"weight": "bolder",
|
|
73
|
+
"wrap": True
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"type": "TextBlock",
|
|
77
|
+
"text": f"{error_trace}",
|
|
78
|
+
"wrap": True
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "TextBlock",
|
|
82
|
+
"text": "Request ID:",
|
|
83
|
+
"weight": "bolder",
|
|
84
|
+
"wrap": True
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"type": "TextBlock",
|
|
88
|
+
"text": f"{request_id}",
|
|
89
|
+
"wrap": True
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "TextBlock",
|
|
93
|
+
"text": "Timestamp:",
|
|
94
|
+
"weight": "bolder",
|
|
95
|
+
"wrap": True
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"type": "TextBlock",
|
|
99
|
+
"text": f"{str(datetime.now())}",
|
|
100
|
+
"wrap": True,
|
|
101
|
+
"isSubtle": True
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_notification_schema(service_url, message):
|
|
111
|
+
"""
|
|
112
|
+
Returns the schema for a message notification to be sent to Microsoft Teams.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
service_url (str): The URL of the service.
|
|
116
|
+
message (str): The log message.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
dict: The schema for the log message.
|
|
120
|
+
"""
|
|
121
|
+
return {
|
|
122
|
+
"type": "message",
|
|
123
|
+
"attachments": [
|
|
124
|
+
{
|
|
125
|
+
"contentType": "application/vnd.microsoft.card.adaptive",
|
|
126
|
+
"content": {
|
|
127
|
+
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
|
128
|
+
"type": "AdaptiveCard",
|
|
129
|
+
"version": "1.0",
|
|
130
|
+
"body": [
|
|
131
|
+
{
|
|
132
|
+
"type": "Container",
|
|
133
|
+
"items": [
|
|
134
|
+
{
|
|
135
|
+
"type": "TextBlock",
|
|
136
|
+
"text": "Notification",
|
|
137
|
+
"color": "good",
|
|
138
|
+
"weight": "bolder",
|
|
139
|
+
"size": "large"
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
"style": "good"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"type": "TextBlock",
|
|
146
|
+
"text": f"Service: {service_url}",
|
|
147
|
+
"weight": "bolder",
|
|
148
|
+
"wrap": True
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"type": "TextBlock",
|
|
152
|
+
"text": f"{message}",
|
|
153
|
+
"weight": "bolder",
|
|
154
|
+
"wrap": True,
|
|
155
|
+
"isSubtle": True
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"type": "TextBlock",
|
|
159
|
+
"text": "Timestamp:",
|
|
160
|
+
"weight": "bolder",
|
|
161
|
+
"wrap": True
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"type": "TextBlock",
|
|
165
|
+
"text": f"{str(datetime.now())}",
|
|
166
|
+
"wrap": True,
|
|
167
|
+
"isSubtle": True
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""
|
|
2
|
+
notifications.py
|
|
3
|
+
|
|
4
|
+
This module provides a `Notifications` class for sending structured messages and alerts
|
|
5
|
+
to external communication tools such as Microsoft Teams and Zenduty. It is used to
|
|
6
|
+
inform stakeholders or developers about system events, including errors and general logs.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
from importlib.util import spec_from_file_location, module_from_spec
|
|
14
|
+
|
|
15
|
+
import requests
|
|
16
|
+
|
|
17
|
+
from bw_essentials.notifications.teams_notification_schemas import get_notification_schema, get_error_schema
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Notifications:
|
|
23
|
+
"""
|
|
24
|
+
Notification module to send alerts and warnings via Microsoft Teams and Zenduty.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
title (str): The title or service name triggering the notification.
|
|
28
|
+
summary (str, optional): A brief summary of the message or error.
|
|
29
|
+
message (str, optional): The main body of the message.
|
|
30
|
+
alert (bool, optional): If True, it's treated as an error; otherwise as a log. Defaults to False.
|
|
31
|
+
trace (str, optional): Optional traceback or detailed error string.
|
|
32
|
+
request_id (str, optional): Optional correlation ID for tracing logs.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self,
|
|
36
|
+
title,
|
|
37
|
+
summary=None,
|
|
38
|
+
message=None,
|
|
39
|
+
alert=False,
|
|
40
|
+
trace=None,
|
|
41
|
+
request_id=None):
|
|
42
|
+
self.message = message
|
|
43
|
+
self.title = title
|
|
44
|
+
self.summary = summary
|
|
45
|
+
self.alert = alert
|
|
46
|
+
self.trace = trace
|
|
47
|
+
self.request_id = request_id
|
|
48
|
+
self.notify_on_teams = self._get_env_var("NOTIFY_ON_TEAMS")
|
|
49
|
+
self.notify_on_calls = self._get_env_var("NOTIFY_ON_CALLS")
|
|
50
|
+
self.webhook_url = self._get_env_var("TEAMS_WEBHOOK_URL")
|
|
51
|
+
self.zenduty_url = self._get_env_var("ZENDUTY_URL")
|
|
52
|
+
self.api_timeout = self._get_env_var("API_TIMEOUT")
|
|
53
|
+
|
|
54
|
+
def _get_env_var(self, key: str) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Fetch a required variable from bw_config.py located in the root directory.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
FileNotFoundError: If bw_config.py is not found.
|
|
60
|
+
AttributeError: If the requested key is not defined in the config.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
str: The value of the config variable.
|
|
64
|
+
"""
|
|
65
|
+
config_path = os.path.join(os.getcwd(), "bw_config.py")
|
|
66
|
+
|
|
67
|
+
if not os.path.exists(config_path):
|
|
68
|
+
raise FileNotFoundError("`bw_config.py` file not found in the root directory. "
|
|
69
|
+
"Please ensure the config file exists.")
|
|
70
|
+
|
|
71
|
+
spec = spec_from_file_location("bw_config", config_path)
|
|
72
|
+
bw_config = module_from_spec(spec)
|
|
73
|
+
sys.modules["bw_config"] = bw_config
|
|
74
|
+
spec.loader.exec_module(bw_config)
|
|
75
|
+
|
|
76
|
+
if not hasattr(bw_config, key):
|
|
77
|
+
raise AttributeError(f"`{key}` not found in bw_config.py. Please define it in the config.")
|
|
78
|
+
|
|
79
|
+
return getattr(bw_config, key)
|
|
80
|
+
|
|
81
|
+
def __notify_teams_workflow(self):
|
|
82
|
+
"""
|
|
83
|
+
Sends a notification to Microsoft Teams using Adaptive Cards.
|
|
84
|
+
|
|
85
|
+
Uses either the error schema or the log schema based on whether the notification
|
|
86
|
+
is an alert or not. This function posts the generated card payload to the configured
|
|
87
|
+
Teams webhook URL.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
None
|
|
91
|
+
"""
|
|
92
|
+
logger.info("In __notify_teams_workflow")
|
|
93
|
+
try:
|
|
94
|
+
if self.notify_on_teams:
|
|
95
|
+
workflow_schema = get_notification_schema(self.title, self.message)
|
|
96
|
+
if self.alert:
|
|
97
|
+
workflow_schema = get_error_schema(
|
|
98
|
+
service_url=self.title,
|
|
99
|
+
message=self.message,
|
|
100
|
+
summary=self.summary,
|
|
101
|
+
error_trace=self.trace,
|
|
102
|
+
request_id=self.request_id
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
headers = {'Content-Type': 'application/json'}
|
|
106
|
+
response = requests.post(
|
|
107
|
+
self.webhook_url,
|
|
108
|
+
data=json.dumps(workflow_schema),
|
|
109
|
+
headers=headers
|
|
110
|
+
)
|
|
111
|
+
logger.info(f"{response =}")
|
|
112
|
+
else:
|
|
113
|
+
logger.info(f"Notification for teams is {self.notify_on_teams}. Message: {self.message}")
|
|
114
|
+
except Exception as exc:
|
|
115
|
+
logger.info("Error while notifying error to teams.")
|
|
116
|
+
logger.exception(exc)
|
|
117
|
+
|
|
118
|
+
def __notify_zenduty(self):
|
|
119
|
+
"""
|
|
120
|
+
Sends a critical alert to Zenduty via its API endpoint.
|
|
121
|
+
|
|
122
|
+
Posts a payload including alert type, message, and summary. Primarily used for error alerts.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
None
|
|
126
|
+
"""
|
|
127
|
+
if self.notify_on_calls:
|
|
128
|
+
payload = {
|
|
129
|
+
"alert_type": "critical",
|
|
130
|
+
"message": self.message,
|
|
131
|
+
"summary": self.summary
|
|
132
|
+
}
|
|
133
|
+
payload_json = json.dumps(payload)
|
|
134
|
+
response = requests.post(
|
|
135
|
+
self.zenduty_url,
|
|
136
|
+
data=payload_json,
|
|
137
|
+
timeout=float(self.api_timeout)
|
|
138
|
+
)
|
|
139
|
+
logger.info(response)
|
|
140
|
+
logger.info("Response from Zenduty Call API: An incident has been created")
|
|
141
|
+
|
|
142
|
+
def notify_message(self, message=None, summary=None, alert=False):
|
|
143
|
+
"""
|
|
144
|
+
Sends a general log or information notification.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
message (str, optional): The content of the message. Overrides initial message if provided.
|
|
148
|
+
summary (str, optional): Optional summary for the message.
|
|
149
|
+
alert (bool, optional): If True, message is sent as an alert.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
None
|
|
153
|
+
"""
|
|
154
|
+
try:
|
|
155
|
+
self.alert = alert
|
|
156
|
+
if message:
|
|
157
|
+
self.message = message
|
|
158
|
+
if summary:
|
|
159
|
+
self.summary = summary
|
|
160
|
+
self.__notify_teams_workflow()
|
|
161
|
+
except Exception as exc:
|
|
162
|
+
logger.info("Error while notifying message to teams")
|
|
163
|
+
logger.exception(exc)
|
|
164
|
+
|
|
165
|
+
def notify_error(self, message=None, summary=None, alert=True, trace=None, request_id=None):
|
|
166
|
+
"""
|
|
167
|
+
Sends an error notification to Microsoft Teams and Zenduty.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
message (str, optional): Error message to be sent.
|
|
171
|
+
summary (str, optional): Summary or context for the error.
|
|
172
|
+
alert (bool, optional): Flag to indicate it's an error. Defaults to True.
|
|
173
|
+
trace (str, optional): Detailed traceback or stack trace of the error.
|
|
174
|
+
request_id (str, optional): Optional request ID for tracking.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
None
|
|
178
|
+
"""
|
|
179
|
+
self.alert = alert
|
|
180
|
+
if summary:
|
|
181
|
+
self.summary = summary
|
|
182
|
+
if message:
|
|
183
|
+
self.message = message
|
|
184
|
+
if trace:
|
|
185
|
+
self.trace = trace
|
|
186
|
+
if request_id:
|
|
187
|
+
self.request_id = request_id
|
|
188
|
+
self.__notify_zenduty()
|
|
189
|
+
self.__notify_teams_workflow()
|
|
File without changes
|