velocity-python 0.1.112__tar.gz → 0.1.114__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 (303) hide show
  1. {velocity_python-0.1.112/src/velocity_python.egg-info → velocity_python-0.1.114}/PKG-INFO +1 -1
  2. {velocity_python-0.1.112 → velocity_python-0.1.114}/pyproject.toml +1 -1
  3. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/context.py +6 -1
  5. velocity_python-0.1.114/src/velocity/db/core/lazy_engine.py +116 -0
  6. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/result.py +13 -4
  7. {velocity_python-0.1.112 → velocity_python-0.1.114/src/velocity_python.egg-info}/PKG-INFO +1 -1
  8. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity_python.egg-info/SOURCES.txt +3 -0
  9. velocity_python-0.1.114/tests/test_lazy_engine.py +179 -0
  10. velocity_python-0.1.114/tests/test_result_returning.py +70 -0
  11. {velocity_python-0.1.112 → velocity_python-0.1.114}/LICENSE +0 -0
  12. {velocity_python-0.1.112 → velocity_python-0.1.114}/README.md +0 -0
  13. {velocity_python-0.1.112 → velocity_python-0.1.114}/setup.cfg +0 -0
  14. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/__init__.py +0 -0
  15. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/amplify.py +0 -0
  16. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/amplify_build.py +0 -0
  17. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/assets/__init__.py +0 -0
  18. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/assets/backfill.py +0 -0
  19. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/assets/indexing.py +0 -0
  20. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/assets/references.py +0 -0
  21. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/assets/service.py +0 -0
  22. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/assets/usage_index.py +0 -0
  23. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/blobs.py +0 -0
  24. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/__init__.py +0 -0
  25. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/base.py +0 -0
  26. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/dispatch.py +0 -0
  27. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/infra.py +0 -0
  28. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/jobs.py +0 -0
  29. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/provisioning.py +0 -0
  30. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/retention.py +0 -0
  31. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/security.py +0 -0
  32. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/capabilities/single_session.py +0 -0
  33. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/deploy/__init__.py +0 -0
  34. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/deploy/config.py +0 -0
  35. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/deploy/operations.py +0 -0
  36. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/deploy/policies.py +0 -0
  37. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/deploy/reconcile.py +0 -0
  38. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/deploy/targets.py +0 -0
  39. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/dirty_pipeline.py +0 -0
  40. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/email.py +0 -0
  41. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/feature_flags.py +0 -0
  42. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/__init__.py +0 -0
  43. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/base_handler.py +0 -0
  44. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/context_factory.py +0 -0
  45. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/exceptions.py +0 -0
  46. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  47. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/masquerade.py +0 -0
  48. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  49. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  50. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/mixins/job_handler.py +0 -0
  51. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/mixins/session_control.py +0 -0
  52. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  53. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/perf.py +0 -0
  54. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/response.py +0 -0
  55. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  56. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/job_lifecycle.py +0 -0
  57. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/job_results.py +0 -0
  58. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/mirror.py +0 -0
  59. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/s3.py +0 -0
  60. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/sms.py +0 -0
  61. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/ssm_config.py +0 -0
  62. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/__init__.py +0 -0
  63. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_amplify_build_policy_size.py +0 -0
  64. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_amplify_build_shim.py +0 -0
  65. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  66. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_deploy_policies.py +0 -0
  67. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_deploy_reconcile.py +0 -0
  68. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_email.py +0 -0
  69. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  70. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_response.py +0 -0
  71. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/aws/tests/test_sms.py +0 -0
  72. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/cache.py +0 -0
  73. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/__init__.py +0 -0
  74. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/__init__.py +0 -0
  75. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/async_support.py +0 -0
  76. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/column.py +0 -0
  77. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/database.py +0 -0
  78. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/decorators.py +0 -0
  79. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/engine.py +0 -0
  80. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/jsonproxy.py +0 -0
  81. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/row.py +0 -0
  82. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/sequence.py +0 -0
  83. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/table.py +0 -0
  84. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/transaction.py +0 -0
  85. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/core/view.py +0 -0
  86. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/exceptions.py +0 -0
  87. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/maintenance.py +0 -0
  88. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/migrations.py +0 -0
  89. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/__init__.py +0 -0
  90. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/base/__init__.py +0 -0
  91. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/base/initializer.py +0 -0
  92. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/base/operators.py +0 -0
  93. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/base/sql.py +0 -0
  94. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/base/types.py +0 -0
  95. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/mysql/__init__.py +0 -0
  96. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/mysql/operators.py +0 -0
  97. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/mysql/reserved.py +0 -0
  98. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/mysql/sql.py +0 -0
  99. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/mysql/types.py +0 -0
  100. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/postgres/__init__.py +0 -0
  101. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/postgres/operators.py +0 -0
  102. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/postgres/reserved.py +0 -0
  103. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/postgres/sql.py +0 -0
  104. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/postgres/types.py +0 -0
  105. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  106. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlite/operators.py +0 -0
  107. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  108. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlite/sql.py +0 -0
  109. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlite/types.py +0 -0
  110. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  111. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  112. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  113. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  114. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/sqlserver/types.py +0 -0
  115. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/servers/tablehelper.py +0 -0
  116. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/__init__.py +0 -0
  117. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/common_db_test.py +0 -0
  118. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/__init__.py +0 -0
  119. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/common.py +0 -0
  120. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/conftest.py +0 -0
  121. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_column.py +0 -0
  122. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  123. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_database.py +0 -0
  124. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  125. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  126. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  127. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_result.py +0 -0
  128. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_row.py +0 -0
  129. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  130. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  131. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  132. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  133. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  134. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_table.py +0 -0
  135. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  136. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  137. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/sql/__init__.py +0 -0
  138. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/sql/common.py +0 -0
  139. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  140. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  141. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  142. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_db_utils.py +0 -0
  143. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_postgres.py +0 -0
  144. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  145. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  146. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_result_caching.py +0 -0
  147. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  148. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  149. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  150. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  151. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_sql_builder.py +0 -0
  152. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_tablehelper.py +0 -0
  153. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/tests/test_view_helper.py +0 -0
  154. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/db/utils.py +0 -0
  155. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/logging.py +0 -0
  156. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/__init__.py +0 -0
  157. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/conv/__init__.py +0 -0
  158. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/conv/iconv.py +0 -0
  159. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/conv/oconv.py +0 -0
  160. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/db.py +0 -0
  161. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/export.py +0 -0
  162. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/format.py +0 -0
  163. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/mail.py +0 -0
  164. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/merge.py +0 -0
  165. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/pdf.py +0 -0
  166. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/__init__.py +0 -0
  167. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_db.py +0 -0
  168. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_fix.py +0 -0
  169. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_format.py +0 -0
  170. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_iconv.py +0 -0
  171. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_mail_send.py +0 -0
  172. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_merge.py +0 -0
  173. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_oconv.py +0 -0
  174. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_original_error.py +0 -0
  175. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tests/test_timer.py +0 -0
  176. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/timer.py +0 -0
  177. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/misc/tools.py +0 -0
  178. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/__init__.py +0 -0
  179. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/core/__init__.py +0 -0
  180. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/core/capabilities.py +0 -0
  181. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/core/store.py +0 -0
  182. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/core/where.py +0 -0
  183. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/exceptions.py +0 -0
  184. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/__init__.py +0 -0
  185. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/base/__init__.py +0 -0
  186. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/cassandra/__init__.py +0 -0
  187. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/cassandra/translation.py +0 -0
  188. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/couchbase/__init__.py +0 -0
  189. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/couchbase/translation.py +0 -0
  190. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/dynamodb/__init__.py +0 -0
  191. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/dynamodb/translation.py +0 -0
  192. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/elasticsearch/__init__.py +0 -0
  193. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/elasticsearch/translation.py +0 -0
  194. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/memory/__init__.py +0 -0
  195. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/mongodb/__init__.py +0 -0
  196. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/mongodb/translation.py +0 -0
  197. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/nosql/servers/redis/__init__.py +0 -0
  198. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/__init__.py +0 -0
  199. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/authorizenet_adapter.py +0 -0
  200. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/authorizenet_mirror.py +0 -0
  201. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/base_adapter.py +0 -0
  202. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/braintree_adapter.py +0 -0
  203. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/braintree_mirror.py +0 -0
  204. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/charge_rules.py +0 -0
  205. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/stripe_adapter.py +0 -0
  206. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity/payment/stripe_mirror.py +0 -0
  207. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  208. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity_python.egg-info/entry_points.txt +0 -0
  209. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity_python.egg-info/requires.txt +0 -0
  210. {velocity_python-0.1.112 → velocity_python-0.1.114}/src/velocity_python.egg-info/top_level.txt +0 -0
  211. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_access_error_403.py +0 -0
  212. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_activity_tracking_aborted_tx.py +0 -0
  213. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_amplify_build.py +0 -0
  214. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_asset_indexing.py +0 -0
  215. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_asset_references.py +0 -0
  216. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_assets_service.py +0 -0
  217. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_async_support.py +0 -0
  218. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_batch_operations.py +0 -0
  219. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_blob_store.py +0 -0
  220. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_capabilities.py +0 -0
  221. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_capability_catalog.py +0 -0
  222. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_cognito_user_cache.py +0 -0
  223. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_column_tx_arg.py +0 -0
  224. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_concurrency_safety.py +0 -0
  225. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_connection_pool.py +0 -0
  226. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_connection_resilience.py +0 -0
  227. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_context_flags_loader.py +0 -0
  228. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_context_job_descriptions.py +0 -0
  229. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_data_service_query_cap.py +0 -0
  230. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_data_service_renumber.py +0 -0
  231. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_data_service_save_as.py +0 -0
  232. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_db_credentials_ssm_cascade.py +0 -0
  233. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_db_maintenance.py +0 -0
  234. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_decorators.py +0 -0
  235. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_delete_hook_fk_blocked.py +0 -0
  236. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_dirty_pipeline_fast_path.py +0 -0
  237. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_email_processing.py +0 -0
  238. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_enqueue_send_failures.py +0 -0
  239. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_feature_flags.py +0 -0
  240. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_get_cognito_user_provider.py +0 -0
  241. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_http_handler_rollback.py +0 -0
  242. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_iconv_money_to_cents.py +0 -0
  243. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_identifier_injection_guard.py +0 -0
  244. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_job_handler.py +0 -0
  245. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_job_lifecycle.py +0 -0
  246. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_job_results.py +0 -0
  247. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_json_columns.py +0 -0
  248. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_jsonb_dict_adapter.py +0 -0
  249. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_lambda_handler.py +0 -0
  250. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_lambda_handler_auth.py +0 -0
  251. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_lambda_handler_masquerade.py +0 -0
  252. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_lambda_handler_user_cache.py +0 -0
  253. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_masquerade_grant.py +0 -0
  254. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_mirror.py +0 -0
  255. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_mixins_import.py +0 -0
  256. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_n_plus_one.py +0 -0
  257. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_nosql_dynamodb.py +0 -0
  258. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_nosql_memory.py +0 -0
  259. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_nosql_mongodb.py +0 -0
  260. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_nosql_redis.py +0 -0
  261. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_nosql_translation.py +0 -0
  262. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_nosql_where.py +0 -0
  263. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_observability.py +0 -0
  264. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_on_commit.py +0 -0
  265. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_payment_authorizenet_adapter.py +0 -0
  266. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_payment_braintree_adapter.py +0 -0
  267. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_payment_braintree_mirror.py +0 -0
  268. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_payment_mirror_empty_table.py +0 -0
  269. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_payment_profile_sorting.py +0 -0
  270. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_payment_stripe_adapter.py +0 -0
  271. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_pdf.py +0 -0
  272. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_prepared_statements.py +0 -0
  273. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_psycopg3_upgrade.py +0 -0
  274. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_query_cache.py +0 -0
  275. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_query_missing_table_unlocked.py +0 -0
  276. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_read_cache.py +0 -0
  277. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_response.py +0 -0
  278. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_restricted_direct_tables.py +0 -0
  279. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_retry_side_effect_guard.py +0 -0
  280. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_return_default_safety.py +0 -0
  281. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_row_batch_update.py +0 -0
  282. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_row_cache_staleness.py +0 -0
  283. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_schema_migrations.py +0 -0
  284. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_security_capability.py +0 -0
  285. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_security_hardening.py +0 -0
  286. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_server_cursor.py +0 -0
  287. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_session_control.py +0 -0
  288. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_single_autocommit_safety.py +0 -0
  289. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_single_session_capability.py +0 -0
  290. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_spreadsheet_functions.py +0 -0
  291. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_sqlite_backend.py +0 -0
  292. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_sqs_per_record_transactions.py +0 -0
  293. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_ssm_config.py +0 -0
  294. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_store_user_data.py +0 -0
  295. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  296. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_table_alter.py +0 -0
  297. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_table_find_cache.py +0 -0
  298. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_table_purge.py +0 -0
  299. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_transaction_class_wrapping.py +0 -0
  300. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_transaction_commit_and_ownership.py +0 -0
  301. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_transaction_edge_cases.py +0 -0
  302. {velocity_python-0.1.112 → velocity_python-0.1.114}/tests/test_where_clause_validation.py +0 -0
  303. {velocity_python-0.1.112 → velocity_python-0.1.114}/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.112
