velocity-python 0.1.133__tar.gz → 0.2.0__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 (392) hide show
  1. {velocity_python-0.1.133/src/velocity_python.egg-info → velocity_python-0.2.0}/PKG-INFO +11 -8
  2. {velocity_python-0.1.133 → velocity_python-0.2.0}/README.md +4 -0
  3. {velocity_python-0.1.133 → velocity_python-0.2.0}/pyproject.toml +15 -11
  4. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/__init__.py +1 -1
  5. velocity_python-0.2.0/src/velocity/aws/blobs.py +256 -0
  6. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/__init__.py +10 -1
  7. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/provisioning.py +109 -2
  8. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/__init__.py +31 -0
  9. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/config.py +94 -10
  10. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/operations.py +29 -6
  11. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/policies.py +196 -42
  12. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/reconcile.py +1 -0
  13. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/facets.py +132 -55
  14. velocity_python-0.2.0/src/velocity/aws/handlers/__init__.py +25 -0
  15. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/context.py +119 -4
  16. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/lambda_handler.py +19 -2
  17. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/__init__.py +6 -1
  18. velocity_python-0.2.0/src/velocity/aws/handlers/mixins/audit_trail.py +421 -0
  19. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/client_errors.py +73 -21
  20. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/client_input.py +45 -12
  21. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/data_service.py +772 -281
  22. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/row_scoped.py +42 -43
  23. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/response.py +17 -0
  24. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/job_results.py +146 -12
  25. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/s3.py +16 -3
  26. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/sms.py +209 -3
  27. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/column.py +5 -2
  28. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/table.py +125 -4
  29. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/transaction.py +7 -0
  30. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/base/initializer.py +9 -3
  31. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/base/sql.py +8 -0
  32. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/mysql/__init__.py +6 -5
  33. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/postgres/__init__.py +7 -6
  34. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/postgres/sql.py +247 -2
  35. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/postgres/types.py +56 -9
  36. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlite/__init__.py +6 -4
  37. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlserver/__init__.py +6 -5
  38. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/tablehelper.py +42 -24
  39. velocity_python-0.2.0/src/velocity/misc/conv/__init__.py +5 -0
  40. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/conv/iconv.py +59 -0
  41. velocity_python-0.2.0/src/velocity/misc/export.py +563 -0
  42. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/core/store.py +6 -2
  43. velocity_python-0.2.0/src/velocity/payment/__init__.py +89 -0
  44. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/_mirror_core.py +20 -2
  45. velocity_python-0.2.0/src/velocity/payment/plaid_api.py +240 -0
  46. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/plaid_webhook.py +22 -36
  47. velocity_python-0.2.0/src/velocity/testing/__init__.py +27 -0
  48. velocity_python-0.2.0/src/velocity/testing/fake_db.py +1468 -0
  49. {velocity_python-0.1.133 → velocity_python-0.2.0/src/velocity_python.egg-info}/PKG-INFO +11 -8
  50. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity_python.egg-info/SOURCES.txt +26 -0
  51. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity_python.egg-info/requires.txt +6 -7
  52. velocity_python-0.2.0/tests/test_audit_mixin.py +496 -0
  53. velocity_python-0.2.0/tests/test_blob_store.py +217 -0
  54. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_capabilities.py +144 -1
  55. velocity_python-0.2.0/tests/test_check_changelog.py +298 -0
  56. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_client_errors_mixin.py +121 -5
  57. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_client_sql_boundary.py +29 -3
  58. velocity_python-0.2.0/tests/test_client_table_gate_case_and_pointers.py +234 -0
  59. velocity_python-0.2.0/tests/test_context_queue_job.py +248 -0
  60. velocity_python-0.2.0/tests/test_conv_combine.py +83 -0
  61. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_data_service_query_cap.py +5 -1
  62. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_data_service_save_as.py +2 -0
  63. velocity_python-0.2.0/tests/test_data_service_security_gates.py +568 -0
  64. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_declared_column_types.py +45 -0
  65. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_deploy_config_fields.py +100 -0
  66. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_deploy_operations_queue.py +66 -0
  67. velocity_python-0.2.0/tests/test_deploy_policies.py +443 -0
  68. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_docs_snippets.py +1 -1
  69. velocity_python-0.2.0/tests/test_export_workbook.py +164 -0
  70. velocity_python-0.2.0/tests/test_facets_and_where.py +238 -0
  71. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_job_results.py +188 -6
  72. velocity_python-0.2.0/tests/test_merge_on_conflict.py +214 -0
  73. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_mirror_upsert_public.py +98 -0
  74. velocity_python-0.2.0/tests/test_payment_extra_bounds.py +63 -0
  75. velocity_python-0.2.0/tests/test_payment_lazy_imports.py +107 -0
  76. velocity_python-0.2.0/tests/test_pgserver_capability_types.py +149 -0
  77. velocity_python-0.2.0/tests/test_pgserver_get_tables.py +73 -0
  78. velocity_python-0.2.0/tests/test_pgserver_search_export.py +109 -0
  79. velocity_python-0.2.0/tests/test_plaid_api.py +293 -0
  80. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_postgres_initializer_config.py +53 -4
  81. velocity_python-0.2.0/tests/test_postgres_py_type.py +120 -0
  82. velocity_python-0.2.0/tests/test_restricted_direct_tables.py +212 -0
  83. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_row_scoped_data_service.py +28 -1
  84. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_s3_upload.py +46 -0
  85. velocity_python-0.2.0/tests/test_schema_lock_config_other_backends.py +94 -0
  86. velocity_python-0.2.0/tests/test_search_paging_export.py +661 -0
  87. velocity_python-0.2.0/tests/test_sms_twilio_signature.py +194 -0
  88. velocity_python-0.2.0/tests/test_table_claim.py +199 -0
  89. velocity_python-0.2.0/tests/test_testing_fake_db.py +652 -0
  90. velocity_python-0.1.133/src/velocity/aws/blobs.py +0 -91
  91. velocity_python-0.1.133/src/velocity/aws/handlers/__init__.py +0 -5
  92. velocity_python-0.1.133/src/velocity/misc/conv/__init__.py +0 -4
  93. velocity_python-0.1.133/src/velocity/misc/export.py +0 -268
  94. velocity_python-0.1.133/src/velocity/payment/__init__.py +0 -50
  95. velocity_python-0.1.133/tests/test_blob_store.py +0 -64
  96. velocity_python-0.1.133/tests/test_restricted_direct_tables.py +0 -59
  97. {velocity_python-0.1.133 → velocity_python-0.2.0}/LICENSE +0 -0
  98. {velocity_python-0.1.133 → velocity_python-0.2.0}/setup.cfg +0 -0
  99. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/__init__.py +0 -0
  100. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/amplify.py +0 -0
  101. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/assets/__init__.py +0 -0
  102. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/assets/backfill.py +0 -0
  103. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/assets/indexing.py +0 -0
  104. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/assets/references.py +0 -0
  105. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/assets/service.py +0 -0
  106. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/assets/usage_index.py +0 -0
  107. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/base.py +0 -0
  108. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/dispatch.py +0 -0
  109. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/infra.py +0 -0
  110. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/jobs.py +0 -0
  111. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/retention.py +0 -0
  112. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/security.py +0 -0
  113. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/capabilities/single_session.py +0 -0
  114. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/ci_gate.py +0 -0
  115. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/frontend_checks.py +0 -0
  116. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/deploy/targets.py +0 -0
  117. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/dirty_pipeline.py +0 -0
  118. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/email.py +0 -0
  119. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/failures.py +0 -0
  120. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/feature_flags.py +0 -0
  121. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/base_handler.py +0 -0
  122. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/context_factory.py +0 -0
  123. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/exceptions.py +0 -0
  124. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/masquerade.py +0 -0
  125. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/job_handler.py +0 -0
  126. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/session_control.py +0 -0
  127. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  128. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/perf.py +0 -0
  129. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  130. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/job_lifecycle.py +0 -0
  131. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/mirror.py +0 -0
  132. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/ops.py +0 -0
  133. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/queue_defaults.py +0 -0
  134. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/schema.py +0 -0
  135. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/ssm_config.py +0 -0
  136. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/__init__.py +0 -0
  137. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  138. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_deploy_least_privilege.py +0 -0
  139. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
  140. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_deploy_policy_size.py +0 -0
  141. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
  142. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_email.py +0 -0
  143. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  144. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_response.py +0 -0
  145. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/aws/tests/test_sms.py +0 -0
  146. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/cache.py +0 -0
  147. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/__init__.py +0 -0
  148. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/__init__.py +0 -0
  149. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/async_support.py +0 -0
  150. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/database.py +0 -0
  151. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/decorators.py +0 -0
  152. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/engine.py +0 -0
  153. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/jsonproxy.py +0 -0
  154. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/lazy_engine.py +0 -0
  155. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/result.py +0 -0
  156. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/row.py +0 -0
  157. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/sequence.py +0 -0
  158. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/core/view.py +0 -0
  159. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/exceptions.py +0 -0
  160. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/fragments.py +0 -0
  161. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/maintenance.py +0 -0
  162. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/migrations.py +0 -0
  163. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/__init__.py +0 -0
  164. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/base/__init__.py +0 -0
  165. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/base/operators.py +0 -0
  166. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/base/types.py +0 -0
  167. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/mysql/operators.py +0 -0
  168. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/mysql/reserved.py +0 -0
  169. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/mysql/sql.py +0 -0
  170. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/mysql/types.py +0 -0
  171. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/postgres/operators.py +0 -0
  172. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/postgres/reserved.py +0 -0
  173. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlite/operators.py +0 -0
  174. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  175. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlite/sql.py +0 -0
  176. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlite/types.py +0 -0
  177. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  178. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  179. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  180. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/servers/sqlserver/types.py +0 -0
  181. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/__init__.py +0 -0
  182. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/common_db_test.py +0 -0
  183. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/__init__.py +0 -0
  184. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/common.py +0 -0
  185. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/conftest.py +0 -0
  186. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_column.py +0 -0
  187. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  188. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_database.py +0 -0
  189. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  190. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  191. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  192. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_result.py +0 -0
  193. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_row.py +0 -0
  194. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  195. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  196. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  197. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  198. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  199. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_table.py +0 -0
  200. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  201. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  202. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/sql/__init__.py +0 -0
  203. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/sql/common.py +0 -0
  204. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  205. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  206. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  207. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_db_utils.py +0 -0
  208. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_postgres.py +0 -0
  209. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  210. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  211. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_result_caching.py +0 -0
  212. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  213. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  214. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  215. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  216. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_sql_builder.py +0 -0
  217. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_tablehelper.py +0 -0
  218. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tests/test_view_helper.py +0 -0
  219. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/tunnel.py +0 -0
  220. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/db/utils.py +0 -0
  221. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/logging.py +0 -0
  222. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/__init__.py +0 -0
  223. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/conv/oconv.py +0 -0
  224. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/db.py +0 -0
  225. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/format.py +0 -0
  226. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/mail.py +0 -0
  227. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/merge.py +0 -0
  228. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/pdf.py +0 -0
  229. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/__init__.py +0 -0
  230. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_db.py +0 -0
  231. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_fix.py +0 -0
  232. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_format.py +0 -0
  233. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_iconv.py +0 -0
  234. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_mail_send.py +0 -0
  235. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_merge.py +0 -0
  236. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_oconv.py +0 -0
  237. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_original_error.py +0 -0
  238. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tests/test_timer.py +0 -0
  239. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/timer.py +0 -0
  240. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/misc/tools.py +0 -0
  241. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/__init__.py +0 -0
  242. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/core/__init__.py +0 -0
  243. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/core/capabilities.py +0 -0
  244. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/core/where.py +0 -0
  245. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/exceptions.py +0 -0
  246. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/__init__.py +0 -0
  247. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/base/__init__.py +0 -0
  248. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
  249. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
  250. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
  251. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
  252. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
  253. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
  254. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
  255. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
  256. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/memory/__init__.py +0 -0
  257. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
  258. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
  259. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/nosql/servers/redis/__init__.py +0 -0
  260. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/authorizenet_adapter.py +0 -0
  261. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/authorizenet_mirror.py +0 -0
  262. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/base_adapter.py +0 -0
  263. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/braintree_adapter.py +0 -0
  264. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/braintree_mirror.py +0 -0
  265. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/charge_rules.py +0 -0
  266. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/money.py +0 -0
  267. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/redact.py +0 -0
  268. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/schema.py +0 -0
  269. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/stripe_adapter.py +0 -0
  270. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity/payment/stripe_mirror.py +0 -0
  271. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  272. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity_python.egg-info/entry_points.txt +0 -0
  273. {velocity_python-0.1.133 → velocity_python-0.2.0}/src/velocity_python.egg-info/top_level.txt +0 -0
  274. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_access_error_403.py +0 -0
  275. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_activity_tracking_aborted_tx.py +0 -0
  276. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_amplify_redirects.py +0 -0
  277. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_asset_indexing.py +0 -0
  278. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_asset_references.py +0 -0
  279. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_assets_service.py +0 -0
  280. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_async_support.py +0 -0
  281. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_aws_package_hygiene.py +0 -0
  282. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_batch_operations.py +0 -0
  283. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_capability_catalog.py +0 -0
  284. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_ci_gate.py +0 -0
  285. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_client_input_contract_export.py +0 -0
  286. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_cognito_user_cache.py +0 -0
  287. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_column_tx_arg.py +0 -0
  288. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_concurrency_safety.py +0 -0
  289. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_connection_pool.py +0 -0
  290. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_connection_resilience.py +0 -0
  291. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_context_flags_loader.py +0 -0
  292. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_context_job_descriptions.py +0 -0
  293. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_data_service_renumber.py +0 -0
  294. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_data_service_row_number.py +0 -0
  295. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_db_credentials_ssm_cascade.py +0 -0
  296. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_db_maintenance.py +0 -0
  297. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_db_tunnel.py +0 -0
  298. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_decorators.py +0 -0
  299. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_delete_hook_fk_blocked.py +0 -0
  300. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_deploy_engine.py +0 -0
  301. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_deploy_frontend_checks.py +0 -0
  302. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_dirty_pipeline_fast_path.py +0 -0
  303. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_dlq_constant.py +0 -0
  304. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_email_processing.py +0 -0
  305. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_enqueue_metric_namespace.py +0 -0
  306. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_enqueue_send_failures.py +0 -0
  307. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_ensure_infrastructure.py +0 -0
  308. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_facets.py +0 -0
  309. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_failures.py +0 -0
  310. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_feature_flags.py +0 -0
  311. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_get_cognito_user_provider.py +0 -0
  312. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_http_handler_rollback.py +0 -0
  313. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_iconv_money_to_cents.py +0 -0
  314. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_identifier_injection_guard.py +0 -0
  315. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_job_handler.py +0 -0
  316. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_job_lifecycle.py +0 -0
  317. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_json_columns.py +0 -0
  318. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_jsonb_dict_adapter.py +0 -0
  319. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_lambda_handler.py +0 -0
  320. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_lambda_handler_auth.py +0 -0
  321. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_lambda_handler_masquerade.py +0 -0
  322. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_lambda_handler_user_cache.py +0 -0
  323. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_lazy_engine.py +0 -0
  324. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_masquerade_grant.py +0 -0
  325. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_mirror.py +0 -0
  326. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_mixins_import.py +0 -0
  327. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_n_plus_one.py +0 -0
  328. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_nosql_dynamodb.py +0 -0
  329. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_nosql_memory.py +0 -0
  330. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_nosql_mongodb.py +0 -0
  331. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_nosql_redis.py +0 -0
  332. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_nosql_translation.py +0 -0
  333. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_nosql_where.py +0 -0
  334. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_observability.py +0 -0
  335. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_on_action_default.py +0 -0
  336. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_on_commit.py +0 -0
  337. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_ops.py +0 -0
  338. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_audit_fixes.py +0 -0
  339. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_authorizenet_adapter.py +0 -0
  340. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_braintree_adapter.py +0 -0
  341. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_braintree_mirror.py +0 -0
  342. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_business_agnostic.py +0 -0
  343. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_mirror_empty_table.py +0 -0
  344. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_profile_sorting.py +0 -0
  345. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_payment_stripe_adapter.py +0 -0
  346. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_pdf.py +0 -0
  347. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_pgserver_bulk_cache.py +0 -0
  348. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_pgserver_ensure_infrastructure.py +0 -0
  349. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_pgserver_pointer_joins.py +0 -0
  350. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_plaid_webhook.py +0 -0
  351. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_pointer_join_sql.py +0 -0
  352. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_prepared_statements.py +0 -0
  353. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_psycopg3_upgrade.py +0 -0
  354. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_query_cache.py +0 -0
  355. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_query_missing_table_unlocked.py +0 -0
  356. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_raw_sql_prefix_policy.py +0 -0
  357. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_read_cache.py +0 -0
  358. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_readme_imports.py +0 -0
  359. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_response.py +0 -0
  360. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_result_returning.py +0 -0
  361. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_retry_side_effect_guard.py +0 -0
  362. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_return_default_safety.py +0 -0
  363. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_row_batch_update.py +0 -0
  364. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_row_cache_staleness.py +0 -0
  365. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_s3_bucket_config.py +0 -0
  366. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_s3_list_client_files.py +0 -0
  367. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_schema_migrations.py +0 -0
  368. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_security_capability.py +0 -0
  369. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_security_hardening.py +0 -0
  370. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_server_cursor.py +0 -0
  371. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_session_control.py +0 -0
  372. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_single_autocommit_safety.py +0 -0
  373. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_single_session_capability.py +0 -0
  374. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_spreadsheet_functions.py +0 -0
  375. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_sqlite_backend.py +0 -0
  376. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_sqs_per_record_transactions.py +0 -0
  377. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_ssm_config.py +0 -0
  378. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_ssm_config_require.py +0 -0
  379. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_store_user_data.py +0 -0
  380. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  381. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_table_alter.py +0 -0
  382. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_table_find_cache.py +0 -0
  383. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_table_purge.py +0 -0
  384. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_transaction_class_wrapping.py +0 -0
  385. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_transaction_commit_and_ownership.py +0 -0
  386. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_transaction_edge_cases.py +0 -0
  387. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_tx_lifecycle_retry.py +0 -0
  388. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_tx_read_cache_and_bulk.py +0 -0
  389. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_user_not_provisioned.py +0 -0
  390. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_where_clause_validation.py +0 -0
  391. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_write_hook_create_flow.py +0 -0
  392. {velocity_python-0.1.133 → velocity_python-0.2.0}/tests/test_write_hook_empty_strings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.133
