velocity-python 0.0.165__tar.gz → 0.0.167__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.
Files changed (138) hide show
  1. {velocity_python-0.0.165 → velocity_python-0.0.167}/PKG-INFO +1 -1
  2. {velocity_python-0.0.165 → velocity_python-0.0.167}/pyproject.toml +1 -1
  3. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/amplify.py +27 -2
  5. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/lambda_handler.py +7 -1
  6. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/mixins/__init__.py +3 -5
  7. velocity_python-0.0.165/src/velocity/aws/handlers/mixins/legacy_mixin.py → velocity_python-0.0.167/src/velocity/aws/handlers/mixins/enhanced_handler_mixin.py +11 -9
  8. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/mixins/error_handler.py +0 -13
  9. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity_python.egg-info/PKG-INFO +1 -1
  10. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity_python.egg-info/SOURCES.txt +1 -3
  11. velocity_python-0.0.165/src/velocity/aws/handlers/mixins/aws_session_mixin.py +0 -192
  12. velocity_python-0.0.165/src/velocity/aws/handlers/mixins/standard_mixin.py +0 -73
  13. {velocity_python-0.0.165 → velocity_python-0.0.167}/LICENSE +0 -0
  14. {velocity_python-0.0.165 → velocity_python-0.0.167}/README.md +0 -0
  15. {velocity_python-0.0.165 → velocity_python-0.0.167}/setup.cfg +0 -0
  16. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/__init__.py +0 -0
  17. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/invoices.py +0 -0
  18. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/orders.py +0 -0
  19. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/payments.py +0 -0
  20. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/purchase_orders.py +0 -0
  21. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/tests/__init__.py +0 -0
  22. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/tests/test_email_processing.py +0 -0
  23. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
  24. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
  25. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/__init__.py +0 -0
  26. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/__init__.py +0 -0
  27. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/base_handler.py +0 -0
  28. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/context.py +0 -0
  29. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/exceptions.py +0 -0
  30. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/mixins/activity_tracker.py +0 -0
  31. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/response.py +0 -0
  32. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  33. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/tests/__init__.py +0 -0
  34. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  35. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/aws/tests/test_response.py +0 -0
  36. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/__init__.py +0 -0
  37. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/__init__.py +0 -0
  38. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/column.py +0 -0
  39. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/database.py +0 -0
  40. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/decorators.py +0 -0
  41. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/engine.py +0 -0
  42. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/result.py +0 -0
  43. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/row.py +0 -0
  44. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/sequence.py +0 -0
  45. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/table.py +0 -0
  46. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/core/transaction.py +0 -0
  47. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/exceptions.py +0 -0
  48. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/__init__.py +0 -0
  49. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/base/__init__.py +0 -0
  50. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/base/initializer.py +0 -0
  51. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/base/operators.py +0 -0
  52. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/base/sql.py +0 -0
  53. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/base/types.py +0 -0
  54. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/mysql/__init__.py +0 -0
  55. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/mysql/operators.py +0 -0
  56. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/mysql/reserved.py +0 -0
  57. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/mysql/sql.py +0 -0
  58. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/mysql/types.py +0 -0
  59. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/postgres/__init__.py +0 -0
  60. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/postgres/operators.py +0 -0
  61. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/postgres/reserved.py +0 -0
  62. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/postgres/sql.py +0 -0
  63. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/postgres/types.py +0 -0
  64. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  65. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlite/operators.py +0 -0
  66. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  67. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlite/sql.py +0 -0
  68. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlite/types.py +0 -0
  69. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  70. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  71. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  72. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  73. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/sqlserver/types.py +0 -0
  74. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/servers/tablehelper.py +0 -0
  75. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/__init__.py +0 -0
  76. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/common_db_test.py +0 -0
  77. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/__init__.py +0 -0
  78. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/common.py +0 -0
  79. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_column.py +0 -0
  80. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  81. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_database.py +0 -0
  82. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  83. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  84. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  85. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_result.py +0 -0
  86. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_row.py +0 -0
  87. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  88. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  89. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  90. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  91. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  92. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_table.py +0 -0
  93. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  94. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  95. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/sql/__init__.py +0 -0
  96. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/sql/common.py +0 -0
  97. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  98. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  99. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  100. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_db_utils.py +0 -0
  101. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_postgres.py +0 -0
  102. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  103. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  104. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_result_caching.py +0 -0
  105. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  106. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  107. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  108. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  109. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_sql_builder.py +0 -0
  110. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/tests/test_tablehelper.py +0 -0
  111. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/db/utils.py +0 -0
  112. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/__init__.py +0 -0
  113. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/conv/__init__.py +0 -0
  114. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/conv/iconv.py +0 -0
  115. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/conv/oconv.py +0 -0
  116. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/db.py +0 -0
  117. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/export.py +0 -0
  118. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/format.py +0 -0
  119. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/mail.py +0 -0
  120. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/merge.py +0 -0
  121. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/__init__.py +0 -0
  122. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_db.py +0 -0
  123. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_fix.py +0 -0
  124. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_format.py +0 -0
  125. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_iconv.py +0 -0
  126. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_merge.py +0 -0
  127. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_oconv.py +0 -0
  128. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_original_error.py +0 -0
  129. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tests/test_timer.py +0 -0
  130. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/timer.py +0 -0
  131. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity/misc/tools.py +0 -0
  132. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  133. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity_python.egg-info/requires.txt +0 -0
  134. {velocity_python-0.0.165 → velocity_python-0.0.167}/src/velocity_python.egg-info/top_level.txt +0 -0
  135. {velocity_python-0.0.165 → velocity_python-0.0.167}/tests/test_decorators.py +0 -0
  136. {velocity_python-0.0.165 → velocity_python-0.0.167}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  137. {velocity_python-0.0.165 → velocity_python-0.0.167}/tests/test_table_alter.py +0 -0
  138. {velocity_python-0.0.165 → velocity_python-0.0.167}/tests/test_where_clause_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.165
