velocity-python 0.0.95__py3-none-any.whl → 0.0.97__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 velocity-python might be problematic. Click here for more details.
- velocity/__init__.py +1 -1
- velocity/aws/handlers/sqs_handler.py +191 -64
- {velocity_python-0.0.95.dist-info → velocity_python-0.0.97.dist-info}/METADATA +1 -1
- {velocity_python-0.0.95.dist-info → velocity_python-0.0.97.dist-info}/RECORD +7 -7
- {velocity_python-0.0.95.dist-info → velocity_python-0.0.97.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.95.dist-info → velocity_python-0.0.97.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.95.dist-info → velocity_python-0.0.97.dist-info}/top_level.txt +0 -0
velocity/__init__.py
CHANGED
|
@@ -1,97 +1,224 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
SQS Handler Module
|
|
3
|
+
|
|
4
|
+
This module provides a base class for handling AWS SQS events in Lambda functions.
|
|
5
|
+
It includes logging capabilities, action routing, and error handling.
|
|
6
|
+
"""
|
|
7
|
+
|
|
2
8
|
import json
|
|
3
|
-
import sys
|
|
4
9
|
import os
|
|
10
|
+
import sys
|
|
5
11
|
import traceback
|
|
12
|
+
from typing import Any, Dict, Optional
|
|
13
|
+
|
|
6
14
|
from velocity.aws import DEBUG
|
|
7
15
|
from velocity.aws.handlers import context as VelocityContext
|
|
16
|
+
from velocity.misc.format import to_json
|
|
8
17
|
|
|
9
18
|
|
|
10
19
|
class SqsHandler:
|
|
20
|
+
"""
|
|
21
|
+
Base class for handling SQS events in AWS Lambda functions.
|
|
22
|
+
|
|
23
|
+
Provides structured processing of SQS records with automatic action routing,
|
|
24
|
+
logging capabilities, and error handling hooks.
|
|
25
|
+
"""
|
|
11
26
|
|
|
12
|
-
def __init__(self, aws_event, aws_context,
|
|
27
|
+
def __init__(self, aws_event: Dict[str, Any], aws_context: Any,
|
|
28
|
+
context_class=VelocityContext.Context):
|
|
29
|
+
"""
|
|
30
|
+
Initialize the SQS handler.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
aws_event: The AWS Lambda event containing SQS records
|
|
34
|
+
aws_context: The AWS Lambda context object
|
|
35
|
+
context_class: The context class to use for processing
|
|
36
|
+
"""
|
|
13
37
|
self.aws_event = aws_event
|
|
14
38
|
self.aws_context = aws_context
|
|
15
39
|
self.serve_action_default = True
|
|
16
40
|
self.skip_action = False
|
|
17
41
|
self.ContextClass = context_class
|
|
18
42
|
|
|
19
|
-
def log(self, tx, message, function=None):
|
|
43
|
+
def log(self, tx, message: str, function: Optional[str] = None):
|
|
44
|
+
"""
|
|
45
|
+
Log a message to the system log table.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
tx: Database transaction object
|
|
49
|
+
message: The message to log
|
|
50
|
+
function: Optional function name, auto-detected if not provided
|
|
51
|
+
"""
|
|
20
52
|
if not function:
|
|
21
|
-
function =
|
|
22
|
-
idx = 0
|
|
23
|
-
while True:
|
|
24
|
-
try:
|
|
25
|
-
temp = sys._getframe(idx).f_code.co_name
|
|
26
|
-
except ValueError as e:
|
|
27
|
-
break
|
|
28
|
-
if temp in ["x", "log", "_transaction"]:
|
|
29
|
-
idx += 1
|
|
30
|
-
continue
|
|
31
|
-
function = temp
|
|
32
|
-
break
|
|
53
|
+
function = self._get_calling_function()
|
|
33
54
|
|
|
34
55
|
data = {
|
|
35
|
-
"app_name": os.environ
|
|
56
|
+
"app_name": os.environ.get("ProjectName", "Unknown"),
|
|
36
57
|
"referer": "SQS",
|
|
37
58
|
"user_agent": "QueueHandler",
|
|
38
59
|
"device_type": "Lambda",
|
|
39
60
|
"function": function,
|
|
40
61
|
"message": message,
|
|
41
|
-
"sys_modified_by": "
|
|
62
|
+
"sys_modified_by": "Lambda:BackOfficeQueueHandler",
|
|
42
63
|
}
|
|
43
64
|
tx.table("sys_log").insert(data)
|
|
65
|
+
|
|
66
|
+
def _get_calling_function(self) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Get the name of the calling function by inspecting the call stack.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The name of the calling function or "<Unknown>" if not found
|
|
72
|
+
"""
|
|
73
|
+
skip_functions = {"x", "log", "_transaction", "_get_calling_function"}
|
|
74
|
+
|
|
75
|
+
for idx in range(10): # Limit search to prevent infinite loops
|
|
76
|
+
try:
|
|
77
|
+
frame = sys._getframe(idx)
|
|
78
|
+
function_name = frame.f_code.co_name
|
|
79
|
+
|
|
80
|
+
if function_name not in skip_functions:
|
|
81
|
+
return function_name
|
|
82
|
+
|
|
83
|
+
except ValueError:
|
|
84
|
+
# No more frames in the stack
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
return "<Unknown>"
|
|
44
88
|
|
|
45
89
|
def serve(self, tx):
|
|
90
|
+
"""
|
|
91
|
+
Process all SQS records in the event.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
tx: Database transaction object
|
|
95
|
+
"""
|
|
46
96
|
records = self.aws_event.get("Records", [])
|
|
97
|
+
|
|
47
98
|
for record in records:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
99
|
+
self._process_record(tx, record)
|
|
100
|
+
|
|
101
|
+
def _process_record(self, tx, record: Dict[str, Any]):
|
|
102
|
+
"""
|
|
103
|
+
Process a single SQS record.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
tx: Database transaction object
|
|
107
|
+
record: Individual SQS record to process
|
|
108
|
+
"""
|
|
109
|
+
attrs = record.get("attributes", {})
|
|
110
|
+
postdata = {}
|
|
111
|
+
|
|
112
|
+
# Parse message body if present
|
|
113
|
+
body = record.get("body")
|
|
114
|
+
if body:
|
|
61
115
|
try:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
postdata = json.loads(body)
|
|
117
|
+
except json.JSONDecodeError as e:
|
|
118
|
+
print(f"Failed to parse SQS message body as JSON: {e}")
|
|
119
|
+
postdata = {"raw_body": body}
|
|
120
|
+
|
|
121
|
+
# Create local context for this record
|
|
122
|
+
local_context = self.ContextClass(
|
|
123
|
+
aws_event=self.aws_event,
|
|
124
|
+
aws_context=self.aws_context,
|
|
125
|
+
args=attrs,
|
|
126
|
+
postdata=postdata,
|
|
127
|
+
response=None,
|
|
128
|
+
session=None,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
self._execute_actions(local_context)
|
|
133
|
+
except Exception as e:
|
|
134
|
+
if hasattr(self, "onError"):
|
|
135
|
+
self.onError(
|
|
136
|
+
local_context,
|
|
137
|
+
exc=e.__class__.__name__,
|
|
138
|
+
tb=traceback.format_exc(),
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
# Re-raise if no error handler is defined
|
|
142
|
+
raise
|
|
143
|
+
|
|
144
|
+
def _execute_actions(self, local_context):
|
|
145
|
+
"""
|
|
146
|
+
Execute the appropriate actions for the given context.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
local_context: The context object for this record
|
|
150
|
+
"""
|
|
151
|
+
# Execute beforeAction hook if available
|
|
152
|
+
if hasattr(self, "beforeAction"):
|
|
153
|
+
self.beforeAction(local_context)
|
|
154
|
+
|
|
155
|
+
# Determine which actions to execute
|
|
156
|
+
actions = self._get_actions_to_execute(local_context)
|
|
157
|
+
|
|
158
|
+
# Execute the first matching action
|
|
159
|
+
for action in actions:
|
|
160
|
+
if self.skip_action:
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
if hasattr(self, action):
|
|
164
|
+
getattr(self, action)(local_context)
|
|
165
|
+
break
|
|
166
|
+
|
|
167
|
+
# Execute afterAction hook if available
|
|
168
|
+
if hasattr(self, "afterAction"):
|
|
169
|
+
self.afterAction(local_context)
|
|
170
|
+
|
|
171
|
+
def _get_actions_to_execute(self, local_context) -> list:
|
|
172
|
+
"""
|
|
173
|
+
Get the list of actions to execute for the given context.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
local_context: The context object for this record
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List of action method names to try executing
|
|
180
|
+
"""
|
|
181
|
+
actions = []
|
|
182
|
+
|
|
183
|
+
# Add specific action if available
|
|
184
|
+
action = local_context.action()
|
|
185
|
+
if action:
|
|
186
|
+
action_method = self._format_action_name(action)
|
|
187
|
+
actions.append(action_method)
|
|
188
|
+
|
|
189
|
+
# Add default action if enabled
|
|
190
|
+
if self.serve_action_default:
|
|
191
|
+
actions.append("OnActionDefault")
|
|
192
|
+
|
|
193
|
+
return actions
|
|
194
|
+
|
|
195
|
+
def _format_action_name(self, action: str) -> str:
|
|
196
|
+
"""
|
|
197
|
+
Format an action string into a method name.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
action: The raw action string
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Formatted method name
|
|
204
|
+
"""
|
|
205
|
+
formatted = action.replace('-', ' ').replace('_', ' ')
|
|
206
|
+
return f"on action {formatted}".title().replace(" ", "")
|
|
89
207
|
|
|
90
208
|
def OnActionDefault(self, tx, context):
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
209
|
+
"""
|
|
210
|
+
Default action handler when no specific action is found.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
tx: Database transaction object
|
|
214
|
+
context: The context object for this record
|
|
215
|
+
"""
|
|
216
|
+
action = context.action() if hasattr(context, 'action') else 'unknown'
|
|
217
|
+
warning_message = (
|
|
218
|
+
f"[Warn] Action handler not found. Calling default action "
|
|
219
|
+
f"`SqsHandler.OnActionDefault` with the following parameters:\n"
|
|
220
|
+
f" - action: {action}\n"
|
|
221
|
+
f" - attrs: {context.args()}\n"
|
|
222
|
+
f" - postdata: {context.postdata()}"
|
|
97
223
|
)
|
|
224
|
+
print(warning_message)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
velocity/__init__.py,sha256=
|
|
1
|
+
velocity/__init__.py,sha256=INVMQ4GO-JInxsuAsrayUJ5jvsooS1cSwDflvVJjvPE,106
|
|
2
2
|
velocity/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
velocity/app/invoices.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
velocity/app/orders.py,sha256=W-HAXEwY8-IFXbKh82HnMeRVZM7P-TWGEQOWtkLIzI4,6298
|
|
@@ -10,7 +10,7 @@ velocity/aws/handlers/__init__.py,sha256=xnpFZJVlC2uoeeFW4zuPST8wA8ajaQDky5Y6iXZ
|
|
|
10
10
|
velocity/aws/handlers/context.py,sha256=UIjNR83y2NSIyK8HMPX8t5tpJHFNabiZvNgmmdQL3HA,1822
|
|
11
11
|
velocity/aws/handlers/lambda_handler.py,sha256=0KrT6UIxDILzBRpoRSvwDgHpQ-vWfubcZFOCbJsewDc,6516
|
|
12
12
|
velocity/aws/handlers/response.py,sha256=LXhtizLKnVBWjtHyE0h0bk-NYDrRpj7CHa7tRz9KkC4,9324
|
|
13
|
-
velocity/aws/handlers/sqs_handler.py,sha256=
|
|
13
|
+
velocity/aws/handlers/sqs_handler.py,sha256=nqt8NMOc5yO-L6CZo7NjgR8Q4KPKTDFBO-0eHu6oxkY,7149
|
|
14
14
|
velocity/db/__init__.py,sha256=vrn2AFNAKaqTdnPwLFS0OcREcCtzUCOodlmH54U7ADg,200
|
|
15
15
|
velocity/db/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
velocity/db/core/column.py,sha256=tAr8tL3a2nyaYpNHhGl508FrY_pGZTzyYgjAV5CEBv4,4092
|
|
@@ -47,8 +47,8 @@ velocity/misc/tools.py,sha256=_bGneHHA_BV-kUonzw5H3hdJ5AOJRCKfzhgpkFbGqIo,1502
|
|
|
47
47
|
velocity/misc/conv/__init__.py,sha256=MLYF58QHjzfDSxb1rdnmLnuEQCa3gnhzzZ30CwZVvQo,40
|
|
48
48
|
velocity/misc/conv/iconv.py,sha256=d4_BucW8HTIkGNurJ7GWrtuptqUf-9t79ObzjJ5N76U,10603
|
|
49
49
|
velocity/misc/conv/oconv.py,sha256=h5Lo05DqOQnxoD3y6Px_MQP_V-pBbWf8Hkgkb9Xp1jk,6032
|
|
50
|
-
velocity_python-0.0.
|
|
51
|
-
velocity_python-0.0.
|
|
52
|
-
velocity_python-0.0.
|
|
53
|
-
velocity_python-0.0.
|
|
54
|
-
velocity_python-0.0.
|
|
50
|
+
velocity_python-0.0.97.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
|
|
51
|
+
velocity_python-0.0.97.dist-info/METADATA,sha256=vQvxtwSQIBj6yC8li-uFlArx8F6IqyhMd3oH4sXB8go,33022
|
|
52
|
+
velocity_python-0.0.97.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
53
|
+
velocity_python-0.0.97.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
|
|
54
|
+
velocity_python-0.0.97.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|