velocity-python 0.1.87__tar.gz → 0.1.88__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 (255) hide show
  1. {velocity_python-0.1.87/src/velocity_python.egg-info → velocity_python-0.1.88}/PKG-INFO +1 -1
  2. {velocity_python-0.1.87 → velocity_python-0.1.88}/pyproject.toml +1 -1
  3. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/context.py +31 -1
  5. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/engine.py +6 -0
  6. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/transaction.py +75 -0
  7. {velocity_python-0.1.87 → velocity_python-0.1.88/src/velocity_python.egg-info}/PKG-INFO +1 -1
  8. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity_python.egg-info/SOURCES.txt +1 -0
  9. velocity_python-0.1.88/tests/test_on_commit.py +216 -0
  10. {velocity_python-0.1.87 → velocity_python-0.1.88}/LICENSE +0 -0
  11. {velocity_python-0.1.87 → velocity_python-0.1.88}/README.md +0 -0
  12. {velocity_python-0.1.87 → velocity_python-0.1.88}/setup.cfg +0 -0
  13. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/__init__.py +0 -0
  14. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/amplify.py +0 -0
  15. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/amplify_build.py +0 -0
  16. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/assets/__init__.py +0 -0
  17. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/assets/backfill.py +0 -0
  18. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/assets/indexing.py +0 -0
  19. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/assets/references.py +0 -0
  20. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/assets/service.py +0 -0
  21. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/assets/usage_index.py +0 -0
  22. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/deploy/__init__.py +0 -0
  23. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/deploy/config.py +0 -0
  24. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/deploy/operations.py +0 -0
  25. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/deploy/policies.py +0 -0
  26. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/deploy/reconcile.py +0 -0
  27. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/deploy/targets.py +0 -0
  28. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/dirty_pipeline.py +0 -0
  29. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/__init__.py +0 -0
  30. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/base_handler.py +0 -0
  31. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/context_factory.py +0 -0
  32. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/exceptions.py +0 -0
  33. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  34. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/masquerade.py +0 -0
  35. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  36. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  37. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  38. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/perf.py +0 -0
  39. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/response.py +0 -0
  40. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  41. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/s3.py +0 -0
  42. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/ssm_config.py +0 -0
  43. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/__init__.py +0 -0
  44. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_amplify_build_policy_size.py +0 -0
  45. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_amplify_build_shim.py +0 -0
  46. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  47. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
  48. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
  49. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  50. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/aws/tests/test_response.py +0 -0
  51. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/__init__.py +0 -0
  52. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/__init__.py +0 -0
  53. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/async_support.py +0 -0
  54. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/column.py +0 -0
  55. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/database.py +0 -0
  56. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/decorators.py +0 -0
  57. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/jsonproxy.py +0 -0
  58. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/result.py +0 -0
  59. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/row.py +0 -0
  60. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/sequence.py +0 -0
  61. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/table.py +0 -0
  62. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/core/view.py +0 -0
  63. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/exceptions.py +0 -0
  64. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/maintenance.py +0 -0
  65. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/migrations.py +0 -0
  66. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/__init__.py +0 -0
  67. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/base/__init__.py +0 -0
  68. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/base/initializer.py +0 -0
  69. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/base/operators.py +0 -0
  70. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/base/sql.py +0 -0
  71. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/base/types.py +0 -0
  72. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/mysql/__init__.py +0 -0
  73. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/mysql/operators.py +0 -0
  74. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/mysql/reserved.py +0 -0
  75. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/mysql/sql.py +0 -0
  76. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/mysql/types.py +0 -0
  77. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/postgres/__init__.py +0 -0
  78. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/postgres/operators.py +0 -0
  79. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/postgres/reserved.py +0 -0
  80. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/postgres/sql.py +0 -0
  81. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/postgres/types.py +0 -0
  82. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  83. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlite/operators.py +0 -0
  84. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  85. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlite/sql.py +0 -0
  86. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlite/types.py +0 -0
  87. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  88. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  89. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  90. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  91. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/sqlserver/types.py +0 -0
  92. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/servers/tablehelper.py +0 -0
  93. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/__init__.py +0 -0
  94. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/common_db_test.py +0 -0
  95. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/__init__.py +0 -0
  96. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/common.py +0 -0
  97. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/conftest.py +0 -0
  98. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_column.py +0 -0
  99. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  100. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_database.py +0 -0
  101. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  102. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  103. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  104. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_result.py +0 -0
  105. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_row.py +0 -0
  106. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  107. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  108. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  109. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  110. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  111. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_table.py +0 -0
  112. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  113. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  114. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/sql/__init__.py +0 -0
  115. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/sql/common.py +0 -0
  116. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  117. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  118. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  119. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_db_utils.py +0 -0
  120. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_postgres.py +0 -0
  121. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  122. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  123. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_result_caching.py +0 -0
  124. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  125. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  126. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  127. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  128. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_sql_builder.py +0 -0
  129. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_tablehelper.py +0 -0
  130. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/tests/test_view_helper.py +0 -0
  131. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/db/utils.py +0 -0
  132. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/logging.py +0 -0
  133. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/__init__.py +0 -0
  134. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/conv/__init__.py +0 -0
  135. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/conv/iconv.py +0 -0
  136. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/conv/oconv.py +0 -0
  137. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/db.py +0 -0
  138. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/export.py +0 -0
  139. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/format.py +0 -0
  140. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/mail.py +0 -0
  141. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/merge.py +0 -0
  142. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/pdf.py +0 -0
  143. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/__init__.py +0 -0
  144. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_db.py +0 -0
  145. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_fix.py +0 -0
  146. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_format.py +0 -0
  147. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_iconv.py +0 -0
  148. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_merge.py +0 -0
  149. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_oconv.py +0 -0
  150. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_original_error.py +0 -0
  151. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tests/test_timer.py +0 -0
  152. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/timer.py +0 -0
  153. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/misc/tools.py +0 -0
  154. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/__init__.py +0 -0
  155. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/core/__init__.py +0 -0
  156. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/core/capabilities.py +0 -0
  157. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/core/store.py +0 -0
  158. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/core/where.py +0 -0
  159. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/exceptions.py +0 -0
  160. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/__init__.py +0 -0
  161. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/base/__init__.py +0 -0
  162. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
  163. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
  164. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
  165. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
  166. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
  167. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
  168. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
  169. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
  170. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/memory/__init__.py +0 -0
  171. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
  172. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
  173. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/nosql/servers/redis/__init__.py +0 -0
  174. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/__init__.py +0 -0
  175. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/authorizenet_adapter.py +0 -0
  176. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/authorizenet_mirror.py +0 -0
  177. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/base_adapter.py +0 -0
  178. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/braintree_adapter.py +0 -0
  179. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/braintree_mirror.py +0 -0
  180. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/charge_rules.py +0 -0
  181. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/stripe_adapter.py +0 -0
  182. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity/payment/stripe_mirror.py +0 -0
  183. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  184. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity_python.egg-info/entry_points.txt +0 -0
  185. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity_python.egg-info/requires.txt +0 -0
  186. {velocity_python-0.1.87 → velocity_python-0.1.88}/src/velocity_python.egg-info/top_level.txt +0 -0
  187. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_activity_tracking_aborted_tx.py +0 -0
  188. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_amplify_build.py +0 -0
  189. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_asset_indexing.py +0 -0
  190. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_asset_references.py +0 -0
  191. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_assets_service.py +0 -0
  192. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_async_support.py +0 -0
  193. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_batch_operations.py +0 -0
  194. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_column_tx_arg.py +0 -0
  195. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_concurrency_safety.py +0 -0
  196. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_connection_pool.py +0 -0
  197. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_connection_resilience.py +0 -0
  198. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_context_job_descriptions.py +0 -0
  199. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_db_credentials_ssm_cascade.py +0 -0
  200. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_db_maintenance.py +0 -0
  201. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_decorators.py +0 -0
  202. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_delete_hook_fk_blocked.py +0 -0
  203. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_dirty_pipeline_fast_path.py +0 -0
  204. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_email_processing.py +0 -0
  205. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_enqueue_send_failures.py +0 -0
  206. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_get_cognito_user_provider.py +0 -0
  207. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_http_handler_rollback.py +0 -0
  208. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_iconv_money_to_cents.py +0 -0
  209. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_identifier_injection_guard.py +0 -0
  210. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_json_columns.py +0 -0
  211. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_jsonb_dict_adapter.py +0 -0
  212. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_lambda_handler.py +0 -0
  213. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_lambda_handler_auth.py +0 -0
  214. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_lambda_handler_masquerade.py +0 -0
  215. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_masquerade_grant.py +0 -0
  216. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_mixins_import.py +0 -0
  217. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_n_plus_one.py +0 -0
  218. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_nosql_dynamodb.py +0 -0
  219. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_nosql_memory.py +0 -0
  220. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_nosql_mongodb.py +0 -0
  221. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_nosql_redis.py +0 -0
  222. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_nosql_translation.py +0 -0
  223. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_nosql_where.py +0 -0
  224. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_observability.py +0 -0
  225. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_payment_authorizenet_adapter.py +0 -0
  226. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_payment_braintree_adapter.py +0 -0
  227. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_payment_braintree_mirror.py +0 -0
  228. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_payment_mirror_empty_table.py +0 -0
  229. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_payment_profile_sorting.py +0 -0
  230. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_payment_stripe_adapter.py +0 -0
  231. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_pdf.py +0 -0
  232. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_prepared_statements.py +0 -0
  233. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_psycopg3_upgrade.py +0 -0
  234. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_query_cache.py +0 -0
  235. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_restricted_direct_tables.py +0 -0
  236. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_retry_side_effect_guard.py +0 -0
  237. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_return_default_safety.py +0 -0
  238. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_row_batch_update.py +0 -0
  239. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_row_cache_staleness.py +0 -0
  240. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_schema_migrations.py +0 -0
  241. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_security_hardening.py +0 -0
  242. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_server_cursor.py +0 -0
  243. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_single_autocommit_safety.py +0 -0
  244. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_spreadsheet_functions.py +0 -0
  245. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_sqlite_backend.py +0 -0
  246. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_sqs_per_record_transactions.py +0 -0
  247. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_ssm_config.py +0 -0
  248. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_store_user_data.py +0 -0
  249. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  250. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_table_alter.py +0 -0
  251. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_transaction_class_wrapping.py +0 -0
  252. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_transaction_commit_and_ownership.py +0 -0
  253. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_transaction_edge_cases.py +0 -0
  254. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_where_clause_validation.py +0 -0
  255. {velocity_python-0.1.87 → velocity_python-0.1.88}/tests/test_write_hook_create_flow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.87
