velocity-python 0.0.183__tar.gz → 0.0.185__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 (143) hide show
  1. {velocity_python-0.0.183 → velocity_python-0.0.185}/PKG-INFO +1 -1
  2. {velocity_python-0.0.183 → velocity_python-0.0.185}/pyproject.toml +1 -1
  3. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/lambda_handler.py +15 -12
  5. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/mixins/__init__.py +3 -2
  6. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/mixins/web_handler.py +111 -1
  7. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity_python.egg-info/PKG-INFO +1 -1
  8. {velocity_python-0.0.183 → velocity_python-0.0.185}/LICENSE +0 -0
  9. {velocity_python-0.0.183 → velocity_python-0.0.185}/README.md +0 -0
  10. {velocity_python-0.0.183 → velocity_python-0.0.185}/setup.cfg +0 -0
  11. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/__init__.py +0 -0
  12. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/invoices.py +0 -0
  13. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/orders.py +0 -0
  14. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/payments.py +0 -0
  15. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/purchase_orders.py +0 -0
  16. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/tests/__init__.py +0 -0
  17. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/tests/test_email_processing.py +0 -0
  18. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
  19. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
  20. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/__init__.py +0 -0
  21. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/amplify.py +0 -0
  22. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/__init__.py +0 -0
  23. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/base_handler.py +0 -0
  24. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/context.py +0 -0
  25. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/exceptions.py +0 -0
  26. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  27. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/response.py +0 -0
  28. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  29. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/tests/__init__.py +0 -0
  30. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  31. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/aws/tests/test_response.py +0 -0
  32. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/__init__.py +0 -0
  33. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/__init__.py +0 -0
  34. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/column.py +0 -0
  35. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/database.py +0 -0
  36. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/decorators.py +0 -0
  37. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/engine.py +0 -0
  38. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/result.py +0 -0
  39. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/row.py +0 -0
  40. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/sequence.py +0 -0
  41. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/table.py +0 -0
  42. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/core/transaction.py +0 -0
  43. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/exceptions.py +0 -0
  44. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/__init__.py +0 -0
  45. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/base/__init__.py +0 -0
  46. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/base/initializer.py +0 -0
  47. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/base/operators.py +0 -0
  48. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/base/sql.py +0 -0
  49. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/base/types.py +0 -0
  50. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/mysql/__init__.py +0 -0
  51. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/mysql/operators.py +0 -0
  52. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/mysql/reserved.py +0 -0
  53. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/mysql/sql.py +0 -0
  54. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/mysql/types.py +0 -0
  55. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/postgres/__init__.py +0 -0
  56. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/postgres/operators.py +0 -0
  57. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/postgres/reserved.py +0 -0
  58. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/postgres/sql.py +0 -0
  59. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/postgres/types.py +0 -0
  60. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  61. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlite/operators.py +0 -0
  62. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  63. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlite/sql.py +0 -0
  64. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlite/types.py +0 -0
  65. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  66. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  67. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  68. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  69. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/sqlserver/types.py +0 -0
  70. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/servers/tablehelper.py +0 -0
  71. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/__init__.py +0 -0
  72. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/common_db_test.py +0 -0
  73. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/__init__.py +0 -0
  74. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/common.py +0 -0
  75. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_column.py +0 -0
  76. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  77. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_database.py +0 -0
  78. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  79. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  80. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  81. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_result.py +0 -0
  82. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_row.py +0 -0
  83. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  84. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  85. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  86. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  87. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  88. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_table.py +0 -0
  89. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  90. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  91. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/sql/__init__.py +0 -0
  92. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/sql/common.py +0 -0
  93. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  94. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  95. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  96. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_db_utils.py +0 -0
  97. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_postgres.py +0 -0
  98. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  99. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  100. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_result_caching.py +0 -0
  101. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  102. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  103. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  104. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  105. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_sql_builder.py +0 -0
  106. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/tests/test_tablehelper.py +0 -0
  107. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/db/utils.py +0 -0
  108. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/logging.py +0 -0
  109. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/__init__.py +0 -0
  110. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/conv/__init__.py +0 -0
  111. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/conv/iconv.py +0 -0
  112. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/conv/oconv.py +0 -0
  113. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/db.py +0 -0
  114. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/export.py +0 -0
  115. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/format.py +0 -0
  116. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/mail.py +0 -0
  117. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/merge.py +0 -0
  118. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/__init__.py +0 -0
  119. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_db.py +0 -0
  120. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_fix.py +0 -0
  121. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_format.py +0 -0
  122. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_iconv.py +0 -0
  123. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_merge.py +0 -0
  124. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_oconv.py +0 -0
  125. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_original_error.py +0 -0
  126. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tests/test_timer.py +0 -0
  127. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/timer.py +0 -0
  128. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/misc/tools.py +0 -0
  129. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/payment/__init__.py +0 -0
  130. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/payment/base_adapter.py +0 -0
  131. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/payment/braintree_adapter.py +0 -0
  132. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/payment/router.py +0 -0
  133. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity/payment/stripe_adapter.py +0 -0
  134. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  135. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  136. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity_python.egg-info/requires.txt +0 -0
  137. {velocity_python-0.0.183 → velocity_python-0.0.185}/src/velocity_python.egg-info/top_level.txt +0 -0
  138. {velocity_python-0.0.183 → velocity_python-0.0.185}/tests/test_decorators.py +0 -0
  139. {velocity_python-0.0.183 → velocity_python-0.0.185}/tests/test_lambda_handler.py +0 -0
  140. {velocity_python-0.0.183 → velocity_python-0.0.185}/tests/test_mixins_import.py +0 -0
  141. {velocity_python-0.0.183 → velocity_python-0.0.185}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  142. {velocity_python-0.0.183 → velocity_python-0.0.185}/tests/test_table_alter.py +0 -0
  143. {velocity_python-0.0.183 → velocity_python-0.0.185}/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.183
