velocity-python 0.2.3__tar.gz → 0.2.5__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 (410) hide show
  1. {velocity_python-0.2.3/src/velocity_python.egg-info → velocity_python-0.2.5}/PKG-INFO +1 -1
  2. {velocity_python-0.2.3 → velocity_python-0.2.5}/pyproject.toml +1 -1
  3. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/authz.py +23 -2
  5. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/context.py +3 -0
  6. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/lambda_handler.py +60 -2
  7. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/__init__.py +6 -2
  8. velocity_python-0.2.5/src/velocity/aws/handlers/mixins/action_names.py +30 -0
  9. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/data_service.py +43 -2
  10. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/permissions_actions.py +6 -0
  11. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/tiles_actions.py +6 -0
  12. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/web_handler.py +8 -0
  13. velocity_python-0.2.5/src/velocity/aws/identity.py +138 -0
  14. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/permissions.py +189 -1
  15. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/export.py +138 -16
  16. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/format.py +29 -0
  17. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_format.py +30 -1
  18. {velocity_python-0.2.3 → velocity_python-0.2.5/src/velocity_python.egg-info}/PKG-INFO +1 -1
  19. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity_python.egg-info/SOURCES.txt +5 -0
  20. velocity_python-0.2.5/tests/test_action_names.py +61 -0
  21. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_authz.py +53 -0
  22. velocity_python-0.2.5/tests/test_export_workbook.py +422 -0
  23. velocity_python-0.2.5/tests/test_identity.py +174 -0
  24. velocity_python-0.2.5/tests/test_permissions_notices.py +259 -0
  25. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_permissions.py +39 -0
  26. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_search_paging_export.py +121 -0
  27. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_store_user_data.py +15 -0
  28. velocity_python-0.2.3/tests/test_export_workbook.py +0 -164
  29. {velocity_python-0.2.3 → velocity_python-0.2.5}/LICENSE +0 -0
  30. {velocity_python-0.2.3 → velocity_python-0.2.5}/README.md +0 -0
  31. {velocity_python-0.2.3 → velocity_python-0.2.5}/setup.cfg +0 -0
  32. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/__init__.py +0 -0
  33. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/amplify.py +0 -0
  34. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/assets/__init__.py +0 -0
  35. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/assets/backfill.py +0 -0
  36. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/assets/indexing.py +0 -0
  37. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/assets/references.py +0 -0
  38. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/assets/service.py +0 -0
  39. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/assets/usage_index.py +0 -0
  40. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/blobs.py +0 -0
  41. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/__init__.py +0 -0
  42. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/base.py +0 -0
  43. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/dispatch.py +0 -0
  44. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/infra.py +0 -0
  45. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/jobs.py +0 -0
  46. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/provisioning.py +0 -0
  47. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/retention.py +0 -0
  48. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/security.py +0 -0
  49. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/capabilities/single_session.py +0 -0
  50. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/__init__.py +0 -0
  51. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/ci_gate.py +0 -0
  52. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/config.py +0 -0
  53. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/frontend_checks.py +0 -0
  54. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/operations.py +0 -0
  55. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/policies.py +0 -0
  56. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/reconcile.py +0 -0
  57. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/deploy/targets.py +0 -0
  58. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/dirty_pipeline.py +0 -0
  59. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/email.py +0 -0
  60. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/facets.py +0 -0
  61. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/failures.py +0 -0
  62. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/feature_flags.py +0 -0
  63. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/__init__.py +0 -0
  64. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/base_handler.py +0 -0
  65. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/context_factory.py +0 -0
  66. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/exceptions.py +0 -0
  67. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/masquerade.py +0 -0
  68. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/audit_trail.py +0 -0
  69. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/client_errors.py +0 -0
  70. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/client_input.py +0 -0
  71. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/job_handler.py +0 -0
  72. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/row_scoped.py +0 -0
  73. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/mixins/session_control.py +0 -0
  74. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/perf.py +0 -0
  75. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/response.py +0 -0
  76. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  77. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/job_lifecycle.py +0 -0
  78. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/job_results.py +0 -0
  79. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/mirror.py +0 -0
  80. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/ops.py +0 -0
  81. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/queue_defaults.py +0 -0
  82. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/s3.py +0 -0
  83. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/schema.py +0 -0
  84. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/sms.py +0 -0
  85. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/ssm_config.py +0 -0
  86. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/__init__.py +0 -0
  87. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  88. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_deploy_least_privilege.py +0 -0
  89. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
  90. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_deploy_policy_size.py +0 -0
  91. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
  92. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_email.py +0 -0
  93. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  94. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_response.py +0 -0
  95. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tests/test_sms.py +0 -0
  96. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/tiles.py +0 -0
  97. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/aws/user_data.py +0 -0
  98. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/cache.py +0 -0
  99. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/__init__.py +0 -0
  100. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/__init__.py +0 -0
  101. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/async_support.py +0 -0
  102. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/column.py +0 -0
  103. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/database.py +0 -0
  104. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/decorators.py +0 -0
  105. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/engine.py +0 -0
  106. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/jsonproxy.py +0 -0
  107. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/lazy_engine.py +0 -0
  108. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/result.py +0 -0
  109. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/row.py +0 -0
  110. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/sequence.py +0 -0
  111. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/table.py +0 -0
  112. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/transaction.py +0 -0
  113. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/core/view.py +0 -0
  114. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/exceptions.py +0 -0
  115. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/fragments.py +0 -0
  116. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/maintenance.py +0 -0
  117. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/migrations.py +0 -0
  118. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/__init__.py +0 -0
  119. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/base/__init__.py +0 -0
  120. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/base/initializer.py +0 -0
  121. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/base/operators.py +0 -0
  122. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/base/sql.py +0 -0
  123. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/base/types.py +0 -0
  124. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/mysql/__init__.py +0 -0
  125. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/mysql/operators.py +0 -0
  126. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/mysql/reserved.py +0 -0
  127. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/mysql/sql.py +0 -0
  128. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/mysql/types.py +0 -0
  129. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/postgres/__init__.py +0 -0
  130. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/postgres/operators.py +0 -0
  131. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/postgres/reserved.py +0 -0
  132. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/postgres/sql.py +0 -0
  133. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/postgres/types.py +0 -0
  134. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  135. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlite/operators.py +0 -0
  136. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  137. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlite/sql.py +0 -0
  138. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlite/types.py +0 -0
  139. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  140. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  141. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  142. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  143. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/sqlserver/types.py +0 -0
  144. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/servers/tablehelper.py +0 -0
  145. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/__init__.py +0 -0
  146. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/common_db_test.py +0 -0
  147. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/__init__.py +0 -0
  148. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/common.py +0 -0
  149. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/conftest.py +0 -0
  150. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_column.py +0 -0
  151. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  152. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_database.py +0 -0
  153. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  154. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  155. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  156. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_result.py +0 -0
  157. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_row.py +0 -0
  158. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  159. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  160. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  161. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  162. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  163. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_table.py +0 -0
  164. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  165. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  166. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/sql/__init__.py +0 -0
  167. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/sql/common.py +0 -0
  168. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  169. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  170. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  171. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_db_utils.py +0 -0
  172. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_postgres.py +0 -0
  173. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  174. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  175. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_result_caching.py +0 -0
  176. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  177. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  178. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  179. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  180. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_sql_builder.py +0 -0
  181. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_tablehelper.py +0 -0
  182. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tests/test_view_helper.py +0 -0
  183. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/tunnel.py +0 -0
  184. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/db/utils.py +0 -0
  185. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/logging.py +0 -0
  186. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/__init__.py +0 -0
  187. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/conv/__init__.py +0 -0
  188. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/conv/iconv.py +0 -0
  189. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/conv/oconv.py +0 -0
  190. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/db.py +0 -0
  191. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/mail.py +0 -0
  192. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/merge.py +0 -0
  193. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/pdf.py +0 -0
  194. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/__init__.py +0 -0
  195. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_db.py +0 -0
  196. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_fix.py +0 -0
  197. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_iconv.py +0 -0
  198. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_mail_send.py +0 -0
  199. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_merge.py +0 -0
  200. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_oconv.py +0 -0
  201. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_original_error.py +0 -0
  202. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tests/test_timer.py +0 -0
  203. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/timer.py +0 -0
  204. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/misc/tools.py +0 -0
  205. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/__init__.py +0 -0
  206. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/core/__init__.py +0 -0
  207. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/core/capabilities.py +0 -0
  208. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/core/store.py +0 -0
  209. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/core/where.py +0 -0
  210. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/exceptions.py +0 -0
  211. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/__init__.py +0 -0
  212. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/base/__init__.py +0 -0
  213. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
  214. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
  215. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
  216. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
  217. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
  218. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
  219. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
  220. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
  221. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/memory/__init__.py +0 -0
  222. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
  223. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
  224. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/nosql/servers/redis/__init__.py +0 -0
  225. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/__init__.py +0 -0
  226. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/_mirror_core.py +0 -0
  227. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/authorizenet_adapter.py +0 -0
  228. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/authorizenet_mirror.py +0 -0
  229. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/base_adapter.py +0 -0
  230. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/braintree_adapter.py +0 -0
  231. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/braintree_mirror.py +0 -0
  232. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/charge_rules.py +0 -0
  233. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/money.py +0 -0
  234. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/plaid_api.py +0 -0
  235. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/plaid_webhook.py +0 -0
  236. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/redact.py +0 -0
  237. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/schema.py +0 -0
  238. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/stripe_adapter.py +0 -0
  239. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/payment/stripe_mirror.py +0 -0
  240. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/testing/__init__.py +0 -0
  241. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity/testing/fake_db.py +0 -0
  242. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  243. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity_python.egg-info/entry_points.txt +0 -0
  244. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity_python.egg-info/requires.txt +0 -0
  245. {velocity_python-0.2.3 → velocity_python-0.2.5}/src/velocity_python.egg-info/top_level.txt +0 -0
  246. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_access_error_403.py +0 -0
  247. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_activity_tracking_aborted_tx.py +0 -0
  248. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_amplify_redirects.py +0 -0
  249. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_asset_indexing.py +0 -0
  250. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_asset_references.py +0 -0
  251. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_assets_service.py +0 -0
  252. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_async_support.py +0 -0
  253. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_audit_mixin.py +0 -0
  254. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_aws_package_hygiene.py +0 -0
  255. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_batch_operations.py +0 -0
  256. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_blob_store.py +0 -0
  257. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_business_objects.py +0 -0
  258. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_capabilities.py +0 -0
  259. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_capability_catalog.py +0 -0
  260. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_check_changelog.py +0 -0
  261. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_ci_gate.py +0 -0
  262. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_client_errors_mixin.py +0 -0
  263. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_client_input_contract_export.py +0 -0
  264. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_client_sql_boundary.py +0 -0
  265. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_client_table_gate_case_and_pointers.py +0 -0
  266. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_cognito_user_cache.py +0 -0
  267. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_column_tx_arg.py +0 -0
  268. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_concurrency_safety.py +0 -0
  269. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_connection_pool.py +0 -0
  270. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_connection_resilience.py +0 -0
  271. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_context_flags_loader.py +0 -0
  272. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_context_job_descriptions.py +0 -0
  273. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_context_queue_job.py +0 -0
  274. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_conv_combine.py +0 -0
  275. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_data_service_owner_scope.py +0 -0
  276. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_data_service_query_cap.py +0 -0
  277. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_data_service_renumber.py +0 -0
  278. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_data_service_row_number.py +0 -0
  279. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_data_service_save_as.py +0 -0
  280. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_data_service_security_gates.py +0 -0
  281. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_db_credentials_ssm_cascade.py +0 -0
  282. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_db_maintenance.py +0 -0
  283. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_db_tunnel.py +0 -0
  284. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_declared_column_types.py +0 -0
  285. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_decorators.py +0 -0
  286. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_delete_hook_fk_blocked.py +0 -0
  287. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_deploy_config_fields.py +0 -0
  288. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_deploy_engine.py +0 -0
  289. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_deploy_frontend_checks.py +0 -0
  290. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_deploy_operations_queue.py +0 -0
  291. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_deploy_policies.py +0 -0
  292. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_dirty_pipeline_fast_path.py +0 -0
  293. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_dlq_constant.py +0 -0
  294. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_docs_snippets.py +0 -0
  295. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_email_processing.py +0 -0
  296. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_enqueue_metric_namespace.py +0 -0
  297. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_enqueue_send_failures.py +0 -0
  298. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_ensure_infrastructure.py +0 -0
  299. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_facets.py +0 -0
  300. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_facets_and_where.py +0 -0
  301. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_failures.py +0 -0
  302. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_feature_flags.py +0 -0
  303. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_get_cognito_user_provider.py +0 -0
  304. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_http_handler_rollback.py +0 -0
  305. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_iconv_money_to_cents.py +0 -0
  306. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_identifier_injection_guard.py +0 -0
  307. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_job_handler.py +0 -0
  308. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_job_lifecycle.py +0 -0
  309. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_job_results.py +0 -0
  310. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_json_columns.py +0 -0
  311. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_jsonb_dict_adapter.py +0 -0
  312. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_lambda_handler.py +0 -0
  313. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_lambda_handler_auth.py +0 -0
  314. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_lambda_handler_masquerade.py +0 -0
  315. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_lambda_handler_user_cache.py +0 -0
  316. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_lazy_engine.py +0 -0
  317. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_masquerade_grant.py +0 -0
  318. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_merge_on_conflict.py +0 -0
  319. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_mirror.py +0 -0
  320. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_mirror_upsert_public.py +0 -0
  321. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_mixins_import.py +0 -0
  322. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_n_plus_one.py +0 -0
  323. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_nosql_dynamodb.py +0 -0
  324. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_nosql_memory.py +0 -0
  325. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_nosql_mongodb.py +0 -0
  326. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_nosql_redis.py +0 -0
  327. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_nosql_translation.py +0 -0
  328. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_nosql_where.py +0 -0
  329. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_observability.py +0 -0
  330. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_on_action_default.py +0 -0
  331. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_on_commit.py +0 -0
  332. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_ops.py +0 -0
  333. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_audit_fixes.py +0 -0
  334. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_authorizenet_adapter.py +0 -0
  335. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_braintree_adapter.py +0 -0
  336. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_braintree_mirror.py +0 -0
  337. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_business_agnostic.py +0 -0
  338. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_charge_reference.py +0 -0
  339. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_extra_bounds.py +0 -0
  340. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_lazy_imports.py +0 -0
  341. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_mirror_empty_table.py +0 -0
  342. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_profile_sorting.py +0 -0
  343. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_payment_stripe_adapter.py +0 -0
  344. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pdf.py +0 -0
  345. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_permissions.py +0 -0
  346. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_permissions_actions.py +0 -0
  347. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_permissions_review.py +0 -0
  348. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_bulk_cache.py +0 -0
  349. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_capability_types.py +0 -0
  350. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_ensure_infrastructure.py +0 -0
  351. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_get_tables.py +0 -0
  352. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_pointer_joins.py +0 -0
  353. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_row_scope.py +0 -0
  354. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_search_export.py +0 -0
  355. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_tiles.py +0 -0
  356. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pgserver_user_data.py +0 -0
  357. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_plaid_api.py +0 -0
  358. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_plaid_webhook.py +0 -0
  359. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_pointer_join_sql.py +0 -0
  360. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_postgres_initializer_config.py +0 -0
  361. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_postgres_py_type.py +0 -0
  362. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_prepared_statements.py +0 -0
  363. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_psycopg3_upgrade.py +0 -0
  364. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_query_cache.py +0 -0
  365. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_query_missing_table_unlocked.py +0 -0
  366. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_raw_sql_prefix_policy.py +0 -0
  367. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_read_cache.py +0 -0
  368. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_readme_imports.py +0 -0
  369. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_response.py +0 -0
  370. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_restricted_direct_tables.py +0 -0
  371. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_result_returning.py +0 -0
  372. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_retry_side_effect_guard.py +0 -0
  373. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_return_default_safety.py +0 -0
  374. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_row_batch_update.py +0 -0
  375. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_row_cache_staleness.py +0 -0
  376. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_row_scoped_data_service.py +0 -0
  377. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_s3_bucket_config.py +0 -0
  378. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_s3_list_client_files.py +0 -0
  379. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_s3_upload.py +0 -0
  380. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_schema_lock_config_other_backends.py +0 -0
  381. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_schema_migrations.py +0 -0
  382. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_security_capability.py +0 -0
  383. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_security_hardening.py +0 -0
  384. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_server_cursor.py +0 -0
  385. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_session_control.py +0 -0
  386. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_single_autocommit_safety.py +0 -0
  387. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_single_session_capability.py +0 -0
  388. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_sms_twilio_signature.py +0 -0
  389. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_spreadsheet_functions.py +0 -0
  390. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_sqlite_backend.py +0 -0
  391. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_sqs_per_record_transactions.py +0 -0
  392. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_ssm_config.py +0 -0
  393. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_ssm_config_require.py +0 -0
  394. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  395. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_table_alter.py +0 -0
  396. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_table_claim.py +0 -0
  397. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_table_find_cache.py +0 -0
  398. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_table_purge.py +0 -0
  399. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_testing_fake_db.py +0 -0
  400. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_tiles.py +0 -0
  401. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_transaction_class_wrapping.py +0 -0
  402. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_transaction_commit_and_ownership.py +0 -0
  403. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_transaction_edge_cases.py +0 -0
  404. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_tx_lifecycle_retry.py +0 -0
  405. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_tx_read_cache_and_bulk.py +0 -0
  406. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_user_data.py +0 -0
  407. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_user_not_provisioned.py +0 -0
  408. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_where_clause_validation.py +0 -0
  409. {velocity_python-0.2.3 → velocity_python-0.2.5}/tests/test_write_hook_create_flow.py +0 -0
  410. {velocity_python-0.2.3 → velocity_python-0.2.5}/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.2.3