3
+ Version: 0.1.88
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Velocity Team <info@codeclubs.org>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.1.87"
7
+ version = "0.1.88"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.87"
1
+ __version__ = version = "0.1.88"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -485,13 +485,43 @@ class Context:
485
485
  def was_job_cancelled(self):
486
486
  return self._job_cancelled_flag
487
487
 
488
- def enqueue(self, action, payload={}, user=None, suppress_job_activity=False):
488
+ def enqueue(
489
+ self,
490
+ action,
491
+ payload={},
492
+ user=None,
493
+ suppress_job_activity=False,
494
+ transaction=None,
495
+ ):
489
496
  """
490
497
  Enqueue jobs to SQS with independent job activity tracking.
491
498
 
492
499
  This method uses its own transaction for aws_job_activity updates to ensure
493
500
  job tracking is never rolled back with other operations.
501
+
502
+ When ``transaction`` (a velocity Transaction) is provided, the entire
503
+ enqueue — job-activity bookkeeping and the SQS send — is deferred until
504
+ that transaction commits, via ``Transaction.on_commit``. Use this
505
+ whenever the queued job will read back rows written in the same
506
+ transaction: sending immediately races the SQS consumer against the
507
+ COMMIT, and the consumer can win and find nothing (this dropped a
508
+ production Braintree webhook). If the transaction rolls back, nothing
509
+ is enqueued.
510
+
511
+ (The parameter is named ``transaction`` rather than ``tx`` because the
512
+ ``@engine.transaction`` class decorator auto-wraps any method with a
513
+ ``tx`` parameter and would inject its own transaction here.)
494
514
  """
