velocity-python 0.1.125__tar.gz → 0.1.127__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.125 → velocity_python-0.1.127}/PKG-INFO +1 -1
- {velocity_python-0.1.125 → velocity_python-0.1.127}/pyproject.toml +1 -1
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/__init__.py +1 -1
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/jsonproxy.py +32 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/maintenance.py +11 -6
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/__init__.py +5 -0
- velocity_python-0.1.127/src/velocity/db/tunnel.py +49 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/PKG-INFO +1 -1
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- velocity_python-0.1.127/tests/test_db_tunnel.py +127 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_json_columns.py +57 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/LICENSE +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/README.md +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/setup.cfg +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/assets/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/assets/backfill.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/assets/indexing.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/assets/references.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/assets/service.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/assets/usage_index.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/blobs.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/base.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/dispatch.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/infra.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/jobs.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/provisioning.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/retention.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/security.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/single_session.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/deploy/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/deploy/config.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/deploy/operations.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/deploy/policies.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/deploy/reconcile.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/deploy/targets.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/dirty_pipeline.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/email.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/facets.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/feature_flags.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/masquerade.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/job_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/session_control.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/job_lifecycle.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/job_results.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/mirror.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/ops.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/s3.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/sms.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/ssm_config.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_amplify_build_policy_size.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_amplify_build_shim.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_email.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_sms.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/cache.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/lazy_engine.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/conftest.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/pdf.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_mail_send.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/core/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/core/capabilities.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/core/store.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/core/where.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/exceptions.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/base/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/memory/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/nosql/servers/redis/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/authorizenet_mirror.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/braintree_mirror.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/payment/stripe_mirror.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_access_error_403.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_activity_tracking_aborted_tx.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_asset_indexing.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_asset_references.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_assets_service.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_blob_store.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_capabilities.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_capability_catalog.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_cognito_user_cache.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_column_tx_arg.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_context_flags_loader.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_context_job_descriptions.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_data_service_query_cap.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_data_service_renumber.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_data_service_save_as.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_db_credentials_ssm_cascade.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_db_maintenance.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_delete_hook_fk_blocked.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_dirty_pipeline_fast_path.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_enqueue_metric_namespace.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_enqueue_send_failures.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_facets.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_feature_flags.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_get_cognito_user_provider.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_http_handler_rollback.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_identifier_injection_guard.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_job_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_job_lifecycle.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_job_results.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_jsonb_dict_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_lambda_handler_masquerade.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_lambda_handler_user_cache.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_lazy_engine.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_masquerade_grant.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_mirror.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_nosql_dynamodb.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_nosql_memory.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_nosql_mongodb.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_nosql_redis.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_nosql_translation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_nosql_where.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_observability.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_on_commit.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_ops.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_payment_authorizenet_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_payment_braintree_mirror.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_payment_mirror_empty_table.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_query_missing_table_unlocked.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_read_cache.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_response.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_restricted_direct_tables.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_result_returning.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_retry_side_effect_guard.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_return_default_safety.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_s3_bucket_config.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_security_capability.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_server_cursor.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_session_control.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_single_autocommit_safety.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_single_session_capability.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_sqlite_backend.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_ssm_config.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_store_user_data.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_table_find_cache.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_table_purge.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_transaction_class_wrapping.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_transaction_commit_and_ownership.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_transaction_edge_cases.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_where_clause_validation.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_write_hook_create_flow.py +0 -0
- {velocity_python-0.1.125 → velocity_python-0.1.127}/tests/test_write_hook_empty_strings.py +0 -0
|
@@ -68,6 +68,22 @@ class BoundList(list):
|
|
|
68
68
|
super().__init__(_wrap(v, ctrl) for v in iterable)
|
|
69
69
|
self._ctrl = ctrl
|
|
70
70
|
|
|
71
|
+
# -- copies are plain values ---------------------------------------
|
|
72
|
+
# A copy of a bound value is a plain list with no link to the row.
|
|
73
|
+
# Without these, copy.deepcopy rebuilt the proxy through the pickle
|
|
74
|
+
# path and refilled it with __setitem__ — one flush (an UPDATE) per
|
|
75
|
+
# nested container for a read-only copy, or an AttributeError when the
|
|
76
|
+
# rebuilt controller had no flush (2026-09-28, found by a dance forms
|
|
77
|
+
# migration deep-copying a definition read from a JSONB column).
|
|
78
|
+
def __copy__(self):
|
|
79
|
+
return unwrap(self)
|
|
80
|
+
|
|
81
|
+
def __deepcopy__(self, memo):
|
|
82
|
+
return unwrap(self)
|
|
83
|
+
|
|
84
|
+
def __reduce__(self):
|
|
85
|
+
return (list, (unwrap(self),))
|
|
86
|
+
|
|
71
87
|
# -- mutators ------------------------------------------------------
|
|
72
88
|
def __setitem__(self, index, value):
|
|
73
89
|
if isinstance(index, slice):
|
|
@@ -131,6 +147,22 @@ class BoundDict(dict):
|
|
|
131
147
|
super().__init__({k: _wrap(v, ctrl) for k, v in mapping.items()})
|
|
132
148
|
self._ctrl = ctrl
|
|
133
149
|
|
|
150
|
+
# -- copies are plain values ---------------------------------------
|
|
151
|
+
# A copy of a bound value is a plain dict with no link to the row.
|
|
152
|
+
# Without these, copy.deepcopy rebuilt the proxy through the pickle
|
|
153
|
+
# path and refilled it with __setitem__ — one flush (an UPDATE) per
|
|
154
|
+
# nested container for a read-only copy, or an AttributeError when the
|
|
155
|
+
# rebuilt controller had no flush (2026-09-28, found by a dance forms
|
|
156
|
+
# migration deep-copying a definition read from a JSONB column).
|
|
157
|
+
def __copy__(self):
|
|
158
|
+
return unwrap(self)
|
|
159
|
+
|
|
160
|
+
def __deepcopy__(self, memo):
|
|
161
|
+
return unwrap(self)
|
|
162
|
+
|
|
163
|
+
def __reduce__(self):
|
|
164
|
+
return (dict, (unwrap(self),))
|
|
165
|
+
|
|
134
166
|
# -- mutators ------------------------------------------------------
|
|
135
167
|
def __setitem__(self, key, value):
|
|
136
168
|
super().__setitem__(key, _wrap(value, self._ctrl))
|
|
@@ -33,6 +33,7 @@ import os
|
|
|
33
33
|
from typing import Iterable, List, Optional
|
|
34
34
|
|
|
35
35
|
from velocity.db.servers import postgres
|
|
36
|
+
from velocity.db.tunnel import apply_db_tunnel
|
|
36
37
|
|
|
37
38
|
SNAPSHOT_INFIX = "-snapshot-"
|
|
38
39
|
TS_FORMAT = "%Y%m%d-%H%M%S" # sortable: lexical order == chronological order
|
|
@@ -136,12 +137,16 @@ class DatabaseMaintenance:
|
|
|
136
137
|
return _run()
|
|
137
138
|
|
|
138
139
|
def _conn_params(self) -> dict:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
# the pg_dump/pg_restore/psql runs follow DB_TUNNEL like the engine does
|
|
141
|
+
return apply_db_tunnel(
|
|
142
|
+
{
|
|
143
|
+
"host": self._config.get("host") or os.environ.get("DBHost"),
|
|
144
|
+
"port": self._config.get("port") or os.environ.get("DBPort"),
|
|
145
|
+
"user": self._config.get("user") or os.environ.get("DBUser"),
|
|
146
|
+
"password": self._config.get("password")
|
|
147
|
+
or os.environ.get("DBPassword"),
|
|
148
|
+
}
|
|
149
|
+
)
|
|
145
150
|
|
|
146
151
|
# ------------------------------------------------------------------ guards
|
|
147
152
|
def _guard(self, db: str, action: str) -> None:
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
from ..base.initializer import BaseInitializer
|
|
3
3
|
from velocity.db.core import engine
|
|
4
4
|
from velocity.aws.ssm_config import getenv as _getenv
|
|
5
|
+
from velocity.db.tunnel import apply_db_tunnel
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
# Default TCP keepalive settings for PostgreSQL connections.
|
|
@@ -60,6 +61,10 @@ class PostgreSQLInitializer(BaseInitializer):
|
|
|
60
61
|
base_config, config, **kwargs
|
|
61
62
|
)
|
|
62
63
|
|
|
64
|
+
# DB_TUNNEL (operator laptops): every connection goes to the local end
|
|
65
|
+
# of a tunnel to a private server. See velocity.db.tunnel.
|
|
66
|
+
apply_db_tunnel(final_config)
|
|
67
|
+
|
|
63
68
|
# Apply TCP keepalive defaults (user config takes precedence).
|
|
64
69
|
for key, default_val in _DEFAULT_KEEPALIVE.items():
|
|
65
70
|
final_config.setdefault(key, default_val)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""``DB_TUNNEL``: reach a private database through a local tunnel end.
|
|
2
|
+
|
|
3
|
+
An operator on a laptop cannot reach a database that has no public address;
|
|
4
|
+
a tunnel (SSH ``-L``, an SSM port forward, ...) exposes it on a local port.
|
|
5
|
+
Setting ``DB_TUNNEL=127.0.0.1:15433`` points every velocity PostgreSQL
|
|
6
|
+
connection in the process -- engines from ``postgres.initialize()`` and the
|
|
7
|
+
``pg_dump``/``pg_restore``/``psql`` runs of ``DatabaseMaintenance`` -- at that
|
|
8
|
+
local end instead of the configured host. Host and port only: the database
|
|
9
|
+
name and credentials still come from wherever they were configured.
|
|
10
|
+
|
|
11
|
+
A tunnel forwards to ONE server, so the override applies to every connection,
|
|
12
|
+
including an explicit ``config={"host": ...}``: under a tunnel, no other host
|
|
13
|
+
is reachable anyway. ``sslmode=require`` still encrypts end to end;
|
|
14
|
+
``verify-full`` would reject the local name, so don't combine the two.
|
|
15
|
+
|
|
16
|
+
Read from ``os.environ`` only (never SSM): it describes this process's
|
|
17
|
+
network path, not the application's configuration.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
from typing import Mapping, Optional, Tuple
|
|
24
|
+
|
|
25
|
+
DB_TUNNEL_VAR = "DB_TUNNEL"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def db_tunnel(environ: Optional[Mapping[str, str]] = None) -> Optional[Tuple[str, str]]:
|
|
29
|
+
"""``(host, port)`` from ``DB_TUNNEL``, or ``None`` when it is unset/blank.
|
|
30
|
+
|
|
31
|
+
Raises ``ValueError`` for anything that is not ``host:port`` -- a typo must
|
|
32
|
+
not silently fall back to the unreachable real host."""
|
|
33
|
+
value = (os.environ if environ is None else environ).get(DB_TUNNEL_VAR, "")
|
|
34
|
+
value = (value or "").strip()
|
|
35
|
+
if not value:
|
|
36
|
+
return None
|
|
37
|
+
host, _, port = value.rpartition(":")
|
|
38
|
+
if not host or not port.isdigit():
|
|
39
|
+
raise ValueError(f"{DB_TUNNEL_VAR} must be host:port, got {value!r}")
|
|
40
|
+
return host, port
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def apply_db_tunnel(config: dict, environ: Optional[Mapping[str, str]] = None) -> dict:
|
|
44
|
+
"""Replace ``config['host']``/``config['port']`` with the tunnel's local end
|
|
45
|
+
when ``DB_TUNNEL`` is set. Mutates and returns ``config``."""
|
|
46
|
+
tunnel = db_tunnel(environ)
|
|
47
|
+
if tunnel:
|
|
48
|
+
config["host"], config["port"] = tunnel
|
|
49
|
+
return config
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
@@ -69,6 +69,7 @@ src/velocity/db/__init__.py
|
|
|
69
69
|
src/velocity/db/exceptions.py
|
|
70
70
|
src/velocity/db/maintenance.py
|
|
71
71
|
src/velocity/db/migrations.py
|
|
72
|
+
src/velocity/db/tunnel.py
|
|
72
73
|
src/velocity/db/utils.py
|
|
73
74
|
src/velocity/db/core/__init__.py
|
|
74
75
|
src/velocity/db/core/async_support.py
|
|
@@ -229,6 +230,7 @@ tests/test_data_service_renumber.py
|
|
|
229
230
|
tests/test_data_service_save_as.py
|
|
230
231
|
tests/test_db_credentials_ssm_cascade.py
|
|
231
232
|
tests/test_db_maintenance.py
|
|
233
|
+
tests/test_db_tunnel.py
|
|
232
234
|
tests/test_decorators.py
|
|
233
235
|
tests/test_delete_hook_fk_blocked.py
|
|
234
236
|
tests/test_dirty_pipeline_fast_path.py
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""``DB_TUNNEL=host:port`` points every PostgreSQL connection in the process at
|
|
3
|
+
a local tunnel end: engines from ``postgres.initialize()`` and the
|
|
4
|
+
``pg_dump``/``pg_restore`` runs of ``DatabaseMaintenance``. Host and port only;
|
|
5
|
+
a malformed value fails loudly instead of falling back to the real host."""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import unittest
|
|
9
|
+
from unittest.mock import MagicMock, patch
|
|
10
|
+
|
|
11
|
+
from velocity.db import maintenance
|
|
12
|
+
from velocity.db.servers import postgres as postgres_server
|
|
13
|
+
from velocity.db.tunnel import DB_TUNNEL_VAR, apply_db_tunnel, db_tunnel
|
|
14
|
+
|
|
15
|
+
FAKE = {
|
|
16
|
+
"DBDatabase": "app_db",
|
|
17
|
+
"DBHost": "private.rds.example.com",
|
|
18
|
+
"DBPort": "5433",
|
|
19
|
+
"DBUser": "app_user",
|
|
20
|
+
"DBPassword": "app_pass",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _no_tunnel():
|
|
25
|
+
env = dict(os.environ)
|
|
26
|
+
env.pop(DB_TUNNEL_VAR, None)
|
|
27
|
+
return patch.dict(os.environ, env, clear=True)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestParse(unittest.TestCase):
|
|
31
|
+
def test_unset_or_blank_is_none(self):
|
|
32
|
+
self.assertIsNone(db_tunnel({}))
|
|
33
|
+
self.assertIsNone(db_tunnel({DB_TUNNEL_VAR: " "}))
|
|
34
|
+
|
|
35
|
+
def test_host_and_port(self):
|
|
36
|
+
self.assertEqual(
|
|
37
|
+
db_tunnel({DB_TUNNEL_VAR: " 127.0.0.1:15433 "}), ("127.0.0.1", "15433")
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def test_malformed_raises(self):
|
|
41
|
+
for bad in ("localhost", ":15433", "127.0.0.1:", "127.0.0.1:abc"):
|
|
42
|
+
with self.subTest(bad=bad), self.assertRaises(ValueError):
|
|
43
|
+
db_tunnel({DB_TUNNEL_VAR: bad})
|
|
44
|
+
|
|
45
|
+
def test_apply_replaces_host_and_port_only(self):
|
|
46
|
+
config = {"host": "h", "port": "1", "user": "u", "dbname": "d"}
|
|
47
|
+
apply_db_tunnel(config, {DB_TUNNEL_VAR: "127.0.0.1:15433"})
|
|
48
|
+
self.assertEqual(
|
|
49
|
+
config,
|
|
50
|
+
{"host": "127.0.0.1", "port": "15433", "user": "u", "dbname": "d"},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def test_apply_without_tunnel_leaves_config(self):
|
|
54
|
+
config = {"host": "h", "port": "1"}
|
|
55
|
+
self.assertEqual(apply_db_tunnel(config, {}), {"host": "h", "port": "1"})
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TestPostgresInitialize(unittest.TestCase):
|
|
59
|
+
def _initialize(self, config=None):
|
|
60
|
+
captured = {}
|
|
61
|
+
|
|
62
|
+
def fake_engine(driver, cfg, sql, **kwargs):
|
|
63
|
+
captured.update(cfg)
|
|
64
|
+
return MagicMock()
|
|
65
|
+
|
|
66
|
+
with (
|
|
67
|
+
patch.object(postgres_server, "_getenv", lambda key: FAKE.get(key)),
|
|
68
|
+
patch.object(postgres_server.engine, "Engine", fake_engine),
|
|
69
|
+
):
|
|
70
|
+
postgres_server.PostgreSQLInitializer.initialize(config)
|
|
71
|
+
return captured
|
|
72
|
+
|
|
73
|
+
def test_without_tunnel_uses_configured_host(self):
|
|
74
|
+
with _no_tunnel():
|
|
75
|
+
cfg = self._initialize()
|
|
76
|
+
self.assertEqual(
|
|
77
|
+
(cfg["host"], cfg["port"]), ("private.rds.example.com", "5433")
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def test_tunnel_overrides_host_and_port_keeps_credentials(self):
|
|
81
|
+
with patch.dict(os.environ, {DB_TUNNEL_VAR: "127.0.0.1:15433"}):
|
|
82
|
+
cfg = self._initialize()
|
|
83
|
+
self.assertEqual((cfg["host"], cfg["port"]), ("127.0.0.1", "15433"))
|
|
84
|
+
self.assertEqual(cfg["dbname"], "app_db")
|
|
85
|
+
self.assertEqual(cfg["user"], "app_user")
|
|
86
|
+
self.assertEqual(cfg["password"], "app_pass")
|
|
87
|
+
|
|
88
|
+
def test_tunnel_overrides_an_explicit_config_host(self):
|
|
89
|
+
# a tunnel reaches one server; any other host is unreachable anyway
|
|
90
|
+
with patch.dict(os.environ, {DB_TUNNEL_VAR: "127.0.0.1:15433"}):
|
|
91
|
+
cfg = self._initialize({"host": "other.example.com", "port": "5432"})
|
|
92
|
+
self.assertEqual((cfg["host"], cfg["port"]), ("127.0.0.1", "15433"))
|
|
93
|
+
|
|
94
|
+
def test_malformed_tunnel_fails_before_connecting(self):
|
|
95
|
+
with patch.dict(os.environ, {DB_TUNNEL_VAR: "localhost"}):
|
|
96
|
+
with self.assertRaises(ValueError):
|
|
97
|
+
self._initialize()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class TestMaintenanceTools(unittest.TestCase):
|
|
101
|
+
def test_pg_dump_follows_the_tunnel(self):
|
|
102
|
+
m = maintenance.DatabaseMaintenance(
|
|
103
|
+
config={"host": "private.rds.example.com", "port": "5433", "user": "u"},
|
|
104
|
+
engine=MagicMock(),
|
|
105
|
+
)
|
|
106
|
+
with (
|
|
107
|
+
patch.dict(os.environ, {DB_TUNNEL_VAR: "127.0.0.1:15433"}),
|
|
108
|
+
patch.object(m, "_run_tool") as run,
|
|
109
|
+
):
|
|
110
|
+
m.backup_to_file("app_db", "/tmp/x.dump")
|
|
111
|
+
args = run.call_args[0][0]
|
|
112
|
+
self.assertEqual(args[args.index("-h") + 1], "127.0.0.1")
|
|
113
|
+
self.assertEqual(args[args.index("-p") + 1], "15433")
|
|
114
|
+
|
|
115
|
+
def test_pg_dump_without_tunnel_uses_configured_host(self):
|
|
116
|
+
m = maintenance.DatabaseMaintenance(
|
|
117
|
+
config={"host": "private.rds.example.com", "port": "5433", "user": "u"},
|
|
118
|
+
engine=MagicMock(),
|
|
119
|
+
)
|
|
120
|
+
with _no_tunnel(), patch.object(m, "_run_tool") as run:
|
|
121
|
+
m.backup_to_file("app_db", "/tmp/x.dump")
|
|
122
|
+
args = run.call_args[0][0]
|
|
123
|
+
self.assertEqual(args[args.index("-h") + 1], "private.rds.example.com")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
if __name__ == "__main__":
|
|
127
|
+
unittest.main()
|
|
@@ -423,3 +423,60 @@ class TestRowJsonTextDecode(unittest.TestCase):
|
|
|
423
423
|
|
|
424
424
|
if __name__ == "__main__":
|
|
425
425
|
unittest.main()
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
class TestProxyCopies(unittest.TestCase):
|
|
429
|
+
"""A copy of a bound JSON value is a plain value: copying never
|
|
430
|
+
touches the row (2026-09-28)."""
|
|
431
|
+
|
|
432
|
+
def _bound(self):
|
|
433
|
+
from velocity.db.core import jsonproxy
|
|
434
|
+
|
|
435
|
+
writes = []
|
|
436
|
+
value = {
|
|
437
|
+
"pages": [{"ui": [{"copy": "x"}], "skippable": {"label": "s"}}],
|
|
438
|
+
"tags": ["a", ["b"]],
|
|
439
|
+
}
|
|
440
|
+
return jsonproxy.bind(value, writes.append), value, writes
|
|
441
|
+
|
|
442
|
+
def _assert_plain(self, value):
|
|
443
|
+
self.assertIn(type(value), (dict, list))
|
|
444
|
+
items = value.values() if isinstance(value, dict) else value
|
|
445
|
+
for item in items:
|
|
446
|
+
if isinstance(item, (dict, list)):
|
|
447
|
+
self._assert_plain(item)
|
|
448
|
+
|
|
449
|
+
def test_deepcopy_and_copy_are_plain_and_write_nothing(self):
|
|
450
|
+
import copy
|
|
451
|
+
|
|
452
|
+
bound, original, writes = self._bound()
|
|
453
|
+
deep = copy.deepcopy(bound)
|
|
454
|
+
shallow = copy.copy(bound)
|
|
455
|
+
self.assertEqual(deep, original)
|
|
456
|
+
self.assertEqual(shallow, original)
|
|
457
|
+
self._assert_plain(deep)
|
|
458
|
+
self._assert_plain(shallow)
|
|
459
|
+
self.assertEqual(writes, [])
|
|
460
|
+
# the copy is independent of the row
|
|
461
|
+
deep["pages"][0]["skippable"]["label"] = "changed"
|
|
462
|
+
self.assertEqual(bound["pages"][0]["skippable"]["label"], "s")
|
|
463
|
+
self.assertEqual(writes, [])
|
|
464
|
+
# nested proxies copy plain too
|
|
465
|
+
self._assert_plain(copy.deepcopy(bound["pages"]))
|
|
466
|
+
self._assert_plain(copy.copy(bound["tags"]))
|
|
467
|
+
self.assertEqual(writes, [])
|
|
468
|
+
|
|
469
|
+
def test_pickle_round_trip_is_plain(self):
|
|
470
|
+
import pickle
|
|
471
|
+
|
|
472
|
+
bound, original, writes = self._bound()
|
|
473
|
+
back = pickle.loads(pickle.dumps(bound))
|
|
474
|
+
self.assertEqual(back, original)
|
|
475
|
+
self._assert_plain(back)
|
|
476
|
+
self.assertEqual(writes, [])
|
|
477
|
+
|
|
478
|
+
def test_mutation_still_flushes(self):
|
|
479
|
+
bound, _original, writes = self._bound()
|
|
480
|
+
bound["pages"][0]["skippable"]["label"] = "t"
|
|
481
|
+
self.assertEqual(len(writes), 1)
|
|
482
|
+
self.assertEqual(writes[0]["pages"][0]["skippable"]["label"], "t")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/dispatch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/provisioning.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/retention.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/security.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/capabilities/single_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/base_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/context_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/job_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/mixins/web_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/handlers/sqs_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_deploy_policies.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/aws/tests/test_deploy_reconcile.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/initializer.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/base/operators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/mysql/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.125 → velocity_python-0.1.127}/src/velocity/db/servers/postgres/operators.py
RENAMED
|
File without changes
|