3
+ Version: 0.2.0
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
@@ -52,11 +52,10 @@ Requires-Dist: python-tds>=1.15.0; extra == "sqlserver"
52
52
  Provides-Extra: postgres
53
53
  Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgres"
54
54
  Provides-Extra: payment
55
- Requires-Dist: stripe>=12.0.0; extra == "payment"
56
- Requires-Dist: braintree>=4.30.0; extra == "payment"
57
- Requires-Dist: xmltodict>=0.13.0; extra == "payment"
55
+ Requires-Dist: stripe<17,>=15.0.0; extra == "payment"
56
+ Requires-Dist: braintree<5,>=4.30.0; extra == "payment"
57
+ Requires-Dist: xmltodict<2,>=0.13.0; extra == "payment"
58
58
  Provides-Extra: plaid
59
- Requires-Dist: velocity-python[payment]; extra == "plaid"
60
59
  Requires-Dist: ecdsa>=0.19.0; extra == "plaid"
61
60
  Provides-Extra: all
62
61
  Requires-Dist: velocity-python[aws,excel,http,payment,pdf,plaid,postgres,templates]; extra == "all"
@@ -76,9 +75,9 @@ Requires-Dist: pytest-asyncio>=1.0.0; extra == "test"
76
75
  Requires-Dist: psycopg[binary]>=3.2.0; extra == "test"