3
+ Version: 0.0.167
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.0.165"
7
+ version = "0.0.167"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.0.165"
1
+ __version__ = version = "0.0.167"
2
2
 
3
3
  from . import aws
4
4
  from . import db
@@ -69,12 +69,37 @@ class AmplifyProject:
69
69
  return all_vars
70
70
 
71
71
  def list_lambda_functions_filtered(self, env_name):
72
+ """
73
+ List Lambda functions that belong to this Amplify app and environment.
74
+ Filters by user:Application tag, checking both exact app name and sanitized version.
75
+ """
72
76
  paginator = self.lambda_client.get_paginator("list_functions")
77
+
78
+ # Create sanitized version (remove dots and special chars for tag comparison)
79
+ sanitized_app_name = self.app_name.replace(".", "").replace("-", "")
80
+
73
81
  for page in paginator.paginate():
74
82
  for fn in page["Functions"]:
75
83
  name = fn["FunctionName"]
76
- if self.app_name in name and env_name in name:
77
- yield fn
84
+ arn = fn["FunctionArn"]
85
+
86
+ # Check if function matches environment name
87
+ if env_name not in name:
88
+ continue
89
+
90
+ # Try to get tags to verify this belongs to our app
91
+ try:
92
+ tags_response = self.lambda_client.list_tags(Resource=arn)
93
+ tags = tags_response.get("Tags", {})
94
+ app_tag = tags.get("user:Application", "")
95
+
96
+ # Check if tag matches either exact or sanitized app name
97
+ if app_tag == self.app_name or app_tag == sanitized_app_name:
98
+ yield fn
99
+ except Exception:
100
+ # Fallback to name-based filtering if tags unavailable
101
+ if self.app_name in name or sanitized_app_name in name:
102
+ yield fn
78
103
 
