velocity-python 0.1.121__tar.gz → 0.1.123__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.121 → velocity_python-0.1.123}/PKG-INFO +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/pyproject.toml +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/__init__.py +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/__init__.py +2 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/provisioning.py +9 -2
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/feature_flags.py +3 -3
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/base_handler.py +7 -6
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/context.py +11 -4
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/masquerade.py +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/data_service.py +2 -2
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/job_handler.py +3 -3
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/session_control.py +2 -2
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/job_results.py +6 -3
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/s3.py +79 -28
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/result.py +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/maintenance.py +20 -7
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/postgres/__init__.py +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_postgres_unchanged.py +3 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_process_error_robustness.py +4 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_mail_send.py +2 -2
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/braintree_adapter.py +3 -3
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/stripe_adapter.py +3 -3
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/PKG-INFO +1 -1
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_amplify_build.py +11 -11
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_capabilities.py +24 -2
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_db_maintenance.py +42 -11
- velocity_python-0.1.123/tests/test_enqueue_metric_namespace.py +52 -0
- velocity_python-0.1.123/tests/test_s3_bucket_config.py +94 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/LICENSE +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/README.md +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/setup.cfg +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/assets/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/assets/backfill.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/assets/indexing.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/assets/references.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/assets/service.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/assets/usage_index.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/blobs.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/base.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/dispatch.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/infra.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/jobs.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/retention.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/security.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/single_session.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/deploy/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/deploy/config.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/deploy/operations.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/deploy/policies.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/deploy/reconcile.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/deploy/targets.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/dirty_pipeline.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/email.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/facets.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/job_lifecycle.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/mirror.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/ops.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/sms.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/ssm_config.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_amplify_build_policy_size.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_amplify_build_shim.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_email.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/tests/test_sms.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/cache.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/jsonproxy.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/lazy_engine.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/conftest.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/pdf.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/core/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/core/capabilities.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/core/store.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/core/where.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/exceptions.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/base/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/memory/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/nosql/servers/redis/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/authorizenet_mirror.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/braintree_mirror.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/stripe_mirror.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_access_error_403.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_activity_tracking_aborted_tx.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_asset_indexing.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_asset_references.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_assets_service.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_blob_store.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_capability_catalog.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_cognito_user_cache.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_column_tx_arg.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_context_flags_loader.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_context_job_descriptions.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_data_service_query_cap.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_data_service_renumber.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_data_service_save_as.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_db_credentials_ssm_cascade.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_delete_hook_fk_blocked.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_dirty_pipeline_fast_path.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_enqueue_send_failures.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_facets.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_feature_flags.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_get_cognito_user_provider.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_http_handler_rollback.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_identifier_injection_guard.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_job_handler.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_job_lifecycle.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_job_results.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_json_columns.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_jsonb_dict_adapter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_lambda_handler_masquerade.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_lambda_handler_user_cache.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_lazy_engine.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_masquerade_grant.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_mirror.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_nosql_dynamodb.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_nosql_memory.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_nosql_mongodb.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_nosql_redis.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_nosql_translation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_nosql_where.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_observability.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_on_commit.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_ops.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_payment_authorizenet_adapter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_payment_braintree_mirror.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_payment_mirror_empty_table.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_query_missing_table_unlocked.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_read_cache.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_response.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_restricted_direct_tables.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_result_returning.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_retry_side_effect_guard.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_return_default_safety.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_security_capability.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_server_cursor.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_session_control.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_single_autocommit_safety.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_single_session_capability.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_sqlite_backend.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_ssm_config.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_store_user_data.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_table_find_cache.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_table_purge.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_transaction_class_wrapping.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_transaction_commit_and_ownership.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_transaction_edge_cases.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_where_clause_validation.py +0 -0
- {velocity_python-0.1.121 → velocity_python-0.1.123}/tests/test_write_hook_create_flow.py +0 -0
|
@@ -44,6 +44,7 @@ _LAZY_ATTRS = {
|
|
|
44
44
|
"CLIENT_FILES_BUCKET": "velocity.aws.s3",
|
|
45
45
|
"PUBLIC_ASSETS_BUCKET": "velocity.aws.s3",
|
|
46
46
|
"BACKOFFICE_BUCKET": "velocity.aws.s3",
|
|
47
|
+
"ADMIN_ASSETS_BUCKET": "velocity.aws.s3",
|
|
47
48
|
"PRIVATE_BUCKETS": "velocity.aws.s3",
|
|
48
49
|
"ALLOWED_UPLOAD_BUCKETS": "velocity.aws.s3",
|
|
49
50
|
# Asset helpers
|
|
@@ -96,6 +97,7 @@ __all__ = [
|
|
|
96
97
|
"CLIENT_FILES_BUCKET",
|
|
97
98
|
"PUBLIC_ASSETS_BUCKET",
|
|
98
99
|
"BACKOFFICE_BUCKET",
|
|
100
|
+
"ADMIN_ASSETS_BUCKET",
|
|
99
101
|
"PRIVATE_BUCKETS",
|
|
100
102
|
"ALLOWED_UPLOAD_BUCKETS",
|
|
101
103
|
"AssetBackfillSummary",
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/capabilities/provisioning.py
RENAMED
|
@@ -102,8 +102,15 @@ def provision(tx, stage: str, entries, *, now=None) -> list:
|
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
def _seed_flag_defaults(tx, stage, cap):
|
|
105
|
-
"""Ensure the knob columns exist and fill only the ones that are unset.
|
|
106
|
-
|
|
105
|
+
"""Ensure the knob columns exist and fill only the ones that are unset.
|
|
106
|
+
|
|
107
|
+
The key column rides along: on a fresh site database this call is what
|
|
108
|
+
CREATES sys_feature_flags, and without ``applied_system`` the get() below
|
|
109
|
+
would 42703 (swallowed by @return_default, so it looked like the normal
|
|
110
|
+
missing-row case and warned on every deploy — dance/demo 2026-09-26)."""
|
|
111
|
+
tx.table(FLAGS_TABLE).ensure_schema(
|
|
112
|
+
{feature_flags.SYSTEM_COLUMN: "TEXT", **{key: "TEXT" for key in cap.defaults}}
|
|
113
|
+
)
|
|
107
114
|
row = feature_flags.get(tx, stage)
|
|
108
115
|
if not row:
|
|
109
116
|
return # the app's own seed creates the stage row; nothing to fill yet
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Environment-scoped feature flags with cross-database mirroring.
|
|
2
2
|
|
|
3
|
-
Generalises a pattern proven in production (
|
|
3
|
+
Generalises a pattern proven in production (an admin back-office app): a
|
|
4
4
|
``sys_feature_flags`` table that holds **one row per system**, keyed by an
|
|
5
5
|
``applied_system`` column, where every copy of the database carries every
|
|
6
6
|
system's row. Two behaviours follow:
|
|
@@ -143,7 +143,7 @@ def load(tx, loader=None) -> dict:
|
|
|
143
143
|
An injected ``loader(tx)`` wins (apps that resolve flags their own way);
|
|
144
144
|
otherwise :func:`get_cached` — velocity's stage-scoped reader behind the
|
|
145
145
|
container cache — is the source, never raising into the request. The
|
|
146
|
-
legacy
|
|
146
|
+
legacy ``support.app.helpers`` loader (an app-layer package) remains only as a last
|
|
147
147
|
resort when the velocity reader finds no row (it raises on a missing
|
|
148
148
|
row, which those apps rely on); absent that package the answer is ``{}``.
|
|
149
149
|
"""
|
|
@@ -159,7 +159,7 @@ def load(tx, loader=None) -> dict:
|
|
|
159
159
|
|
|
160
160
|
|
|
161
161
|
def _legacy_support_loader(tx):
|
|
162
|
-
"""
|
|
162
|
+
"""The legacy app-layer ``support.app.helpers`` reader, or None when that package
|
|
163
163
|
is not installed. Kept as its own seam so the fallback can be exercised
|
|
164
164
|
(or silenced) deterministically wherever the layer happens to be on the
|
|
165
165
|
path. It keeps its own raise-on-missing-row behaviour on purpose."""
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/base_handler.py
RENAMED
|
@@ -64,12 +64,13 @@ class BaseHandler:
|
|
|
64
64
|
def _update_lambda_ca_certificates(self):
|
|
65
65
|
"""Configure SSL certificates for HTTPS requests in Lambda environments."""
|
|
66
66
|
# This is helpful for running HTTPS clients on lambda.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
os.environ
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
# A layer may ship a CA bundle at /opt/python; set an explicit
|
|
68
|
+
# ``VELOCITY_CA_BUNDLE`` path to use one elsewhere (e.g. local dev).
|
|
69
|
+
bundle = (
|
|
70
|
+
os.environ.get("VELOCITY_CA_BUNDLE") or "/opt/python/ca-certificates.crt"
|
|
71
|
+
)
|
|
72
|
+
if os.path.exists(bundle):
|
|
73
|
+
os.environ["REQUESTS_CA_BUNDLE"] = bundle
|
|
73
74
|
|
|
74
75
|
def get_calling_function(self) -> str:
|
|
75
76
|
"""
|
|
@@ -42,8 +42,14 @@ def _get_work_queue_name() -> str:
|
|
|
42
42
|
return queue_name
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
DEFAULT_ENQUEUE_METRIC_NAMESPACE = "Velocity/Enqueue"
|
|
46
|
+
|
|
47
|
+
|
|
45
48
|
def _emit_enqueue_failure_metric(action, count):
|
|
46
|
-
"""Emit a CloudWatch ``
|
|
49
|
+
"""Emit a CloudWatch ``SendFailures`` metric.
|
|
50
|
+
|
|
51
|
+
The namespace is the ``EnqueueMetricNamespace`` config key (SSM/env), default
|
|
52
|
+
``Velocity/Enqueue``; set it to keep existing alarms pointed at the metric.
|
|
47
53
|
|
|
48
54
|
SQS send failures are a pre-queue loss the dead-letter queue can never see
|
|
49
55
|
(a message that was never sent never reaches the DLQ), so this metric makes
|
|
@@ -55,7 +61,8 @@ def _emit_enqueue_failure_metric(action, count):
|
|
|
55
61
|
try:
|
|
56
62
|
stage = config_get_stage("") or "unknown"
|
|
57
63
|
boto3.client("cloudwatch").put_metric_data(
|
|
58
|
-
Namespace="
|
|
64
|
+
Namespace=config_getenv("EnqueueMetricNamespace")
|
|
65
|
+
or DEFAULT_ENQUEUE_METRIC_NAMESPACE,
|
|
59
66
|
MetricData=[
|
|
60
67
|
{
|
|
61
68
|
"MetricName": "SendFailures",
|
|
@@ -726,7 +733,7 @@ class Context:
|
|
|
726
733
|
|
|
727
734
|
An injected loader wins. Otherwise velocity's own stage-scoped reader
|
|
728
735
|
(``velocity.aws.feature_flags.get``) is the source — one reader for
|
|
729
|
-
the whole framework. The legacy
|
|
736
|
+
the whole framework. The legacy app-layer ``support.app.helpers``
|
|
730
737
|
loader remains only as a last resort when the velocity reader finds
|
|
731
738
|
no row (it raises on a missing row, which those apps rely on).
|
|
732
739
|
"""
|
|
@@ -834,7 +841,7 @@ class Context:
|
|
|
834
841
|
|
|
835
842
|
# Federated identities that are not Cognito User Pool logins — e.g.
|
|
836
843
|
# developer-authenticated Identity Pool identities used for admin
|
|
837
|
-
# masquerade — carry a provider name (like "login.
|
|
844
|
+
# masquerade — carry a provider name (like "login.example.masquerade")
|
|
838
845
|
# that is not a user-pool id. Detect that and fail with a clear message
|
|
839
846
|
# rather than passing an invalid value to admin_get_user (which raises a
|
|
840
847
|
# cryptic "userPoolId failed to satisfy constraint" error).
|
|
@@ -21,7 +21,7 @@ Payload claims:
|
|
|
21
21
|
exp expiry unix seconds
|
|
22
22
|
jti unique id for one-time-use / revocation tracking
|
|
23
23
|
|
|
24
|
-
This module is business-agnostic: it knows nothing about
|
|
24
|
+
This module is business-agnostic: it knows nothing about user pools,
|
|
25
25
|
Cognito, or specific apps. Callers supply the secret and claim values.
|
|
26
26
|
"""
|
|
27
27
|
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
@@ -207,8 +207,8 @@ class DataServiceMixin:
|
|
|
207
207
|
|
|
208
208
|
# Ceiling on rows a single un-paginated `query` may materialize (None =
|
|
209
209
|
# no cap). Apps set the class attribute; the `QueryMaxRows` config key
|
|
210
|
-
# overrides it per environment. Promoted 2026-09-04 from
|
|
211
|
-
#
|
|
210
|
+
# overrides it per environment. Promoted 2026-09-04 from an app's full
|
|
211
|
+
# query_hook override, which existed largely to carry this.
|
|
212
212
|
query_max_rows = None
|
|
213
213
|
|
|
214
214
|
# PostgreSQL type mappings for frontend display
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/aws/handlers/mixins/job_handler.py
RENAMED
|
@@ -7,8 +7,8 @@ three ``/event`` actions after a response carries ``jobs.events``:
|
|
|
7
7
|
* ``download-job-result`` → a ``file-download`` (or ``redirect``) response action
|
|
8
8
|
* ``cancel-job`` → flags the job ``CancelRequested`` for the worker
|
|
9
9
|
|
|
10
|
-
They are identical for every app, so they live here (extracted from
|
|
11
|
-
|
|
10
|
+
They are identical for every app, so they live here (extracted from an
|
|
11
|
+
admin app's HTTP handler). Mix into the HTTP handler alongside ``WebHandler``::
|
|
12
12
|
|
|
13
13
|
class HttpEventHandler(ButtonHandler, JobHandler, WebHandler, LambdaHandler):
|
|
14
14
|
...
|
|
@@ -112,7 +112,7 @@ class JobHandler:
|
|
|
112
112
|
raise AlertError("Job result is not ready")
|
|
113
113
|
|
|
114
114
|
# One file per job result; descriptors without a store are legacy
|
|
115
|
-
#
|
|
115
|
+
# S3-only entries written before stores existed.
|
|
116
116
|
descriptor = dict(files[0])
|
|
117
117
|
descriptor.setdefault("store", "s3" if descriptor.get("bucket") else "db")
|
|
118
118
|
deliver_job_result(tx, context, descriptor)
|
|
@@ -31,8 +31,8 @@ Usage::
|
|
|
31
31
|
user_table = "app_user"
|
|
32
32
|
single_session_enforcement = True
|
|
33
33
|
|
|
34
|
-
Promoted 2026-09-07 from
|
|
35
|
-
|
|
34
|
+
Promoted 2026-09-07 from a production app (proven in the app, then
|
|
35
|
+
centralized).
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
38
|
import datetime
|
|
@@ -7,7 +7,7 @@ velocity-react is already polling via ``get-job-status`` — fetches it with
|
|
|
7
7
|
|
|
8
8
|
* workers call :func:`store_job_result` — persist the bytes through a
|
|
9
9
|
:class:`JobResultStore` and record a *file descriptor* on the job's
|
|
10
|
-
``aws_job_activity.message.result.files`` (the shape
|
|
10
|
+
``aws_job_activity.message.result.files`` (the shape the original export
|
|
11
11
|
pipeline established, so existing UI code keeps working);
|
|
12
12
|
* the web tier (``JobHandler.OnActionDownloadJobResult``) calls
|
|
13
13
|
:func:`deliver_job_result`, which routes the descriptor back to the store
|
|
@@ -50,6 +50,7 @@ def _alert(message: str) -> Exception:
|
|
|
50
50
|
|
|
51
51
|
return AlertError(message)
|
|
52
52
|
|
|
53
|
+
|
|
53
54
|
__all__ = [
|
|
54
55
|
"JOB_RESULTS_TABLE",
|
|
55
56
|
"JOB_RESULTS_SCHEMA",
|
|
@@ -392,7 +393,7 @@ def record_job_result(
|
|
|
392
393
|
|
|
393
394
|
Status is left alone: the queue handler's ``afterAction`` flips it to
|
|
394
395
|
``Completed``, and a lifecycle that preserves a message carrying ``result``
|
|
395
|
-
|
|
396
|
+
keeps these descriptors intact.
|
|
396
397
|
"""
|
|
397
398
|
if isinstance(descriptors, dict):
|
|
398
399
|
descriptors = [descriptors]
|
|
@@ -430,7 +431,9 @@ def store_job_result(
|
|
|
430
431
|
store = store or default_job_result_store()
|
|
431
432
|
if created_by is None:
|
|
432
433
|
payload_meta = context.payload() or {}
|
|
433
|
-
created_by =
|
|
434
|
+
created_by = (
|
|
435
|
+
payload_meta.get("requested_by") if isinstance(payload_meta, dict) else None
|
|
436
|
+
)
|
|
434
437
|
descriptor = store.put(
|
|
435
438
|
tx,
|
|
436
439
|
job_id=job_id,
|
|
@@ -2,20 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
Architectural principles enforced here
|
|
4
4
|
---------------------------------------
|
|
5
|
-
* All files in *private* buckets
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
* All files in *private* buckets MUST be stored without a public ACL. Access
|
|
6
|
+
is granted exclusively through time-limited presigned GET URLs generated by
|
|
7
|
+
this module.
|
|
8
8
|
* Direct browser-to-S3 uploads are supported via presigned PUT URLs so that
|
|
9
9
|
file bytes never pass through Lambda (avoids the 6 MB API Gateway payload
|
|
10
10
|
ceiling and reduces Lambda cost).
|
|
11
|
-
* Public-asset buckets
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
* Public-asset buckets remain unaffected by this module; they continue to use
|
|
12
|
+
``ACL: public-read`` when uploaded via ``helpers.upload(public=True)``.
|
|
13
|
+
|
|
14
|
+
Bucket names
|
|
15
|
+
------------
|
|
16
|
+
Bucket names are deployment configuration, not library constants. They are
|
|
17
|
+
resolved on access through :mod:`velocity.aws.ssm_config` (SSM
|
|
18
|
+
``/{ProjectName}/{stage}/<key>``, then ``/Global/{stage}/<key>``, then the
|
|
19
|
+
environment):
|
|
20
|
+
|
|
21
|
+
========================== =================== ==========================
|
|
22
|
+
attribute config key purpose
|
|
23
|
+
========================== =================== ==========================
|
|
24
|
+
``CLIENT_FILES_BUCKET`` ``ClientFilesBucket`` private per-client files
|
|
25
|
+
``PUBLIC_ASSETS_BUCKET`` ``PublicAssetsBucket`` public images / form assets
|
|
26
|
+
``ADMIN_ASSETS_BUCKET`` ``AdminAssetsBucket`` internal admin assets
|
|
27
|
+
========================== =================== ==========================
|
|
28
|
+
|
|
29
|
+
``BACKOFFICE_BUCKET`` is a legacy alias of ``ADMIN_ASSETS_BUCKET``. Reading an
|
|
30
|
+
unconfigured bucket raises :class:`LookupError` naming the missing key, so a
|
|
31
|
+
misconfigured deployment fails loudly instead of writing to the wrong place.
|
|
32
|
+
``PRIVATE_BUCKETS`` and ``ALLOWED_UPLOAD_BUCKETS`` are derived from whichever
|
|
33
|
+
buckets are configured. Import and compare against these rather than
|
|
34
|
+
hard-coding bucket names in handlers so a rename is a config change.
|
|
19
35
|
"""
|
|
20
36
|
|
|
21
37
|
from __future__ import annotations
|
|
@@ -23,26 +39,61 @@ from __future__ import annotations
|
|
|
23
39
|
import re
|
|
24
40
|
import boto3
|
|
25
41
|
|
|
42
|
+
from velocity.aws import ssm_config
|
|
43
|
+
|
|
26
44
|
# ---------------------------------------------------------------------------
|
|
27
|
-
# Bucket name
|
|
45
|
+
# Bucket name configuration (resolved lazily, see module docstring)
|
|
28
46
|
# ---------------------------------------------------------------------------
|
|
29
47
|
|
|
30
|
-
|
|
31
|
-
""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
BUCKET_CONFIG_KEYS: dict[str, str] = {
|
|
49
|
+
"CLIENT_FILES_BUCKET": "ClientFilesBucket",
|
|
50
|
+
"PUBLIC_ASSETS_BUCKET": "PublicAssetsBucket",
|
|
51
|
+
"ADMIN_ASSETS_BUCKET": "AdminAssetsBucket",
|
|
52
|
+
"BACKOFFICE_BUCKET": "AdminAssetsBucket", # legacy alias
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def configured_bucket(attr: str) -> str | None:
|
|
57
|
+
"""The configured bucket name for ``attr`` (e.g. ``"CLIENT_FILES_BUCKET"``),
|
|
58
|
+
or None when that key is not set anywhere."""
|
|
59
|
+
key = BUCKET_CONFIG_KEYS[attr]
|
|
60
|
+
value = ssm_config.getenv(key)
|
|
61
|
+
return value.strip() if isinstance(value, str) and value.strip() else None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _require_bucket(attr: str) -> str:
|
|
65
|
+
value = configured_bucket(attr)
|
|
66
|
+
if value is None:
|
|
67
|
+
key = BUCKET_CONFIG_KEYS[attr]
|
|
68
|
+
raise LookupError(
|
|
69
|
+
f"velocity.aws.s3.{attr} is not configured: set the {key!r} config key "
|
|
70
|
+
f"(SSM /{{ProjectName}}/{{stage}}/{key}, /Global/{{stage}}/{key}, or the "
|
|
71
|
+
f"{key} environment variable)"
|
|
72
|
+
)
|
|
73
|
+
return value
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def __getattr__(name: str):
|
|
77
|
+
if name in BUCKET_CONFIG_KEYS:
|
|
78
|
+
return _require_bucket(name)
|
|
79
|
+
if name == "PRIVATE_BUCKETS":
|
|
80
|
+
# Buckets that must never be served with a public ACL.
|
|
81
|
+
return frozenset(b for b in [configured_bucket("CLIENT_FILES_BUCKET")] if b)
|
|
82
|
+
if name == "ALLOWED_UPLOAD_BUCKETS":
|
|
83
|
+
# Buckets that are permitted as presigned-upload destinations.
|
|
84
|
+
return frozenset(
|
|
85
|
+
b
|
|
86
|
+
for b in (
|
|
87
|
+
configured_bucket(a)
|
|
88
|
+
for a in (
|
|
89
|
+
"CLIENT_FILES_BUCKET",
|
|
90
|
+
"PUBLIC_ASSETS_BUCKET",
|
|
91
|
+
"ADMIN_ASSETS_BUCKET",
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
if b
|
|
95
|
+
)
|
|
96
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
46
97
|
|
|
47
98
|
|
|
48
99
|
# ---------------------------------------------------------------------------
|
|
@@ -85,7 +85,7 @@ class Result:
|
|
|
85
85
|
# INSERT/UPDATE/DELETE ... RETURNING (PostgreSQL), OUTPUT (SQL Server).
|
|
86
86
|
# Judging by the verb alone marked EVERY write as row-less, so
|
|
87
87
|
# `UPDATE ... RETURNING sys_id` silently reported nothing — a claim taken
|
|
88
|
-
# that way looked refused forever (
|
|
88
|
+
# that way looked refused forever (a claim-queue consumer, 2026-09-17). A write
|
|
89
89
|
# with no described columns has only a rowcount, and fetchone() on it
|
|
90
90
|
# raises on most drivers, so that case is still short-circuited.
|
|
91
91
|
if (
|
|
@@ -12,13 +12,15 @@ runs DDL in autocommit, and terminates other sessions as needed.
|
|
|
12
12
|
m = maintenance.DatabaseMaintenance() # env (DBHost/DBUser/...), maint db 'postgres'
|
|
13
13
|
|
|
14
14
|
# Server-side template clone -- instant, no dump/restore round-trip:
|
|
15
|
-
m.refresh("
|
|
16
|
-
m.snapshot("
|
|
17
|
-
m.prune_snapshots("
|
|
15
|
+
m.refresh("app-production", "app-develop") # snapshot dest, then clone source -> dest
|
|
16
|
+
m.snapshot("app-develop") # -> app-develop-snapshot-<ts>
|
|
17
|
+
m.prune_snapshots("app-develop", keep=3) # drop all but the 3 newest snapshots
|
|
18
18
|
|
|
19
19
|
Every database name is identifier-quoted; string-literal comparisons are escaped.
|
|
20
20
|
A configurable ``protected`` set blocks destructive ops (drop / rename / overwrite)
|
|
21
|
-
on critical databases
|
|
21
|
+
on critical databases. Pass ``protected={...}`` explicitly, or set the
|
|
22
|
+
``VELOCITY_PROTECTED_DATABASES`` environment variable (comma-separated) as the
|
|
23
|
+
default; the library itself protects nothing by default.
|
|
22
24
|
|
|
23
25
|
Snapshot databases are named ``<db>-snapshot-<YYYYMMDD-HHMMSS>`` -- a **sortable**
|
|
24
26
|
timestamp, so listing/pruning by name is chronological.
|
|
@@ -34,7 +36,16 @@ from velocity.db.servers import postgres
|
|
|
34
36
|
|
|
35
37
|
SNAPSHOT_INFIX = "-snapshot-"
|
|
36
38
|
TS_FORMAT = "%Y%m%d-%H%M%S" # sortable: lexical order == chronological order
|
|
37
|
-
DEFAULT_PROTECTED = frozenset(
|
|
39
|
+
DEFAULT_PROTECTED: frozenset = frozenset()
|
|
40
|
+
PROTECTED_ENV_VAR = "VELOCITY_PROTECTED_DATABASES"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def default_protected() -> frozenset:
|
|
44
|
+
"""Protected database names from ``VELOCITY_PROTECTED_DATABASES`` (comma-separated),
|
|
45
|
+
or an empty set."""
|
|
46
|
+
raw = os.environ.get(PROTECTED_ENV_VAR, "")
|
|
47
|
+
return frozenset(name.strip() for name in raw.split(",") if name.strip())
|
|
48
|
+
|
|
38
49
|
|
|
39
50
|
_BACKUP_FORMAT_FLAGS = {
|
|
40
51
|
"custom": "-Fc",
|
|
@@ -66,11 +77,13 @@ class DatabaseMaintenance:
|
|
|
66
77
|
*,
|
|
67
78
|
maintenance_db: str = "postgres",
|
|
68
79
|
config: Optional[dict] = None,
|
|
69
|
-
protected: Iterable[str] =
|
|
80
|
+
protected: Optional[Iterable[str]] = None,
|
|
70
81
|
engine=None,
|
|
71
82
|
):
|
|
72
83
|
self.maintenance_db = maintenance_db
|
|
73
|
-
self.protected =
|
|
84
|
+
self.protected = (
|
|
85
|
+
frozenset(protected) if protected is not None else default_protected()
|
|
86
|
+
)
|
|
74
87
|
self._config = dict(config or {})
|
|
75
88
|
# Lazily initialized so construction never opens a connection (keeps the
|
|
76
89
|
# class unit-testable without a live database).
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
@@ -71,7 +71,7 @@ class PostgreSQLInitializer(BaseInitializer):
|
|
|
71
71
|
final_config.setdefault("sslmode", ssl_mode)
|
|
72
72
|
|
|
73
73
|
# R25 — optional server-side timeouts (milliseconds), composed into the
|
|
74
|
-
# libpq `options` parameter. Both default OFF: the dominant
|
|
74
|
+
# libpq `options` parameter. Both default OFF: the dominant application
|
|
75
75
|
# pattern is an external HTTP call (Stripe/Plaid/Braintree) *inside* an
|
|
76
76
|
# open transaction, which leaves the session idle-in-transaction — so an
|
|
77
77
|
# aggressive idle_in_transaction_session_timeout would abort legitimate
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/db/tests/test_postgres_unchanged.py
RENAMED
|
@@ -5,7 +5,9 @@ Quick test to verify PostgreSQL implementation is functionally unchanged.
|
|
|
5
5
|
import sys
|
|
6
6
|
import os
|
|
7
7
|
|
|
8
|
-
sys.path.insert(
|
|
8
|
+
sys.path.insert(
|
|
9
|
+
0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..")
|
|
10
|
+
)
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def test_postgres_unchanged():
|
|
@@ -4,13 +4,16 @@
|
|
|
4
4
|
Test the robustness of the improved process_error method
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import os
|
|
7
8
|
import sys
|
|
8
9
|
import unittest
|
|
9
10
|
from unittest.mock import Mock, patch
|
|
10
11
|
import logging
|
|
11
12
|
|
|
12
13
|
# Add the source directory to the path
|
|
13
|
-
sys.path.insert(
|
|
14
|
+
sys.path.insert(
|
|
15
|
+
0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..")
|
|
16
|
+
)
|
|
14
17
|
|
|
15
18
|
from velocity.db.core.engine import Engine
|
|
16
19
|
from velocity.db import exceptions
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/misc/tests/test_mail_send.py
RENAMED
|
@@ -74,7 +74,7 @@ def config(**overrides):
|
|
|
74
74
|
port=587,
|
|
75
75
|
username="test-user@example.com",
|
|
76
76
|
password="test-password",
|
|
77
|
-
sender="
|
|
77
|
+
sender="Example Co <info@example.com>",
|
|
78
78
|
use_tls=True,
|
|
79
79
|
)
|
|
80
80
|
base.update(overrides)
|
|
@@ -179,7 +179,7 @@ class TestMailer(unittest.TestCase):
|
|
|
179
179
|
self.assertEqual(smtp.login_args, ("test-user@example.com", "test-password"))
|
|
180
180
|
self.assertTrue(smtp.quit_called)
|
|
181
181
|
sender, recipients, raw = smtp.sent[0]
|
|
182
|
-
self.assertEqual(sender, "
|
|
182
|
+
self.assertEqual(sender, "Example Co <info@example.com>")
|
|
183
183
|
self.assertEqual(recipients, ["b@example.com"])
|
|
184
184
|
self.assertIn("Subject: Hello", raw)
|
|
185
185
|
self.assertEqual(message["To"], "b@example.com")
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity/payment/braintree_adapter.py
RENAMED
|
@@ -78,7 +78,7 @@ class BraintreeAdapter(PaymentProcessorAdapter):
|
|
|
78
78
|
|
|
79
79
|
The retry policy lives here, once — apps were hand-rolling identical
|
|
80
80
|
backoff loops around raw ``client_token.generate()`` calls (promoted
|
|
81
|
-
2026-09-04 from
|
|
81
|
+
2026-09-04 from per-app copies).
|
|
82
82
|
"""
|
|
83
83
|
params: Dict[str, Any] = {"customer_id": customer_id} if customer_id else {}
|
|
84
84
|
last_exc: Optional[Exception] = None
|
|
@@ -295,7 +295,7 @@ class BraintreeAdapter(PaymentProcessorAdapter):
|
|
|
295
295
|
) -> Optional[str]:
|
|
296
296
|
"""
|
|
297
297
|
Braintree doesn't support hosted onboarding flows.
|
|
298
|
-
Returns None (onboarding must be done via
|
|
298
|
+
Returns None (onboarding must be done via the merchant admin UI).
|
|
299
299
|
"""
|
|
300
300
|
return None
|
|
301
301
|
|
|
@@ -732,7 +732,7 @@ class BraintreeAdapter(PaymentProcessorAdapter):
|
|
|
732
732
|
"""
|
|
733
733
|
Generate initial onboarding checklist for Braintree sub-merchants.
|
|
734
734
|
|
|
735
|
-
Note: Braintree onboarding is simpler - mostly done via
|
|
735
|
+
Note: Braintree onboarding is simpler - mostly done via the merchant admin UI.
|
|
736
736
|
"""
|
|
737
737
|
return {
|
|
738
738
|
"version": "1.0",
|
|
@@ -460,7 +460,7 @@ class StripeAdapter(PaymentProcessorAdapter):
|
|
|
460
460
|
# Calculate platform fee (revenue split). An explicit
|
|
461
461
|
# application_fee_amount in payment_data overrides this so the caller can
|
|
462
462
|
# carry platform + donor-paid processing fee + tip in a single application
|
|
463
|
-
# fee (see
|
|
463
|
+
# fee (see the platform fee model). Backward
|
|
464
464
|
# compatible: when omitted, the destination charge keeps the platform fee.
|
|
465
465
|
platform_fee_cents = self.calculate_platform_fee(
|
|
466
466
|
amount_cents, revenue_split_percentage
|
|
@@ -592,7 +592,7 @@ class StripeAdapter(PaymentProcessorAdapter):
|
|
|
592
592
|
amount_cents, revenue_split_percentage
|
|
593
593
|
)
|
|
594
594
|
# Explicit override lets the caller carry platform + donor fee + tip in one
|
|
595
|
-
# application fee (
|
|
595
|
+
# application fee (platform fee model); falls back to the platform fee.
|
|
596
596
|
application_fee_cents = payment_data.get("application_fee_amount")
|
|
597
597
|
if application_fee_cents is None:
|
|
598
598
|
application_fee_cents = platform_fee_cents
|
|
@@ -1054,7 +1054,7 @@ class StripeAdapter(PaymentProcessorAdapter):
|
|
|
1054
1054
|
(``balance_transaction.fee``). Returns ``None`` when it is not yet available
|
|
1055
1055
|
(e.g. an uncaptured manual authorization) or cannot be fetched — callers then
|
|
1056
1056
|
keep their formula estimate rather than over-reporting. Never raises. This is the
|
|
1057
|
-
``stripe_settled`` actual-cost source
|
|
1057
|
+
``stripe_settled`` actual-cost source for fee reconciliation.
|
|
1058
1058
|
"""
|
|
1059
1059
|
if not charge:
|
|
1060
1060
|
return None
|
{velocity_python-0.1.121 → velocity_python-0.1.123}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
@@ -233,6 +233,7 @@ tests/test_decorators.py
|
|
|
233
233
|
tests/test_delete_hook_fk_blocked.py
|
|
234
234
|
tests/test_dirty_pipeline_fast_path.py
|
|
235
235
|
tests/test_email_processing.py
|
|
236
|
+
tests/test_enqueue_metric_namespace.py
|
|
236
237
|
tests/test_enqueue_send_failures.py
|
|
237
238
|
tests/test_facets.py
|
|
238
239
|
tests/test_feature_flags.py
|
|
@@ -282,6 +283,7 @@ tests/test_retry_side_effect_guard.py
|
|
|
282
283
|
tests/test_return_default_safety.py
|
|
283
284
|
tests/test_row_batch_update.py
|
|
284
285
|
tests/test_row_cache_staleness.py
|
|
286
|
+
tests/test_s3_bucket_config.py
|
|
285
287
|
tests/test_schema_migrations.py
|
|
286
288
|
tests/test_security_capability.py
|
|
287
289
|
tests/test_security_hardening.py
|