3
+ Version: 0.0.185
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.183"
7
+ version = "0.0.185"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.0.183"
1
+ __version__ = version = "0.0.185"
2
2
 
3
3
  from . import aws
4
4
  from . import db
@@ -24,13 +24,15 @@ class LambdaHandler(BaseHandler):
24
24
  ):
25
25
  self.start = time.time()
26
26
  super().__init__(aws_event, aws_context, context_class)
27
-
28
- # LambdaHandler-specific initialization
27
+ self.session = self.create_session(aws_event, aws_context)
28
+
29
+ def create_session(self, aws_event, aws_context):
30
+ # LambdaHandler-specific initialization
29
31
  requestContext = aws_event.get("requestContext") or {}
30
32
  identity = requestContext.get("identity") or {}
31
33
  headers = aws_event.get("headers") or {}
32
34
  auth = identity.get("cognitoAuthenticationProvider")
33
- self.session = {
35
+ session = {
34
36
  "authentication_provider": identity.get("cognitoAuthenticationProvider"),
35
37
  "authentication_type": identity.get("cognitoAuthenticationType"),
36
38
  "cognito_user": identity.get("user"),
@@ -45,16 +47,17 @@ class LambdaHandler(BaseHandler):
45
47
  "user_agent": identity.get("userAgent"),
46
48
  "sub": auth.split(":")[-1] if auth else None,
47
49
  }
48
- if self.session.get("is_mobile"):
49
- self.session["device_type"] = "mobile"
50
- elif self.session.get("is_desktop"):
51
- self.session["device_type"] = "desktop"
52
- elif self.session.get("is_tablet"):
53
- self.session["device_type"] = "tablet"
54
- elif self.session.get("is_smart_tv"):
55
- self.session["device_type"] = "smart_tv"
50
+ if session.get("is_mobile"):
51
+ session["device_type"] = "mobile"
52
+ elif session.get("is_desktop"):
53
+ session["device_type"] = "desktop"
54
+ elif session.get("is_tablet"):
55
+ session["device_type"] = "tablet"
56
+ elif session.get("is_smart_tv"):
57
+ session["device_type"] = "smart_tv"
56
58
  else:
57
- self.session["device_type"] = "unknown"
59
+ session["device_type"] = "unknown"
60
+ return session
58
61
 
59
62
 
60
63
  def beforeAction(self, tx, context):
@@ -3,10 +3,11 @@ Mixins for AWS Lambda handlers.
3
3
 
4
4
  This package provides mixins for common Lambda handler patterns:
5
5
  - WebHandler: Activity tracking, logging, and error handling
6
+ - ButtonHandler: Dynamic button action handler loading
6
7
  - DataServiceMixin: Generic CRUD operations for database-backed APIs
7
8
  """
8
9
 
9
- from .web_handler import WebHandler
10
+ from .web_handler import WebHandler, ButtonHandler
10
11
  from .data_service import DataServiceMixin, RWXHookSystem, apply_sys_modified_by
11
12
 
12
- __all__ = ['WebHandler', 'DataServiceMixin', 'RWXHookSystem', 'apply_sys_modified_by']
13
+ __all__ = ['WebHandler', 'ButtonHandler', 'DataServiceMixin', 'RWXHookSystem', 'apply_sys_modified_by']
@@ -7,6 +7,7 @@ onError implementations in handlers.
7
7
  """
8
8
 
9
9
  import copy
10
+ import importlib
10
11
  import json
11
12
  import os
12
13
  import pprint
@@ -15,6 +16,7 @@ from abc import ABC
15
16
  from datetime import date, datetime
16
17
  from typing import Any, Dict, List
17
18
 
19
+ from velocity.aws.handlers.exceptions import AlertError
18
20
 
19
21
  class WebHandler(ABC):
20
22
  """
@@ -380,4 +382,112 @@ Request Details:
380
382
 
381
383
  if not getattr(self, "_handles_own_error_notifications", False):
382
384
  if self._should_notify_error(exc):
383
- self.send_error_notification(tx, context, exc, tb)
385
+ self.send_error_notification(tx, context, exc, tb)
386
+
387
+
388
+
389
+ class ButtonHandler:
390
+ """
391
+ Button handler mixin for dynamically loading and executing button action handlers.
392
+
393
+ This class provides a way to dynamically load button handler modules and execute
394
+ actions defined within them, similar to the RWXHookSystem pattern.
395
+
396
+ Usage:
397
+ from velocity.aws.handlers.mixins import ButtonHandler
398
+
399
+ class LocalButtonHandler(ButtonHandler):
400
+ module_name = 'buttons' # Your buttons package
401
+
402
+ class HttpEventHandler(LocalButtonHandler, WebHandler, LambdaHandler):
403
+ # Handler will automatically have OnActionButtonClick available
404
+ pass
405
+
406
+ The OnActionButtonClick method expects the context.dataset() to contain:
407
+ - handler: Name of the module in the buttons package
408
+ - action: Action name (e.g., "refresh-data" becomes "RefreshData")
409
+ """
410
+
411
+ module_name = None # Override in subclass (e.g., 'buttons')
412
+
413
+ @classmethod
414
+ def _get_button_module(cls, handler):
415
+ """
416
+ Load button-specific handler module if it exists.
417
+
418
+ Args:
419
+ handler: Name of the handler module to load
420
+
421
+ Returns:
422
+ The loaded module or None if not found
423
+ """
424
+ if not cls.module_name:
425
+ raise AlertError("ButtonHandler.module_name not set in subclass. This is a configuration issue that needs to be handled by the developer.")
426
+ try:
427
+ return importlib.import_module(f".{handler}", cls.module_name)
428
+ except ImportError:
429
+ raise AlertError(f"Unable to import ButtonHandler module `{handler}`. Please ensure the code has been deployed.")
430
+
431
+ @classmethod
432
+ def _get_button_function(cls, handler, action):
433
+ """
434
+ Get a specific function from a button handler module.
435
+
436
+ Args:
437
+ handler: Name of the handler module
438
+ action: Action name to convert to function name
439
+
440
+ Returns:
441
+ The function object or None if not found
442
+ """
443
+ module = cls._get_button_module(handler)
444
+
445
+ # Convert action name: "refresh-data" -> "RefreshData"
446
+ func_name = action.replace("-", " ").title().replace(" ", "")
447
+
448
+ if hasattr(module, func_name):
449
+ return getattr(module, func_name)
450
+
451
+ raise AlertError(f"Function `{func_name}` not found in handler `{handler}`. Please ensure the code has been deployed.")
452
+
453
+ def OnActionButtonClick(self, tx, context):
454
+ """
455
+ Handle button click actions by dynamically loading and executing handlers.
456
+
457
+ This method:
458
+ 1. Extracts handler and action from the dataset
459
+ 2. Dynamically loads the appropriate button handler module
460
+ 3. Converts the action name to a function name
461
+ 4. Executes the function with proper error handling
462
+
463
+ The button handler functions should modify context.response() directly
464
+ and should not return values (to avoid triggering base handler warnings).
465
+
466
+ Args:
467
+ tx: Database transaction
468
+ context: Request context containing dataset with 'handler' and 'action'
469
+
470
+ Raises:
471
+ AlertError: If handler or action not found, or if module/function missing
472
+ """
473
+
474
+
475
+ dataset = context.dataset()
476
+
477
+ # Validate required fields
478
+ if "handler" not in dataset:
479
+ raise AlertError("Handler not found in payload")
480
+ if "action" not in dataset:
481
+ raise AlertError("Action not found in payload")
482
+
483
+ handler = dataset["handler"]
484
+ action = dataset["action"]
485
+
486
+ # Resolve the function using the helper
487
+ func = self._get_button_function(handler, action)
488
+
489
+ # Execute the button handler
490
+ # Don't return its result to avoid triggering base handler warnings
491
+ func(self, tx, context)
492
+
493
+ # Handler methods should modify context.response() directly
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.183
3
+ Version: 0.0.185
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