velocity-python 0.0.120__tar.gz → 0.0.124__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.

Potentially problematic release.


This version of velocity-python might be problematic. Click here for more details.

Files changed (84) hide show
  1. {velocity_python-0.0.120/src/velocity_python.egg-info → velocity_python-0.0.124}/PKG-INFO +1 -1
  2. {velocity_python-0.0.120 → velocity_python-0.0.124}/pyproject.toml +1 -1
  3. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/base_handler.py +9 -6
  5. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/lambda_handler.py +12 -1
  6. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/sqs_handler.py +8 -2
  7. {velocity_python-0.0.120 → velocity_python-0.0.124/src/velocity_python.egg-info}/PKG-INFO +1 -1
  8. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity_python.egg-info/SOURCES.txt +1 -0
  9. velocity_python-0.0.124/tests/test_lambda_handler_json_serialization.py +120 -0
  10. {velocity_python-0.0.120 → velocity_python-0.0.124}/LICENSE +0 -0
  11. {velocity_python-0.0.120 → velocity_python-0.0.124}/README.md +0 -0
  12. {velocity_python-0.0.120 → velocity_python-0.0.124}/setup.cfg +0 -0
  13. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/app/__init__.py +0 -0
  14. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/app/invoices.py +0 -0
  15. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/app/orders.py +0 -0
  16. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/app/payments.py +0 -0
  17. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/app/purchase_orders.py +0 -0
  18. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/__init__.py +0 -0
  19. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/amplify.py +0 -0
  20. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/__init__.py +0 -0
  21. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/context.py +0 -0
  22. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/exceptions.py +0 -0
  23. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/aws/handlers/response.py +0 -0
  24. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/__init__.py +0 -0
  25. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/__init__.py +0 -0
  26. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/column.py +0 -0
  27. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/database.py +0 -0
  28. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/decorators.py +0 -0
  29. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/engine.py +0 -0
  30. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/result.py +0 -0
  31. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/row.py +0 -0
  32. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/sequence.py +0 -0
  33. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/table.py +0 -0
  34. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/core/transaction.py +0 -0
  35. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/exceptions.py +0 -0
  36. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/__init__.py +0 -0
  37. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/mysql.py +0 -0
  38. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/mysql_reserved.py +0 -0
  39. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/postgres/__init__.py +0 -0
  40. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/postgres/operators.py +0 -0
  41. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/postgres/reserved.py +0 -0
  42. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/postgres/sql.py +0 -0
  43. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/postgres/types.py +0 -0
  44. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/sqlite.py +0 -0
  45. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/sqlite_reserved.py +0 -0
  46. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/sqlserver.py +0 -0
  47. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/sqlserver_reserved.py +0 -0
  48. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/servers/tablehelper.py +0 -0
  49. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/db/utils.py +0 -0
  50. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/__init__.py +0 -0
  51. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/conv/__init__.py +0 -0
  52. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/conv/iconv.py +0 -0
  53. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/conv/oconv.py +0 -0
  54. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/db.py +0 -0
  55. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/export.py +0 -0
  56. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/format.py +0 -0
  57. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/mail.py +0 -0
  58. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/merge.py +0 -0
  59. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/timer.py +0 -0
  60. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity/misc/tools.py +0 -0
  61. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  62. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity_python.egg-info/requires.txt +0 -0
  63. {velocity_python-0.0.120 → velocity_python-0.0.124}/src/velocity_python.egg-info/top_level.txt +0 -0
  64. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_cursor_rowcount_fix.py +0 -0
  65. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_db.py +0 -0
  66. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_db_utils.py +0 -0
  67. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_email_processing.py +0 -0
  68. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_fix.py +0 -0
  69. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_format.py +0 -0
  70. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_iconv.py +0 -0
  71. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_merge.py +0 -0
  72. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_oconv.py +0 -0
  73. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_original_error.py +0 -0
  74. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_payment_profile_sorting.py +0 -0
  75. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_postgres.py +0 -0
  76. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_process_error_robustness.py +0 -0
  77. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_response.py +0 -0
  78. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_result_caching.py +0 -0
  79. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_result_sql_aware.py +0 -0
  80. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_row_get_missing_column.py +0 -0
  81. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_spreadsheet_functions.py +0 -0
  82. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_sql_builder.py +0 -0
  83. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_tablehelper.py +0 -0
  84. {velocity_python-0.0.120 → velocity_python-0.0.124}/tests/test_timer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.120