77
76
  Requires-Dist: boto3>=1.35.0; extra == "test"
78
77
  Requires-Dist: requests>=2.32.0; extra == "test"
79
- Requires-Dist: stripe>=12.0.0; extra == "test"
80
- Requires-Dist: braintree>=4.30.0; extra == "test"
81
- Requires-Dist: xmltodict>=0.13.0; extra == "test"
78
+ Requires-Dist: stripe<17,>=15.0.0; extra == "test"
79
+ Requires-Dist: braintree<5,>=4.30.0; extra == "test"
80
+ Requires-Dist: xmltodict<2,>=0.13.0; extra == "test"
82
81
  Requires-Dist: authorizenet>=1.1.3; extra == "test"
83
82
  Requires-Dist: ecdsa>=0.19.0; extra == "test"
84
83
  Requires-Dist: openpyxl>=3.1.0; extra == "test"
@@ -247,6 +246,8 @@ def import_customers(tx, records):
247
246
  ## Documentation
248
247
 
249
248
  Full documentation is included in the `docs/` directory of the source distribution.
249
+ What changed in each release, and what callers must do before upgrading, is in
250
+ [`CHANGELOG.md`](CHANGELOG.md) (Breaking / Deploy ordering / Added / Fixed per version).
250
251
 
251
252
  | Guide | File | Description |