3
+ Version: 0.2.5
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.2.3"
7
+ version = "0.2.5"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.2.3"
1
+ __version__ = version = "0.2.5"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -80,6 +80,7 @@ from __future__ import annotations
80
80
 
81
81
  import logging
82
82
  import re
83
+ import sys
83
84
  from dataclasses import dataclass, field, replace
84
85
  from fnmatch import fnmatchcase
85
86
  from typing import Any, Callable, Optional
@@ -379,22 +380,42 @@ BUILTIN_RULES = (permit("data.ordinary_tables", DATA_ACCESS, when=_ordinary_tabl
379
380
 
380
381
  _REGISTERED = {}
381
382
  _REGISTERED_TUPLE = None
383
+ # name -> the globals of the module that registered it. A module imported a
384
+ # second time (importlib.reload, a test that patches sys.modules) runs with
385
+ # new globals under the same __name__ and builds new condition closures, so
386
+ # its rules never compare equal to the first import's.
387
+ _OWNERS = {}
382
388
 
383
389
 
384
390
  def register(*rules):
385
391
  """Add rules to the ones every handler evaluates. Registering the same
386
- rule again is a no-op; a different rule under a taken name is an error."""
392
+ rule again is a no-op, and so is a module re-registering its own rules
393
+ when it is imported again (the new rules replace the old). A different
394
+ rule under a taken name is otherwise an error."""
387
395
  global _REGISTERED_TUPLE
396
+ caller = sys._getframe(1).f_globals
388
397
  for rule in rules:
389
398
  if not isinstance(rule, Rule):
390
399
  raise ValueError("register() takes rules made by permit() or forbid().")
391
400
  known = _REGISTERED.get(rule.name)
392
- if known is not None and known != rule:
401
+ if known is not None and known != rule and not _reimported(rule.name, caller):
393
402
  raise ValueError(f"An authorization rule named '{rule.name}' exists.")
394
403
  _REGISTERED[rule.name] = rule
404
+ _OWNERS[rule.name] = caller
395
405
  _REGISTERED_TUPLE = None
396
406
 
397
407
 
408
+ def _reimported(name, caller):
409
+ """True when ``caller`` is a fresh import of the module that registered
410
+ ``name``: same module name, different globals."""
411
+ owner = _OWNERS.get(name)
412
+ return (
413
+ owner is not None
414
+ and owner is not caller
415
+ and owner.get("__name__") == caller.get("__name__")
416
+ )
417
+
418
+
398
419
  def registered():
399
420
  """Every rule a handler evaluates before its own. The same tuple object
400
421
  until a rule is registered, so its action index is built once."""
@@ -1093,6 +1093,9 @@ class Context:
1093
1093
  "enabled": response.get("Enabled"),
1094
1094
  "user_status": response.get("UserStatus"),
1095
1095
  "sub": attributes.get("sub", user_sub),
1096
+ # the token issuer for this pool: with "sub", the identity
1097
+ # the provider never reassigns (velocity.aws.identity)
1098
+ "issuer": f"https://{user_pool_segment}",
1096
1099
  }
1097
1100
 
1098
1101
  return user
@@ -177,10 +177,15 @@ class LambdaHandler(BaseHandler):
177
177
  )
178
178
 
179
179
  context.perf.start("user lookup")
180
- user = self._cached_user(tx, session.get("email_address"))
180
+ user = self._find_current_user(tx, session, masquerade)
181
181
  context.perf.log("user lookup")
182
182
  if not user and not masquerade and _stage_allows_provisioning():
183
- user = self._provision_and_reload(tx, session)
183
+ if self._by_subject(masquerade):
184
+ # the hook's new row is bound on this, its first, sign-in
185
+ self.provision_missing_user(tx, session)
186
+ user = self._find_current_user(tx, session, masquerade)
187
+ else:
188
+ user = self._provision_and_reload(tx, session)
184
189
  if not user:
185
190
  raise UserNotProvisionedError(
186
191
  "A valid user with permission is required to access this function [DB]"
@@ -245,6 +250,59 @@ class LambdaHandler(BaseHandler):
245
250
  )
246
251
  return user
247
252
 
253
+ # How a request finds its user row (velocity.aws.identity): "email" (the
254
+ # default) or "subject" — the identity provider's issuer + subject, the
255
+ # row bound once by verified email on the first sign-in after the switch.
256
+ # The IdentityMode config key (per environment) overrides this.
257
+ identity_mode = "email"
258
+
259
+ def _by_subject(self, masquerade):
260
+ from velocity.aws import identity
261
+
262
+ # a masquerade identity is the grant's user, not a provider subject;
263
+ # the mode is the IdentityMode config key, else identity_mode
264
+ return not masquerade and identity.mode_of(self) == identity.IDENTITY_SUBJECT
265
+
266
+ def _find_current_user(self, tx, session, masquerade=False):
267
+ """The signed-in caller's user row (dict) or None, by email or — in
268
+ ``identity_mode = "subject"`` — by issuer + subject."""
269
+ if not self._by_subject(masquerade):
270
+ return self._cached_user(tx, session.get("email_address"))
271
+ from velocity.aws import identity
272
+
273
+ issuer, subject, email, verified = identity.claims_of(self.cognito_user)
274
+ session["iss"], session["sub"] = issuer, subject
275
+ if not (issuer and subject):
276
+ return None
277
+ return self._cached_subject_user(tx, issuer, subject, email, verified)
278
+
279
+ def _cached_subject_user(self, tx, issuer, subject, email, verified):
280
+ """``_cached_user`` by issuer + subject. A first sign-in binds its row
281
+ inside the load; a miss is never cached."""
282
+ from velocity.cache import memo
283
+
284
+ from velocity.aws import identity
285
+ from velocity.aws.handlers.context import user_cache_seconds
286
+
287
+ def load():
288
+ return identity.find_user(
289
+ tx, self.user_table, issuer, subject, email, verified
290
+ )
291
+
292
+ key = ("user-subject", self.user_table, issuer, subject)
293
+ if getattr(self, "permission_source", None) == "tables":
294
+ from velocity.aws import permissions as _grants
295
+
296
+ key = (*key, _grants.cached_version(tx))
297
+ user = memo(
298
+ key,
299
+ load,
300
+ user_cache_seconds(),
301
+ tables=(self.user_table,),
302
+ cache_none=False,
303
+ )
304
+ return dict(user) if user else None
305
+
248
306
  def _cached_user(self, tx, email_address):
249
307
  """The user-table row for the signed-in user as a dict, through the
250
308
  process read cache (velocity.cache) for ``UserCacheSeconds``: one
@@ -23,8 +23,9 @@ from .row_scoped import RowScopedDataService
23
23
  from .audit_trail import AuditTrailMixin
24
24
  from .job_handler import JobHandler
25
25
  from .session_control import SessionControlMixin
26
- from .permissions_actions import PermissionsMixin
27
- from .tiles_actions import TilesMixin
26
+ from .action_names import action_names
27
+ from .permissions_actions import PERMISSION_ACTIONS, PermissionsMixin
28
+ from .tiles_actions import TILE_ACTIONS, TilesMixin
28
29
  from .client_errors import ClientErrorReporting, AnonymousClientErrorReporting
29
30
 
30
31
  __all__ = [
@@ -37,7 +38,10 @@ __all__ = [
37
38
  "JobHandler",
38
39
  "SessionControlMixin",
39
40
  "PermissionsMixin",
41
+ "PERMISSION_ACTIONS",
40
42
  "TilesMixin",
43
+ "TILE_ACTIONS",
44
+ "action_names",
41
45
  "ClientErrorReporting",
42
46
  "AnonymousClientErrorReporting",
43
47
  ]
@@ -0,0 +1,30 @@
1
+ """The client action names a handler class serves, from its methods.
2
+
3
+ ``BaseHandler.format_action_name`` turns ``"tiles-load"`` into
4
+ ``"OnActionTilesLoad"``; this is the inverse, for a site's ``client_actions``
5
+ allow-list: ``client_actions = MINE | TILE_ACTIONS | PERMISSION_ACTIONS``
6
+ picks up every action a mixin gains with a release, instead of a list each
7
+ site copies by hand (and forgets to extend: admin refused every tile action
8
+ until its list was edited, 2026-10-14).
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import re
14
+
15
+ _PREFIX = "OnAction"
16
+ _WORD = re.compile(r"[A-Z][a-z0-9]*")
17
+
18
+
19
+ def action_names(cls) -> frozenset:
20
+ """The kebab-case action of every ``OnAction<Name>`` method ``cls``
21
+ itself defines (not inherited ones; not ``OnActionDefault``)."""
22
+ names = set()
23
+ for attr, value in vars(cls).items():
24
+ if not attr.startswith(_PREFIX) or not callable(value):
25
+ continue
26
+ rest = attr[len(_PREFIX) :]
27
+ if not rest or rest == "Default":
28
+ continue
29
+ names.add("-".join(word.lower() for word in _WORD.findall(rest)))
30
+ return frozenset(names)
@@ -426,6 +426,19 @@ def plan_row_number(params):
426
426
 
427
427
  # result_formats query answers with a file download (velocity.misc.export).
428
428
  FILE_EXPORT_FORMATS = frozenset(export.EXPORT_FORMATS)
429
+ # Formats written as XLSX cells, which carry no time zone: aware values are
430
+ # converted to the handler's display_timezone() first.
431
+ XLSX_EXPORT_FORMATS = frozenset({"excel", "xlsx"})
432
+
433
+
434
+ def _export_zone(handler, result_format, context):
435
+ """The display zone for an export: the handler's ``display_timezone``
436
+ for the XLSX formats, ``None`` for the text formats (which write values
437
+ as given and need no SSM read)."""
438
+ if result_format not in XLSX_EXPORT_FORMATS:
439
+ return None
440
+ zone_for = getattr(handler, "display_timezone", None)
441
+ return zone_for(context) if zone_for is not None else None
429
442
 
430
443
 
431
444
  def _positive_int(value):
@@ -679,7 +692,11 @@ class ExportStream:
679
692
  """The whole export as one file: :func:`velocity.misc.export.build_buffer`
680
693
  over :meth:`rows` (line formats are written as the batches arrive)."""
681
694
  built = export.build_buffer(
682
- result_format, self.headers, self.rows(), filename_base
695
+ result_format,
696
+ self.headers,
697
+ self.rows(),
698
+ filename_base,
699
+ display_timezone=_export_zone(self.handler, result_format, self.context),
683
700
  )
684
701
  if built is None:
685
702
  raise BadRequestError(f"Unsupported export format: {result_format!r}")
@@ -838,6 +855,24 @@ class DataServiceMixin:
838
855
  "timestamp": "string",
839
856
  }
840
857
 
858
+ def display_timezone(self, context=None):
859
+ """The zone XLSX exports show times in: Excel cells carry no zone,
860
+ so an aware value (every ``timestamptz``) is written as its wall time
861
+ here. Default: the site's ``SiteTimezone`` config key (an IANA name
862
+ such as ``America/Denver``, read through ``ssm_config.getenv``, which
863
+ caches it per process); UTC, with a warning, when it is unset or not
864
+ a zone. Override to choose per request (``context`` is the request
865
+ context) or per handler. Returns a ``tzinfo``."""
866
+ try:
867
+ name = ssm_config.getenv("SiteTimezone", None)
868
+ except Exception:
869
+ logger.warning("SiteTimezone could not be read; exports use UTC")
870
+ name = None
871
+ if not name:
872
+ logger.warning("SiteTimezone is not set; exports show times in UTC")
873
+ return datetime.timezone.utc
874
+ return export.resolve_display_timezone(name)
875
+
841
876
  def _resolve_query_max_rows(self):
842
877
  """Effective query row ceiling: `QueryMaxRows` config key first, then
843
878
  the class attribute. Returns a positive int or None (no cap)."""
@@ -2231,6 +2266,7 @@ class DataServiceMixin:
2231
2266
  data.get("headers", []),
2232
2267
  data.get("rows", []),
2233
2268
  filename_base,
2269
+ display_timezone=_export_zone(self, result_format, context),
2234
2270
  )
2235
2271
  if result_format == "excel":
2236
2272
  # the legacy excel download keeps its caller-chosen filename
@@ -2412,7 +2448,12 @@ class DataServiceMixin:
2412
2448
  )
2413
2449
  rows = result.as_list().all()
2414
2450
  filebuffer = BytesIO()
2415
- export.create_spreadsheet(headers, rows, filebuffer)
2451
+ export.create_spreadsheet(
2452
+ headers,
2453
+ rows,
2454
+ filebuffer,
2455
+ display_timezone=self.display_timezone(context),
2456
+ )
2416
2457
  context.response().file_download(
2417
2458
  {
2418
2459
  "filename": payload.get("filename", "temp_file.xls"),
@@ -63,6 +63,7 @@ from types import SimpleNamespace
63
63
 
64
64
  from velocity.aws import authz, permissions
65
65
  from velocity.aws.handlers.exceptions import AlertError
66
+ from .action_names import action_names
66
67
 
67
68
  READ = "permissions.read"
68
69
  READ_ACTION = "permissions.read"
@@ -804,3 +805,8 @@ class PermissionsMixin:
804
805
  )
805
806
  )
806
807
  context.response().set_body(self._inbox_body(tx, actor))
808
+
809
+
810
+ # every action PermissionsMixin serves, for a site's ``client_actions``:
811
+ # ``client_actions = MINE | PERMISSION_ACTIONS``
812
+ PERMISSION_ACTIONS = action_names(PermissionsMixin)
@@ -39,6 +39,7 @@ from velocity.aws import authz, facets, permissions, tiles
39
39
  from velocity.aws.handlers.exceptions import AccessError, AlertError
40
40
  from velocity.db.fragments import Expr
41
41
  from velocity.db.servers.tablehelper import TableHelper
42
+ from .action_names import action_names
42
43
 
43
44
  logger = logging.getLogger(__name__)
44
45
 
@@ -659,3 +660,8 @@ class TilesMixin:
659
660
  )
660
661
  )
661
662
  context.response().set_body(self._manage_body(tx, actor))
663
+
664
+
665
+ # every action TilesMixin serves, for a site's ``client_actions``:
666
+ # ``client_actions = MINE | TILE_ACTIONS``
667
+ TILE_ACTIONS = action_names(TilesMixin)
@@ -621,6 +621,14 @@ Request Details:
621
621
  return
622
622
  session = context.session() or {}
623
623
  email = session.get("email_address")
624
+ if not email:
625
+ # Nobody is signed in (a public page that saves its layout as it
626
+ # goes): there is no owner, so nothing is saved. Rows mode used to
627
+ # upsert under a blank userid — one shared junk row per key that
628
+ # every anonymous visitor overwrote. Not an error, so a public
629
+ # page does not report a failure on every change.
630
+ context.response().set_body({"saved": False, "reason": "signed_out"})
631
+ return
624
632
  if self.user_data_mode == USER_DATA_DOCUMENT:
625
633
  owner = (getattr(self, "current_user", None) or {}).get("sys_id")
626
634
  decision = authz.decide(
@@ -0,0 +1,138 @@
1
+ """Who is signed in: the user row bound to the identity provider's issuer and
2
+ subject, never found by email.
3
+
4
+ An email address can change, be reused, or be claimed by an external identity
5
+ provider; the provider's issuer plus subject (``iss`` + ``sub``) is the one
6
+ pair it guarantees never to reassign (OpenID Connect Core 1.0, section 5.7).
7
+ So a user row carries the pair it is bound to, and each request finds its
8
+ user by that pair.
9
+
10
+ The mode is the ``IdentityMode`` config key (SSM ``/{Project}/{env}/`` then
11
+ ``/Global/{env}/``) when set, else the handler's ``identity_mode``
12
+ (see ``LambdaHandler.beforeAction``), else ``"email"`` — so a site switches
13
+ one environment at a time, demo first, with no code change:
14
+
15
+ * ``"email"`` — the default and the behaviour before this module: the user
16
+ row is found by ``email_address``.
17
+ * ``"subject"`` — the user row is found by :data:`ISSUER_COLUMN` +
18
+ :data:`SUBJECT_COLUMN`. The first sign-in after a site switches binds its
19
+ existing row ONCE, by the caller's *verified* email, and only a row not
20
+ yet bound to anyone; from then on email is never used to find that user.
21
+ A row already bound to another identity is never re-bound by email (the
22
+ address moved to a different account), and an unverified email binds
23
+ nothing.
24
+
25
+ Both columns are TEXT on the site's user table. Declare them in the site's
26
+ schema lane before switching a locked environment
27
+ (``SCHEMA_COLUMNS``); in an unlocked one the first binding creates them.
28
+
29
+ A masquerade session keeps the email path: its identity is the verified
30
+ grant's user, not a provider subject.
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ import logging
36
+
37
+ from velocity.aws import ssm_config
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+ IDENTITY_EMAIL = "email"
42
+ IDENTITY_SUBJECT = "subject"
43
+ IDENTITY_MODES = (IDENTITY_EMAIL, IDENTITY_SUBJECT)
44
+
45
+ ISSUER_COLUMN = "identity_issuer"
46
+ SUBJECT_COLUMN = "identity_subject"
47
+ # for a site's schema lane: ensure_columns(tx, user_table, SCHEMA_COLUMNS)
48
+ SCHEMA_COLUMNS = {ISSUER_COLUMN: "TEXT", SUBJECT_COLUMN: "TEXT"}
49
+
50
+
51
+ def mode_of(handler):
52
+ """``IdentityMode`` config first, then the handler's ``identity_mode``,
53
+ then ``"email"``. A value that is not a mode is ``"email"`` (logged):
54
+ unlike authorization, the safe fallback is the established lookup, so a
55
+ typo never locks every user out."""
56
+ raw = None
57
+ try:
58
+ raw = ssm_config.getenv("IdentityMode", None)
59
+ except Exception:
60
+ raw = None
61
+ raw = str(raw or getattr(handler, "identity_mode", None) or IDENTITY_EMAIL)
62
+ mode = raw.strip().lower()
63
+ if mode not in IDENTITY_MODES:
64
+ logger.warning("identity: unknown IdentityMode %r; using email", raw)
65
+ return IDENTITY_EMAIL
66
+ return mode
67
+
68
+
69
+ def claims_of(cognito_user):
70
+ """``(issuer, subject, email, email_verified)`` from a resolved Cognito
71
+ user (``Context.get_cognito_user``); ``None`` parts when absent."""
72
+ user = cognito_user if isinstance(cognito_user, dict) else {}
73
+ attributes = user.get("attributes") or {}
74
+ email = (attributes.get("email") or user.get("email") or "").strip().lower() or None
75
+ verified = str(attributes.get("email_verified", "")).strip().lower() == "true"
76
+ return user.get("issuer") or None, user.get("sub") or None, email, verified
77
+
78
+
79
+ def _row(found):
80
+ if not found:
81
+ return None
82
+ return found.to_dict() if hasattr(found, "to_dict") else dict(found)
83
+
84
+
85
+ def find_bound(tx, user_table, issuer, subject):
86
+ """The user row bound to ``issuer`` + ``subject``, or None."""
87
+ if not (issuer and subject):
88
+ return None
89
+ return _row(
90
+ tx.table(user_table).find({ISSUER_COLUMN: issuer, SUBJECT_COLUMN: subject})
91
+ )
92
+
93
+
94
+ def bind_by_verified_email(tx, user_table, issuer, subject, email, verified):
95
+ """Bind the unbound row with this verified email to ``issuer`` +
96
+ ``subject`` and return it; None when there is nothing it may bind.
97
+
98
+ Refuses (returns None, logs why) when the email is not verified, when no
99
+ row has it, or when that row is already bound to a different identity —
100
+ the address now belongs to another account, and following it would hand
101
+ that account someone else's row.
102
+ """
103
+ if not (issuer and subject and email):
104
+ return None
105
+ if not verified:
106
+ logger.warning("identity: not binding %s — email not verified", email)
107
+ return None
108
+ row = _row(tx.table(user_table).find({"email_address": email}))
109
+ if not row:
110
+ return None
111
+ bound = (row.get(ISSUER_COLUMN), row.get(SUBJECT_COLUMN))
112
+ if any(bound):
113
+ if bound != (issuer, subject):
114
+ logger.warning(
115
+ "identity: %s row %s is bound to another identity; not re-binding by email",
116
+ user_table,
117
+ row.get("sys_id"),
118
+ )
119
+ return None
120
+ return row
121
+ tx.table(user_table).update(
122
+ {ISSUER_COLUMN: issuer, SUBJECT_COLUMN: subject}, {"sys_id": row["sys_id"]}
123
+ )
124
+ logger.info(
125
+ "identity: bound %s row %s to its sign-in (first sign-in by subject)",
126
+ user_table,
127
+ row.get("sys_id"),
128
+ )
129
+ row.update({ISSUER_COLUMN: issuer, SUBJECT_COLUMN: subject})
130
+ return row
131
+
132
+
133
+ def find_user(tx, user_table, issuer, subject, email=None, verified=False):
134
+ """The signed-in caller's user row: by ``issuer`` + ``subject``, else (on
135
+ the first sign-in after the switch) the row its verified email binds."""
136
+ return find_bound(tx, user_table, issuer, subject) or bind_by_verified_email(
137
+ tx, user_table, issuer, subject, email, verified
138
+ )