3
+ Version: 0.0.124
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.120"
7
+ version = "0.0.124"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.0.120"
1
+ __version__ = version = "0.0.124"
2
2
 
3
3
  from . import aws
4
4
  from . import db
@@ -116,11 +116,12 @@ class BaseHandler:
116
116
 
117
117
  return actions
118
118
 
119
- def execute_actions(self, local_context, actions: List[str]) -> bool:
119
+ def execute_actions(self, tx, local_context, actions: List[str]) -> bool:
120
120
  """
121
121
  Execute the appropriate actions for the given context.
122
122
 
123
123
  Args:
124
+ tx: Database transaction object
124
125
  local_context: The context object
125
126
  actions: List of action method names to try
126
127
 
@@ -129,7 +130,7 @@ class BaseHandler:
129
130
  """
130
131
  # Execute beforeAction hook if available
131
132
  if hasattr(self, "beforeAction"):
132
- self.beforeAction(local_context)
133
+ self.beforeAction(tx, local_context)
133
134
 
134
135
  action_executed = False
135
136
 
@@ -139,7 +140,7 @@ class BaseHandler:
139
140
  break
140
141
 
141
142
  if hasattr(self, action):
142
- result = getattr(self, action)(local_context)
143
+ result = getattr(self, action)(tx, local_context)
143
144
 
144
145
  # Check for deprecated return values (LambdaHandler specific)
145
146
  if result is not None and hasattr(self, "_check_deprecated_return"):
@@ -150,27 +151,29 @@ class BaseHandler:
150
151
 
151
152
  # Execute afterAction hook if available
152
153
  if hasattr(self, "afterAction"):
153
- self.afterAction(local_context)
154
+ self.afterAction(tx, local_context)
154
155
 
155
156
  return action_executed
156
157
 
157
- def handle_error(self, local_context, exception: Exception):
158
+ def handle_error(self, tx, local_context, exception: Exception):
158
159
  """
159
160
  Handle errors that occur during action execution.
160
161
 
161
162
  Args:
163
+ tx: Database transaction object
162
164
  local_context: The context object
163
165
  exception: The exception that occurred
164
166
  """
165
167
  if hasattr(self, "onError"):
166
168
  self.onError(
169
+ tx,
167
170
  local_context,
168
171
  exc=exception.__class__.__name__,
169
172
  tb=traceback.format_exc(),
170
173
  )
171
174
  else:
172
175
  # Re-raise if no error handler is defined
173
- raise
176
+ raise exception
174
177
 
175
178
  def log(self, tx, message: str, function: Optional[str] = None):
