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