515
+ if transaction is not None:
516
+ transaction.on_commit(
517
+ lambda: self.enqueue(
518
+ action,
519
+ payload=payload,
520
+ user=user,
521
+ suppress_job_activity=suppress_job_activity,
522
+ )
523
+ )
524
+ return {"deferred_until_commit": True}
495
525
  batch_id = str(uuid.uuid4())
496
526
  results = {"batch_id": batch_id}
497
527
  queue = boto3.resource("sqs").get_queue_by_name(
@@ -650,6 +650,12 @@ class Engine:
650
650
  loop_start = time.perf_counter()
651
651
  while True:
652
652
  try:
653
+ # Each attempt must start with no stale on_commit
654
+ # callbacks from a previous failed attempt — not every
655
+ # retry path rolls back (the transient-connection path
656
+ # discards the connection instead), and the re-run
657
+ # function registers its own callbacks again.
658
+ _tx.discard_on_commit_callbacks()
653
659
  result = function(*args, **kwds)
654
660
  # Commit INSIDE the retry envelope so a commit-time
655
661
  # serialization failure / deadlock / deferred-constraint
@@ -194,6 +194,12 @@ class Transaction:
194
194
  # fresh transaction and lose the prior uncommitted statements without
195
195
  # any error. Reset on connect/commit/rollback.
196
196
  self._in_progress = False
197
+ # R32 — Callables to run once, after the transaction's work is durably
198
+ # committed (see on_commit()). Discarded on rollback and whenever a
199
+ # dead connection is dropped, so callbacks from a failed attempt never
200
+ # fire; the @engine.transaction retry envelope also clears them before
201
+ # each attempt so a re-run function re-registers from a clean slate.
202
+ self._on_commit_callbacks = []
197
203
 
198
204
  def __str__(self):
199
205
  config = mask_config_for_display(self.engine.config)
@@ -248,6 +254,9 @@ class Transaction:
248
254
  dead = self.connection
249
255
  self.connection = None
250
256
  self._in_progress = False
257
+ # Uncommitted work is gone; anything queued to run after its commit
258
+ # must never fire.
259
+ self._on_commit_callbacks = []
251
260
  if dead is None:
252
261
  return
253
262
  if self.__pooled:
@@ -306,6 +315,9 @@ class Transaction:
306
315
  the pool instead of being closed.
307
316
  """
308
317
  if not self.connection:
318
+ # No DB work happened, so there is nothing to commit — but the
319
+ # transaction still completed; run any on_commit callbacks.
320
+ self._fire_on_commit_callbacks()
309
321
  return
310
322
  if debug:
311
323
  print(f"<<< {id(self)} close connection.")
@@ -565,6 +577,67 @@ class Transaction:
565
577
  "query_time_ms": round(self._query_time_ms, 1),
566
578
  },
567
579
  )
580
+ # Fire after the DB work is durable (or when there was no DB work at
581
+ # all — a transaction that only registered callbacks still completes).
582
+ # A commit-time DB error raises above, so callbacks from a failed
583
+ # commit never run here.
584
+ self._fire_on_commit_callbacks()
585
+
586
+ def on_commit(self, callback):
587
+ """Register a callable to run once, after this transaction commits.
588
+
589
+ Use this for side effects that must not become visible before the
590
+ transaction's DB work does — e.g. sending an SQS message that a
591
+ consumer will immediately read back from the database. Sending inside
592
+ the open transaction races the consumer against the commit; deferring
593
+ with ``on_commit`` closes that race::
594
+
595
+ @engine.transaction
596
+ def handler(tx, context):
597
+ row = tx.table("webhooks").new({...})
598
+ tx.on_commit(lambda: context.enqueue(..., payload={"webhook_id": row.sys_id}))
599
+
600
+ Semantics:
601
+
602
+ * Callbacks run in registration order, once, immediately after a
603
+ successful COMMIT (``commit()``/``close()``/decorator exit). If the
604
+ transaction never touched the database, they run when it completes.
605
+ * They are discarded — never run — on ``rollback()``, when a dead
606
+ connection is dropped, and before each ``@engine.transaction`` retry
607
+ attempt (the re-run function registers its own again).
608
+ * A callback exception is logged and does not propagate: the commit is
609
+ already durable, so raising would misreport a committed transaction
610
+ as failed (and e.g. make a webhook caller retry a done request).
611
+ Callbacks needing delivery guarantees must handle their own errors.
612
+ """
613
+ if not callable(callback):
614
+ raise TypeError("on_commit callback must be callable")
615
+ # getattr-guarded: some tests (and potential subclasses) build a
616
+ # Transaction without running __init__.
617
+ callbacks = getattr(self, "_on_commit_callbacks", None)
618
+ if callbacks is None:
619
+ callbacks = self._on_commit_callbacks = []
620
+ callbacks.append(callback)
621
+ return callback
622
+
623
+ def discard_on_commit_callbacks(self):
624
+ """Drop any registered on_commit callbacks without running them."""
625
+ self._on_commit_callbacks = []
626
+
627
+ def _fire_on_commit_callbacks(self):
628
+ callbacks = getattr(self, "_on_commit_callbacks", None)
629
+ self._on_commit_callbacks = []
630
+ if not callbacks:
631
+ return
632
+ for callback in callbacks:
633
+ try:
634
+ callback()
635
+ except Exception:
636
+ _logger.exception(
637
+ "on_commit callback %r failed; the transaction is already "
638
+ "committed, so the error is logged and not raised",
639
+ callback,
640
+ )
568
641
 
569
642
  def rollback(self):
570
643
  """
@@ -576,6 +649,8 @@ class Transaction:
576
649
  self.connection.rollback()
577
650
  # Transaction is clean again — no uncommitted work pending.
578
651
  self._in_progress = False
652
+ # The work these were waiting on is rolled back — never run them.
653
+ self._on_commit_callbacks = []
579
654
 
580
655
  def is_aborted(self):
581
656
  """Return True if the connection is in a failed/aborted transaction.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.87
3
+ Version: 0.1.88
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
@@ -219,6 +219,7 @@ tests/test_nosql_redis.py
219
219
  tests/test_nosql_translation.py
220
220
  tests/test_nosql_where.py
221
221
  tests/test_observability.py
222
+ tests/test_on_commit.py
222
223
  tests/test_payment_authorizenet_adapter.py
223
224
  tests/test_payment_braintree_adapter.py
224
225
  tests/test_payment_braintree_mirror.py
@@ -0,0 +1,216 @@
1
+ """Transaction.on_commit and Context.enqueue(tx=...) — post-commit side effects.
2
+
3
+ Motivation: sending an SQS message inside a still-open transaction races the
4
+ consumer against the COMMIT; the consumer can read the database before the
5
+ producer's rows are visible (this dropped a production Braintree webhook).
6
+ ``tx.on_commit`` defers such side effects until the work is durable, and
7
+ ``Context.enqueue(..., transaction=tx)`` uses it to defer the whole enqueue.
8
+ """
9
+
10
+ import unittest
11
+ from unittest.mock import MagicMock, patch
12
+
13
+ from velocity.db import exceptions
14
+ from velocity.db.core.engine import Engine
15
+ from velocity.db.core.transaction import Transaction
16
+ from velocity.aws.handlers import context as handler_context
17
+
18
+
19
+ def _make_tx(connection=None):
20
+ engine = MagicMock()
21
+ engine.pool_enabled = False
22
+ connection = connection if connection is not None else MagicMock()
23
+ return Transaction(engine, connection), connection
24
+
25
+
26
+ class TransactionOnCommitTests(unittest.TestCase):
27
+ def test_callbacks_fire_in_order_after_commit(self):
28
+ tx, _ = _make_tx()
29
+ fired = []
30
+ tx.on_commit(lambda: fired.append("first"))
31
+ tx.on_commit(lambda: fired.append("second"))
32
+ self.assertEqual([], fired) # nothing runs before commit
33
+ tx.commit()
34
+ self.assertEqual(["first", "second"], fired)
35
+
36
+ def test_callbacks_fire_only_once(self):
37
+ tx, _ = _make_tx()
38
+ fired = []
39
+ tx.on_commit(lambda: fired.append(1))
40
+ tx.commit()
41
+ tx.commit() # e.g. close() after an explicit commit
42
+ self.assertEqual([1], fired)
43
+
44
+ def test_rollback_discards_callbacks(self):
45
+ tx, _ = _make_tx()
46
+ fired = []
47
+ tx.on_commit(lambda: fired.append(1))
48
+ tx.rollback()
49
+ tx.commit()
50
+ self.assertEqual([], fired)
51
+
52
+ def test_close_without_db_work_still_fires(self):
53
+ tx, _ = _make_tx(connection=False)
54
+ tx.connection = None # transaction never touched the database
55
+ fired = []
56
+ tx.on_commit(lambda: fired.append(1))
57
+ tx.close()
58
+ self.assertEqual([1], fired)
59
+
60
+ def test_commit_time_db_error_does_not_fire(self):
61
+ tx, connection = _make_tx()
62
+ connection.commit.side_effect = RuntimeError("deadlock at COMMIT")
63
+ tx.engine.process_error.side_effect = lambda e: exceptions.DbRetryTransaction(
64
+ str(e)
65
+ )
66
+ fired = []
67
+ tx.on_commit(lambda: fired.append(1))
68
+ with self.assertRaises(exceptions.DbRetryTransaction):
69
+ tx.commit()
70
+ self.assertEqual([], fired)
71
+ # The retry envelope rolls back next; the callback must stay discarded.
72
+ tx.rollback()
73
+ connection.commit.side_effect = None
74
+ tx.commit()
75
+ self.assertEqual([], fired)
76
+
77
+ def test_callback_exception_is_swallowed_and_rest_run(self):
78
+ tx, _ = _make_tx()
79
+ fired = []
80
+
81
+ def _explodes():
82
+ raise ValueError("boom")
83
+
84
+ tx.on_commit(_explodes)
85
+ tx.on_commit(lambda: fired.append("still ran"))
86
+ with self.assertLogs("velocity.db.transaction", level="ERROR"):
87
+ tx.commit()
88
+ self.assertEqual(["still ran"], fired)
89
+
90
+ def test_dead_connection_discard_clears_callbacks(self):
91
+ tx, _ = _make_tx()
92
+ fired = []
93
+ tx.on_commit(lambda: fired.append(1))
94
+ tx._discard_dead_connection()
95
+ tx.commit()
96
+ self.assertEqual([], fired)
97
+
98
+ def test_non_callable_rejected(self):
99
+ tx, _ = _make_tx()
100
+ with self.assertRaises(TypeError):
101
+ tx.on_commit("not callable")
102
+
103
+
104
+ class ExecFunctionRetryTests(unittest.TestCase):
105
+ def test_retry_attempt_does_not_replay_previous_attempts_callbacks(self):
106
+ """A failed attempt's callbacks must never fire; only the committed
107
+ attempt's do — and exactly once."""
108
+ tx, _ = _make_tx()
109
+ engine = MagicMock()
110
+ engine.MAX_RETRIES = 3
111
+ fired = []
112
+ attempts = {"n": 0}
113
+
114
+ def function():
115
+ attempts["n"] += 1
116
+ attempt = attempts["n"]
117
+ tx.on_commit(lambda: fired.append(attempt))
118
+ if attempt == 1:
119
+ raise exceptions.DbRetryTransaction("serialization failure")
120
+
121
+ with patch("velocity.db.core.engine.time.sleep"):
122
+ Engine.exec_function(engine, function, tx, _owns_tx=True)
123
+
124
+ self.assertEqual(2, attempts["n"])
125
+ self.assertEqual([2], fired) # attempt 1's callback discarded
126
+
127
+
128
+ class EnqueueDeferredTests(unittest.TestCase):
129
+ class _FakeQueue:
130
+ def __init__(self):
131
+ self.sent = []
132
+
133
+ def send_messages(self, Entries):
134
+ self.sent.extend(Entries)
135
+ return {"Successful": [{"Id": e["Id"]} for e in Entries], "Failed": []}
136
+
137
+ class _FakeContext:
138
+ def __init__(self):
139
+ self.jobs = []
140
+
141
+ def session(self):
142
+ return {"email_address": "owner@example.com"}
143
+
144
+ def create_job(self, job_data=None):
145
+ self.jobs.append(job_data)
146
+
147
+ def fail_enqueue(self, **kwargs):
148
+ raise AssertionError("no send failures expected")
149
+
150
+ # Bind the real method so the deferred callback re-enters it.
151
+ enqueue = handler_context.Context.enqueue
152
+
153
+ def _patched(self, queue):
154
+ class _Resource:
155
+ def get_queue_by_name(self, QueueName):
156
+ return queue
157
+
158
+ return (
159
+ patch.dict(
160
+ handler_context.os.environ,
161
+ {"SqsWorkQueue": "example-queue"},
162
+ clear=False,
163
+ ),
164
+ patch.object(handler_context.boto3, "resource", return_value=_Resource()),
165
+ )
166
+
167
+ def test_enqueue_with_tx_defers_until_commit(self):
168
+ ctx = self._FakeContext()
169
+ queue = self._FakeQueue()
170
+ tx, _ = _make_tx()
171
+
172
+ env_patch, boto_patch = self._patched(queue)
173
+ with env_patch, boto_patch:
174
+ result = ctx.enqueue(
175
+ "process-braintree-webhook",
176
+ payload={"webhook_id": 1116},
177
+ transaction=tx,
178
+ )
179
+ # Nothing sent or tracked while the transaction is open.
180
+ self.assertEqual({"deferred_until_commit": True}, result)
181
+ self.assertEqual([], queue.sent)
182
+ self.assertEqual([], ctx.jobs)
183
+
184
+ tx.commit()
185
+
186
+ self.assertEqual(1, len(queue.sent))
187
+ self.assertEqual(1, len(ctx.jobs))
188
+ self.assertIn("process-braintree-webhook", queue.sent[0]["MessageBody"])
189
+
190
+ def test_enqueue_with_tx_rollback_sends_nothing(self):
191
+ ctx = self._FakeContext()
192
+ queue = self._FakeQueue()
193
+ tx, _ = _make_tx()
194
+
195
+ env_patch, boto_patch = self._patched(queue)
196
+ with env_patch, boto_patch:
197
+ ctx.enqueue("some-action", payload={"x": 1}, transaction=tx)
198
+ tx.rollback()
199
+ tx.commit()
200
+
201
+ self.assertEqual([], queue.sent)
202
+ self.assertEqual([], ctx.jobs)
203
+
204
+ def test_enqueue_without_tx_sends_immediately(self):
205
+ ctx = self._FakeContext()
206
+ queue = self._FakeQueue()
207
+
208
+ env_patch, boto_patch = self._patched(queue)
209
+ with env_patch, boto_patch:
210
+ ctx.enqueue("some-action", payload={"x": 1})
211
+
212
+ self.assertEqual(1, len(queue.sent))
213
+
214
+
215
+ if __name__ == "__main__":
216
+ unittest.main()