252
253
  |-------|------|-------------|
@@ -265,6 +266,8 @@ Full documentation is included in the `docs/` directory of the source distributi
265
266
  | Utilities | `docs/utilities.md` | Excel/PDF export, data conversion, formatting, timers, email parsing and SMTP sending |
266
267
  | Testing Guide | `docs/TESTING.md` | Running tests, markers, coverage |
267
268
  | Security | `docs/SECURITY.md` | Pre-commit hooks, credential scanning |
269
+ | Changelog | `CHANGELOG.md` | Per-release breaking changes, deploy ordering, additions and fixes |
270
+ | Improvement Backlog | `docs/IMPROVEMENT_BACKLOG.md` | Proposed and deferred library improvements |
268
271
 
269
272
  ---
270
273
 
@@ -153,6 +153,8 @@ def import_customers(tx, records):
153
153
  ## Documentation
154
154
 
155
155
  Full documentation is included in the `docs/` directory of the source distribution.
156
+ What changed in each release, and what callers must do before upgrading, is in
157
+ [`CHANGELOG.md`](CHANGELOG.md) (Breaking / Deploy ordering / Added / Fixed per version).
156
158
 
157
159
  | Guide | File | Description |
158
160
  |-------|------|-------------|
@@ -171,6 +173,8 @@ Full documentation is included in the `docs/` directory of the source distributi
171
173
  | Utilities | `docs/utilities.md` | Excel/PDF export, data conversion, formatting, timers, email parsing and SMTP sending |
172
174
  | Testing Guide | `docs/TESTING.md` | Running tests, markers, coverage |
173
175
  | Security | `docs/SECURITY.md` | Pre-commit hooks, credential scanning |
176
+ | Changelog | `CHANGELOG.md` | Per-release breaking changes, deploy ordering, additions and fixes |
177
+ | Improvement Backlog | `docs/IMPROVEMENT_BACKLOG.md` | Proposed and deferred library improvements |
174
178
 
175
179
  ---