176
179
  """
@@ -71,8 +71,19 @@ class LambdaHandler(BaseHandler):
71
71
  log=lambda message, function=None: self.log(tx, message, function),
72
72
  )
73
73
 
74
+ # Determine action from postdata or query parameters
75
+ action = postdata.get("action") or req_params.get("action")
76
+
77
+ # Get the list of actions to execute
78
+ actions = self.get_actions_to_execute(action)
79
+
74
80
  # Use BaseHandler's execute_actions method
75
- return self.execute_actions(tx, local_context, postdata, req_params)
81
+ try:
82
+ self.execute_actions(tx, local_context, actions)
83
+ except Exception as e:
84
+ self.handle_error(tx, local_context, e)
85
+
86
+ return local_context.response.render()
76
87
 
77
88
  def track(self, tx, data={}, user=None):
78
89
  data = data.copy()
@@ -78,11 +78,17 @@ class SqsHandler(BaseHandler):
78
78
  session=None,
79
79
  )
80
80
 
81
+ # Determine action from postdata
82
+ action = postdata.get("action") if isinstance(postdata, dict) else None
83
+
84
+ # Get the list of actions to execute
85
+ actions = self.get_actions_to_execute(action)
86
+
81
87
  # Use BaseHandler's execute_actions method
82
88
  try:
83
- self.execute_actions(tx, local_context, postdata, attrs)
89
+ self.execute_actions(tx, local_context, actions)
84
90
  except Exception as e:
85
- self.handle_error(local_context, e)
91
+ self.handle_error(tx, local_context, e)
86
92
 
87
93
  def OnActionDefault(self, tx, context):
88
94
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.120
3
+ Version: 0.0.124
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
@@ -65,6 +65,7 @@ tests/test_email_processing.py
65
65
  tests/test_fix.py
66
66
  tests/test_format.py
67
67
  tests/test_iconv.py
68
+ tests/test_lambda_handler_json_serialization.py
68
69
  tests/test_merge.py
69
70
  tests/test_oconv.py
70
71
  tests/test_original_error.py
@@ -0,0 +1,120 @@
1
+ """
2
+ Test Lambda Handler JSON Serialization Fix
3
+
4
+ This test verifies that LambdaHandler.serve() returns a JSON-serializable
5
+ dictionary instead of a Response object, preventing the
6
+ "Object of type method is not JSON serializable" error.
7
+ """
8
+
9
+ import json
10
+ import unittest
11
+ from unittest.mock import MagicMock, patch
12
+ import sys
13
+ import os
14
+
15
+ # Add src to path for testing
16
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
17
+
18
+ from velocity.aws.handlers.lambda_handler import LambdaHandler
19
+ from velocity.aws.handlers.response import Response
20
+
21
+
22
+ class TestLambdaHandlerJSONSerialization(unittest.TestCase):
23
+ """Test cases for Lambda Handler JSON serialization."""
24
+
25
+ def setUp(self):
26
+ """Set up test fixtures."""
27
+ self.test_event = {
28
+ "body": '{"action": "test", "payload": {}}',
29
+ "httpMethod": "POST",
30
+ "headers": {"Content-Type": "application/json"},
31
+ "requestContext": {
32
+ "identity": {
33
+ "sourceIp": "127.0.0.1", # localhost test IP for unit testing
34
+ "userAgent": "test-agent"
35
+ }
36
+ },
37
+ "queryStringParameters": {}
38
+ }
39
+
40
+ self.test_context = MagicMock()
41
+ self.test_context.function_name = "test-function"
42
+
43
+ def test_serve_returns_json_serializable_dict(self):
44
+ """Test that serve() returns a JSON-serializable dictionary."""
45
+
46
+ # Create handler
47
+ handler = LambdaHandler(self.test_event, self.test_context)
48
+
49
+ # Mock the transaction decorator to pass through tx
50
+ with patch('velocity.aws.handlers.lambda_handler.engine') as mock_engine:
51
+ def mock_transaction(func):
52
+ def wrapper(*args, **kwargs):
53
+ mock_tx = MagicMock()
54
+ return func(mock_tx, *args, **kwargs)
55
+ return wrapper
56
+
57
+ mock_engine.transaction = mock_transaction
58
+
59
+ # Call serve method
60
+ result = handler.serve(MagicMock())
61
+
62
+ # Verify result is a dictionary (JSON-serializable)
63
+ self.assertIsInstance(result, dict)
64
+
65
+ # Verify it has the expected Lambda response structure
66
+ self.assertIn("statusCode", result)
67
+ self.assertIn("headers", result)
68
+ self.assertIn("body", result)
69
+
70
+ # Verify the body is a JSON string
71
+ self.assertIsInstance(result["body"], str)
72
+
73
+ # Verify the entire result can be JSON serialized
74
+ try:
75
+ json.dumps(result)
76
+ except (TypeError, ValueError) as e:
77
+ self.fail(f"Result is not JSON serializable: {e}")
78
+
79
+ def test_response_object_has_render_method(self):
80
+ """Test that Response object has a proper render method."""
81
+ response = Response()
82
+
83
+ # Verify render method exists
84
+ self.assertTrue(hasattr(response, 'render'))
85
+ self.assertTrue(callable(response.render))
86
+
87
+ # Verify render returns a dictionary
88
+ rendered = response.render()
89
+ self.assertIsInstance(rendered, dict)
90
+
91
+ # Verify structure
92
+ self.assertIn("statusCode", rendered)
93
+ self.assertIn("headers", rendered)
94
+ self.assertIn("body", rendered)
95
+
96
+ # Verify JSON serializable
97
+ try:
98
+ json.dumps(rendered)
99
+ except (TypeError, ValueError) as e:
100
+ self.fail(f"Rendered response is not JSON serializable: {e}")
101
+
102
+ def test_response_render_vs_raw_object(self):
103
+ """Test the difference between Response object and rendered response."""
104
+ response = Response()
105
+
106
+ # Raw response object should not be directly JSON serializable
107
+ # (it contains method references)
108
+ with self.assertRaises((TypeError, ValueError)):
109
+ json.dumps(response)
110
+
111
+ # But rendered response should be JSON serializable
112
+ rendered = response.render()
113
+ try:
114
+ json.dumps(rendered)
115
+ except (TypeError, ValueError) as e:
116
+ self.fail(f"Rendered response should be JSON serializable: {e}")
117
+
118
+
119
+ if __name__ == '__main__':
120
+ unittest.main()