velocity-python 0.0.187__tar.gz → 0.0.189__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.
- {velocity_python-0.0.187/src/velocity_python.egg-info → velocity_python-0.0.189}/PKG-INFO +1 -1
- {velocity_python-0.0.187 → velocity_python-0.0.189}/pyproject.toml +1 -1
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/__init__.py +1 -1
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/mixins/__init__.py +2 -2
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/mixins/data_service.py +27 -138
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/mixins/web_handler.py +13 -7
- {velocity_python-0.0.187 → velocity_python-0.0.189/src/velocity_python.egg-info}/PKG-INFO +1 -1
- {velocity_python-0.0.187 → velocity_python-0.0.189}/LICENSE +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/README.md +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/setup.cfg +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/invoices.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/orders.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/payments.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/purchase_orders.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/tests/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/tests/test_email_processing.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/logging.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/payment/router.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/SOURCES.txt +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_decorators.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_table_alter.py +0 -0
- {velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_where_clause_validation.py +0 -0
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/mixins/__init__.py
RENAMED
|
@@ -8,6 +8,6 @@ This package provides mixins for common Lambda handler patterns:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from .web_handler import WebHandler, ButtonHandler
|
|
11
|
-
from .data_service import DataServiceMixin
|
|
11
|
+
from .data_service import DataServiceMixin
|
|
12
12
|
|
|
13
|
-
__all__ = ['WebHandler', 'ButtonHandler', 'DataServiceMixin',
|
|
13
|
+
__all__ = ['WebHandler', 'ButtonHandler', 'DataServiceMixin',]
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
@@ -8,10 +8,13 @@ that uses velocity.db for database access.
|
|
|
8
8
|
import base64
|
|
9
9
|
import datetime
|
|
10
10
|
import importlib
|
|
11
|
+
import logging
|
|
11
12
|
from io import BytesIO
|
|
12
13
|
|
|
13
14
|
from velocity.misc import export
|
|
14
15
|
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
15
18
|
|
|
16
19
|
class DataServiceMixin:
|
|
17
20
|
"""
|
|
@@ -71,6 +74,7 @@ class DataServiceMixin:
|
|
|
71
74
|
*args: Arguments to pass to the hook
|
|
72
75
|
**kwargs: Keyword arguments to pass to the hook
|
|
73
76
|
"""
|
|
77
|
+
|
|
74
78
|
try:
|
|
75
79
|
m = importlib.import_module(f".{table}", "rwx")
|
|
76
80
|
if hasattr(m, hook_name):
|
|
@@ -275,10 +279,14 @@ class DataServiceMixin:
|
|
|
275
279
|
if not any(value is not None for value in incoming.values()):
|
|
276
280
|
raise ValueError("Parameter 'object' cannot contain only None values")
|
|
277
281
|
|
|
278
|
-
|
|
279
|
-
|
|
282
|
+
logger.debug(
|
|
283
|
+
"Writing to table",
|
|
284
|
+
extra={
|
|
285
|
+
"table_name": table_name,
|
|
286
|
+
"sys_id": incoming.get("sys_id"),
|
|
287
|
+
"object_keys": list(incoming.keys()),
|
|
288
|
+
},
|
|
280
289
|
)
|
|
281
|
-
print(f"WRITE_LOG: Object keys: {list(incoming.keys())}")
|
|
282
290
|
|
|
283
291
|
try:
|
|
284
292
|
row = self.write_hook(
|
|
@@ -290,7 +298,10 @@ class DataServiceMixin:
|
|
|
290
298
|
)
|
|
291
299
|
|
|
292
300
|
if not row:
|
|
293
|
-
|
|
301
|
+
logger.warning(
|
|
302
|
+
"write_hook returned empty row",
|
|
303
|
+
extra={"table_name": table_name},
|
|
304
|
+
)
|
|
294
305
|
row = {}
|
|
295
306
|
|
|
296
307
|
context.response().set_body(
|
|
@@ -299,11 +310,20 @@ class DataServiceMixin:
|
|
|
299
310
|
"lastFetch": datetime.datetime.now(),
|
|
300
311
|
}
|
|
301
312
|
)
|
|
302
|
-
|
|
313
|
+
logger.debug(
|
|
314
|
+
"Successfully wrote to table",
|
|
315
|
+
extra={"table_name": table_name},
|
|
316
|
+
)
|
|
303
317
|
|
|
304
318
|
except Exception as e:
|
|
305
|
-
|
|
306
|
-
|
|
319
|
+
logger.error(
|
|
320
|
+
"Error in OnActionWriteObject",
|
|
321
|
+
extra={
|
|
322
|
+
"exception": str(e),
|
|
323
|
+
"table_name": table_name,
|
|
324
|
+
"incoming_keys": list(incoming.keys()),
|
|
325
|
+
},
|
|
326
|
+
)
|
|
307
327
|
raise
|
|
308
328
|
context.response().load_object(row)
|
|
309
329
|
|
|
@@ -532,134 +552,3 @@ class DataServiceMixin:
|
|
|
532
552
|
)
|
|
533
553
|
raise Exception(f"Failed to retrieve table schema: {str(e)}")
|
|
534
554
|
|
|
535
|
-
|
|
536
|
-
class RWXHookSystem:
|
|
537
|
-
"""
|
|
538
|
-
RWX (Read/Write/eXecute) hook system for table-specific business logic.
|
|
539
|
-
|
|
540
|
-
This system allows you to create table-specific hook modules in an 'rwx' package
|
|
541
|
-
and have them automatically called during CRUD operations. This is useful for
|
|
542
|
-
adding custom business logic (validation, permissions, data enrichment) for
|
|
543
|
-
specific tables without modifying the generic DataServiceMixin.
|
|
544
|
-
|
|
545
|
-
How it works:
|
|
546
|
-
1. Create a Python package called 'rwx' in your Lambda handler
|
|
547
|
-
2. For each table that needs custom logic, create a module (e.g., rwx/admin_users.py)
|
|
548
|
-
3. Define hook functions in the module (before_read, after_write, before_delete, etc.)
|
|
549
|
-
4. Subclass RWXHookSystem and set hook_module_name = 'rwx'
|
|
550
|
-
5. Use it from your handler class
|
|
551
|
-
|
|
552
|
-
Example structure:
|
|
553
|
-
src/
|
|
554
|
-
index.py
|
|
555
|
-
rwx/
|
|
556
|
-
__init__.py
|
|
557
|
-
admin_users.py # hooks for admin_users table
|
|
558
|
-
donors.py # hooks for donors table
|
|
559
|
-
|
|
560
|
-
Example hook in rwx/admin_users.py:
|
|
561
|
-
def before_write(tx, table, sys_id, incoming, context):
|
|
562
|
-
# Validate incoming data
|
|
563
|
-
if not incoming.get('email_address'):
|
|
564
|
-
raise ValueError("Email is required")
|
|
565
|
-
# Modify data
|
|
566
|
-
incoming['description'] = f"{incoming['full_name']} ({incoming['email_address']})"
|
|
567
|
-
|
|
568
|
-
def after_read(tx, table, sys_id, row, context):
|
|
569
|
-
# Enrich response data
|
|
570
|
-
context.response().set_body({'extra_data': 'value'})
|
|
571
|
-
|
|
572
|
-
Hook signatures:
|
|
573
|
-
- on_new(tx, table, row, context) - When creating new empty object
|
|
574
|
-
- before_read(tx, table, sys_id, context) - Before reading an object
|
|
575
|
-
- after_read(tx, table, sys_id, row, context) - After reading an object
|
|
576
|
-
- before_find(tx, table, query, context) - Before finding by query
|
|
577
|
-
- after_find(tx, table, query, row, context) - After finding by query
|
|
578
|
-
- before_new(tx, table, sys_id, incoming, context) - Before creating new object
|
|
579
|
-
- after_new(tx, table, sys_id, row, context) - After creating new object
|
|
580
|
-
- before_write(tx, table, sys_id, incoming, context) - Before write (insert/update)
|
|
581
|
-
- after_write(tx, table, sys_id, row, context) - After write (insert/update)
|
|
582
|
-
- before_delete(tx, table, sys_id, context) - Before deleting an object
|
|
583
|
-
- after_delete(tx, table, sys_id, context) - After deleting an object
|
|
584
|
-
- before_query(tx, table, payload, context) - Before querying objects
|
|
585
|
-
- after_query(tx, table, data, payload, context) - After querying objects
|
|
586
|
-
|
|
587
|
-
Usage in a Lambda handler:
|
|
588
|
-
from velocity.aws.handlers.mixins import DataServiceMixin, RWXHookSystem
|
|
589
|
-
|
|
590
|
-
class MyRWXSystem(RWXHookSystem):
|
|
591
|
-
hook_module_name = 'rwx' # Name of your rwx package
|
|
592
|
-
|
|
593
|
-
@engine.transaction
|
|
594
|
-
class HttpEventHandler(DataServiceMixin, LambdaHandler):
|
|
595
|
-
def __init__(self, aws_event, aws_context):
|
|
596
|
-
super().__init__(aws_event, aws_context)
|
|
597
|
-
"""
|
|
598
|
-
|
|
599
|
-
hook_module_name = None # Override in subclass (e.g., 'rwx')
|
|
600
|
-
|
|
601
|
-
@classmethod
|
|
602
|
-
def _get_table_module(cls, table):
|
|
603
|
-
"""Load table-specific hook module if it exists"""
|
|
604
|
-
if not cls.hook_module_name:
|
|
605
|
-
return None
|
|
606
|
-
try:
|
|
607
|
-
return importlib.import_module(f".{table}", cls.hook_module_name)
|
|
608
|
-
except ImportError:
|
|
609
|
-
return None
|
|
610
|
-
|
|
611
|
-
@classmethod
|
|
612
|
-
def _call_hook(cls, hook_name, table, *args, **kwargs):
|
|
613
|
-
"""Call a hook on table-specific module if it exists"""
|
|
614
|
-
module = cls._get_table_module(table)
|
|
615
|
-
if module and hasattr(module, hook_name):
|
|
616
|
-
return getattr(module, hook_name)(*args, **kwargs)
|
|
617
|
-
return None
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
def apply_sys_modified_by(incoming, context):
|
|
621
|
-
"""
|
|
622
|
-
Strip sys_* fields and set sys_modified_by from context.
|
|
623
|
-
|
|
624
|
-
Common pattern for applications that track who modified records.
|
|
625
|
-
Call this from your write_hook implementation.
|
|
626
|
-
|
|
627
|
-
Args:
|
|
628
|
-
incoming: Dictionary of data being written
|
|
629
|
-
context: Request context with session/payload
|
|
630
|
-
"""
|
|
631
|
-
payload = context.payload()
|
|
632
|
-
|
|
633
|
-
# Strip system fields from incoming data
|
|
634
|
-
for key in list(incoming.keys()):
|
|
635
|
-
if "sys_" in key:
|
|
636
|
-
incoming.pop(key)
|
|
637
|
-
|
|
638
|
-
# Extract email from session
|
|
639
|
-
session = context.session() if hasattr(context, "session") else None
|
|
640
|
-
email_address = None
|
|
641
|
-
|
|
642
|
-
if isinstance(session, dict):
|
|
643
|
-
email_address = session.get("cognito_user_email")
|
|
644
|
-
if not email_address:
|
|
645
|
-
cognito_user = session.get("cognito_user")
|
|
646
|
-
if isinstance(cognito_user, dict):
|
|
647
|
-
email_address = cognito_user.get("email") or (
|
|
648
|
-
cognito_user.get("attributes") or {}
|
|
649
|
-
).get("email")
|
|
650
|
-
if not email_address:
|
|
651
|
-
email_address = session.get("email_address")
|
|
652
|
-
|
|
653
|
-
if not email_address and isinstance(payload, dict):
|
|
654
|
-
payload_user = payload.get("cognito_user")
|
|
655
|
-
if isinstance(payload_user, dict):
|
|
656
|
-
email_address = payload_user.get("email") or (
|
|
657
|
-
payload_user.get("attributes") or {}
|
|
658
|
-
).get("email")
|
|
659
|
-
|
|
660
|
-
incoming["sys_modified_by"] = (
|
|
661
|
-
email_address.lower()
|
|
662
|
-
if isinstance(email_address, str)
|
|
663
|
-
else incoming.get("sys_modified_by", "unknown")
|
|
664
|
-
)
|
|
665
|
-
incoming["sys_dirty"] = True
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/mixins/web_handler.py
RENAMED
|
@@ -9,6 +9,7 @@ onError implementations in handlers.
|
|
|
9
9
|
import copy
|
|
10
10
|
import importlib
|
|
11
11
|
import json
|
|
12
|
+
import logging
|
|
12
13
|
import os
|
|
13
14
|
import pprint
|
|
14
15
|
import time
|
|
@@ -18,6 +19,8 @@ from typing import Any, Dict, List
|
|
|
18
19
|
|
|
19
20
|
from velocity.aws.handlers.exceptions import AlertError
|
|
20
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
21
24
|
class WebHandler(ABC):
|
|
22
25
|
"""
|
|
23
26
|
Mixin providing unified activity tracking plus standardized error handling.
|
|
@@ -72,9 +75,12 @@ class WebHandler(ABC):
|
|
|
72
75
|
try:
|
|
73
76
|
self.activity_log_key = tx.table("aws_api_activity").new(self.activity_data).pk
|
|
74
77
|
except Exception as exc:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
logger.error(
|
|
79
|
+
"WebHandler.track_activity_start failed",
|
|
80
|
+
extra={
|
|
81
|
+
"exception": str(exc),
|
|
82
|
+
"activity_data_keys": list(self.activity_data.keys()),
|
|
83
|
+
},
|
|
78
84
|
)
|
|
79
85
|
raise
|
|
80
86
|
|
|
@@ -254,7 +260,7 @@ Request Details:
|
|
|
254
260
|
html = html.replace("\n", "<br>").replace(" ", " ")
|
|
255
261
|
recipients = self._resolve_error_notification_recipients(tx, context)
|
|
256
262
|
if not recipients:
|
|
257
|
-
|
|
263
|
+
logger.debug("No error notification recipients configured; skipping notification.")
|
|
258
264
|
return
|
|
259
265
|
|
|
260
266
|
sender = self._resolve_error_notification_sender(tx, context)
|
|
@@ -271,7 +277,7 @@ Request Details:
|
|
|
271
277
|
email_settings_id=1001,
|
|
272
278
|
)
|
|
273
279
|
except Exception as email_error: # pragma: no cover
|
|
274
|
-
|
|
280
|
+
logger.error("Failed to send error notification email", extra={"error": str(email_error)})
|
|
275
281
|
|
|
276
282
|
def _resolve_error_notification_recipients(self, tx, context) -> List[str]:
|
|
277
283
|
recipients: List[str] = []
|
|
@@ -280,7 +286,7 @@ Request Details:
|
|
|
280
286
|
try:
|
|
281
287
|
recipients = context_method(tx) or []
|
|
282
288
|
except Exception as exc:
|
|
283
|
-
|
|
289
|
+
logger.warning("Failed to load recipients from context", extra={"error": str(exc)})
|
|
284
290
|
if recipients:
|
|
285
291
|
return recipients
|
|
286
292
|
return self._get_error_notification_recipients()
|
|
@@ -292,7 +298,7 @@ Request Details:
|
|
|
292
298
|
try:
|
|
293
299
|
sender = context_method(tx)
|
|
294
300
|
except Exception as exc:
|
|
295
|
-
|
|
301
|
+
logger.warning("Failed to load sender from context", extra={"error": str(exc)})
|
|
296
302
|
if sender:
|
|
297
303
|
return sender
|
|
298
304
|
return self._get_error_notification_sender()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/app/tests/test_email_processing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/base_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/aws/handlers/sqs_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/initializer.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/base/operators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/mysql/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/postgres/types.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlite/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/reserved.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/sql.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/servers/sqlserver/types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/common.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_column.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_database.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_engine.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_imports.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_result.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_row.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_sequence.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/postgres/test_table.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_postgres_unchanged.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_result_caching.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_result_sql_aware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_sql_builder.py
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/db/tests/test_tablehelper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/misc/tests/test_original_error.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity/payment/braintree_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/src/velocity_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.187 → velocity_python-0.0.189}/tests/test_sys_modified_count_postgres_demo.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|