176
180
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.1.133"
7
+ version = "0.2.0"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -83,18 +83,22 @@ sqlserver = [
83
83
  postgres = [
84
84
  "psycopg[binary]>=3.2.0",
85
85
  ]
86
+ # Tested bounds: the unit suite passes on stripe 15.0.x and 16.0.0 and on
87
+ # braintree 4.42 and 4.47. Raise an upper bound only after `make test-unit`
88
+ # passes on the new major (stripe objects stopped being dicts in 13; each
89
+ # stripe major also moves the default API version, so callers should pin
90
+ # stripe.api_version). Apps pin exact versions inside these bounds (see
91
+ # docs/payment.md "Installation").
86
92
  payment = [
87
- "stripe>=12.0.0",
88
- "braintree>=4.30.0",
89
- "xmltodict>=0.13.0",
93
+ "stripe>=15.0.0,<17",
94
+ "braintree>=4.30.0,<5",
95
+ "xmltodict>=0.13.0,<2",
90
96
  ]
91
97
  # Plaid webhook ES256 verification (velocity.payment.plaid_webhook). ecdsa is
92
98
  # pure Python, so it fits a Lambda layer where `cryptography` does not.
93
- # Includes [payment] because importing velocity.payment.plaid_webhook runs
94
- # velocity/payment/__init__.py, which imports stripe and braintree eagerly;
95
- # drop it once those package-level imports are lazy or guarded.
99
+ # velocity/payment/__init__.py imports the processor adapters lazily, so
100
+ # importing plaid_webhook needs no stripe/braintree (tests/test_payment_lazy_imports.py).
96
101
  plaid = [
97
- "velocity-python[payment]",
98
102
  "ecdsa>=0.19.0",
99
103
  ]
100
104
  all = [
@@ -120,9 +124,9 @@ test = [
120
124
  "psycopg[binary]>=3.2.0",
121
125
  "boto3>=1.35.0",
122
126
  "requests>=2.32.0",
123
- "stripe>=12.0.0",
124
- "braintree>=4.30.0",
125
- "xmltodict>=0.13.0",
127
+ "stripe>=15.0.0,<17",
128
+ "braintree>=4.30.0,<5",
129
+ "xmltodict>=0.13.0,<2",
126
130
  "authorizenet>=1.1.3",
127
131
  "ecdsa>=0.19.0",
128
132
  "openpyxl>=3.1.0",
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.133"
1
+ __version__ = version = "0.2.0"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -0,0 +1,256 @@
1
+ """Content-addressed S3 blob store.
2
+
3
+ For offloading large row payloads (raw emails, documents, exports) out of
4
+ Postgres while the row keeps only the content hash. Keys are derived from
5
+ the sha256 of the content, so storage is idempotent and deduplicating by
6
+ construction: the same bytes always land on the same key, and a re-upload
7
+ of an existing object is skipped.
8
+
9
+ store = BlobStore("my-bucket", prefix="demo/gmail-raw", suffix=".eml")
10
+ sha, key = store.put_bytes(raw) # no-op if already stored
11
+ raw = store.get_bytes(sha) # or get_bytes(key)
12
+ url = store.presigned_get(sha) # hand-off to a browser
13
+
14
+ A site's per-stage store (keys under ``{stage}/{family}``, the bucket named by
15
+ a config key) comes from :meth:`BlobStore.for_stage`; browser uploads go
16
+ straight to S3 through :meth:`BlobStore.presigned_put`:
17
+
18
+ store = BlobStore.for_stage("BlobBucket", "forms/assets")
19
+ upload = store.presigned_put(key, content_type="image/png")
20
+ # -> {"url": ..., "key": key, "bucket": ...}; the browser PUTs the body
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import hashlib
26
+ import os
27
+ import re
28
+ import unicodedata
29
+ from typing import Optional, Tuple
30
+ from urllib.parse import quote
31
+
32
+ #: The stage segment used when neither the caller nor the environment names one.
33
+ UNKNOWN_STAGE = "unknown"
34
+
35
+ _UNSAFE_HEADER_CHARS = re.compile(r'["\\\x00-\x1f\x7f]')
36
+
37
+
38
+ class BlobStoreNotConfigured(LookupError):
39
+ """No bucket is configured for a :meth:`BlobStore.for_stage` store.
40
+
41
+ ``bucket_key`` is the config key that was looked up; the message names it
42
+ and is safe to show an operator.
43
+ """
44
+
45
+ def __init__(self, bucket_key: str):
46
+ self.bucket_key = bucket_key
47
+ super().__init__(f"no {bucket_key} is configured for this environment")
48
+
49
+
50
+ def resolve_bucket(bucket_key: str, bucket: Optional[str] = None) -> Optional[str]:
51
+ """``bucket`` when given, else the ``bucket_key`` config value
52
+ (:func:`velocity.aws.ssm_config.getenv`), else None. Whitespace is stripped."""
53
+ value = str(bucket or "").strip()
54
+ if value:
55
+ return value
56
+ from velocity.aws import ssm_config
57
+
58
+ return str(ssm_config.getenv(bucket_key) or "").strip() or None
59
+
60
+
61
+ def resolve_stage(stage: Optional[str] = None, default: str = UNKNOWN_STAGE) -> str:
62
+ """``stage`` when given, else :func:`velocity.aws.ssm_config.get_stage`
63
+ (``AppStage``, then its compatibility aliases), else ``default``."""
64
+ value = str(stage or "").strip()
65
+ if value:
66
+ return value
67
+ from velocity.aws import ssm_config
68
+
69
+ return str(ssm_config.get_stage() or "").strip() or default
70
+
71
+
72
+ def stage_prefix(family: str, stage: Optional[str] = None) -> str:
73
+ """``{stage}/{family}``: the per-environment key prefix of a store family."""
74
+ family = str(family or "").strip("/")
75
+ if not family:
76
+ raise ValueError("stage_prefix requires a family")
77
+ return f"{resolve_stage(stage)}/{family}"
78
+
79
+
80
+ def attachment_disposition(filename: str) -> str:
81
+ """A ``Content-Disposition: attachment`` value naming ``filename``.
82
+
83
+ S3 refuses a response header it cannot represent in ISO-8859-1, and a
84
+ quote would end the value early, so ``filename=`` carries an ASCII
85
+ rendering (accents folded, quotes / backslashes / control characters
86
+ replaced, ``download`` when nothing ASCII is left of the stem); a name that is not plain ASCII also gets the RFC 5987
87
+ ``filename*=UTF-8''...`` form, which browsers prefer.
88
+ """
89
+
90
+ def fold(text):
91
+ folded = unicodedata.normalize("NFKD", text).encode("ascii", "ignore")
92
+ return _UNSAFE_HEADER_CHARS.sub("_", folded.decode("ascii"))
93
+
94
+ name = str(filename or "").strip()
95
+ stem, extension = os.path.splitext(name)
96
+ stem = fold(stem).strip()
97
+ ascii_name = (stem if stem.strip(" ._") else "download") + fold(extension)
98
+ value = f'attachment; filename="{ascii_name}"'
99
+ if name and ascii_name != name:
100
+ value += f"; filename*=UTF-8''{quote(name, safe='')}"
101
+ return value
102
+
103
+
104
+ class BlobStore:
105
+ def __init__(
106
+ self,
107
+ bucket: str,
108
+ prefix: str = "",
109
+ suffix: str = "",
110
+ region: Optional[str] = None,
111
+ client=None,
112
+ ):
113
+ if not bucket:
114
+ raise ValueError("BlobStore requires a bucket name")
115
+ self.bucket = bucket
116
+ self.prefix = prefix.strip("/")
117
+ self.suffix = suffix
118
+ self.region = region
119
+ self._client = client
120
+
121
+ @classmethod
122
+ def for_stage(
123
+ cls,
124
+ bucket_key: str,
125
+ family: str,
126
+ *,
127
+ suffix: str = "",
128
+ bucket: Optional[str] = None,
129
+ stage: Optional[str] = None,
130
+ region: Optional[str] = None,
131
+ client=None,
132
+ ) -> "BlobStore":
133
+ """The store for one key family of this environment.
134
+
135
+ The bucket is ``bucket`` or the ``bucket_key`` config value
136
+ (:func:`resolve_bucket`); keys live under ``{stage}/{family}``, the
137
+ stage being ``stage`` or :func:`velocity.aws.ssm_config.get_stage`
138
+ (:func:`resolve_stage`). Raises :class:`BlobStoreNotConfigured` when no
139
+ bucket resolves. Explicit ``bucket`` / ``stage`` serve local tools,
140
+ where nothing sets the Lambda environment.
141
+ """
142
+ name = resolve_bucket(bucket_key, bucket)
143
+ if name is None:
144
+ raise BlobStoreNotConfigured(bucket_key)
145
+ return cls(
146
+ name,
147
+ prefix=stage_prefix(family, stage),
148
+ suffix=suffix,
149
+ region=region,
150
+ client=client,
151
+ )
152
+
153
+ @property
154
+ def client(self):
155
+ if self._client is None:
156
+ import boto3
157
+
158
+ kwargs = {"region_name": self.region} if self.region else {}
159
+ self._client = boto3.client("s3", **kwargs)
160
+ return self._client
161
+
162
+ def key_for(self, sha256_hex: str) -> str:
163
+ name = f"{sha256_hex}{self.suffix}"
164
+ return f"{self.prefix}/{name}" if self.prefix else name
165
+
166
+ def _resolve_key(self, sha_or_key: str) -> str:
167
+ # A bare 64-hex-char sha resolves through key_for; anything else is
168
+ # treated as a full key (lets callers store either form).
169
+ value = str(sha_or_key)
170
+ if len(value) == 64 and all(c in "0123456789abcdef" for c in value.lower()):
171
+ return self.key_for(value.lower())
172
+ return value
173
+
174
+ def exists(self, sha_or_key: str) -> bool:
175
+ try:
176
+ self.client.head_object(
177
+ Bucket=self.bucket, Key=self._resolve_key(sha_or_key)
178
+ )
179
+ return True
180
+ except Exception:
181
+ return False
182
+
183
+ def put_bytes(
184
+ self, data: bytes, content_type: Optional[str] = None
185
+ ) -> Tuple[str, str]:
186
+ """Store ``data`` (idempotent); returns (sha256_hex, key)."""
187
+ payload = bytes(data or b"")
188
+ sha = hashlib.sha256(payload).hexdigest()
189
+ key = self.key_for(sha)
190
+ if not self.exists(key):
191
+ params = {"Bucket": self.bucket, "Key": key, "Body": payload}
192
+ if content_type:
193
+ params["ContentType"] = content_type
194
+ self.client.put_object(**params)
195
+ return sha, key
196
+
197
+ def get_bytes(self, sha_or_key: str) -> bytes:
198
+ response = self.client.get_object(
199
+ Bucket=self.bucket, Key=self._resolve_key(sha_or_key)
200
+ )
201
+ return response["Body"].read()
202
+
203
+ def presigned_get(
204
+ self,
205
+ sha_or_key: str,
206
+ expires_seconds: int = 900,
207
+ *,
208
+ filename: Optional[str] = None,
209
+ content_type: Optional[str] = None,
210
+ ) -> str:
211
+ """A presigned GET URL. ``filename`` makes the browser save the object
212
+ under that name (:func:`attachment_disposition`) rather than its hash
213
+ key; ``content_type`` overrides the served ``Content-Type``."""
214
+ params = {"Bucket": self.bucket, "Key": self._resolve_key(sha_or_key)}
215
+ if filename:
216
+ params["ResponseContentDisposition"] = attachment_disposition(filename)
217
+ if content_type:
218
+ params["ResponseContentType"] = content_type
219
+ return self.client.generate_presigned_url(
220
+ "get_object", Params=params, ExpiresIn=int(expires_seconds)
221
+ )
222
+
223
+ def presigned_put(
224
+ self,
225
+ sha_or_key: str,
226
+ *,
227
+ content_type: Optional[str] = None,
228
+ expires_seconds: int = 900,
229
+ content_length: Optional[int] = None,
230
+ ) -> dict:
231
+ """A presigned PUT for a direct browser-to-S3 upload.
232
+
233
+ Returns ``{"url", "key", "bucket"}``; the client sends
234
+ ``fetch(url, {method: "PUT", body})``. ``content_type``, when given, is
235
+ signed, so the PUT must send that exact ``Content-Type`` (S3 answers
236
+ 403 otherwise). ``content_length`` signs ``Content-Length`` too, so a
237
+ SigV4 URL accepts only a body of exactly that many bytes — the way to
238
+ make a size limit the caller validated binding (a presigned PUT cannot
239
+ carry a range; that needs a presigned POST policy).
240
+
241
+ Mint the key server-side (``key_for(sha)``, or a key derived from a
242
+ record id) and never sign a key the client names.
243
+ """
244
+ key = self._resolve_key(sha_or_key)
245
+ params = {"Bucket": self.bucket, "Key": key}
246
+ if content_type:
247
+ params["ContentType"] = content_type
248
+ if content_length is not None:
249
+ length = int(content_length)
250
+ if length < 0:
251
+ raise ValueError("content_length must not be negative")
252
+ params["ContentLength"] = length
253
+ url = self.client.generate_presigned_url(
254
+ "put_object", Params=params, ExpiresIn=int(expires_seconds)
255
+ )
256
+ return {"url": url, "key": key, "bucket": self.bucket}
@@ -28,7 +28,13 @@ from .dispatch import ( # noqa: F401
28
28
  CapabilityDispatcher,
29
29
  run_capability,
30
30
  )
31
- from .provisioning import provision, trigger_key # noqa: F401
31
+ from .provisioning import ( # noqa: F401
32
+ as_bool,
33
+ provision,
34
+ row_enabled,
35
+ trigger_key,
36
+ upgrade_column_types,
37
+ )
32
38
 
33
39
  # built-ins (importing registers them)
34
40
  from . import retention # noqa: E402,F401
@@ -44,6 +50,7 @@ __all__ = [
44
50
  "CapabilityDispatcher",
45
51
  "POLICY_KINDS",
46
52
  "REGISTRY",
53
+ "as_bool",
47
54
  "capability",
48
55
  "catalog",
49
56
  "describe",
@@ -52,9 +59,11 @@ __all__ = [
52
59
  "policy_field",
53
60
  "provision",
54
61
  "resolve_config",
62
+ "row_enabled",
55
63
  "run_capability",
56
64
  "summarize_policy",
57
65
  "trigger_key",
66
+ "upgrade_column_types",
58
67
  "validate_policy",
59
68
  "NIGHTLY",
60
69
  "HOURLY",
@@ -44,13 +44,21 @@ PROGRAM_SOURCE = (
44
44
  )
45
45
 
46
46
 
47
+ CAPABILITIES_NAME_INDEX = f"idx__{SITE_TABLE}__name"
48
+
47
49
  # The table velocity owns for this module; ensured by provision() and by
48
50
  # velocity.aws.schema.ensure_infrastructure() (the pre-lock schema step).
49
51
  SCHEMA = {
50
52
  SITE_TABLE: {
51
- "columns": {"name": "TEXT", "enabled": "BOOLEAN", "config": "TEXT"},
53
+ # Declared SQL types. Sites provisioned before velocity honoured them
54
+ # hold TEXT here; upgrade_column_types() casts those in place.
55
+ "columns": {"name": "TEXT", "enabled": "BOOLEAN", "config": "JSONB"},
52
56
  # provision() merges on name: ON CONFLICT needs this unique index.
53
- "unique_indexes": [{"columns": ["name"], "name": "sys_capabilities_name_uidx"}],
57
+ # Named as velocity's merge self-heal names it (idx__<table>__<cols>),
58
+ # which is also the name app schema lanes declare with
59
+ # CREATE UNIQUE INDEX IF NOT EXISTS, so an environment provisioned
60
+ # first and one synced first end up with one identical index.
61
+ "unique_indexes": [{"columns": ["name"], "name": CAPABILITIES_NAME_INDEX}],
54
62
  },
55
63
  }
56
64
 
@@ -79,6 +87,105 @@ def row_enabled(row) -> bool:
79
87
  return as_bool((row or {}).get("enabled"), default=True)
80
88
 
81
89
 
90
+ def _enabled_using(column: str) -> str:
91
+ """``USING`` expression casting a TEXT ``enabled`` exactly as
92
+ :func:`as_bool` reads it: NULL stays NULL (on), the false spellings are
93
+ FALSE, anything else TRUE — never a cast error on an odd value."""
94
+ falses = ", ".join(f"'{text}'" for text in sorted(_FALSE_TEXT))
95
+ return (
96
+ f"CASE WHEN {column} IS NULL THEN NULL "
97
+ f"WHEN lower(btrim({column})) IN ({falses}) THEN FALSE ELSE TRUE END"
98
+ )
99
+
100
+
101
+ def _config_using(column: str) -> str:
102
+ """``USING`` expression for a TEXT ``config``: blank becomes NULL (read as
103
+ ``{}``), everything else is cast as JSON — pre-checked by
104
+ :func:`_invalid_configs`, so the cast cannot fail half-way."""
105
+ return f"NULLIF(btrim({column}), '')::jsonb"
106
+
107
+
108
+ # column -> (information_schema data_type wanted, declared DDL, USING builder)
109
+ COLUMN_UPGRADES = {
110
+ "enabled": ("boolean", "BOOLEAN", _enabled_using),
111
+ "config": ("jsonb", "JSONB", _config_using),
112
+ }
113
+
114
+
115
+ def _invalid_configs(table) -> list:
116
+ """Names of rows whose TEXT ``config`` is not blank and not a JSON
117
+ object — the rows that would fail the JSONB cast or fail
118
+ :func:`velocity.aws.capabilities.base.load_config` afterwards."""
119
+ bad = []
120
+ for row in table.select(columns=["name", "config"]):
121
+ raw = row.get("config")
122
+ if raw is None or not str(raw).strip():
123
+ continue
124
+ try:
125
+ value = json.loads(raw)
126
+ except ValueError:
127
+ value = None
128
+ if not isinstance(value, dict):
129
+ bad.append(row.get("name"))
130
+ return bad
131
+
132
+
133
+ def upgrade_column_types(tx, *, dry_run: bool = False) -> list:
134
+ """Cast a TEXT ``sys_capabilities.enabled`` / ``config`` to the declared
135
+ BOOLEAN / JSONB, in place. Idempotent: an absent table, a column already
136
+ typed, or a non-PostgreSQL server is a no-op (``[]``).
137
+
138
+ For an app's migration lane: provisioning and ``ensure_infrastructure``
139
+ never rewrite an existing column's type, so a site whose table was created
140
+ while velocity read declared types as sample values keeps TEXT until this
141
+ runs. Returns ``[{"column", "from", "to", "sql"}, ...]`` for each column
142
+ changed (or, with ``dry_run=True``, that would change — nothing runs).
143
+
144
+ Raises ``ValueError`` before any DDL when a column has a type other than
145
+ TEXT or the declared one, or when a ``config`` value is not a JSON object
146
+ (named, so an operator can fix those rows first).
147
+ """
148
+ table = tx.table(SITE_TABLE)
149
+ if not str(getattr(table.sql, "server", "")).lower().startswith("postgre"):
150
+ return []
151
+ if not table.exists():
152
+ return []
153
+ types = {str(k).lower(): str(v).lower() for k, v in table.column_types().items()}
154
+
155
+ pending = {}
156
+ for column, (wanted, ddl, using) in COLUMN_UPGRADES.items():
157
+ current = types.get(column)
158
+ if current is None or current == wanted:
159
+ continue
160
+ if current != "text":
161
+ raise ValueError(
162
+ f"{SITE_TABLE}.{column} is {current!r}; expected text or "
163
+ f"{wanted} — inspect it by hand"
164
+ )
165
+ pending[column] = (current, wanted, ddl, using)
166
+ if not pending:
167
+ return []
168
+
169
+ if "config" in pending:
170
+ bad = _invalid_configs(table)
171
+ if bad:
172
+ raise ValueError(
173
+ f"{SITE_TABLE}.config is not a JSON object for: "
174
+ f"{', '.join(map(str, bad))} — fix those rows, then rerun"
175
+ )
176
+
177
+ changes = []
178
+ columns = {}
179
+ for column, (current, wanted, ddl, using) in pending.items():
180
+ spec = {"type": ddl, "using": using(table.sql.quote_identifier(column))}
181
+ sql, _vals = table.alter({column: spec}, sql_only=True, declared=True)
182
+ changes.append({"column": column, "from": current, "to": wanted, "sql": sql})
183
+ columns[column] = spec
184
+ if not dry_run:
185
+ table.migrate_schema(columns=columns)
186
+ return changes
187
+
188
+
82
189
  def trigger_key(cap_name: str, action: str) -> str:
83
190
  return f"cap:{cap_name}:{action}"
84
191
 
@@ -25,6 +25,15 @@ Frontend build check (``python build.py validate-frontend``):
25
25
  from velocity.aws.deploy import validate_yarn_frontend
26
26
  validate_yarn_frontend(PROJECT_ROOT, extra_amplify_yml_steps=(...))
27
27
 
28
+ IAM statement builders (pure; resources may be CloudFormation intrinsics),
29
+ for templates that should grant exactly what velocity's deploys grant:
30
+
31
+ from velocity.aws.deploy import (
32
+ ssm_parameter_arns, ssm_read_statement, queue_consumer_statement,
33
+ queue_producer_statement, failure_topic_publish_statement,
34
+ dlq_redrive_policy,
35
+ )
36
+
28
37
  See docs/deploy.md in the velocity-python repo for deployment, and the
29
38
  "CI regression gate" section of docs/aws-handlers.md for ci_gate.
30
39
  """
@@ -40,13 +49,24 @@ from velocity.aws.deploy.frontend_checks import (
40
49
  from velocity.aws.deploy.policies import (
41
50
  AWS_LAMBDA_VPC_ACCESS_ARN,
42
51
  IAM_MANAGED_POLICY_MAX_CHARS,
52
+ QUEUE_CONSUME_ACTIONS,
53
+ SEND_QUEUE_ACTIONS,
54
+ SSM_READ_ACTIONS,
43
55
  ManagedPolicySizeError,
44
56
  app_policy_name,
45
57
  app_runtime_statements,
46
58
  baseline_lambda_policy_document,
59
+ dlq_redrive_policy,
47
60
  ensure_app_policy,
61
+ failure_topic_publish_statement,
62
+ queue_consumer_statement,
63
+ queue_producer_statement,
64
+ queue_worker_statement,
48
65
  reconcile_role_policies,
49
66
  retire_policy,
67
+ ssm_decrypt_statement,
68
+ ssm_parameter_arns,
69
+ ssm_read_statement,
50
70
  sync_managed_policy_document,
51
71
  )
52
72
  from velocity.aws.deploy.operations import (
@@ -93,10 +113,14 @@ __all__ = [
93
113
  "ManagedPolicySizeError",
94
114
  "MasqueradeReconcile",
95
115
  "PlainTarget",
116
+ "QUEUE_CONSUME_ACTIONS",
117
+ "SEND_QUEUE_ACTIONS",
118
+ "SSM_READ_ACTIONS",
96
119
  "app_policy_name",
97
120
  "app_runtime_statements",
98
121
  "apply_reserved_concurrency",
99
122
  "baseline_lambda_policy_document",
123
+ "dlq_redrive_policy",
100
124
  "ensure_alarm_topic",
101
125
  "ensure_api_cors_header",
102
126
  "ensure_app_policy",
@@ -105,11 +129,15 @@ __all__ = [
105
129
  "ensure_identity_pool_developer_provider",
106
130
  "ensure_queue_alarms",
107
131
  "ensure_queue_event_source_mapping",
132
+ "failure_topic_publish_statement",
108
133
  "get_amplify_app_id_and_branch",
109
134
  "initialize_build_environment",
110
135
  "list_functions_by_tag",
111
136
  "queue_alarm_definitions",
137
+ "queue_consumer_statement",
138
+ "queue_producer_statement",
112
139
  "queue_visibility_timeout",
140
+ "queue_worker_statement",
113
141
  "reconcile_role_policies",
114
142
  "resolve_deploy_config_value",
115
143
  "resolve_latest_layer_arns",
@@ -121,6 +149,9 @@ __all__ = [
121
149
  "run_post_deploy_reconcilers",
122
150
  "set_cloudwatch_logging",
123
151
  "setup_sqs_queue_and_permissions",
152
+ "ssm_decrypt_statement",
153
+ "ssm_parameter_arns",
154
+ "ssm_read_statement",
124
155
  "sync_managed_policy_document",
125
156
  "update_lambda_function_config",
126
157
  "update_lambda_layers_to_latest",