velocity-python 0.0.128__py3-none-any.whl → 0.0.131__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/lambda_handler.py +1 -1
- velocity/aws/handlers/mixins/__init__.py +16 -0
- velocity/aws/handlers/mixins/activity_tracker.py +142 -0
- velocity/aws/handlers/mixins/error_handler.py +192 -0
- velocity/aws/handlers/mixins/legacy_mixin.py +53 -0
- velocity/aws/handlers/mixins/standard_mixin.py +73 -0
- {velocity_python-0.0.128.dist-info → velocity_python-0.0.131.dist-info}/METADATA +1 -1
- {velocity_python-0.0.128.dist-info → velocity_python-0.0.131.dist-info}/RECORD +12 -7
- {velocity_python-0.0.128.dist-info → velocity_python-0.0.131.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.128.dist-info → velocity_python-0.0.131.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.128.dist-info → velocity_python-0.0.131.dist-info}/top_level.txt +0 -0
velocity/__init__.py
CHANGED
|
@@ -68,7 +68,7 @@ class LambdaHandler(BaseHandler):
|
|
|
68
68
|
postdata=postdata,
|
|
69
69
|
response=response,
|
|
70
70
|
session=self.session,
|
|
71
|
-
log=lambda message, function=None: self.log(
|
|
71
|
+
log=lambda message, function=None: self.log(message, function),
|
|
72
72
|
)
|
|
73
73
|
|
|
74
74
|
# Determine action from postdata or query parameters
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mixins for AWS Lambda handlers.
|
|
3
|
+
|
|
4
|
+
This package provides reusable mixins for common Lambda handler functionality:
|
|
5
|
+
- ActivityTracker: Standardized activity logging and tracking
|
|
6
|
+
- ErrorHandler: Standardized error handling and notifications
|
|
7
|
+
- StandardMixin: Combined mixin for most common use cases
|
|
8
|
+
- LegacyMixin: Backward-compatible enhanced tracking for existing handlers
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .activity_tracker import ActivityTracker
|
|
12
|
+
from .error_handler import ErrorHandler
|
|
13
|
+
from .standard_mixin import StandardMixin
|
|
14
|
+
from .legacy_mixin import LegacyMixin
|
|
15
|
+
|
|
16
|
+
__all__ = ['ActivityTracker', 'ErrorHandler', 'StandardMixin', 'LegacyMixin']
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Activity Tracker Mixin for Lambda Handlers.
|
|
3
|
+
|
|
4
|
+
Provides standardized activity tracking and logging functionality
|
|
5
|
+
for Lambda handlers using the aws_api_activity table.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import copy
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import time
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from typing import Dict, Any, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ActivityTracker(ABC):
|
|
17
|
+
"""
|
|
18
|
+
Mixin class providing standardized activity tracking for Lambda handlers.
|
|
19
|
+
|
|
20
|
+
Tracks API calls to the aws_api_activity table with consistent data structure
|
|
21
|
+
and automatic duration calculation.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, *args, **kwargs):
|
|
25
|
+
super().__init__(*args, **kwargs)
|
|
26
|
+
self.activity_log_key = None
|
|
27
|
+
self.start_time = None
|
|
28
|
+
self.end_time = None
|
|
29
|
+
self.activity_data = {}
|
|
30
|
+
|
|
31
|
+
def track_activity_start(self, tx, context):
|
|
32
|
+
"""Start tracking activity for the current request"""
|
|
33
|
+
self.start_time = time.time()
|
|
34
|
+
|
|
35
|
+
# Gather common activity data
|
|
36
|
+
postdata = context.postdata()
|
|
37
|
+
payload = context.payload()
|
|
38
|
+
|
|
39
|
+
self.activity_data = {
|
|
40
|
+
"action": context.action(),
|
|
41
|
+
"args": json.dumps(context.args()),
|
|
42
|
+
"postdata": self._sanitize_postdata(postdata),
|
|
43
|
+
"handler_name": self.__class__.__name__,
|
|
44
|
+
"function_name": os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "Unknown"),
|
|
45
|
+
"user_branch": os.environ.get("USER_BRANCH", "Unknown"),
|
|
46
|
+
"start_timestamp": self.start_time,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Add user information if available
|
|
50
|
+
user_info = self._extract_user_info(payload)
|
|
51
|
+
if user_info:
|
|
52
|
+
self.activity_data.update(user_info)
|
|
53
|
+
|
|
54
|
+
# Add session information
|
|
55
|
+
session_data = context.session()
|
|
56
|
+
if session_data:
|
|
57
|
+
self.activity_data.update({k: v for k, v in session_data.items()
|
|
58
|
+
if k not in ['cognito_user']})
|
|
59
|
+
|
|
60
|
+
# Create the activity record
|
|
61
|
+
self.activity_log_key = tx.table("aws_api_activity").new(self.activity_data).pk
|
|
62
|
+
|
|
63
|
+
return self.activity_log_key
|
|
64
|
+
|
|
65
|
+
def track_activity_success(self, tx, context):
|
|
66
|
+
"""Update activity record with success information"""
|
|
67
|
+
if not self.activity_log_key:
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
self.end_time = time.time()
|
|
71
|
+
update_data = {
|
|
72
|
+
"end_timestamp": self.end_time,
|
|
73
|
+
"duration": self.end_time - self.start_time,
|
|
74
|
+
"status": "success"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
tx.table("aws_api_activity").update(update_data, self.activity_log_key)
|
|
78
|
+
|
|
79
|
+
def track_activity_error(self, tx, context, exception, tb_string):
|
|
80
|
+
"""Update activity record with error information"""
|
|
81
|
+
if not self.activity_log_key:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
self.end_time = time.time()
|
|
85
|
+
update_data = {
|
|
86
|
+
"end_timestamp": self.end_time,
|
|
87
|
+
"duration": self.end_time - self.start_time if self.start_time else 0,
|
|
88
|
+
"status": "error",
|
|
89
|
+
"exception_type": exception.__class__.__name__,
|
|
90
|
+
"exception_message": str(exception),
|
|
91
|
+
"traceback": tb_string,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Handle legacy field names for backward compatibility
|
|
95
|
+
update_data["exception"] = exception.__class__.__name__
|
|
96
|
+
|
|
97
|
+
tx.table("aws_api_activity").update(update_data, self.activity_log_key)
|
|
98
|
+
|
|
99
|
+
def _sanitize_postdata(self, postdata: Dict) -> str:
|
|
100
|
+
"""Remove sensitive information from postdata before logging"""
|
|
101
|
+
if not postdata:
|
|
102
|
+
return "{}"
|
|
103
|
+
|
|
104
|
+
sanitized = copy.deepcopy(postdata)
|
|
105
|
+
|
|
106
|
+
# Remove cognito user data from payload if present
|
|
107
|
+
if "payload" in sanitized and isinstance(sanitized["payload"], dict):
|
|
108
|
+
sanitized["payload"].pop("cognito_user", None)
|
|
109
|
+
|
|
110
|
+
# Remove other sensitive fields as needed
|
|
111
|
+
sensitive_fields = ["password", "token", "secret", "key", "auth", "cognito_user"]
|
|
112
|
+
self._recursive_sanitize(sanitized, sensitive_fields)
|
|
113
|
+
|
|
114
|
+
return json.dumps(sanitized)
|
|
115
|
+
|
|
116
|
+
def _recursive_sanitize(self, data: Any, sensitive_fields: list):
|
|
117
|
+
"""Recursively remove sensitive fields from nested data structures"""
|
|
118
|
+
if isinstance(data, dict):
|
|
119
|
+
for key in list(data.keys()):
|
|
120
|
+
if any(field in key.lower() for field in sensitive_fields):
|
|
121
|
+
data[key] = "[REDACTED]"
|
|
122
|
+
else:
|
|
123
|
+
self._recursive_sanitize(data[key], sensitive_fields)
|
|
124
|
+
elif isinstance(data, list):
|
|
125
|
+
for item in data:
|
|
126
|
+
self._recursive_sanitize(item, sensitive_fields)
|
|
127
|
+
|
|
128
|
+
def _extract_user_info(self, payload: Dict) -> Dict:
|
|
129
|
+
"""Extract user information from payload"""
|
|
130
|
+
user_info = {}
|
|
131
|
+
|
|
132
|
+
if payload and "cognito_user" in payload:
|
|
133
|
+
try:
|
|
134
|
+
attrs = payload["cognito_user"]["attributes"]
|
|
135
|
+
if "email" in attrs:
|
|
136
|
+
user_info["email_address"] = attrs["email"].lower()
|
|
137
|
+
if "sub" in attrs:
|
|
138
|
+
user_info["user_id"] = attrs["sub"]
|
|
139
|
+
except (KeyError, TypeError):
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
return user_info
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Error Handler Mixin for Lambda Handlers.
|
|
3
|
+
|
|
4
|
+
Provides standardized error handling, logging, and notification functionality
|
|
5
|
+
for Lambda handlers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import copy
|
|
9
|
+
import os
|
|
10
|
+
import pprint
|
|
11
|
+
import time
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from typing import Dict, Any, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ErrorHandler(ABC):
|
|
17
|
+
"""
|
|
18
|
+
Mixin class providing standardized error handling for Lambda handlers.
|
|
19
|
+
|
|
20
|
+
Handles error logging to sys_log table, email notifications to administrators,
|
|
21
|
+
and error metrics collection.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def handle_standard_error(self, tx, context, exception: Exception, tb_string: str):
|
|
25
|
+
"""Handle errors with consistent logging and notification patterns"""
|
|
26
|
+
|
|
27
|
+
# Log to sys_log for centralized logging
|
|
28
|
+
self.log_error_to_system(tx, context, exception, tb_string)
|
|
29
|
+
|
|
30
|
+
# Determine if this error requires notification
|
|
31
|
+
if self._should_notify_error(exception):
|
|
32
|
+
self.send_error_notification(tx, context, exception, tb_string)
|
|
33
|
+
|
|
34
|
+
# Log error metrics for monitoring
|
|
35
|
+
self.log_error_metrics(tx, context, exception)
|
|
36
|
+
|
|
37
|
+
def log_error_to_system(self, tx, context, exception: Exception, tb_string: str):
|
|
38
|
+
"""Log error to sys_log table"""
|
|
39
|
+
error_data = {
|
|
40
|
+
"level": "ERROR",
|
|
41
|
+
"message": str(exception),
|
|
42
|
+
"function": f"{self.__class__.__name__}.{context.action()}",
|
|
43
|
+
"traceback": tb_string,
|
|
44
|
+
"exception_type": exception.__class__.__name__,
|
|
45
|
+
"handler_name": self.__class__.__name__,
|
|
46
|
+
"action": context.action(),
|
|
47
|
+
"user_branch": os.environ.get("USER_BRANCH", "Unknown"),
|
|
48
|
+
"function_name": os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "Unknown"),
|
|
49
|
+
"app_name": os.environ.get("ProjectName", "Unknown"),
|
|
50
|
+
"user_agent": "AWS Lambda",
|
|
51
|
+
"device_type": "Lambda",
|
|
52
|
+
"sys_modified_by": "Lambda",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Add user context if available
|
|
56
|
+
try:
|
|
57
|
+
if hasattr(self, 'current_user') and self.current_user:
|
|
58
|
+
error_data["user_email"] = self.current_user.get("email_address")
|
|
59
|
+
except:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
tx.table("sys_log").insert(error_data)
|
|
63
|
+
|
|
64
|
+
def send_error_notification(self, tx, context, exception: Exception, tb_string: str):
|
|
65
|
+
"""Send error notification email to administrators"""
|
|
66
|
+
try:
|
|
67
|
+
# Import here to avoid circular dependency
|
|
68
|
+
from support.app import helpers
|
|
69
|
+
|
|
70
|
+
environment = os.environ.get('USER_BRANCH', 'Unknown').title()
|
|
71
|
+
function_name = os.environ.get('AWS_LAMBDA_FUNCTION_NAME', 'Unknown')
|
|
72
|
+
|
|
73
|
+
subject = f"{environment} Lambda Error - {function_name}"
|
|
74
|
+
|
|
75
|
+
body = f"""
|
|
76
|
+
Error Details:
|
|
77
|
+
- Handler: {self.__class__.__name__}
|
|
78
|
+
- Action: {context.action()}
|
|
79
|
+
- Exception: {exception.__class__.__name__}
|
|
80
|
+
- Message: {str(exception)}
|
|
81
|
+
- Environment: {environment}
|
|
82
|
+
- Function: {function_name}
|
|
83
|
+
|
|
84
|
+
Full Traceback:
|
|
85
|
+
{tb_string}
|
|
86
|
+
|
|
87
|
+
Request Details:
|
|
88
|
+
{self._get_error_context(context)}
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
sender = self._get_error_notification_sender()
|
|
92
|
+
recipients = self._get_error_notification_recipients()
|
|
93
|
+
|
|
94
|
+
helpers.sendmail(
|
|
95
|
+
tx,
|
|
96
|
+
subject=subject,
|
|
97
|
+
body=body,
|
|
98
|
+
html=None,
|
|
99
|
+
sender=sender,
|
|
100
|
+
recipient=recipients[0],
|
|
101
|
+
cc=recipients[1:] if len(recipients) > 1 else None,
|
|
102
|
+
bcc=None,
|
|
103
|
+
email_settings_id=1001,
|
|
104
|
+
)
|
|
105
|
+
except Exception as email_error:
|
|
106
|
+
print(f"Failed to send error notification email: {email_error}")
|
|
107
|
+
|
|
108
|
+
def _should_notify_error(self, exception: Exception) -> bool:
|
|
109
|
+
"""Determine if an error should trigger email notifications"""
|
|
110
|
+
# Don't notify for user authentication errors or validation errors
|
|
111
|
+
non_notification_types = [
|
|
112
|
+
"AuthenticationError",
|
|
113
|
+
"ValidationError",
|
|
114
|
+
"ValueError",
|
|
115
|
+
"AlertError"
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
exception_name = exception.__class__.__name__
|
|
119
|
+
|
|
120
|
+
# Check for authentication-related exceptions
|
|
121
|
+
if "Authentication" in exception_name or "Auth" in exception_name:
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
return exception_name not in non_notification_types
|
|
125
|
+
|
|
126
|
+
@abstractmethod
|
|
127
|
+
def _get_error_notification_recipients(self) -> list:
|
|
128
|
+
"""
|
|
129
|
+
Get list of email recipients for error notifications.
|
|
130
|
+
|
|
131
|
+
Must be implemented by the handler class.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
List of email addresses to notify when errors occur
|
|
135
|
+
|
|
136
|
+
Example:
|
|
137
|
+
return ["admin@company.com", "devops@company.com"]
|
|
138
|
+
"""
|
|
139
|
+
pass
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
def _get_error_notification_sender(self) -> str:
|
|
143
|
+
"""
|
|
144
|
+
Get email sender for error notifications.
|
|
145
|
+
|
|
146
|
+
Must be implemented by the handler class.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Email address to use as sender for error notifications
|
|
150
|
+
|
|
151
|
+
Example:
|
|
152
|
+
return "no-reply@company.com"
|
|
153
|
+
"""
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
def _get_error_context(self, context) -> str:
|
|
157
|
+
"""Get sanitized request context for error reporting"""
|
|
158
|
+
try:
|
|
159
|
+
postdata = context.postdata()
|
|
160
|
+
sanitized = copy.deepcopy(postdata)
|
|
161
|
+
|
|
162
|
+
# Remove sensitive data
|
|
163
|
+
if "payload" in sanitized and isinstance(sanitized["payload"], dict):
|
|
164
|
+
sanitized["payload"].pop("cognito_user", None)
|
|
165
|
+
|
|
166
|
+
return pprint.pformat(sanitized)
|
|
167
|
+
except:
|
|
168
|
+
return "Unable to retrieve request context"
|
|
169
|
+
|
|
170
|
+
def log_error_metrics(self, tx, context, exception: Exception):
|
|
171
|
+
"""Log error metrics for monitoring and alerting"""
|
|
172
|
+
try:
|
|
173
|
+
metrics_data = {
|
|
174
|
+
"metric_type": "error_count",
|
|
175
|
+
"handler_name": self.__class__.__name__,
|
|
176
|
+
"action": context.action(),
|
|
177
|
+
"exception_type": exception.__class__.__name__,
|
|
178
|
+
"environment": os.environ.get("USER_BRANCH", "Unknown"),
|
|
179
|
+
"function_name": os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "Unknown"),
|
|
180
|
+
"timestamp": time.time(),
|
|
181
|
+
"sys_modified_by": "Lambda"
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# Try to insert into metrics table if it exists
|
|
185
|
+
try:
|
|
186
|
+
tx.table("lambda_metrics").insert(metrics_data)
|
|
187
|
+
except:
|
|
188
|
+
# Metrics table might not exist yet, don't fail error handler
|
|
189
|
+
pass
|
|
190
|
+
except:
|
|
191
|
+
# Don't fail the error handler if metrics logging fails
|
|
192
|
+
pass
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Legacy Mixin for backward compatibility.
|
|
3
|
+
|
|
4
|
+
Provides enhanced activity tracking while maintaining existing
|
|
5
|
+
beforeAction/afterAction/onError implementations in handlers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from .activity_tracker import ActivityTracker
|
|
10
|
+
from .error_handler import ErrorHandler
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LegacyMixin(ActivityTracker, ErrorHandler):
|
|
14
|
+
"""
|
|
15
|
+
Legacy-compatible mixin that enhances existing handlers without breaking them.
|
|
16
|
+
|
|
17
|
+
This mixin adds standardized activity tracking and error handling
|
|
18
|
+
while preserving existing beforeAction/afterAction/onError implementations.
|
|
19
|
+
|
|
20
|
+
Use this when migrating existing handlers that have complex custom logic
|
|
21
|
+
in their action methods.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def _enhanced_before_action(self, tx, context):
|
|
25
|
+
"""Enhanced beforeAction that adds activity tracking"""
|
|
26
|
+
# Start activity tracking
|
|
27
|
+
self.track_activity_start(tx, context)
|
|
28
|
+
|
|
29
|
+
def _enhanced_after_action(self, tx, context):
|
|
30
|
+
"""Enhanced afterAction that adds activity tracking"""
|
|
31
|
+
# Update activity tracking with success
|
|
32
|
+
self.track_activity_success(tx, context)
|
|
33
|
+
|
|
34
|
+
def _enhanced_error_handler(self, tx, context, exc, tb):
|
|
35
|
+
"""Enhanced onError that adds standardized error handling"""
|
|
36
|
+
# Convert exc to exception object if it's a string
|
|
37
|
+
if isinstance(exc, str):
|
|
38
|
+
exception = Exception(exc)
|
|
39
|
+
else:
|
|
40
|
+
exception = exc
|
|
41
|
+
|
|
42
|
+
# Update activity tracking with error
|
|
43
|
+
self.track_activity_error(tx, context, exception, tb)
|
|
44
|
+
|
|
45
|
+
# Handle error with standard patterns (but don't send duplicate emails)
|
|
46
|
+
self.log_error_to_system(tx, context, exception, tb)
|
|
47
|
+
self.log_error_metrics(tx, context, exception)
|
|
48
|
+
|
|
49
|
+
# Only send notification if handler doesn't already handle it
|
|
50
|
+
# Check for a flag that handlers can set to indicate they handle their own notifications
|
|
51
|
+
if not getattr(self, '_handles_own_error_notifications', False):
|
|
52
|
+
if self._should_notify_error(exception):
|
|
53
|
+
self.send_error_notification(tx, context, exception, tb)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Standard Mixin combining ActivityTracker and ErrorHandler.
|
|
3
|
+
|
|
4
|
+
Provides a single mixin that includes both activity tracking and error handling
|
|
5
|
+
with standardized beforeAction, afterAction, and onError implementations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import copy
|
|
9
|
+
import pprint
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
|
|
12
|
+
from .activity_tracker import ActivityTracker
|
|
13
|
+
from .error_handler import ErrorHandler
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class StandardMixin(ActivityTracker, ErrorHandler):
|
|
17
|
+
"""
|
|
18
|
+
Combined mixin providing both activity tracking and error handling.
|
|
19
|
+
Use this as the primary mixin for Lambda handlers.
|
|
20
|
+
|
|
21
|
+
Provides standard implementations of:
|
|
22
|
+
- beforeAction: Starts activity tracking + custom logic
|
|
23
|
+
- afterAction: Records success + custom logic
|
|
24
|
+
- onError: Records error + handles notifications + custom logic
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def beforeAction(self, tx, context):
|
|
28
|
+
"""Standard beforeAction implementation"""
|
|
29
|
+
# Start activity tracking
|
|
30
|
+
self.track_activity_start(tx, context)
|
|
31
|
+
|
|
32
|
+
# Call any custom beforeAction logic
|
|
33
|
+
self._custom_before_action(tx, context)
|
|
34
|
+
|
|
35
|
+
def afterAction(self, tx, context):
|
|
36
|
+
"""Standard afterAction implementation"""
|
|
37
|
+
# Update activity tracking with success
|
|
38
|
+
self.track_activity_success(tx, context)
|
|
39
|
+
|
|
40
|
+
# Call any custom afterAction logic
|
|
41
|
+
self._custom_after_action(tx, context)
|
|
42
|
+
|
|
43
|
+
def onError(self, tx, context, exc, tb):
|
|
44
|
+
"""Standard onError implementation"""
|
|
45
|
+
# Convert exc to exception object if it's a string
|
|
46
|
+
if isinstance(exc, str):
|
|
47
|
+
exception = Exception(exc)
|
|
48
|
+
else:
|
|
49
|
+
exception = exc
|
|
50
|
+
|
|
51
|
+
# Update activity tracking with error
|
|
52
|
+
self.track_activity_error(tx, context, exception, tb)
|
|
53
|
+
|
|
54
|
+
# Handle error with standard patterns
|
|
55
|
+
self.handle_standard_error(tx, context, exception, tb)
|
|
56
|
+
|
|
57
|
+
# Call any custom error handling
|
|
58
|
+
self._custom_error_handler(tx, context, exception, tb)
|
|
59
|
+
|
|
60
|
+
@abstractmethod
|
|
61
|
+
def _custom_before_action(self, tx, context):
|
|
62
|
+
"""Override this method for handler-specific beforeAction logic"""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
@abstractmethod
|
|
66
|
+
def _custom_after_action(self, tx, context):
|
|
67
|
+
"""Override this method for handler-specific afterAction logic"""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
@abstractmethod
|
|
71
|
+
def _custom_error_handler(self, tx, context, exception, tb):
|
|
72
|
+
"""Override this method for handler-specific error handling"""
|
|
73
|
+
pass
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
velocity/__init__.py,sha256=
|
|
1
|
+
velocity/__init__.py,sha256=BLvCt7oG0pOKOxVPemY9WH6NtsP7cw04_KsA56xXCwk,147
|
|
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=fr1oTBjSFfyeMBUXRG06LV4jgwrlwYNL5mbEBleFwf0,6328
|
|
@@ -10,9 +10,14 @@ velocity/aws/handlers/__init__.py,sha256=4-NKj8dBzjYEdIlNdfm_Ip5mI0oOGcpjjBcMwU4
|
|
|
10
10
|
velocity/aws/handlers/base_handler.py,sha256=bapdzWss5lXesoLPsVwJo9hQMZLdz7XOubo3sK70xC8,7960
|
|
11
11
|
velocity/aws/handlers/context.py,sha256=0kPZ8y-XjmBZY5NcexynR5htnWYfF0nwM1n5UH-6c5w,8413
|
|
12
12
|
velocity/aws/handlers/exceptions.py,sha256=i4wcB8ZSWUHglX2xnesDlWLsU9AMYU72cHCWRBDmjQ8,361
|
|
13
|
-
velocity/aws/handlers/lambda_handler.py,sha256=
|
|
13
|
+
velocity/aws/handlers/lambda_handler.py,sha256=0wa_CHyJOaI5RsHqB0Ae83-B-SwlKR0qkGUlc7jitQI,4427
|
|
14
14
|
velocity/aws/handlers/response.py,sha256=s2Kw7yv5zAir1mEmfv6yBVIvRcRQ__xyryf1SrvtiRc,9317
|
|
15
15
|
velocity/aws/handlers/sqs_handler.py,sha256=azuV8DrFOh0hM13EnPzyYVBS-3fLe2fn9OPc4ho7sGc,3375
|
|
16
|
+
velocity/aws/handlers/mixins/__init__.py,sha256=_zyEpsnKikF7D7X-F0GA4cyIrQ6wBq7k5j6Vhp17vaQ,623
|
|
17
|
+
velocity/aws/handlers/mixins/activity_tracker.py,sha256=b2Cu46FM0fLS2-FkWXXAPw6yvMV_Viu5-IlpGkVAlmk,5254
|
|
18
|
+
velocity/aws/handlers/mixins/error_handler.py,sha256=uN2YF9v-3LzS3o_HdVpO-XMcPy3sS7SHjUg_LfbsG7Q,6803
|
|
19
|
+
velocity/aws/handlers/mixins/legacy_mixin.py,sha256=_YhiPU-zzXQjGNSAKhoUwfTFlnczmU-3BkwNFqr0hYE,2117
|
|
20
|
+
velocity/aws/handlers/mixins/standard_mixin.py,sha256=-wBX0PFlZAnxQsaMDEWr-xmU8TcRbQ4BZD3wmAKR2d0,2489
|
|
16
21
|
velocity/db/__init__.py,sha256=7XRUHY2af0HL1jvL0SAMpxSe5a2Phbkm-YLJCvC1C_0,739
|
|
17
22
|
velocity/db/exceptions.py,sha256=XHREJvzNctrtYE-ScBRLnbk7thxTswkfWojKhMmBmd8,2185
|
|
18
23
|
velocity/db/utils.py,sha256=IoXeAL_0wZE15gbxlb2TtNdHzUSV9bIvw8jNkqjz38o,7020
|
|
@@ -50,8 +55,8 @@ velocity/misc/tools.py,sha256=4TWa-ja2gMZJr1EhqTKsJNirvDclCruyRGMttPhCIGw,1487
|
|
|
50
55
|
velocity/misc/conv/__init__.py,sha256=qhHFl_UqW5tjPm--6shO171IysWIdH3mmp3uwiQVyqY,70
|
|
51
56
|
velocity/misc/conv/iconv.py,sha256=16aPWtreHCxmpl5ufku0KWWZj8PIUFI5J1dP0aXyM3o,10794
|
|
52
57
|
velocity/misc/conv/oconv.py,sha256=h5Lo05DqOQnxoD3y6Px_MQP_V-pBbWf8Hkgkb9Xp1jk,6032
|
|
53
|
-
velocity_python-0.0.
|
|
54
|
-
velocity_python-0.0.
|
|
55
|
-
velocity_python-0.0.
|
|
56
|
-
velocity_python-0.0.
|
|
57
|
-
velocity_python-0.0.
|
|
58
|
+
velocity_python-0.0.131.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
|
|
59
|
+
velocity_python-0.0.131.dist-info/METADATA,sha256=hrp_x5Sgp7kautE2OXlW0UbonLT7lTVKvQDgHKXqkqI,34262
|
|
60
|
+
velocity_python-0.0.131.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
61
|
+
velocity_python-0.0.131.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
|
|
62
|
+
velocity_python-0.0.131.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|