3
+ Version: 0.1.114
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.112"
7
+ version = "0.1.114"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.112"
1
+ __version__ = version = "0.1.114"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -18,8 +18,13 @@ from velocity.aws.ssm_config import get_region as config_get_region
18
18
  from velocity.aws.ssm_config import get_stage as config_get_stage
19
19
  from velocity.logging import get_logger
20
20
  from velocity.cache import memo
21
+ from velocity.db.core.lazy_engine import LazyEngine
21
22
 
22
- engine = velocity.db.postgres.initialize()
23
+ # Built on first use, not at import: importing a handler must not demand DB
24
+ # configuration (see LazyEngine). ``@engine.transaction`` on Context below is
25
+ # honoured lazily — the first call of a ``tx``-taking method constructs the
26
+ # engine and dispatches through the real decorator.
27
+ engine = LazyEngine(velocity.db.postgres.initialize)
23
28
 
24
29
 
25
30
  cognito_client = boto3.client("cognito-idp")
@@ -0,0 +1,116 @@
1
+ """A module-level engine that is built on first use, not at import.
2
+
3
+ ``velocity.aws.handlers.context`` used to run ``postgres.initialize()`` at
4
+ import, so merely importing a handler (or collecting a test that touches one)
5
+ demanded DB configuration — three unrelated test suites ended up stubbing DB
6
+ env vars just to import the package (IMPROVEMENT_BACKLOG, 2026-08-14).
7
+
8
+ ``LazyEngine`` is a drop-in stand-in for that module attribute:
9
+
10
+ * attribute access (``engine.schema_locked``, ``engine.transaction()``) builds
11
+ the real engine once, then delegates;
12
+ * ``@engine.transaction`` still works as a function, ``classmethod`` and class
13
+ decorator — decoration never builds the engine; the first *call* of a
14
+ decorated callable that declares ``tx`` does, and then dispatches through the
15
+ real ``Engine.transaction`` so retry/commit semantics are unchanged;
16
+ * callables that do not declare ``tx`` are returned untouched, exactly as the
17
+ real decorator would run them, so using them never needs configuration.
18
+
19
+ The configuration error a missing DB env produces therefore surfaces at first
20
+ use, with the same message, instead of at import.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import inspect
26
+ from functools import wraps
27
+ from typing import Any, Callable
28
+
29
+
30
+ class LazyEngine:
31
+ """Proxy that constructs ``factory()`` on first use and delegates to it."""
32
+
33
+ def __init__(self, factory: Callable[[], Any]):
34
+ self._factory = factory
35
+ self._engine = None
36
+
37
+ # ── construction ──────────────────────────────────────────────────────
38
+
39
+ def resolve(self):
40
+ """The real engine, built on the first call."""
41
+ if self._engine is None:
42
+ self._engine = self._factory()
43
+ return self._engine
44
+
45
+ @property
46
+ def initialized(self) -> bool:
47
+ """True once the real engine has been built."""
48
+ return self._engine is not None
49
+
50
+ def __getattr__(self, name: str):
51
+ # Only reached for names not found on the proxy itself.
52
+ return getattr(self.resolve(), name)
53
+
54
+ def __repr__(self) -> str:
55
+ state = repr(self._engine) if self._engine is not None else "uninitialized"
56
+ return f"LazyEngine({state})"
57
+
58
+ # ── @engine.transaction ───────────────────────────────────────────────
59
+
60
+ def transaction(self, func_or_cls=None):
61
+ """Mirror ``Engine.transaction``: no args → a Transaction on the real
62
+ engine; a function / classmethod / class → wrapped lazily."""
63
+ if func_or_cls is None:
64
+ return self.resolve().transaction()
65
+ if isinstance(func_or_cls, classmethod):
66
+ return classmethod(self._lazy_function(func_or_cls.__func__))
67
+ if inspect.isclass(func_or_cls):
68
+ return self._lazy_class(func_or_cls)
69
+ if inspect.isfunction(func_or_cls) or inspect.ismethod(func_or_cls):
70
+ return self._lazy_function(func_or_cls)
71
+ return self.resolve().transaction(func_or_cls)
72
+
73
+ def _lazy_function(self, func):
74
+ names = list(inspect.signature(func).parameters.keys())
75
+ if "_tx" in names:
76
+ # Same contract as Engine.transaction, enforced at decoration time.
77
+ raise NameError(
78
+ f"In function {func.__name__}, '_tx' is not allowed as a parameter."
79
+ )
80
+ if "tx" not in names:
81
+ # Engine.transaction would call such a function straight through;
82
+ # returning it untouched is the same behaviour with no engine needed.
83
+ return func
84
+
85
+ wrapped = None
86
+
87
+ @wraps(func)
88
+ def lazy(*args, **kwds):
89
+ nonlocal wrapped
90
+ if wrapped is None:
91
+ wrapped = self.resolve().transaction(func)
92
+ return wrapped(*args, **kwds)
93
+
94
+ return lazy
95
+
96
+ def _lazy_class(self, cls):
97
+ # Same shape as Engine.transaction's class branch: a subclass carrying
98
+ # wrapped copies of every public callable, descriptors preserved.
99
+ new_cls = type(cls.__name__, (cls,), {})
100
+ for attr_name in dir(cls):
101
+ if attr_name.startswith("__") and attr_name.endswith("__"):
102
+ continue
103
+ raw = inspect.getattr_static(cls, attr_name, None)
104
+ if isinstance(raw, staticmethod):
105
+ setattr(
106
+ new_cls, attr_name, staticmethod(self._lazy_function(raw.__func__))
107
+ )
108
+ elif isinstance(raw, classmethod):
109
+ setattr(
110
+ new_cls, attr_name, classmethod(self._lazy_function(raw.__func__))
111
+ )
112
+ else:
113
+ attr = getattr(cls, attr_name)
114
+ if callable(attr):
115
+ setattr(new_cls, attr_name, self._lazy_function(attr))
116
+ return new_cls
@@ -81,10 +81,19 @@ class Result:
81
81
  if self._first_row_fetched or not self._cursor:
82
82
  return
83
83
 
84
- # Don't try to fetch from INSERT/UPDATE/DELETE operations
85
- # These operations don't return rows, only rowcount
86
- if self.__sql and self.__sql.strip().upper().startswith(
87
- ("INSERT", "UPDATE", "DELETE", "TRUNCATE")
84
+ # A write returns rows exactly when the driver describes a result set:
85
+ # INSERT/UPDATE/DELETE ... RETURNING (PostgreSQL), OUTPUT (SQL Server).
86
+ # Judging by the verb alone marked EVERY write as row-less, so
87
+ # `UPDATE ... RETURNING sys_id` silently reported nothing — a claim taken
88
+ # that way looked refused forever (tenspace.gmail, 2026-09-17). A write
89
+ # with no described columns has only a rowcount, and fetchone() on it
90
+ # raises on most drivers, so that case is still short-circuited.
91
+ if (
92
+ self.__sql
93
+ and self.__sql.strip()
94
+ .upper()
95
+ .startswith(("INSERT", "UPDATE", "DELETE", "TRUNCATE"))
96
+ and not self._headers
88
97
  ):
89
98
  self._exhausted = True
90
99
  self._first_row_fetched = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.112
3
+ Version: 0.1.114
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
@@ -75,6 +75,7 @@ src/velocity/db/core/database.py
75
75
  src/velocity/db/core/decorators.py
76
76
  src/velocity/db/core/engine.py
77
77
  src/velocity/db/core/jsonproxy.py
78
+ src/velocity/db/core/lazy_engine.py
78
79
  src/velocity/db/core/result.py
79
80
  src/velocity/db/core/row.py
80
81
  src/velocity/db/core/sequence.py
@@ -245,6 +246,7 @@ tests/test_lambda_handler.py
245
246
  tests/test_lambda_handler_auth.py
246
247
  tests/test_lambda_handler_masquerade.py
247
248
  tests/test_lambda_handler_user_cache.py
249
+ tests/test_lazy_engine.py
248
250
  tests/test_masquerade_grant.py
249
251
  tests/test_mirror.py
250
252
  tests/test_mixins_import.py
@@ -271,6 +273,7 @@ tests/test_query_missing_table_unlocked.py
271
273
  tests/test_read_cache.py
272
274
  tests/test_response.py
273
275
  tests/test_restricted_direct_tables.py
276
+ tests/test_result_returning.py
274
277
  tests/test_retry_side_effect_guard.py
275
278
  tests/test_return_default_safety.py
276
279
  tests/test_row_batch_update.py
@@ -0,0 +1,179 @@
1
+ """LazyEngine: the handler package imports without DB configuration, the
2
+ engine is built exactly once on first use, and @engine.transaction keeps the
3
+ real decorator's semantics (tx injected on call, static/class methods intact,
4
+ tx-less callables untouched)."""
5
+
6
+ import os
7
+ import subprocess
8
+ import sys
9
+
10
+ import pytest
11
+
12
+ import velocity
13
+ from velocity.db.core.lazy_engine import LazyEngine
14
+
15
+ SENTINEL_TX = object()
16
+
17
+
18
+ class FakeEngine:
19
+ """Stands in for Engine: transaction(func) injects SENTINEL_TX when the
20
+ caller passed no tx, transaction() returns a marker."""
21
+
22
+ schema_locked = "fake-flag"
23
+
24
+ def transaction(self, func_or_cls=None):
25
+ if func_or_cls is None:
26
+ return "TX"
27
+
28
+ def wrapper(*args, **kwds):
29
+ if "tx" not in kwds:
30
+ kwds["tx"] = SENTINEL_TX
31
+ return func_or_cls(*args, **kwds)
32
+
33
+ return wrapper
34
+
35
+
36
+ def make_lazy():
37
+ calls = []
38
+
39
+ def factory():
40
+ calls.append(1)
41
+ return FakeEngine()
42
+
43
+ return LazyEngine(factory), calls
44
+
45
+
46
+ def test_construction_and_decoration_do_not_build_the_engine():
47
+ lazy, calls = make_lazy()
48
+
49
+ @lazy.transaction
50
+ class Ctx:
51
+ def with_tx(self, tx=None, value=None):
52
+ return tx, value
53
+
54
+ def plain(self, value):
55
+ return value
56
+
57
+ @staticmethod
58
+ def static(tx=None):
59
+ return tx
60
+
61
+ @classmethod
62
+ def klass(cls, tx=None):
63
+ return cls, tx
64
+
65
+ assert calls == []
66
+ assert not lazy.initialized
67
+ assert Ctx.__name__ == "Ctx"
68
+
69
+
70
+ def test_first_tx_call_builds_once_and_injects_tx():
71
+ lazy, calls = make_lazy()
72
+
73
+ @lazy.transaction
74
+ class Ctx:
75
+ def with_tx(self, tx=None, value=None):
76
+ return tx, value
77
+
78
+ ctx = Ctx()
79
+ assert ctx.with_tx(value=1) == (SENTINEL_TX, 1)
80
+ assert ctx.with_tx(value=2) == (SENTINEL_TX, 2)
81
+ assert calls == [1]
82
+ assert lazy.initialized
83
+
84
+
85
+ def test_callables_without_tx_never_need_the_engine():
86
+ lazy, calls = make_lazy()
87
+
88
+ @lazy.transaction
89
+ class Ctx:
90
+ def plain(self, value):
91
+ return value * 2
92
+
93
+ assert Ctx().plain(21) == 42
94
+ assert calls == []
95
+
96
+
97
+ def test_static_and_class_methods_keep_their_nature():
98
+ lazy, _calls = make_lazy()
99
+
100
+ @lazy.transaction
101
+ class Ctx:
102
+ @staticmethod
103
+ def static(tx=None):
104
+ return tx
105
+
106
+ @classmethod
107
+ def klass(cls, tx=None):
108
+ return cls.__name__, tx
109
+
110
+ assert Ctx.static() is SENTINEL_TX
111
+ assert Ctx().static() is SENTINEL_TX
112
+ assert Ctx.klass() == ("Ctx", SENTINEL_TX)
113
+
114
+
115
+ def test_function_and_classmethod_decoration():
116
+ lazy, calls = make_lazy()
117
+
118
+ @lazy.transaction
119
+ def work(tx=None, n=0):
120
+ return tx, n
121
+
122
+ assert calls == []
123
+ assert work(n=3) == (SENTINEL_TX, 3)
124
+ assert calls == [1]
125
+
126
+
127
+ def test_tx_underscore_parameter_is_rejected_at_decoration_without_building():
128
+ lazy, calls = make_lazy()
129
+ with pytest.raises(NameError):
130
+
131
+ @lazy.transaction
132
+ def bad(_tx=None):
133
+ return _tx
134
+
135
+ assert calls == []
136
+
137
+
138
+ def test_attribute_access_and_bare_transaction_delegate():
139
+ lazy, calls = make_lazy()
140
+ assert lazy.schema_locked == "fake-flag"
141
+ assert lazy.transaction() == "TX"
142
+ assert calls == [1]
143
+ assert "LazyEngine(" in repr(lazy)
144
+
145
+
146
+ def _run_without_db_env(code: str) -> subprocess.CompletedProcess:
147
+ env = {k: v for k, v in os.environ.items() if not k.startswith("DB")}
148
+ src = os.path.dirname(os.path.dirname(os.path.abspath(velocity.__file__)))
149
+ env["PYTHONPATH"] = src + os.pathsep + env.get("PYTHONPATH", "")
150
+ return subprocess.run(
151
+ [sys.executable, "-c", code],
152
+ env=env,
153
+ capture_output=True,
154
+ text=True,
155
+ timeout=120,
156
+ )
157
+
158
+
159
+ def test_handlers_import_without_db_configuration():
160
+ result = _run_without_db_env(
161
+ "import velocity.aws.handlers.context as c\n"
162
+ "assert not c.engine.initialized, 'engine built at import'\n"
163
+ "print('imported')"
164
+ )
165
+ assert result.returncode == 0, result.stderr
166
+ assert "imported" in result.stdout
167
+
168
+
169
+ def test_missing_configuration_surfaces_on_first_use_not_import():
170
+ result = _run_without_db_env(
171
+ "import velocity.aws.handlers.context as c\n"
172
+ "try:\n"
173
+ " c.engine.transaction()\n"
174
+ "except Exception as e:\n"
175
+ " print('FIRST_USE:', type(e).__name__, e)\n"
176
+ )
177
+ assert result.returncode == 0, result.stderr
178
+ assert "FIRST_USE:" in result.stdout
179
+ assert "Missing required configuration keys" in result.stdout
@@ -0,0 +1,70 @@
1
+ """A write that describes a result set (INSERT/UPDATE/DELETE ... RETURNING)
2
+ yields its rows through Result; a write without one is row-less and its
3
+ cursor is never fetched; SELECT is unchanged.
4
+
5
+ Regression: Result used to mark every statement starting with a write verb
6
+ as exhausted, so `UPDATE ... RETURNING sys_id` reported no rows and a claim
7
+ taken that way looked refused forever."""
8
+
9
+ from velocity.db.core.result import Result
10
+
11
+
12
+ class FakeCursor:
13
+ def __init__(self, description, rows):
14
+ self.description = description
15
+ self._rows = list(rows)
16
+ self.fetches = 0
17
+
18
+ def fetchone(self):
19
+ self.fetches += 1
20
+ return self._rows.pop(0) if self._rows else None
21
+
22
+
23
+ class NoResultSetCursor(FakeCursor):
24
+ """What a driver does after a write without RETURNING."""
25
+
26
+ def __init__(self):
27
+ super().__init__(None, [])
28
+
29
+ def fetchone(self):
30
+ self.fetches += 1
31
+ raise RuntimeError("the last operation didn't produce a result")
32
+
33
+
34
+ UPDATE_RETURNING = (
35
+ "update gmail_account set sync_claimed_at = %s where sys_id = %s returning sys_id"
36
+ )
37
+
38
+
39
+ def test_update_returning_yields_its_rows():
40
+ result = Result(FakeCursor([("sys_id",)], [(7,)]), None, UPDATE_RETURNING, [])
41
+ assert bool(result) is True
42
+ assert list(result.as_dict()) == [{"sys_id": 7}]
43
+
44
+
45
+ def test_update_returning_nothing_is_empty():
46
+ result = Result(FakeCursor([("sys_id",)], []), None, UPDATE_RETURNING, [])
47
+ assert bool(result) is False
48
+ assert list(result.as_dict()) == []
49
+
50
+
51
+ def test_insert_and_delete_returning_too():
52
+ for sql in (
53
+ "INSERT INTO t (a) VALUES (%s) RETURNING sys_id, a",
54
+ " delete from t where a = %s returning sys_id, a",
55
+ ):
56
+ result = Result(FakeCursor([("sys_id",), ("a",)], [(1, "x"), (2, "y")]), None, sql, [])
57
+ assert result.as_dict().all() == [{"sys_id": 1, "a": "x"}, {"sys_id": 2, "a": "y"}]
58
+
59
+
60
+ def test_write_without_a_result_set_is_rowless_and_never_fetched():
61
+ cursor = NoResultSetCursor()
62
+ result = Result(cursor, None, "UPDATE t SET a = %s WHERE sys_id = %s", [])
63
+ assert bool(result) is False
64
+ assert list(result) == []
65
+ assert cursor.fetches == 0 # fetchone() would raise on a real driver
66
+
67
+
68
+ def test_select_is_unchanged():
69
+ result = Result(FakeCursor([("a",)], [(1,), (2,)]), None, "select a from t", [])
70
+ assert [row["a"] for row in result.as_dict()] == [1, 2]