velocity-python 0.1.104__tar.gz → 0.1.105__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.104 → velocity_python-0.1.105}/PKG-INFO +1 -1
- {velocity_python-0.1.104 → velocity_python-0.1.105}/pyproject.toml +1 -1
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/__init__.py +1 -1
- velocity_python-0.1.105/src/velocity/aws/feature_flags.py +159 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/PKG-INFO +1 -1
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- velocity_python-0.1.105/tests/test_feature_flags.py +176 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/LICENSE +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/README.md +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/setup.cfg +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/amplify_build.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/assets/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/assets/backfill.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/assets/indexing.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/assets/references.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/assets/service.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/assets/usage_index.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/blobs.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/deploy/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/deploy/config.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/deploy/operations.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/deploy/policies.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/deploy/reconcile.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/deploy/targets.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/dirty_pipeline.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/email.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/base_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/context_factory.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/exceptions.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/masquerade.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/job_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/session_control.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/perf.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/job_results.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/s3.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/sms.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/ssm_config.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_amplify_build_policy_size.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_amplify_build_shim.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_email.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_response.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_sms.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/async_support.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/jsonproxy.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/core/view.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/maintenance.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/migrations.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/initializer.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/operators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/sql.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/types.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/operators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/reserved.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/sql.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/types.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/operators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/reserved.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/sql.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/types.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/operators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/sql.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/types.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/common_db_test.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/common.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/conftest.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_column.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_connections.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_database.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_engine.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_imports.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_result.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_row.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_table.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/sql/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/sql/common.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_db_utils.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_postgres.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_result_caching.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_sql_builder.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_tablehelper.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/tests/test_view_helper.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/logging.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/pdf.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_db.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_fix.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_format.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_iconv.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_mail_send.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_merge.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_oconv.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_original_error.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tests/test_timer.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/core/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/core/capabilities.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/core/store.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/core/where.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/exceptions.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/base/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/memory/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/nosql/servers/redis/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/__init__.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/authorizenet_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/authorizenet_mirror.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/base_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/braintree_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/braintree_mirror.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/charge_rules.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/stripe_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/payment/stripe_mirror.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/entry_points.txt +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_activity_tracking_aborted_tx.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_amplify_build.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_asset_indexing.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_asset_references.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_assets_service.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_async_support.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_batch_operations.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_blob_store.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_column_tx_arg.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_concurrency_safety.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_connection_pool.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_connection_resilience.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_context_job_descriptions.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_data_service_query_cap.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_data_service_renumber.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_data_service_save_as.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_db_credentials_ssm_cascade.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_db_maintenance.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_decorators.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_delete_hook_fk_blocked.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_dirty_pipeline_fast_path.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_email_processing.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_enqueue_send_failures.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_get_cognito_user_provider.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_http_handler_rollback.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_iconv_money_to_cents.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_identifier_injection_guard.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_job_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_job_results.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_json_columns.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_jsonb_dict_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_lambda_handler.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_lambda_handler_auth.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_lambda_handler_masquerade.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_masquerade_grant.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_mixins_import.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_n_plus_one.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_nosql_dynamodb.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_nosql_memory.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_nosql_mongodb.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_nosql_redis.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_nosql_translation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_nosql_where.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_observability.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_on_commit.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_payment_authorizenet_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_payment_braintree_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_payment_braintree_mirror.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_payment_mirror_empty_table.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_payment_stripe_adapter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_pdf.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_prepared_statements.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_psycopg3_upgrade.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_query_cache.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_query_missing_table_unlocked.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_response.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_restricted_direct_tables.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_retry_side_effect_guard.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_return_default_safety.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_row_batch_update.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_row_cache_staleness.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_schema_migrations.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_security_hardening.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_server_cursor.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_session_control.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_single_autocommit_safety.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_sqlite_backend.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_sqs_per_record_transactions.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_ssm_config.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_store_user_data.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_sys_modified_count_postgres_demo.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_table_alter.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_transaction_class_wrapping.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_transaction_commit_and_ownership.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_transaction_edge_cases.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_where_clause_validation.py +0 -0
- {velocity_python-0.1.104 → velocity_python-0.1.105}/tests/test_write_hook_create_flow.py +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Environment-scoped feature flags with cross-database mirroring.
|
|
2
|
+
|
|
3
|
+
Generalises a pattern proven in production (CaringCent BackOffice): a
|
|
4
|
+
``sys_feature_flags`` table that holds **one row per system**, keyed by an
|
|
5
|
+
``applied_system`` column, where every copy of the database carries every
|
|
6
|
+
system's row. Two behaviours follow:
|
|
7
|
+
|
|
8
|
+
* **Reads are scoped to the current system.** A bare ``find({})`` is wrong the
|
|
9
|
+
moment a second system's row exists — it returns an arbitrary one. Callers go
|
|
10
|
+
through :func:`get`, which selects the row for :func:`current_system`.
|
|
11
|
+
* **Writes mirror to the alternate database.** demo and production are separate
|
|
12
|
+
databases on the same instance; a flag saved in either is copied to the other
|
|
13
|
+
(matched by ``applied_system``, never ``sys_id`` — row ids differ between
|
|
14
|
+
databases) so the two converge no matter where the edit happened, and a
|
|
15
|
+
demo refresh preserves the demo row. :func:`mirror_row` does one row (the
|
|
16
|
+
real-time hook); :func:`reconcile` does all rows (the catch-up after the
|
|
17
|
+
alternate was unreachable, or a fresh environment).
|
|
18
|
+
|
|
19
|
+
velocity owns only the **mechanism**. The flag columns and what they mean stay
|
|
20
|
+
in each app's schema and code — this module never names a business flag. The
|
|
21
|
+
row key is the runtime **stage** (``demo`` / ``production``), so every database
|
|
22
|
+
carries one row per stage and each environment reads its own; the alternate
|
|
23
|
+
database name comes from config (:data:`ALTERNATE_DB_CONFIG_KEY`). (An app that
|
|
24
|
+
one day consolidates several systems into one database can widen the key then;
|
|
25
|
+
today the stage is the whole identity.)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import logging
|
|
31
|
+
|
|
32
|
+
log = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
SYSTEM_COLUMN = "applied_system"
|
|
35
|
+
DEFAULT_TABLE = "sys_feature_flags"
|
|
36
|
+
ALTERNATE_DB_CONFIG_KEY = "DBAlternate"
|
|
37
|
+
|
|
38
|
+
_alternate_engines: dict = {}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def current_system(default: str | None = None) -> str | None:
|
|
42
|
+
"""The ``applied_system`` key for the running environment — the runtime
|
|
43
|
+
stage (``demo`` / ``production``). Every database carries one row per stage;
|
|
44
|
+
this selects the running one.
|
|
45
|
+
"""
|
|
46
|
+
from velocity.aws import ssm_config
|
|
47
|
+
|
|
48
|
+
return (ssm_config.get_stage() or "").strip() or default
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get(tx, system: str | None = None, *, table: str = DEFAULT_TABLE,
|
|
52
|
+
raise_on_missing: bool = False) -> dict:
|
|
53
|
+
"""The feature-flag row for ``system`` (defaults to :func:`current_system`).
|
|
54
|
+
|
|
55
|
+
Returns a plain dict; ``{}`` when no row matches unless ``raise_on_missing``.
|
|
56
|
+
"""
|
|
57
|
+
system = system if system is not None else current_system()
|
|
58
|
+
row = tx.table(table).find({SYSTEM_COLUMN: system})
|
|
59
|
+
if not row:
|
|
60
|
+
if raise_on_missing:
|
|
61
|
+
raise KeyError(f"no {table} row for {SYSTEM_COLUMN}={system!r}")
|
|
62
|
+
return {}
|
|
63
|
+
return dict(row)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _without_sys(row) -> dict:
|
|
67
|
+
"""A row's business columns — the ``sys_*`` bookkeeping never crosses over."""
|
|
68
|
+
return {k: v for k, v in dict(row).items() if not str(k).startswith("sys_")}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def alternate_engine(alternate_db: str | None = None):
|
|
72
|
+
"""Engine for the alternate database — same instance, other ``database``.
|
|
73
|
+
|
|
74
|
+
Host/port/user/password are inherited from the running config, so no
|
|
75
|
+
separate credentials are needed; only the database name changes. Cached per
|
|
76
|
+
database name so repeated mirrors in one process reuse the connection.
|
|
77
|
+
"""
|
|
78
|
+
from velocity.aws import ssm_config
|
|
79
|
+
from velocity.db.servers import postgres
|
|
80
|
+
|
|
81
|
+
if alternate_db is None:
|
|
82
|
+
alternate_db = ssm_config.getenv(ALTERNATE_DB_CONFIG_KEY, raise_on_missing=True)
|
|
83
|
+
if alternate_db not in _alternate_engines:
|
|
84
|
+
_alternate_engines[alternate_db] = postgres.initialize({"database": alternate_db})
|
|
85
|
+
return _alternate_engines[alternate_db]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def mirror_row(row, *, alternate_db: str | None = None, engine=None,
|
|
89
|
+
table: str = DEFAULT_TABLE) -> str | None:
|
|
90
|
+
"""Upsert one flags row into the alternate database by ``applied_system``.
|
|
91
|
+
|
|
92
|
+
Returns the mirrored key, or ``None`` when the row has no system key (a
|
|
93
|
+
keyless row is skipped, never mirrored to an arbitrary target).
|
|
94
|
+
"""
|
|
95
|
+
data = _without_sys(row)
|
|
96
|
+
key = data.get(SYSTEM_COLUMN)
|
|
97
|
+
if not key:
|
|
98
|
+
return None
|
|
99
|
+
engine = engine or alternate_engine(alternate_db)
|
|
100
|
+
with engine.transaction() as alt:
|
|
101
|
+
alt.table(table).merge(data, pk={SYSTEM_COLUMN: key})
|
|
102
|
+
return key
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def reconcile(tx, *, alternate_db: str | None = None, engine=None,
|
|
106
|
+
table: str = DEFAULT_TABLE) -> dict:
|
|
107
|
+
"""Mirror every flags row into the alternate database. Catch-up companion of
|
|
108
|
+
:func:`mirror_row`. Returns ``{"synced": [...], "skipped": [...]}``."""
|
|
109
|
+
engine = engine or alternate_engine(alternate_db)
|
|
110
|
+
synced: list = []
|
|
111
|
+
skipped: list = []
|
|
112
|
+
rows = list(tx.table(table).select())
|
|
113
|
+
with engine.transaction() as alt:
|
|
114
|
+
for row in rows:
|
|
115
|
+
data = _without_sys(row)
|
|
116
|
+
key = data.get(SYSTEM_COLUMN)
|
|
117
|
+
if not key:
|
|
118
|
+
skipped.append(dict(row).get("sys_id"))
|
|
119
|
+
continue
|
|
120
|
+
alt.table(table).merge(data, pk={SYSTEM_COLUMN: key})
|
|
121
|
+
synced.append(key)
|
|
122
|
+
return {"synced": synced, "skipped": skipped}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _toast(context, message: str, level: str) -> None:
|
|
126
|
+
"""Best-effort operator toast; a context without one is fine (a queue run)."""
|
|
127
|
+
response = getattr(context, "response", None)
|
|
128
|
+
toast = getattr(response() if callable(response) else None, "toast", None)
|
|
129
|
+
if callable(toast):
|
|
130
|
+
toast(message, level)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def make_mirror_hook(*, alternate_db: str | None = None,
|
|
134
|
+
table: str = DEFAULT_TABLE, notify: bool = True):
|
|
135
|
+
"""An RWX ``after_new`` / ``after_write`` callable that mirrors the saved
|
|
136
|
+
row to the alternate database.
|
|
137
|
+
|
|
138
|
+
This is how the sync stays in ONE place: the app's ``rwx/<table>.py`` is a
|
|
139
|
+
two-line re-export (``after_new = after_write = make_mirror_hook()``) — the
|
|
140
|
+
logic lives here in velocity, not copied per repo. Warn-and-continue: a flag
|
|
141
|
+
save is never blocked by the alternate database being unreachable; the
|
|
142
|
+
:func:`reconcile` action (also here) is the catch-up.
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
def hook(tx, table_name, sys_id, row, context):
|
|
146
|
+
del tx, table_name, sys_id
|
|
147
|
+
try:
|
|
148
|
+
key = mirror_row(row, alternate_db=alternate_db, table=table)
|
|
149
|
+
if notify and key:
|
|
150
|
+
_toast(context, f"Feature flags for '{key}' mirrored to the "
|
|
151
|
+
"alternate database.", "success")
|
|
152
|
+
except Exception as exc: # warn-and-continue — never block the save
|
|
153
|
+
log.warning("feature-flag mirror to alternate DB failed", exc_info=True)
|
|
154
|
+
if notify:
|
|
155
|
+
_toast(context, "Flag change saved HERE but NOT mirrored to the "
|
|
156
|
+
f"alternate database ({exc}). Run the reconcile once it "
|
|
157
|
+
"is reachable.", "warning")
|
|
158
|
+
|
|
159
|
+
return hook
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
@@ -9,6 +9,7 @@ src/velocity/aws/amplify_build.py
|
|
|
9
9
|
src/velocity/aws/blobs.py
|
|
10
10
|
src/velocity/aws/dirty_pipeline.py
|
|
11
11
|
src/velocity/aws/email.py
|
|
12
|
+
src/velocity/aws/feature_flags.py
|
|
12
13
|
src/velocity/aws/job_results.py
|
|
13
14
|
src/velocity/aws/s3.py
|
|
14
15
|
src/velocity/aws/sms.py
|
|
@@ -213,6 +214,7 @@ tests/test_delete_hook_fk_blocked.py
|
|
|
213
214
|
tests/test_dirty_pipeline_fast_path.py
|
|
214
215
|
tests/test_email_processing.py
|
|
215
216
|
tests/test_enqueue_send_failures.py
|
|
217
|
+
tests/test_feature_flags.py
|
|
216
218
|
tests/test_get_cognito_user_provider.py
|
|
217
219
|
tests/test_http_handler_rollback.py
|
|
218
220
|
tests/test_iconv_money_to_cents.py
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Environment-scoped feature flags: current-system resolution, scoped reads,
|
|
2
|
+
and the cross-database mirror/reconcile mechanism (no DB — fakes throughout)."""
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from velocity.aws import feature_flags as ff
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ── fakes ────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
class FakeTable:
|
|
12
|
+
def __init__(self, rows):
|
|
13
|
+
self.rows = rows
|
|
14
|
+
self.merges = [] # (data, pk)
|
|
15
|
+
|
|
16
|
+
def find(self, where):
|
|
17
|
+
for row in self.rows:
|
|
18
|
+
if all(row.get(k) == v for k, v in where.items()):
|
|
19
|
+
return dict(row)
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
def select(self, *_a, **_k):
|
|
23
|
+
return list(self.rows)
|
|
24
|
+
|
|
25
|
+
def merge(self, data, pk):
|
|
26
|
+
self.merges.append((dict(data), dict(pk)))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FakeTx:
|
|
30
|
+
def __init__(self, rows):
|
|
31
|
+
self._table = FakeTable(rows)
|
|
32
|
+
|
|
33
|
+
def table(self, _name):
|
|
34
|
+
return self._table
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FakeEngine:
|
|
38
|
+
"""Alternate-DB stand-in: hands out one table and records its merges."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, rows=None):
|
|
41
|
+
self.table_obj = FakeTable(rows or [])
|
|
42
|
+
|
|
43
|
+
def transaction(self):
|
|
44
|
+
engine = self
|
|
45
|
+
|
|
46
|
+
class _Ctx:
|
|
47
|
+
def __enter__(self_):
|
|
48
|
+
return engine
|
|
49
|
+
|
|
50
|
+
def __exit__(self_, *exc):
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
return _Ctx()
|
|
54
|
+
|
|
55
|
+
def table(self, _name):
|
|
56
|
+
return self.table_obj
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class FakeResponse:
|
|
60
|
+
def __init__(self):
|
|
61
|
+
self.toasts = []
|
|
62
|
+
|
|
63
|
+
def toast(self, message, level):
|
|
64
|
+
self.toasts.append((message, level))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FakeContext:
|
|
68
|
+
def __init__(self):
|
|
69
|
+
self._response = FakeResponse()
|
|
70
|
+
|
|
71
|
+
def response(self):
|
|
72
|
+
return self._response
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
DEMO = {"sys_id": 1, "applied_system": "demo",
|
|
76
|
+
"gmail_sync_allowlist": "a@example.com", "sys_dirty": True}
|
|
77
|
+
PROD = {"sys_id": 2, "applied_system": "production",
|
|
78
|
+
"gmail_sync_allowlist": None}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ── current_system (the runtime stage) ───────────────────────────────────
|
|
82
|
+
|
|
83
|
+
def test_current_system_is_the_stage(monkeypatch):
|
|
84
|
+
import velocity.aws.ssm_config as ssm
|
|
85
|
+
monkeypatch.setattr(ssm, "get_stage", lambda *a, **k: "production")
|
|
86
|
+
assert ff.current_system() == "production"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_current_system_default_when_no_stage(monkeypatch):
|
|
90
|
+
import velocity.aws.ssm_config as ssm
|
|
91
|
+
monkeypatch.setattr(ssm, "get_stage", lambda *a, **k: None)
|
|
92
|
+
assert ff.current_system(default="demo") == "demo"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ── get (scoped read) ────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
def test_get_scopes_to_the_named_stage():
|
|
98
|
+
tx = FakeTx([DEMO, PROD])
|
|
99
|
+
assert ff.get(tx, "production")["applied_system"] == "production"
|
|
100
|
+
assert ff.get(tx, "demo")["gmail_sync_allowlist"] == "a@example.com"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_get_missing_returns_empty_or_raises():
|
|
104
|
+
tx = FakeTx([DEMO])
|
|
105
|
+
assert ff.get(tx, "nope") == {}
|
|
106
|
+
with pytest.raises(KeyError):
|
|
107
|
+
ff.get(tx, "nope", raise_on_missing=True)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_get_defaults_system_to_current(monkeypatch):
|
|
111
|
+
monkeypatch.setattr(ff, "current_system", lambda: "production")
|
|
112
|
+
assert ff.get(FakeTx([DEMO, PROD]))["applied_system"] == "production"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ── mirror_row ───────────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
def test_mirror_row_strips_sys_and_keys_by_stage():
|
|
118
|
+
engine = FakeEngine()
|
|
119
|
+
key = ff.mirror_row(DEMO, engine=engine)
|
|
120
|
+
assert key == "demo"
|
|
121
|
+
data, pk = engine.table_obj.merges[0]
|
|
122
|
+
assert pk == {"applied_system": "demo"}
|
|
123
|
+
assert "sys_dirty" not in data and "sys_id" not in data
|
|
124
|
+
assert data["gmail_sync_allowlist"] == "a@example.com"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_mirror_row_skips_keyless_row():
|
|
128
|
+
engine = FakeEngine()
|
|
129
|
+
assert ff.mirror_row({"sys_id": 9, "flag": "x"}, engine=engine) is None
|
|
130
|
+
assert engine.table_obj.merges == []
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ── reconcile ────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
def test_reconcile_mirrors_every_keyed_row():
|
|
136
|
+
tx = FakeTx([DEMO, PROD, {"sys_id": 3, "applied_system": None}])
|
|
137
|
+
engine = FakeEngine()
|
|
138
|
+
result = ff.reconcile(tx, engine=engine)
|
|
139
|
+
assert result["synced"] == ["demo", "production"]
|
|
140
|
+
assert result["skipped"] == [3]
|
|
141
|
+
assert len(engine.table_obj.merges) == 2
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ── the reusable RWX hook ────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
def test_mirror_hook_delegates_and_toasts_success():
|
|
147
|
+
engine = FakeEngine()
|
|
148
|
+
hook = ff.make_mirror_hook()
|
|
149
|
+
ctx = FakeContext()
|
|
150
|
+
# engine is injected via a closure over alternate_engine; patch it
|
|
151
|
+
import velocity.aws.feature_flags as mod
|
|
152
|
+
orig = mod.alternate_engine
|
|
153
|
+
mod.alternate_engine = lambda *a, **k: engine
|
|
154
|
+
try:
|
|
155
|
+
hook(None, "sys_feature_flags", 1, DEMO, ctx)
|
|
156
|
+
finally:
|
|
157
|
+
mod.alternate_engine = orig
|
|
158
|
+
assert engine.table_obj.merges[0][1] == {"applied_system": "demo"}
|
|
159
|
+
assert ctx.response().toasts[0][1] == "success"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_mirror_hook_warns_and_continues_on_failure():
|
|
163
|
+
hook = ff.make_mirror_hook()
|
|
164
|
+
ctx = FakeContext()
|
|
165
|
+
import velocity.aws.feature_flags as mod
|
|
166
|
+
orig = mod.alternate_engine
|
|
167
|
+
|
|
168
|
+
def boom(*a, **k):
|
|
169
|
+
raise RuntimeError("alternate unreachable")
|
|
170
|
+
|
|
171
|
+
mod.alternate_engine = boom
|
|
172
|
+
try:
|
|
173
|
+
hook(None, "sys_feature_flags", 1, DEMO, ctx) # must NOT raise
|
|
174
|
+
finally:
|
|
175
|
+
mod.alternate_engine = orig
|
|
176
|
+
assert ctx.response().toasts[0][1] == "warning"
|
|
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.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/base_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/context_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/data_service.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/job_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/handlers/mixins/web_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/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
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/aws/tests/test_deploy_policies.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/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.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/initializer.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/base/operators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/mysql/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/postgres/types.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlite/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/reserved.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/sql.py
RENAMED
|
File without changes
|
{velocity_python-0.1.104 → velocity_python-0.1.105}/src/velocity/db/servers/sqlserver/types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|