79
104
  def update_lambda_function(
80
105
  self,
@@ -1,4 +1,5 @@
1
1
  import json
2
+ from typing import Type
2
3
  from velocity.aws.handlers.base_handler import BaseHandler
3
4
  from velocity.aws.handlers.response import Response
4
5
  from . import context
@@ -8,7 +9,12 @@ from . import context
8
9
 
9
10
 
10
11
  class LambdaHandler(BaseHandler):
11
- def __init__(self, aws_event, aws_context, context_class=context.Context):
12
+ def __init__(
13
+ self,
14
+ aws_event,
15
+ aws_context,
16
+ context_class: Type[context.Context] = context.Context
17
+ ):
12
18
  super().__init__(aws_event, aws_context, context_class)
13
19
 
14
20
  # LambdaHandler-specific initialization
@@ -4,13 +4,11 @@ Mixins for AWS Lambda handlers.
4
4
  This package provides reusable mixins for common Lambda handler functionality:
5
5
  - ActivityTracker: Standardized activity logging and tracking
6
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
7
+ - EnhancedHandlerMixin: Combined activity tracking and error handling with lifecycle hooks
9
8
  """
10
9
 
11
10
  from .activity_tracker import ActivityTracker
12
11
  from .error_handler import ErrorHandler
13
- from .standard_mixin import StandardMixin
14
- from .legacy_mixin import LegacyMixin
12
+ from .enhanced_handler_mixin import EnhancedHandlerMixin
15
13
 
16
- __all__ = ['ActivityTracker', 'ErrorHandler', 'StandardMixin', 'LegacyMixin']
14
+ __all__ = ['ActivityTracker', 'ErrorHandler', 'EnhancedHandlerMixin']
@@ -1,8 +1,9 @@
1
1
  """
2
- Legacy Mixin for backward compatibility.
2
+ Enhanced Handler Mixin for Lambda handlers.
3
3
 
4
- Provides enhanced activity tracking while maintaining existing
5
- beforeAction/afterAction/onError implementations in handlers.
4
+ Provides comprehensive activity tracking and error handling through enhanced
5
+ lifecycle hooks that work alongside existing beforeAction/afterAction/onError
6
+ implementations in handlers.
6
7
  """
7
8
 
8
9
  import os
@@ -10,15 +11,16 @@ from .activity_tracker import ActivityTracker
10
11
  from .error_handler import ErrorHandler
11
12
 
12
13
 
13
- class LegacyMixin(ActivityTracker, ErrorHandler):
14
+ class EnhancedHandlerMixin(ActivityTracker, ErrorHandler):
14
15
  """
15
- Legacy-compatible mixin that enhances existing handlers without breaking them.
16
+ Enhanced handler mixin providing comprehensive activity tracking and error handling.
16
17
 
17
- This mixin adds standardized activity tracking and error handling
18
- while preserving existing beforeAction/afterAction/onError implementations.
18
+ This mixin adds standardized activity tracking to aws_api_activity table
19
+ and error handling (logging, notifications, metrics) through enhanced hooks
20
+ that preserve existing handler implementations.
19
21
 
20
- Use this when migrating existing handlers that have complex custom logic
21
- in their action methods.
22
+ Use this for handlers that need full activity/error tracking alongside
23
+ custom logic in their action methods.
22
24
  """
23
25
 
24
26
  def _enhanced_before_action(self, tx, context):
@@ -21,19 +21,6 @@ class ErrorHandler(ABC):
21
21
  and error metrics collection.
22
22
  """
23
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
24
  def log_error_to_system(self, tx, context, exception: Exception, tb_string: str):
38
25
  """Log error to sys_log table"""
39
26
  error_data = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.165
3
+ Version: 0.0.167
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -22,10 +22,8 @@ src/velocity/aws/handlers/response.py
22
22
  src/velocity/aws/handlers/sqs_handler.py
23
23
  src/velocity/aws/handlers/mixins/__init__.py
24
24
  src/velocity/aws/handlers/mixins/activity_tracker.py
25
- src/velocity/aws/handlers/mixins/aws_session_mixin.py
25
+ src/velocity/aws/handlers/mixins/enhanced_handler_mixin.py
26
26
  src/velocity/aws/handlers/mixins/error_handler.py
27
- src/velocity/aws/handlers/mixins/legacy_mixin.py
28
- src/velocity/aws/handlers/mixins/standard_mixin.py
29
27
  src/velocity/aws/tests/__init__.py
30
28
  src/velocity/aws/tests/test_lambda_handler_json_serialization.py
31
29
  src/velocity/aws/tests/test_response.py
@@ -1,192 +0,0 @@
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 AwsSessionMixin(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
@@ -1,73 +0,0 @@
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