velocity-python 0.1.12__tar.gz → 0.1.14__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.1.12/src/velocity_python.egg-info → velocity_python-0.1.14}/PKG-INFO +4 -2
- {velocity_python-0.1.12 → velocity_python-0.1.14}/pyproject.toml +5 -2
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/__init__.py +1 -1
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/engine.py +97 -75
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/base/sql.py +24 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/mysql/sql.py +23 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/postgres/sql.py +36 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlite/sql.py +19 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlserver/sql.py +23 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_engine.py +4 -8
- velocity_python-0.1.14/src/velocity/db/tests/test_process_error_robustness.py +305 -0
- velocity_python-0.1.14/src/velocity/misc/pdf.py +199 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14/src/velocity_python.egg-info}/PKG-INFO +4 -2
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity_python.egg-info/requires.txt +4 -1
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_connection_pool.py +5 -5
- velocity_python-0.1.14/tests/test_pdf.py +188 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_security_hardening.py +4 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_where_clause_validation.py +12 -0
- velocity_python-0.1.12/src/velocity/db/tests/test_process_error_robustness.py +0 -292
- {velocity_python-0.1.12 → velocity_python-0.1.14}/LICENSE +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/README.md +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/setup.cfg +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/formbuilder/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/formbuilder/reshaper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/invoices.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/orders.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/payments.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/purchase_orders.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/validators/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/app/validators/formbuilder_template.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/demo_profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/router.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_formbuilder_reshaper.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_formbuilder_template_validator.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_observability.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_payment_demo_profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_payment_profiles.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_payment_router.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_row_dirty_tracking.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.12 → velocity_python-0.1.14}/tests/test_table_alter.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: velocity-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.14
|
|
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
|
|
@@ -29,6 +29,8 @@ Provides-Extra: excel
|
|
|
29
29
|
Requires-Dist: openpyxl>=3.1.0; extra == "excel"
|
|
30
30
|
Provides-Extra: templates
|
|
31
31
|
Requires-Dist: jinja2>=3.1.0; extra == "templates"
|
|
32
|
+
Provides-Extra: pdf
|
|
33
|
+
Requires-Dist: weasyprint>=62.0; extra == "pdf"
|
|
32
34
|
Provides-Extra: http
|
|
33
35
|
Requires-Dist: requests>=2.32.0; extra == "http"
|
|
34
36
|
Provides-Extra: mysql
|
|
@@ -41,7 +43,7 @@ Provides-Extra: payment
|
|
|
41
43
|
Requires-Dist: stripe>=12.0.0; extra == "payment"
|
|
42
44
|
Requires-Dist: braintree>=4.30.0; extra == "payment"
|
|
43
45
|
Provides-Extra: all
|
|
44
|
-
Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
|
|
46
|
+
Requires-Dist: velocity-python[aws,excel,http,payment,pdf,postgres,templates]; extra == "all"
|
|
45
47
|
Provides-Extra: dev
|
|
46
48
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
47
49
|
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "velocity-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.14"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Velocity Team", email="info@codeclubs.org" },
|
|
10
10
|
]
|
|
@@ -48,6 +48,9 @@ excel = [
|
|
|
48
48
|
templates = [
|
|
49
49
|
"jinja2>=3.1.0",
|
|
50
50
|
]
|
|
51
|
+
pdf = [
|
|
52
|
+
"weasyprint>=62.0",
|
|
53
|
+
]
|
|
51
54
|
http = [
|
|
52
55
|
"requests>=2.32.0",
|
|
53
56
|
]
|
|
@@ -65,7 +68,7 @@ payment = [
|
|
|
65
68
|
"braintree>=4.30.0",
|
|
66
69
|
]
|
|
67
70
|
all = [
|
|
68
|
-
"velocity-python[postgres,aws,excel,templates,http,payment]",
|
|
71
|
+
"velocity-python[postgres,aws,excel,templates,http,payment,pdf]",
|
|
69
72
|
]
|
|
70
73
|
dev = [
|
|
71
74
|
"pytest>=8.0.0",
|
|
@@ -2,6 +2,7 @@ import inspect
|
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
4
|
import time
|
|
5
|
+
import traceback
|
|
5
6
|
import threading
|
|
6
7
|
from contextlib import contextmanager
|
|
7
8
|
from functools import wraps
|
|
@@ -14,6 +15,51 @@ import logging
|
|
|
14
15
|
logger = logging.getLogger("velocity.db.engine")
|
|
15
16
|
logger.setLevel(logging.INFO) # Or DEBUG for more verbosity
|
|
16
17
|
|
|
18
|
+
# Map category keys (matching SQL dialect attribute name prefixes) to exception classes.
|
|
19
|
+
_CATEGORY_EXCEPTION_MAP = {
|
|
20
|
+
"Application": exceptions.DbApplicationError,
|
|
21
|
+
"ColumnMissing": exceptions.DbColumnMissingError,
|
|
22
|
+
"TableMissing": exceptions.DbTableMissingError,
|
|
23
|
+
"DatabaseMissing": exceptions.DbDatabaseMissingError,
|
|
24
|
+
"ForeignKeyMissing": exceptions.DbForeignKeyMissingError,
|
|
25
|
+
"Truncation": exceptions.DbTruncationError,
|
|
26
|
+
"DataIntegrity": exceptions.DbDataIntegrityError,
|
|
27
|
+
"Connection": exceptions.DbConnectionError,
|
|
28
|
+
"DuplicateKey": exceptions.DbDuplicateKeyError,
|
|
29
|
+
"ObjectExists": exceptions.DbObjectExistsError,
|
|
30
|
+
"LockTimeout": exceptions.DbLockTimeoutError,
|
|
31
|
+
"RetryTransaction": exceptions.DbRetryTransaction,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Attribute names on BaseSQLDialect, in the order they should be checked.
|
|
35
|
+
_CODE_LIST_ATTRS = [
|
|
36
|
+
("ApplicationErrorCodes", "Application"),
|
|
37
|
+
("ColumnMissingErrorCodes", "ColumnMissing"),
|
|
38
|
+
("TableMissingErrorCodes", "TableMissing"),
|
|
39
|
+
("DatabaseMissingErrorCodes", "DatabaseMissing"),
|
|
40
|
+
("ForeignKeyMissingErrorCodes", "ForeignKeyMissing"),
|
|
41
|
+
("TruncationErrorCodes", "Truncation"),
|
|
42
|
+
("DataIntegrityErrorCodes", "DataIntegrity"),
|
|
43
|
+
("ConnectionErrorCodes", "Connection"),
|
|
44
|
+
("DuplicateKeyErrorCodes", "DuplicateKey"),
|
|
45
|
+
("DatabaseObjectExistsErrorCodes", "ObjectExists"),
|
|
46
|
+
("LockTimeoutErrorCodes", "LockTimeout"),
|
|
47
|
+
("RetryTransactionCodes", "RetryTransaction"),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _build_error_code_map(sql_dialect) -> dict:
|
|
52
|
+
"""Build a {code: exception_class} dict from a dialect's code lists."""
|
|
53
|
+
code_map: dict = {}
|
|
54
|
+
for attr, category in _CODE_LIST_ATTRS:
|
|
55
|
+
exc_cls = _CATEGORY_EXCEPTION_MAP[category]
|
|
56
|
+
for code in getattr(sql_dialect, attr, ()):
|
|
57
|
+
code_map.setdefault(code, exc_cls) # first match wins
|
|
58
|
+
return code_map
|
|
59
|
+
|
|
60
|
+
# Path of this file — used to filter stack frames.
|
|
61
|
+
_ENGINE_FILE = os.path.normpath(__file__)
|
|
62
|
+
|
|
17
63
|
|
|
18
64
|
class ConnectionPool:
|
|
19
65
|
"""
|
|
@@ -198,6 +244,9 @@ class Engine:
|
|
|
198
244
|
self.__sql = sql
|
|
199
245
|
self.__driver = driver
|
|
200
246
|
|
|
247
|
+
# Pre-build the error-code → exception-class lookup for O(1) classification.
|
|
248
|
+
self.__error_code_map = _build_error_code_map(sql) if sql else {}
|
|
249
|
+
|
|
201
250
|
if connect_timeout is None:
|
|
202
251
|
connect_timeout = int(os.environ.get("VELOCITY_CONNECT_TIMEOUT", "5"))
|
|
203
252
|
self.__connect_timeout = connect_timeout
|
|
@@ -739,115 +788,88 @@ class Engine:
|
|
|
739
788
|
"""
|
|
740
789
|
Central method to parse driver exceptions and re-raise them as our custom exceptions.
|
|
741
790
|
"""
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
# If it's already a velocity exception, just re-raise it
|
|
791
|
+
# If it's already a velocity exception, just re-raise it.
|
|
745
792
|
if isinstance(exception, exceptions.DbException):
|
|
746
793
|
raise exception
|
|
747
794
|
|
|
748
|
-
#
|
|
795
|
+
# Extract error code & message from the driver exception.
|
|
749
796
|
try:
|
|
750
797
|
error_code, error_message = self.sql.get_error(exception)
|
|
751
798
|
except Exception:
|
|
752
799
|
error_code, error_message = None, str(exception)
|
|
753
800
|
|
|
754
|
-
msg = str(exception)
|
|
801
|
+
msg = str(exception)
|
|
755
802
|
|
|
756
|
-
#
|
|
757
|
-
enhanced_message =
|
|
803
|
+
# ── Build enhanced message ───────────────────────────────────
|
|
804
|
+
enhanced_message = msg
|
|
758
805
|
|
|
759
|
-
#
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
"Common fixes:\n"
|
|
767
|
-
" - Change WHERE 1001 to WHERE sys_id = 1001\n"
|
|
768
|
-
" - Change WHERE {'column': value} format in dictionaries\n"
|
|
769
|
-
" - Ensure string WHERE clauses are complete SQL expressions"
|
|
770
|
-
)
|
|
806
|
+
# Dialect-specific developer guidance (e.g. WHERE-clause hints).
|
|
807
|
+
try:
|
|
808
|
+
hint = self.sql.enhance_message(msg)
|
|
809
|
+
except (AttributeError, TypeError):
|
|
810
|
+
hint = None
|
|
811
|
+
if isinstance(hint, str):
|
|
812
|
+
enhanced_message += hint
|
|
771
813
|
|
|
772
814
|
if sql:
|
|
773
815
|
enhanced_message += (
|
|
774
816
|
f"\n\nSQL Query:\n{self._format_sql_with_params(sql, parameters)}"
|
|
775
817
|
)
|
|
776
818
|
|
|
777
|
-
#
|
|
778
|
-
import traceback
|
|
779
|
-
|
|
780
|
-
stack_trace = traceback.format_stack()
|
|
781
|
-
# Get the last few frames that aren't in the error handling itself
|
|
819
|
+
# Append a few relevant call-stack frames for context.
|
|
782
820
|
relevant_frames = [
|
|
783
|
-
frame
|
|
784
|
-
|
|
785
|
-
if "process_error" not in frame and "logging" not in frame
|
|
821
|
+
frame for frame in traceback.format_stack()
|
|
822
|
+
if _ENGINE_FILE not in frame
|
|
786
823
|
][-3:]
|
|
787
824
|
if relevant_frames:
|
|
788
825
|
enhanced_message += "\n\nCall Context:\n" + "".join(relevant_frames)
|
|
789
826
|
|
|
790
|
-
# Mask
|
|
791
|
-
# (e.g. connection strings containing password=...).
|
|
827
|
+
# Mask credentials that may have leaked into driver error text.
|
|
792
828
|
enhanced_message = mask_sensitive_in_string(enhanced_message)
|
|
793
829
|
|
|
794
|
-
#
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
# Direct error code mapping
|
|
798
|
-
if error_code in self.sql.ApplicationErrorCodes:
|
|
799
|
-
raise exceptions.DbApplicationError(enhanced_message) from exception
|
|
800
|
-
if error_code in self.sql.ColumnMissingErrorCodes:
|
|
801
|
-
raise exceptions.DbColumnMissingError(enhanced_message) from exception
|
|
802
|
-
if error_code in self.sql.TableMissingErrorCodes:
|
|
803
|
-
raise exceptions.DbTableMissingError(enhanced_message) from exception
|
|
804
|
-
if error_code in self.sql.DatabaseMissingErrorCodes:
|
|
805
|
-
raise exceptions.DbDatabaseMissingError(enhanced_message) from exception
|
|
806
|
-
if error_code in self.sql.ForeignKeyMissingErrorCodes:
|
|
807
|
-
raise exceptions.DbForeignKeyMissingError(enhanced_message) from exception
|
|
808
|
-
if error_code in self.sql.TruncationErrorCodes:
|
|
809
|
-
raise exceptions.DbTruncationError(enhanced_message) from exception
|
|
810
|
-
if error_code in self.sql.DataIntegrityErrorCodes:
|
|
811
|
-
raise exceptions.DbDataIntegrityError(enhanced_message) from exception
|
|
812
|
-
if error_code in self.sql.ConnectionErrorCodes:
|
|
813
|
-
raise exceptions.DbConnectionError(enhanced_message) from exception
|
|
814
|
-
if error_code in self.sql.DuplicateKeyErrorCodes:
|
|
815
|
-
raise exceptions.DbDuplicateKeyError(enhanced_message) from exception
|
|
816
|
-
if error_code in self.sql.DatabaseObjectExistsErrorCodes:
|
|
817
|
-
raise exceptions.DbObjectExistsError(enhanced_message) from exception
|
|
818
|
-
if error_code in self.sql.LockTimeoutErrorCodes:
|
|
819
|
-
raise exceptions.DbLockTimeoutError(enhanced_message) from exception
|
|
820
|
-
if error_code in self.sql.RetryTransactionCodes:
|
|
821
|
-
raise exceptions.DbRetryTransaction(enhanced_message) from exception
|
|
822
|
-
|
|
823
|
-
# Regex-based fallback patterns
|
|
824
|
-
if re.search(r"key \(sys_id\)=\(\d+\) already exists.", msg, re.M):
|
|
825
|
-
raise exceptions.DbDuplicateKeyError(enhanced_message) from exception
|
|
826
|
-
if re.findall(r"database.*does not exist", msg, re.M):
|
|
827
|
-
raise exceptions.DbDatabaseMissingError(enhanced_message) from exception
|
|
828
|
-
if re.findall(r"no such database", msg, re.M):
|
|
829
|
-
raise exceptions.DbDatabaseMissingError(enhanced_message) from exception
|
|
830
|
-
if re.findall(r"already exists", msg, re.M):
|
|
831
|
-
raise exceptions.DbObjectExistsError(enhanced_message) from exception
|
|
832
|
-
# Dialect-specific connection error message classification (fallback when no/unknown code).
|
|
833
|
-
if getattr(self.sql, "is_connection_error_message", lambda _m: False)(msg):
|
|
834
|
-
raise exceptions.DbConnectionError(enhanced_message) from exception
|
|
835
|
-
if "no such table:" in msg:
|
|
836
|
-
raise exceptions.DbTableMissingError(enhanced_message) from exception
|
|
830
|
+
# ── Classify by error code (O(1) dict lookup) ────────────────
|
|
831
|
+
code_map = getattr(self, '_Engine__error_code_map', None) or {}
|
|
832
|
+
exc_cls = code_map.get(error_code) if error_code else None
|
|
837
833
|
|
|
834
|
+
# ── Classify by message text (dialect-specific fallback) ─────
|
|
835
|
+
if exc_cls is None:
|
|
836
|
+
try:
|
|
837
|
+
category = self.sql.classify_by_message(msg)
|
|
838
|
+
except (AttributeError, TypeError):
|
|
839
|
+
category = None
|
|
840
|
+
if isinstance(category, str):
|
|
841
|
+
exc_cls = _CATEGORY_EXCEPTION_MAP.get(category)
|
|
842
|
+
|
|
843
|
+
# ── Raise the classified exception ───────────────────────────
|
|
844
|
+
if exc_cls is not None:
|
|
845
|
+
logger.warning(
|
|
846
|
+
"DB error classified: code=%s message=%s type=%s → %s",
|
|
847
|
+
error_code, error_message,
|
|
848
|
+
type(exception).__name__, exc_cls.__name__,
|
|
849
|
+
extra={
|
|
850
|
+
"error_code": error_code,
|
|
851
|
+
"error_msg": error_message,
|
|
852
|
+
"classified_as": exc_cls.__name__,
|
|
853
|
+
"sql_stmt": sql,
|
|
854
|
+
"sql_params": parameters,
|
|
855
|
+
},
|
|
856
|
+
)
|
|
857
|
+
raise exc_cls(enhanced_message) from exception
|
|
858
|
+
|
|
859
|
+
# ── Unclassified — log and wrap in DbException ───────────────
|
|
838
860
|
logger.error(
|
|
839
861
|
"Unhandled/Unknown Error in engine.process_error",
|
|
840
862
|
exc_info=True,
|
|
841
863
|
extra={
|
|
842
864
|
"error_code": error_code,
|
|
843
865
|
"error_msg": error_message,
|
|
866
|
+
"original_exception_type": type(exception).__name__,
|
|
867
|
+
"available_error_codes": list(code_map.keys()),
|
|
844
868
|
"sql_stmt": sql,
|
|
845
869
|
"sql_params": parameters,
|
|
846
870
|
},
|
|
847
871
|
)
|
|
848
|
-
|
|
849
|
-
# If we can't classify it, re-raise with enhanced message
|
|
850
|
-
raise type(exception)(enhanced_message) from exception
|
|
872
|
+
raise exceptions.DbException(enhanced_message) from exception
|
|
851
873
|
|
|
852
874
|
def _format_sql_with_params(self, sql, parameters):
|
|
853
875
|
"""
|
|
@@ -79,6 +79,30 @@ class BaseSQLDialect(ABC):
|
|
|
79
79
|
"""
|
|
80
80
|
return False
|
|
81
81
|
|
|
82
|
+
@classmethod
|
|
83
|
+
def classify_by_message(cls, msg: str) -> Optional[str]:
|
|
84
|
+
"""Classify an error by its message text when no error code is available.
|
|
85
|
+
|
|
86
|
+
Returns an exception-category key understood by Engine._error_code_map,
|
|
87
|
+
or None if the message cannot be classified. Dialects override this to
|
|
88
|
+
add database-specific message patterns.
|
|
89
|
+
|
|
90
|
+
Recognised keys (matching the code-list attribute names):
|
|
91
|
+
"DuplicateKey", "DatabaseMissing", "TableMissing", "ColumnMissing",
|
|
92
|
+
"Connection", "ObjectExists", "Application", "DataIntegrity",
|
|
93
|
+
"Truncation", "ForeignKeyMissing", "LockTimeout", "RetryTransaction"
|
|
94
|
+
"""
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def enhance_message(cls, msg: str) -> Optional[str]:
|
|
99
|
+
"""Return additional guidance text for a driver error, or None.
|
|
100
|
+
|
|
101
|
+
Dialects override this to provide developer-friendly hints for common
|
|
102
|
+
mistakes (e.g. bare values in WHERE clauses).
|
|
103
|
+
"""
|
|
104
|
+
return None
|
|
105
|
+
|
|
82
106
|
# Core CRUD Operations
|
|
83
107
|
@classmethod
|
|
84
108
|
@abstractmethod
|
|
@@ -116,6 +116,29 @@ class SQL(BaseSQLDialect):
|
|
|
116
116
|
)
|
|
117
117
|
return not any(n in m for n in non_transient)
|
|
118
118
|
|
|
119
|
+
@classmethod
|
|
120
|
+
def classify_by_message(cls, msg: str):
|
|
121
|
+
if not msg:
|
|
122
|
+
return None
|
|
123
|
+
m = msg.strip().lower()
|
|
124
|
+
if "duplicate entry" in m:
|
|
125
|
+
return "DuplicateKey"
|
|
126
|
+
if "unknown database" in m:
|
|
127
|
+
return "DatabaseMissing"
|
|
128
|
+
if "doesn't exist" in m and "table" in m:
|
|
129
|
+
return "TableMissing"
|
|
130
|
+
if "unknown column" in m:
|
|
131
|
+
return "ColumnMissing"
|
|
132
|
+
if "already exists" in m:
|
|
133
|
+
return "ObjectExists"
|
|
134
|
+
if "deadlock found" in m:
|
|
135
|
+
return "RetryTransaction"
|
|
136
|
+
if "lock wait timeout" in m:
|
|
137
|
+
return "LockTimeout"
|
|
138
|
+
if cls.is_connection_error_message(msg):
|
|
139
|
+
return "Connection"
|
|
140
|
+
return None
|
|
141
|
+
|
|
119
142
|
@classmethod
|
|
120
143
|
def select(
|
|
121
144
|
cls,
|
|
@@ -116,6 +116,42 @@ class SQL(BaseSQLDialect):
|
|
|
116
116
|
# For Postgres, low-level disconnects/restarts are typically transient.
|
|
117
117
|
return cls.is_connection_error_message(msg)
|
|
118
118
|
|
|
119
|
+
@classmethod
|
|
120
|
+
def classify_by_message(cls, msg: str):
|
|
121
|
+
if not msg:
|
|
122
|
+
return None
|
|
123
|
+
m = msg.strip().lower()
|
|
124
|
+
# Order matters — more specific patterns first.
|
|
125
|
+
if re.search(r"key \(.*?\)=\(.*?\) already exists", m):
|
|
126
|
+
return "DuplicateKey"
|
|
127
|
+
if re.search(r"duplicate key value violates unique constraint", m):
|
|
128
|
+
return "DuplicateKey"
|
|
129
|
+
if re.search(r"database.*does not exist", m):
|
|
130
|
+
return "DatabaseMissing"
|
|
131
|
+
if "no such database" in m:
|
|
132
|
+
return "DatabaseMissing"
|
|
133
|
+
if re.search(r"relation .* already exists", m):
|
|
134
|
+
return "ObjectExists"
|
|
135
|
+
if "already exists" in m:
|
|
136
|
+
return "ObjectExists"
|
|
137
|
+
if cls.is_connection_error_message(msg):
|
|
138
|
+
return "Connection"
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def enhance_message(cls, msg: str):
|
|
143
|
+
if msg and "argument of where must be type boolean" in msg.lower():
|
|
144
|
+
return (
|
|
145
|
+
"\n\n*** WHERE CLAUSE ERROR ***\n"
|
|
146
|
+
"This error typically occurs when a WHERE clause contains a bare value "
|
|
147
|
+
"instead of a proper boolean expression.\n"
|
|
148
|
+
"Common fixes:\n"
|
|
149
|
+
" - Change WHERE 1001 to WHERE sys_id = 1001\n"
|
|
150
|
+
" - Change WHERE {'column': value} format in dictionaries\n"
|
|
151
|
+
" - Ensure string WHERE clauses are complete SQL expressions"
|
|
152
|
+
)
|
|
153
|
+
return None
|
|
154
|
+
|
|
119
155
|
@staticmethod
|
|
120
156
|
def _validate_where_string(where):
|
|
121
157
|
"""
|
|
@@ -90,6 +90,25 @@ class SQL(BaseSQLDialect):
|
|
|
90
90
|
# SQLite connection/file errors are typically not transient in-process.
|
|
91
91
|
return False
|
|
92
92
|
|
|
93
|
+
@classmethod
|
|
94
|
+
def classify_by_message(cls, msg: str):
|
|
95
|
+
if not msg:
|
|
96
|
+
return None
|
|
97
|
+
m = msg.strip().lower()
|
|
98
|
+
if "unique constraint failed" in m or "is not unique" in m:
|
|
99
|
+
return "DuplicateKey"
|
|
100
|
+
if "no such table:" in m:
|
|
101
|
+
return "TableMissing"
|
|
102
|
+
if "no such column:" in m:
|
|
103
|
+
return "ColumnMissing"
|
|
104
|
+
if "already exists" in m:
|
|
105
|
+
return "ObjectExists"
|
|
106
|
+
if "database is locked" in m:
|
|
107
|
+
return "LockTimeout"
|
|
108
|
+
if cls.is_connection_error_message(msg):
|
|
109
|
+
return "Connection"
|
|
110
|
+
return None
|
|
111
|
+
|
|
93
112
|
@classmethod
|
|
94
113
|
def select(
|
|
95
114
|
cls,
|
|
@@ -113,6 +113,29 @@ class SQL(BaseSQLDialect):
|
|
|
113
113
|
return False
|
|
114
114
|
return True
|
|
115
115
|
|
|
116
|
+
@classmethod
|
|
117
|
+
def classify_by_message(cls, msg: str):
|
|
118
|
+
if not msg:
|
|
119
|
+
return None
|
|
120
|
+
m = msg.strip().lower()
|
|
121
|
+
if "violation of primary key" in m or "violation of unique key" in m:
|
|
122
|
+
return "DuplicateKey"
|
|
123
|
+
if "cannot open database" in m:
|
|
124
|
+
return "DatabaseMissing"
|
|
125
|
+
if "invalid object name" in m:
|
|
126
|
+
return "TableMissing"
|
|
127
|
+
if "invalid column name" in m:
|
|
128
|
+
return "ColumnMissing"
|
|
129
|
+
if "already exists" in m:
|
|
130
|
+
return "ObjectExists"
|
|
131
|
+
if "deadlock victim" in m:
|
|
132
|
+
return "RetryTransaction"
|
|
133
|
+
if "lock request time out" in m:
|
|
134
|
+
return "LockTimeout"
|
|
135
|
+
if cls.is_connection_error_message(msg):
|
|
136
|
+
return "Connection"
|
|
137
|
+
return None
|
|
138
|
+
|
|
116
139
|
@classmethod
|
|
117
140
|
def select(
|
|
118
141
|
cls,
|
{velocity_python-0.1.12 → velocity_python-0.1.14}/src/velocity/db/tests/postgres/test_engine.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import datetime
|
|
3
3
|
import unittest
|
|
4
|
+
from velocity.db import exceptions
|
|
4
5
|
from velocity.db.core.engine import Engine
|
|
5
6
|
from velocity.db.core.transaction import Transaction
|
|
6
7
|
from .common import CommonPostgresTest, engine, test_db
|
|
@@ -51,14 +52,9 @@ class TestEngine(CommonPostgresTest):
|
|
|
51
52
|
assert [] == engine.tables
|
|
52
53
|
|
|
53
54
|
def test_process_error(self, tx):
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
with self.assertRaises(
|
|
58
|
-
Exception
|
|
59
|
-
): # Replace Exception with the specific exception raised by process_error
|
|
60
|
-
local_engine.process_error(sql_stmt=None, sql_params=None)
|
|
61
|
-
# Add additional assertions as needed
|
|
55
|
+
exc = Exception("some driver error")
|
|
56
|
+
with self.assertRaises(exceptions.DbException):
|
|
57
|
+
engine.process_error(exc)
|
|
62
58
|
|
|
63
59
|
def test_transaction_injection_1(self, tx):
|
|
64
60
|
@engine.transaction
|