velocity-python 0.1.14__tar.gz → 0.1.16__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.14/src/velocity_python.egg-info → velocity_python-0.1.16}/PKG-INFO +1 -1
- {velocity_python-0.1.14 → velocity_python-0.1.16}/pyproject.toml +1 -1
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/__init__.py +2 -3
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/pdf.py +3 -1
- {velocity_python-0.1.14 → velocity_python-0.1.16/src/velocity_python.egg-info}/PKG-INFO +1 -1
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity_python.egg-info/SOURCES.txt +3 -15
- velocity_python-0.1.14/src/velocity/app/formbuilder/__init__.py +0 -1
- velocity_python-0.1.14/src/velocity/app/formbuilder/reshaper.py +0 -201
- velocity_python-0.1.14/src/velocity/app/invoices.py +0 -0
- velocity_python-0.1.14/src/velocity/app/orders.py +0 -179
- velocity_python-0.1.14/src/velocity/app/payments.py +0 -0
- velocity_python-0.1.14/src/velocity/app/purchase_orders.py +0 -0
- velocity_python-0.1.14/src/velocity/app/tests/__init__.py +0 -1
- velocity_python-0.1.14/src/velocity/app/validators/__init__.py +0 -1
- velocity_python-0.1.14/src/velocity/app/validators/formbuilder_template.py +0 -204
- velocity_python-0.1.14/src/velocity/misc/__init__.py +0 -0
- velocity_python-0.1.14/tests/test_formbuilder_reshaper.py +0 -315
- velocity_python-0.1.14/tests/test_formbuilder_template_validator.py +0 -240
- {velocity_python-0.1.14 → velocity_python-0.1.16}/LICENSE +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/README.md +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/setup.cfg +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.14/src/velocity/app → velocity_python-0.1.16/src/velocity/db/core}/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.14/src/velocity/db/core → velocity_python-0.1.16/src/velocity/db/servers}/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.14/src/velocity/db/servers → velocity_python-0.1.16/src/velocity/misc}/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/demo_profiles.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/profiles.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/router.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.14/src/velocity/app → velocity_python-0.1.16}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_observability.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_payment_demo_profiles.py +0 -0
- {velocity_python-0.1.14/src/velocity/app → velocity_python-0.1.16}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_payment_profiles.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_payment_router.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_row_dirty_tracking.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.14/src/velocity/app → velocity_python-0.1.16}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.14 → velocity_python-0.1.16}/tests/test_where_clause_validation.py +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
__version__ = version = "0.1.
|
|
1
|
+
__version__ = version = "0.1.16"
|
|
2
2
|
|
|
3
3
|
import importlib as _importlib
|
|
4
4
|
|
|
5
5
|
from . import db
|
|
6
6
|
from . import misc
|
|
7
|
-
from . import app
|
|
8
7
|
|
|
9
|
-
__all__ = ["aws", "db", "misc"
|
|
8
|
+
__all__ = ["aws", "db", "misc"]
|
|
10
9
|
|
|
11
10
|
_LAZY_SUBMODULES = {"aws"}
|
|
12
11
|
|
|
@@ -46,7 +46,9 @@ if "AWS_LAMBDA_FUNCTION_NAME" in os.environ:
|
|
|
46
46
|
|
|
47
47
|
try:
|
|
48
48
|
import weasyprint
|
|
49
|
-
except ImportError:
|
|
49
|
+
except (ImportError, OSError):
|
|
50
|
+
# OSError: WeasyPrint's ffi.py raises OSError when native libs
|
|
51
|
+
# (libgobject, libpango, etc.) cannot be loaded via cffi.dlopen().
|
|
50
52
|
weasyprint = None # type: ignore[assignment]
|
|
51
53
|
|
|
52
54
|
_DEFAULT_BODY_CSS = """\
|
|
@@ -3,19 +3,6 @@ README.md
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
src/velocity/__init__.py
|
|
5
5
|
src/velocity/logging.py
|
|
6
|
-
src/velocity/app/__init__.py
|
|
7
|
-
src/velocity/app/invoices.py
|
|
8
|
-
src/velocity/app/orders.py
|
|
9
|
-
src/velocity/app/payments.py
|
|
10
|
-
src/velocity/app/purchase_orders.py
|
|
11
|
-
src/velocity/app/formbuilder/__init__.py
|
|
12
|
-
src/velocity/app/formbuilder/reshaper.py
|
|
13
|
-
src/velocity/app/tests/__init__.py
|
|
14
|
-
src/velocity/app/tests/test_email_processing.py
|
|
15
|
-
src/velocity/app/tests/test_payment_profile_sorting.py
|
|
16
|
-
src/velocity/app/tests/test_spreadsheet_functions.py
|
|
17
|
-
src/velocity/app/validators/__init__.py
|
|
18
|
-
src/velocity/app/validators/formbuilder_template.py
|
|
19
6
|
src/velocity/aws/__init__.py
|
|
20
7
|
src/velocity/aws/amplify.py
|
|
21
8
|
src/velocity/aws/amplify_build.py
|
|
@@ -158,8 +145,7 @@ tests/test_concurrency_safety.py
|
|
|
158
145
|
tests/test_connection_pool.py
|
|
159
146
|
tests/test_connection_resilience.py
|
|
160
147
|
tests/test_decorators.py
|
|
161
|
-
tests/
|
|
162
|
-
tests/test_formbuilder_template_validator.py
|
|
148
|
+
tests/test_email_processing.py
|
|
163
149
|
tests/test_iconv_money_to_cents.py
|
|
164
150
|
tests/test_lambda_handler.py
|
|
165
151
|
tests/test_lambda_handler_auth.py
|
|
@@ -168,6 +154,7 @@ tests/test_n_plus_one.py
|
|
|
168
154
|
tests/test_observability.py
|
|
169
155
|
tests/test_payment_braintree_adapter.py
|
|
170
156
|
tests/test_payment_demo_profiles.py
|
|
157
|
+
tests/test_payment_profile_sorting.py
|
|
171
158
|
tests/test_payment_profiles.py
|
|
172
159
|
tests/test_payment_router.py
|
|
173
160
|
tests/test_payment_stripe_adapter.py
|
|
@@ -180,6 +167,7 @@ tests/test_row_cache_staleness.py
|
|
|
180
167
|
tests/test_row_dirty_tracking.py
|
|
181
168
|
tests/test_schema_migrations.py
|
|
182
169
|
tests/test_security_hardening.py
|
|
170
|
+
tests/test_spreadsheet_functions.py
|
|
183
171
|
tests/test_sqs_per_record_transactions.py
|
|
184
172
|
tests/test_sys_modified_count_postgres_demo.py
|
|
185
173
|
tests/test_table_alter.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""velocity.app.formbuilder — shared logic for form_builder_template records."""
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
"""velocity.app.formbuilder.reshaper
|
|
2
|
-
|
|
3
|
-
Reshape a raw ``form_builder_template`` database row into the public ``fb``
|
|
4
|
-
payload structure as produced by ``DonateMainEvents.OnActionGetFormBuilder``.
|
|
5
|
-
|
|
6
|
-
The single public entry-point is :func:`reshape_formbuilder_template`. It is
|
|
7
|
-
a **pure function** — the input is deep-copied and never mutated.
|
|
8
|
-
|
|
9
|
-
Payment tokens, reCAPTCHA keys, and live thermometer totals are **not**
|
|
10
|
-
included; those are runtime secrets and database query results that the caller
|
|
11
|
-
must add separately (as DonateMain does in
|
|
12
|
-
``OnActionGetFormBuilder``). The returned dict is safe to serialise and
|
|
13
|
-
return as a preview payload.
|
|
14
|
-
|
|
15
|
-
Usage::
|
|
16
|
-
|
|
17
|
-
from velocity.app.formbuilder.reshaper import reshape_formbuilder_template
|
|
18
|
-
|
|
19
|
-
fb = reshape_formbuilder_template(template_row.to_dict())
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
import ast
|
|
23
|
-
import copy
|
|
24
|
-
from typing import Any, Dict, Optional
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# ---------------------------------------------------------------------------
|
|
28
|
-
# Internal per-metric / per-donation helpers
|
|
29
|
-
# ---------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
def _parse_key_value_string(raw: Optional[str]) -> Dict[str, Any]:
|
|
32
|
-
"""Parse a ``"key1: val1, key2: val2"`` string into a dict.
|
|
33
|
-
|
|
34
|
-
Wraps the string in braces and calls ``ast.literal_eval``, exactly as the
|
|
35
|
-
original DonateMain ``getMetric`` / ``getDonation`` functions do.
|
|
36
|
-
Returns an empty dict on failure so a bad value never crashes the reshaper.
|
|
37
|
-
"""
|
|
38
|
-
if not raw:
|
|
39
|
-
return {}
|
|
40
|
-
try:
|
|
41
|
-
return ast.literal_eval("{" + raw + "}")
|
|
42
|
-
except Exception:
|
|
43
|
-
return {}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _extract_metric(count: int, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
47
|
-
"""Extract metric_{count}_* fields from *data* (mutates *data*).
|
|
48
|
-
|
|
49
|
-
Returns the nested metric dict when the metric has a label and is not
|
|
50
|
-
hidden, otherwise returns ``{}``. Either way all flat metric_N_* keys
|
|
51
|
-
are removed from *data*.
|
|
52
|
-
"""
|
|
53
|
-
prefix = f"metric_{count}_"
|
|
54
|
-
flat_keys = [
|
|
55
|
-
"header", "image", "label", "secondarytext", "helpertext",
|
|
56
|
-
"values", "defaultvalue", "show_other", "other_minimum_value",
|
|
57
|
-
"orientation",
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
is_hidden = data.get(f"{prefix}hide_donation_from_ui")
|
|
61
|
-
has_label = data.get(f"{prefix}label")
|
|
62
|
-
|
|
63
|
-
if not is_hidden and has_label:
|
|
64
|
-
result = {
|
|
65
|
-
"header": data.pop(f"{prefix}header", None),
|
|
66
|
-
"image": data.pop(f"{prefix}image", None),
|
|
67
|
-
"label": data.pop(f"{prefix}label", None),
|
|
68
|
-
"secondarytext": data.pop(f"{prefix}secondarytext", None),
|
|
69
|
-
"helpertext": data.pop(f"{prefix}helpertext", None),
|
|
70
|
-
"values": _parse_key_value_string(data.pop(f"{prefix}values", None)),
|
|
71
|
-
"defaultvalue": data.pop(f"{prefix}defaultvalue", None),
|
|
72
|
-
"show_other": data.pop(f"{prefix}show_other", ""),
|
|
73
|
-
"other_minimum_value": data.pop(f"{prefix}other_minimum_value", ""),
|
|
74
|
-
"orientation": data.pop(f"{prefix}orientation", ""),
|
|
75
|
-
}
|
|
76
|
-
data.pop(f"{prefix}hide_donation_from_ui", None)
|
|
77
|
-
return result
|
|
78
|
-
|
|
79
|
-
# Strip all flat keys even when hidden / empty
|
|
80
|
-
for key in flat_keys:
|
|
81
|
-
data.pop(f"{prefix}{key}", None)
|
|
82
|
-
data.pop(f"{prefix}hide_donation_from_ui", None)
|
|
83
|
-
return {}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def _extract_donation(count: int, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
87
|
-
"""Extract donation_{count}_* fields from *data* (mutates *data*).
|
|
88
|
-
|
|
89
|
-
Returns the nested donation dict when the donation has a label and is not
|
|
90
|
-
hidden, otherwise returns ``{}``. Either way all flat donation_N_* keys
|
|
91
|
-
are removed from *data*.
|
|
92
|
-
"""
|
|
93
|
-
prefix = f"donation_{count}_"
|
|
94
|
-
flat_keys = [
|
|
95
|
-
"header", "image", "html", "label", "secondarytext", "helpertext",
|
|
96
|
-
"values", "defaultvalue", "show_other", "other_minimum_value",
|
|
97
|
-
"orientation", "dropdown", "dropdown_label",
|
|
98
|
-
]
|
|
99
|
-
|
|
100
|
-
is_hidden = data.get(f"{prefix}hide_donation_from_ui")
|
|
101
|
-
has_label = data.get(f"{prefix}label")
|
|
102
|
-
|
|
103
|
-
if not is_hidden and has_label:
|
|
104
|
-
result = {
|
|
105
|
-
"header": data.pop(f"{prefix}header", None),
|
|
106
|
-
"image": data.pop(f"{prefix}image", None),
|
|
107
|
-
"html": data.pop(f"{prefix}html", None),
|
|
108
|
-
"label": data.pop(f"{prefix}label", None),
|
|
109
|
-
"secondarytext": data.pop(f"{prefix}secondarytext", None),
|
|
110
|
-
"helpertext": data.pop(f"{prefix}helpertext", None),
|
|
111
|
-
"values": _parse_key_value_string(data.pop(f"{prefix}values", None)),
|
|
112
|
-
"defaultvalue": data.pop(f"{prefix}defaultvalue", None),
|
|
113
|
-
"show_other": data.pop(f"{prefix}show_other", ""),
|
|
114
|
-
"other_minimum_value": data.pop(f"{prefix}other_minimum_value", ""),
|
|
115
|
-
"orientation": data.pop(f"{prefix}orientation", ""),
|
|
116
|
-
"dropdown": data.pop(f"{prefix}dropdown", None),
|
|
117
|
-
"dropdown_label": data.pop(f"{prefix}dropdown_label", None),
|
|
118
|
-
}
|
|
119
|
-
data.pop(f"{prefix}hide_donation_from_ui", None)
|
|
120
|
-
return result
|
|
121
|
-
|
|
122
|
-
for key in flat_keys:
|
|
123
|
-
data.pop(f"{prefix}{key}", None)
|
|
124
|
-
data.pop(f"{prefix}hide_donation_from_ui", None)
|
|
125
|
-
return {}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# ---------------------------------------------------------------------------
|
|
129
|
-
# Public API
|
|
130
|
-
# ---------------------------------------------------------------------------
|
|
131
|
-
|
|
132
|
-
def reshape_formbuilder_template(raw_row: Dict[str, Any]) -> Dict[str, Any]:
|
|
133
|
-
"""Reshape a raw ``form_builder_template`` DB row into the public ``fb`` dict.
|
|
134
|
-
|
|
135
|
-
This replicates exactly what ``DonateMainEvents.OnActionGetFormBuilder``
|
|
136
|
-
does to reshape the flat database row before returning it to the browser,
|
|
137
|
-
without the live DB queries (thermometer totals) or runtime secrets
|
|
138
|
-
(payment tokens, reCAPTCHA keys).
|
|
139
|
-
|
|
140
|
-
The caller is responsible for:
|
|
141
|
-
|
|
142
|
-
- Passing in a plain Python dict (call ``.to_dict()`` on a velocity DB
|
|
143
|
-
row first so that Decimal and datetime values are already serialisable).
|
|
144
|
-
- Optionally adding ``fb["thermometer"]`` / ``fb["rival_thermometer"]``
|
|
145
|
-
after the call if live totals are desired.
|
|
146
|
-
|
|
147
|
-
Returns a new dict; the input is never mutated.
|
|
148
|
-
|
|
149
|
-
Example::
|
|
150
|
-
|
|
151
|
-
row = tx.table("form_builder_template").one({"sys_id": sys_id})
|
|
152
|
-
fb = reshape_formbuilder_template(row.to_dict())
|
|
153
|
-
"""
|
|
154
|
-
fb = copy.deepcopy(raw_row)
|
|
155
|
-
|
|
156
|
-
fb["metrics"] = {
|
|
157
|
-
f"metric_{i}": _extract_metric(i, fb) for i in range(1, 10)
|
|
158
|
-
}
|
|
159
|
-
fb["donations"] = {
|
|
160
|
-
f"donation_{i}": _extract_donation(i, fb) for i in range(1, 10)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
# Expose the primary key under the public name used by DonateMain
|
|
164
|
-
fb["_num_entries"] = fb.get("sys_id")
|
|
165
|
-
|
|
166
|
-
# Strip internal / private fields
|
|
167
|
-
for key in list(fb.keys()):
|
|
168
|
-
if key.startswith("sys_"):
|
|
169
|
-
del fb[key]
|
|
170
|
-
|
|
171
|
-
for key in (
|
|
172
|
-
# UI-only computed column (row counter) — never a real DB column
|
|
173
|
-
"row_number",
|
|
174
|
-
"url_slug",
|
|
175
|
-
"url_slug_alternate",
|
|
176
|
-
# Administrative / validation metadata — not read by DonateMain frontend
|
|
177
|
-
"is_published",
|
|
178
|
-
"datetime_last_validated",
|
|
179
|
-
"last_validation_result",
|
|
180
|
-
"last_validation_reason",
|
|
181
|
-
# Backend-only: security / fraud prevention
|
|
182
|
-
"whitelist_end_date",
|
|
183
|
-
"recaptcha_version",
|
|
184
|
-
"recaptcha_v3_score_threshold",
|
|
185
|
-
# Backend-only: routing / campaign metadata
|
|
186
|
-
"campaign",
|
|
187
|
-
"sub_campaign",
|
|
188
|
-
# Backend-only: email receipts (server-side sending only)
|
|
189
|
-
"receipt_from_address",
|
|
190
|
-
"receipt_subject",
|
|
191
|
-
"receipt_body_text",
|
|
192
|
-
"mail_bcc",
|
|
193
|
-
# Backend-only: rally out-of-band receipts
|
|
194
|
-
"rally_receipt_from_address",
|
|
195
|
-
"rally_receipt_subject",
|
|
196
|
-
"rally_receipt_body_text",
|
|
197
|
-
"rally_mail_bcc",
|
|
198
|
-
):
|
|
199
|
-
fb.pop(key, None)
|
|
200
|
-
|
|
201
|
-
return fb
|
|
File without changes
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import pprint
|
|
3
|
-
import velocity.db
|
|
4
|
-
|
|
5
|
-
engine = velocity.db.postgres.initialize()
|
|
6
|
-
REQUIRED = object()
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@engine.transaction
|
|
10
|
-
class Order:
|
|
11
|
-
SCHEMA = {
|
|
12
|
-
"headers": {
|
|
13
|
-
"customer_email": REQUIRED,
|
|
14
|
-
"order_date": REQUIRED,
|
|
15
|
-
"order_type": REQUIRED,
|
|
16
|
-
},
|
|
17
|
-
"lineitems": {
|
|
18
|
-
"sku": REQUIRED,
|
|
19
|
-
"qty": REQUIRED,
|
|
20
|
-
"price": REQUIRED,
|
|
21
|
-
},
|
|
22
|
-
"lineitems_supp": {
|
|
23
|
-
"note": str,
|
|
24
|
-
},
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
DEFAULTS = {
|
|
28
|
-
"headers": {
|
|
29
|
-
"order_date": lambda: datetime.date.today(),
|
|
30
|
-
"effective_date": lambda: datetime.date.today(),
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
def __init__(self, order_id=None):
|
|
35
|
-
self.order_id = order_id
|
|
36
|
-
self.headers = {}
|
|
37
|
-
self.lineitems = {}
|
|
38
|
-
self.lineitems_supp = {}
|
|
39
|
-
|
|
40
|
-
def __repr__(self):
|
|
41
|
-
return f"Order(order_id={self.order_id}, headers={pprint.pformat(self.headers)}, lineitems={pprint.pformat(self.lineitems)}, lineitems_supp={pprint.pformat(self.lineitems_supp)})"
|
|
42
|
-
|
|
43
|
-
def exists(self, tx):
|
|
44
|
-
if not self.order_id:
|
|
45
|
-
raise ValueError("order_id must be set to check existence")
|
|
46
|
-
return tx.table("orders").find(self.order_id)
|
|
47
|
-
|
|
48
|
-
def __bool__(self):
|
|
49
|
-
return bool(self.order_id) and self.exists(engine.transaction())
|
|
50
|
-
|
|
51
|
-
def load(self, tx):
|
|
52
|
-
if not self.order_id:
|
|
53
|
-
raise ValueError("order_id must be set to load an order")
|
|
54
|
-
|
|
55
|
-
order = tx.table("orders").one(self.order_id)
|
|
56
|
-
if not order:
|
|
57
|
-
raise ValueError(f"Order {self.order_id} not found")
|
|
58
|
-
|
|
59
|
-
self.headers = dict(order)
|
|
60
|
-
|
|
61
|
-
items = (
|
|
62
|
-
tx.table("order_lineitems")
|
|
63
|
-
.select(where={"order_id": self.order_id}, orderby="line_number")
|
|
64
|
-
.all()
|
|
65
|
-
)
|
|
66
|
-
for idx, row in enumerate(items):
|
|
67
|
-
self.lineitems[idx] = dict(row)
|
|
68
|
-
|
|
69
|
-
supps = (
|
|
70
|
-
tx.table("order_lineitems_supp")
|
|
71
|
-
.select(where={"order_id": self.order_id}, orderby="line_number")
|
|
72
|
-
.all()
|
|
73
|
-
)
|
|
74
|
-
for idx, row in enumerate(supps):
|
|
75
|
-
self.lineitems_supp[idx] = dict(row)
|
|
76
|
-
|
|
77
|
-
def update_header(self, key, value):
|
|
78
|
-
self.headers[key] = value
|
|
79
|
-
|
|
80
|
-
def add_lineitem(self, data: dict, supp_data: dict = None):
|
|
81
|
-
index = len(self.lineitems)
|
|
82
|
-
self.lineitems[index] = data
|
|
83
|
-
self.lineitems_supp[index] = supp_data or {}
|
|
84
|
-
|
|
85
|
-
def update_lineitem(self, index: int, data: dict = None, supp_data: dict = None):
|
|
86
|
-
if index not in self.lineitems:
|
|
87
|
-
raise IndexError(f"No line item at index {index}")
|
|
88
|
-
if data:
|
|
89
|
-
self.lineitems[index].update(data)
|
|
90
|
-
if supp_data is not None:
|
|
91
|
-
self.lineitems_supp[index].update(supp_data)
|
|
92
|
-
|
|
93
|
-
def delete_lineitem(self, index: int):
|
|
94
|
-
if index not in self.lineitems:
|
|
95
|
-
raise IndexError(f"No line item at index {index}")
|
|
96
|
-
del self.lineitems[index]
|
|
97
|
-
if index in self.lineitems_supp:
|
|
98
|
-
del self.lineitems_supp[index]
|
|
99
|
-
self._reindex_lineitems()
|
|
100
|
-
|
|
101
|
-
def _reindex_lineitems(self):
|
|
102
|
-
"""Re-index lineitems and supplemental data after deletion."""
|
|
103
|
-
new_items = {}
|
|
104
|
-
new_supps = {}
|
|
105
|
-
for i, key in enumerate(sorted(self.lineitems)):
|
|
106
|
-
new_items[i] = self.lineitems[key]
|
|
107
|
-
new_supps[i] = self.lineitems_supp.get(key, {})
|
|
108
|
-
self.lineitems = new_items
|
|
109
|
-
self.lineitems_supp = new_supps
|
|
110
|
-
|
|
111
|
-
def _apply_defaults(self):
|
|
112
|
-
for section, defaults in self.DEFAULTS.items():
|
|
113
|
-
target = getattr(self, section)
|
|
114
|
-
for key, default in defaults.items():
|
|
115
|
-
if key not in target:
|
|
116
|
-
target[key] = default() if callable(default) else default
|
|
117
|
-
|
|
118
|
-
def _validate(self):
|
|
119
|
-
self._apply_defaults()
|
|
120
|
-
|
|
121
|
-
for key, requirement in self.SCHEMA["headers"].items():
|
|
122
|
-
if requirement is REQUIRED and key not in self.headers:
|
|
123
|
-
raise ValueError(f"Missing required header field: {key}")
|
|
124
|
-
if (
|
|
125
|
-
key in self.headers
|
|
126
|
-
and requirement is not REQUIRED
|
|
127
|
-
and not isinstance(self.headers[key], requirement)
|
|
128
|
-
):
|
|
129
|
-
raise TypeError(
|
|
130
|
-
f"Header field '{key}' must be of type {requirement.__name__}"
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
for idx, item in self.lineitems.items():
|
|
134
|
-
for key, requirement in self.SCHEMA["lineitems"].items():
|
|
135
|
-
if requirement is REQUIRED and key not in item:
|
|
136
|
-
raise ValueError(f"Line item {idx} missing required field: {key}")
|
|
137
|
-
|
|
138
|
-
for idx, supp in self.lineitems_supp.items():
|
|
139
|
-
for key, expected in self.SCHEMA["lineitems_supp"].items():
|
|
140
|
-
if key in supp and not isinstance(supp[key], expected):
|
|
141
|
-
raise TypeError(
|
|
142
|
-
f"Supplemental field '{key}' in item {idx} must be of type {expected.__name__}"
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
def persist(self, tx):
|
|
146
|
-
self._validate()
|
|
147
|
-
|
|
148
|
-
if self.order_id:
|
|
149
|
-
tx.table("orders").update(self.headers, self.order_id)
|
|
150
|
-
else:
|
|
151
|
-
record = tx.table("orders").new(self.headers)
|
|
152
|
-
self.order_id = record["sys_id"]
|
|
153
|
-
|
|
154
|
-
tx.table("order_lineitems").delete(where={"order_id": self.order_id})
|
|
155
|
-
tx.table("order_lineitems_supp").delete(where={"order_id": self.order_id})
|
|
156
|
-
|
|
157
|
-
for index in sorted(self.lineitems):
|
|
158
|
-
tx.table("order_lineitems").insert(
|
|
159
|
-
{
|
|
160
|
-
"order_id": self.order_id,
|
|
161
|
-
"line_number": index,
|
|
162
|
-
**self.lineitems[index],
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
tx.table("order_lineitems_supp").insert(
|
|
166
|
-
{
|
|
167
|
-
"order_id": self.order_id,
|
|
168
|
-
"line_number": index,
|
|
169
|
-
**self.lineitems_supp.get(index, {}),
|
|
170
|
-
}
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
def to_dict(self):
|
|
174
|
-
return {
|
|
175
|
-
"order_id": self.order_id,
|
|
176
|
-
"headers": self.headers,
|
|
177
|
-
"lineitems": self.lineitems,
|
|
178
|
-
"lineitems_supp": self.lineitems_supp,
|
|
179
|
-
}
|
|
File without changes
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# App module tests
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""velocity.app.validators — domain validators for shared application entities."""
|