velocity-python 0.1.46__tar.gz → 0.1.48__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 (191) hide show
  1. {velocity_python-0.1.46/src/velocity_python.egg-info → velocity_python-0.1.48}/PKG-INFO +1 -1
  2. {velocity_python-0.1.46 → velocity_python-0.1.48}/pyproject.toml +1 -1
  3. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/amplify.py +10 -0
  5. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/amplify_build.py +47 -0
  6. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/context.py +9 -1
  7. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/ssm_config.py +63 -14
  8. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/postgres/__init__.py +4 -46
  9. {velocity_python-0.1.46 → velocity_python-0.1.48/src/velocity_python.egg-info}/PKG-INFO +1 -1
  10. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_ssm_config.py +30 -0
  11. {velocity_python-0.1.46 → velocity_python-0.1.48}/LICENSE +0 -0
  12. {velocity_python-0.1.46 → velocity_python-0.1.48}/README.md +0 -0
  13. {velocity_python-0.1.46 → velocity_python-0.1.48}/setup.cfg +0 -0
  14. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/__init__.py +0 -0
  15. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/assets/__init__.py +0 -0
  16. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/assets/backfill.py +0 -0
  17. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/assets/indexing.py +0 -0
  18. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/assets/references.py +0 -0
  19. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/assets/service.py +0 -0
  20. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/assets/usage_index.py +0 -0
  21. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/dirty_pipeline.py +0 -0
  22. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/__init__.py +0 -0
  23. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/base_handler.py +0 -0
  24. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/context_factory.py +0 -0
  25. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/exceptions.py +0 -0
  26. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  27. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  28. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  29. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  30. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/perf.py +0 -0
  31. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/response.py +0 -0
  32. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  33. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/s3.py +0 -0
  34. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/tests/__init__.py +0 -0
  35. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  36. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  37. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/aws/tests/test_response.py +0 -0
  38. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/__init__.py +0 -0
  39. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/__init__.py +0 -0
  40. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/async_support.py +0 -0
  41. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/column.py +0 -0
  42. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/database.py +0 -0
  43. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/decorators.py +0 -0
  44. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/engine.py +0 -0
  45. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/result.py +0 -0
  46. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/row.py +0 -0
  47. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/sequence.py +0 -0
  48. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/table.py +0 -0
  49. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/transaction.py +0 -0
  50. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/core/view.py +0 -0
  51. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/exceptions.py +0 -0
  52. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/migrations.py +0 -0
  53. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/__init__.py +0 -0
  54. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/base/__init__.py +0 -0
  55. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/base/initializer.py +0 -0
  56. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/base/operators.py +0 -0
  57. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/base/sql.py +0 -0
  58. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/base/types.py +0 -0
  59. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/mysql/__init__.py +0 -0
  60. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/mysql/operators.py +0 -0
  61. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/mysql/reserved.py +0 -0
  62. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/mysql/sql.py +0 -0
  63. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/mysql/types.py +0 -0
  64. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/postgres/operators.py +0 -0
  65. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/postgres/reserved.py +0 -0
  66. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/postgres/sql.py +0 -0
  67. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/postgres/types.py +0 -0
  68. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  69. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlite/operators.py +0 -0
  70. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  71. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlite/sql.py +0 -0
  72. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlite/types.py +0 -0
  73. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  74. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  75. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  76. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  77. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/sqlserver/types.py +0 -0
  78. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/servers/tablehelper.py +0 -0
  79. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/__init__.py +0 -0
  80. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/common_db_test.py +0 -0
  81. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/__init__.py +0 -0
  82. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/common.py +0 -0
  83. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_column.py +0 -0
  84. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  85. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_database.py +0 -0
  86. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  87. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  88. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  89. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_result.py +0 -0
  90. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_row.py +0 -0
  91. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  92. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  93. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  94. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  95. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  96. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_table.py +0 -0
  97. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  98. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  99. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/sql/__init__.py +0 -0
  100. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/sql/common.py +0 -0
  101. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  102. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  103. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  104. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_db_utils.py +0 -0
  105. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_postgres.py +0 -0
  106. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  107. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  108. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_result_caching.py +0 -0
  109. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  110. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  111. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  112. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  113. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_sql_builder.py +0 -0
  114. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_tablehelper.py +0 -0
  115. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/tests/test_view_helper.py +0 -0
  116. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/db/utils.py +0 -0
  117. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/logging.py +0 -0
  118. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/__init__.py +0 -0
  119. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/conv/__init__.py +0 -0
  120. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/conv/iconv.py +0 -0
  121. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/conv/oconv.py +0 -0
  122. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/db.py +0 -0
  123. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/export.py +0 -0
  124. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/format.py +0 -0
  125. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/mail.py +0 -0
  126. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/merge.py +0 -0
  127. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/pdf.py +0 -0
  128. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/__init__.py +0 -0
  129. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_db.py +0 -0
  130. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_fix.py +0 -0
  131. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_format.py +0 -0
  132. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_iconv.py +0 -0
  133. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_merge.py +0 -0
  134. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_oconv.py +0 -0
  135. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_original_error.py +0 -0
  136. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tests/test_timer.py +0 -0
  137. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/timer.py +0 -0
  138. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/misc/tools.py +0 -0
  139. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/__init__.py +0 -0
  140. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/authorizenet_adapter.py +0 -0
  141. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/authorizenet_mirror.py +0 -0
  142. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/base_adapter.py +0 -0
  143. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/braintree_adapter.py +0 -0
  144. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/braintree_mirror.py +0 -0
  145. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/charge_rules.py +0 -0
  146. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/stripe_adapter.py +0 -0
  147. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity/payment/stripe_mirror.py +0 -0
  148. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  149. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  150. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity_python.egg-info/entry_points.txt +0 -0
  151. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity_python.egg-info/requires.txt +0 -0
  152. {velocity_python-0.1.46 → velocity_python-0.1.48}/src/velocity_python.egg-info/top_level.txt +0 -0
  153. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_amplify_build.py +0 -0
  154. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_asset_indexing.py +0 -0
  155. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_asset_references.py +0 -0
  156. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_assets_service.py +0 -0
  157. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_async_support.py +0 -0
  158. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_batch_operations.py +0 -0
  159. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_concurrency_safety.py +0 -0
  160. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_connection_pool.py +0 -0
  161. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_connection_resilience.py +0 -0
  162. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_context_job_descriptions.py +0 -0
  163. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_decorators.py +0 -0
  164. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_dirty_pipeline_fast_path.py +0 -0
  165. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_email_processing.py +0 -0
  166. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_iconv_money_to_cents.py +0 -0
  167. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_lambda_handler.py +0 -0
  168. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_lambda_handler_auth.py +0 -0
  169. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_mixins_import.py +0 -0
  170. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_n_plus_one.py +0 -0
  171. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_observability.py +0 -0
  172. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_payment_authorizenet_adapter.py +0 -0
  173. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_payment_braintree_adapter.py +0 -0
  174. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_payment_braintree_mirror.py +0 -0
  175. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_payment_profile_sorting.py +0 -0
  176. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_payment_stripe_adapter.py +0 -0
  177. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_pdf.py +0 -0
  178. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_prepared_statements.py +0 -0
  179. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_psycopg3_upgrade.py +0 -0
  180. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_query_cache.py +0 -0
  181. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_row_batch_update.py +0 -0
  182. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_row_cache_staleness.py +0 -0
  183. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_row_dirty_tracking.py +0 -0
  184. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_schema_migrations.py +0 -0
  185. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_security_hardening.py +0 -0
  186. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_server_cursor.py +0 -0
  187. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_spreadsheet_functions.py +0 -0
  188. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_sqs_per_record_transactions.py +0 -0
  189. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  190. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_table_alter.py +0 -0
  191. {velocity_python-0.1.46 → velocity_python-0.1.48}/tests/test_where_clause_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.46
3
+ Version: 0.1.48
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.46"
7
+ version = "0.1.48"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.46"
1
+ __version__ = version = "0.1.48"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -337,6 +337,7 @@ class AmplifyProject:
337
337
  }}"""
338
338
 
339
339
  def get_lambda_vpc_policy_template(self):
340
+ account_id = self.get_account_id()
340
341
  return {
341
342
  "Version": "2012-10-17",
342
343
  "Statement": [
@@ -356,6 +357,15 @@ class AmplifyProject:
356
357
  "ec2:RevokeSecurityGroupEgress",
357
358
  "cognito-idp:*",
358
359
  ],
360
+ },
361
+ {
362
+ "Effect": "Allow",
363
+ "Resource": f"arn:aws:ssm:*:{account_id}:parameter/*",
364
+ "Action": [
365
+ "ssm:GetParameter",
366
+ "ssm:GetParameters",
367
+ "ssm:GetParametersByPath",
368
+ ],
359
369
  }
360
370
  ],
361
371
  }
@@ -7,6 +7,7 @@ import time
7
7
  from dataclasses import dataclass, field
8
8
  from pathlib import Path
9
9
  from typing import Any, Dict, Mapping, Optional, Sequence, Tuple, Union
10
+ from urllib.parse import unquote
10
11
 
11
12
  import boto3
12
13
  import botocore.exceptions
@@ -271,6 +272,50 @@ def _serialize_policy_document(policy_document: Any) -> str:
271
272
  return json.dumps(policy_document)
272
273
 
273
274
 
275
+ def _normalize_policy_document(policy_document: Any) -> Any:
276
+ if not isinstance(policy_document, str):
277
+ return policy_document
278
+ try:
279
+ return json.loads(unquote(policy_document))
280
+ except json.JSONDecodeError:
281
+ return json.loads(policy_document)
282
+
283
+
284
+ def _sync_managed_policy_document(iam_client, policy_arn: str, policy_document: Any) -> None:
285
+ policy = retryable_call(iam_client.get_policy, PolicyArn=policy_arn)["Policy"]
286
+ current_version = retryable_call(
287
+ iam_client.get_policy_version,
288
+ PolicyArn=policy_arn,
289
+ VersionId=policy["DefaultVersionId"],
290
+ )["PolicyVersion"]
291
+
292
+ current_document = _normalize_policy_document(current_version["Document"])
293
+ desired_document = _normalize_policy_document(policy_document)
294
+ if json.dumps(current_document, sort_keys=True) == json.dumps(desired_document, sort_keys=True):
295
+ return
296
+
297
+ versions = retryable_call(iam_client.list_policy_versions, PolicyArn=policy_arn)["Versions"]
298
+ nondefault_versions = sorted(
299
+ (version for version in versions if not version["IsDefaultVersion"]),
300
+ key=lambda version: version["CreateDate"],
301
+ )
302
+ if len(versions) >= 5 and nondefault_versions:
303
+ retryable_call(
304
+ iam_client.delete_policy_version,
305
+ PolicyArn=policy_arn,
306
+ VersionId=nondefault_versions[0]["VersionId"],
307
+ )
308
+
309
+ print(f"Updating policy {policy['PolicyName']}")
310
+ retryable_call(
311
+ iam_client.create_policy_version,
312
+ PolicyArn=policy_arn,
313
+ PolicyDocument=_serialize_policy_document(desired_document),
314
+ SetAsDefault=True,
315
+ )
316
+ time.sleep(10)
317
+
318
+
274
319
  def ensure_lambda_policies_and_attach(
275
320
  app: AmplifyProject,
276
321
  function: Mapping[str, str],
@@ -318,6 +363,8 @@ def ensure_lambda_policies_and_attach(
318
363
  PolicyDocument=_serialize_policy_document(policy_doc),
319
364
  )
320
365
  time.sleep(10)
366
+ else:
367
+ _sync_managed_policy_document(iam_client, policy_arn, policy_doc)
321
368
 
322
369
  role_name = function["Role"].split("/")[-1]
323
370
  attached_policies = retryable_call(
@@ -12,6 +12,7 @@ from botocore.exceptions import ClientError
12
12
  import hashlib
13
13
  import velocity
14
14
  import velocity.db
15
+ from velocity.aws.ssm_config import getenv as config_getenv
15
16
  from velocity.logging import get_logger
16
17
 
17
18
  engine = velocity.db.postgres.initialize()
@@ -21,6 +22,13 @@ cognito_client = boto3.client("cognito-idp")
21
22
  logger = get_logger("velocity.aws.handlers.context")
22
23
 
23
24
 
25
+ def _get_work_queue_name() -> str:
26
+ queue_name = str(config_getenv("SqsWorkQueue", "") or "").strip()
27
+ if not queue_name:
28
+ raise KeyError("SqsWorkQueue")
29
+ return queue_name
30
+
31
+
24
32
  @engine.transaction
25
33
  class Context:
26
34
 
@@ -372,7 +380,7 @@ class Context:
372
380
  batch_id = str(uuid.uuid4())
373
381
  results = {"batch_id": batch_id}
374
382
  queue = boto3.resource("sqs").get_queue_by_name(
375
- QueueName=os.environ["SqsWorkQueue"]
383
+ QueueName=_get_work_queue_name()
376
384
  )
377
385
  if isinstance(payload, dict):
378
386
  payload = [payload]
@@ -1,20 +1,20 @@
1
1
  """
2
2
  SSM-backed configuration with environment-variable fallback.
3
3
 
4
- Opt-in: set ``VELOCITY_SSM_ENABLED=true`` in your Amplify environment variables
5
- (pushed via ``bootstrap.py secrets``).
6
-
7
- When enabled, ``getenv(key)`` reads from SSM at::
4
+ ``getenv(key)`` reads from SSM at::
8
5
 
9
6
  /{ProjectName}/{stage}/{key}
10
7
 
11
- and falls back to ``os.environ`` on a miss or any error. Results are cached
12
- for the process lifetime so SSM is called at most once per key per Lambda
13
- cold start.
8
+ when SSM loading is enabled. An explicit ``VELOCITY_SSM_ENABLED`` environment
9
+ variable still overrides the behavior, but Lambda runtimes now auto-enable SSM
10
+ when they can resolve both project and stage from the runtime environment.
11
+
12
+ On an SSM miss or any other SSM error, ``getenv`` falls back to ``os.environ``.
13
+ Results are cached for the process lifetime so SSM is called at most once per
14
+ key per Lambda cold start.
14
15
 
15
- When **not** enabled (the default), ``getenv`` is a thin wrapper around
16
- ``os.environ.get`` with zero extra overhead — preserving full backward
17
- compatibility for projects that don't use SSM (e.g. caringcent).
16
+ Outside Lambda, or when project/stage cannot be resolved, ``getenv`` remains a
17
+ thin wrapper around ``os.environ.get`` with no SSM call.
18
18
  """
19
19
 
20
20
  from __future__ import annotations
@@ -25,6 +25,15 @@ from typing import Optional
25
25
 
26
26
  logger = logging.getLogger(__name__)
27
27
 
28
+ _LAMBDA_PROJECT_SUFFIXES = (
29
+ 'QueueHandler',
30
+ 'Scheduler',
31
+ 'WebHooks',
32
+ 'Public',
33
+ 'Events',
34
+ 'Data',
35
+ )
36
+
28
37
  # Per-process cache: key → value (str) or sentinel _MISS.
29
38
  _MISS = object()
30
39
  _cache: dict[str, object] = {}
@@ -36,7 +45,11 @@ _SSM_ENABLED: bool | None = None
36
45
  def _is_enabled() -> bool:
37
46
  global _SSM_ENABLED
38
47
  if _SSM_ENABLED is None:
39
- _SSM_ENABLED = os.environ.get('VELOCITY_SSM_ENABLED', '').lower() in ('1', 'true', 'yes')
48
+ configured = os.environ.get('VELOCITY_SSM_ENABLED')
49
+ if configured is not None:
50
+ _SSM_ENABLED = configured.lower() in ('1', 'true', 'yes')
51
+ else:
52
+ _SSM_ENABLED = _is_lambda_runtime() and bool(get_project_name()) and bool(get_stage())
40
53
  return _SSM_ENABLED
41
54
 
42
55
 
@@ -51,8 +64,41 @@ def _first_nonempty_env(*keys: str) -> str | None:
51
64
  return None
52
65
 
53
66
 
67
+ def _lambda_function_name() -> str | None:
68
+ value = os.environ.get('AWS_LAMBDA_FUNCTION_NAME')
69
+ if value is None:
70
+ return None
71
+ value = value.strip()
72
+ return value or None
73
+
74
+
75
+ def _is_lambda_runtime() -> bool:
76
+ return _lambda_function_name() is not None or os.environ.get('AWS_EXECUTION_ENV', '').startswith('AWS_Lambda_')
77
+
78
+
79
+ def _infer_project_name_from_lambda_name() -> str | None:
80
+ function_name = _lambda_function_name()
81
+ if function_name is None:
82
+ return None
83
+
84
+ stage = _first_nonempty_env('AppStage', 'ENV', 'USER_BRANCH', 'AWS_BRANCH')
85
+ base_name = function_name
86
+ if stage:
87
+ suffix = f'-{stage}'
88
+ if base_name.endswith(suffix):
89
+ base_name = base_name[:-len(suffix)]
90
+
91
+ for suffix in _LAMBDA_PROJECT_SUFFIXES:
92
+ if base_name.endswith(suffix) and len(base_name) > len(suffix):
93
+ candidate = base_name[:-len(suffix)].strip()
94
+ if candidate:
95
+ return candidate
96
+
97
+ return base_name or None
98
+
99
+
54
100
  def get_project_name(default: Optional[str] = None) -> Optional[str]:
55
- return _first_nonempty_env('ProjectName') or default
101
+ return _first_nonempty_env('ProjectName') or _infer_project_name_from_lambda_name() or default
56
102
 
57
103
 
58
104
  def get_stage(default: Optional[str] = None) -> Optional[str]:
@@ -97,8 +143,11 @@ def getenv(
97
143
  """
98
144
  Read a config value, checking SSM before ``os.environ``.
99
145
 
100
- SSM is only consulted when ``VELOCITY_SSM_ENABLED=true`` is set in the
101
- Lambda environment *and* both ``ProjectName`` and a resolved stage are present.
146
+ SSM is consulted when it is explicitly enabled via
147
+ ``VELOCITY_SSM_ENABLED=true`` or when Lambda runtime context provides enough
148
+ information to resolve both project and stage. Explicitly setting
149
+ ``VELOCITY_SSM_ENABLED=false`` disables SSM even in Lambda.
150
+
102
151
  All other cases fall straight through to ``os.environ``.
103
152
 
104
153
  Results are cached per process so SSM is queried at most once per key
@@ -98,51 +98,9 @@ class PostgreSQLInitializer(BaseInitializer):
98
98
 
99
99
  # Maintain backward compatibility
100
100
  def initialize(config=None, schema_locked=False, **kwargs):
101
- """Backward compatible initialization function - matches original behavior exactly."""
102
- try:
103
- import psycopg
104
- except ImportError as e:
105
- raise ImportError(
106
- "PostgreSQL driver not available. Install with: pip install velocity-python[postgres]"
107
- ) from e
108
-
109
- from .sql import SQL
110
-
111
- konfig = {
112
- "dbname": _getenv("DBDatabase") or os.environ["DBDatabase"],
113
- "host": _getenv("DBHost") or os.environ["DBHost"],
114
- "port": _getenv("DBPort") or os.environ["DBPort"],
115
- "user": _getenv("DBUser") or os.environ["DBUser"],
116
- "password": _getenv("DBPassword") or os.environ["DBPassword"],
117
- }
118
- konfig.update(config or {})
119
- konfig.update(kwargs)
120
-
121
- # Apply TCP keepalive defaults (user config takes precedence).
122
- for key, default_val in _DEFAULT_KEEPALIVE.items():
123
- konfig.setdefault(key, default_val)
124
-
125
- # SSL mode.
126
- ssl_mode = _getenv("VELOCITY_SSL_MODE")
127
- if ssl_mode:
128
- konfig.setdefault("sslmode", ssl_mode)
129
-
130
- # Remap legacy 'database' key to 'dbname' for psycopg v3.
131
- if "database" in konfig:
132
- konfig["dbname"] = konfig.pop("database")
133
-
134
- # Extract pool kwargs so they don't end up in the psycopg connect() call.
135
- pool_kwargs = {}
136
- for pool_key in ("pool_min", "pool_max", "pool_enabled", "pool_validate"):
137
- if pool_key in konfig:
138
- pool_kwargs[pool_key] = konfig.pop(pool_key)
139
-
140
- # Check for environment variable override for schema locking
141
- if os.environ.get("VELOCITY_SCHEMA_LOCKED", "").lower() in ("true", "1", "yes"):
142
- schema_locked = True
143
-
144
- return engine.Engine(
145
- psycopg, konfig, SQL,
101
+ """Backward compatible wrapper around the shared PostgreSQL initializer."""
102
+ return PostgreSQLInitializer.initialize(
103
+ config=config,
146
104
  schema_locked=schema_locked,
147
- **pool_kwargs,
105
+ **kwargs,
148
106
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.46
3
+ Version: 0.1.48
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
@@ -25,6 +25,15 @@ def test_ssm_prefix_uses_aws_branch_when_env_missing(monkeypatch):
25
25
  assert ssm_config._ssm_prefix() == "/Client/production"
26
26
 
27
27
 
28
+ def test_get_project_name_infers_from_lambda_function_name(monkeypatch):
29
+ ssm_config.clear_cache()
30
+ monkeypatch.delenv("ProjectName", raising=False)
31
+ monkeypatch.setenv("AWS_LAMBDA_FUNCTION_NAME", "BackOfficeScheduler-demo")
32
+ monkeypatch.setenv("ENV", "demo")
33
+
34
+ assert ssm_config.get_project_name() == "BackOffice"
35
+
36
+
28
37
  def test_getenv_falls_back_to_environment_when_disabled(monkeypatch):
29
38
  ssm_config.clear_cache()
30
39
  monkeypatch.delenv("VELOCITY_SSM_ENABLED", raising=False)
@@ -53,6 +62,27 @@ def test_getenv_reads_ssm_with_region_aliases(monkeypatch):
53
62
  client_factory.assert_called_once_with("ssm", region_name="us-west-2")
54
63
 
55
64
 
65
+ def test_getenv_auto_enables_ssm_in_lambda_with_inferred_project(monkeypatch):
66
+ ssm_config.clear_cache()
67
+ monkeypatch.delenv("VELOCITY_SSM_ENABLED", raising=False)
68
+ monkeypatch.delenv("ProjectName", raising=False)
69
+ monkeypatch.setenv("AWS_LAMBDA_FUNCTION_NAME", "BackOfficeScheduler-demo")
70
+ monkeypatch.setenv("ENV", "demo")
71
+ monkeypatch.setenv("AWS_REGION", "us-west-2")
72
+ monkeypatch.setenv("DBDatabase", "env-db")
73
+
74
+ class FakeSSM:
75
+ def get_parameter(self, Name, WithDecryption):
76
+ assert Name == "/BackOffice/demo/DBDatabase"
77
+ assert WithDecryption is True
78
+ return {"Parameter": {"Value": "ssm-db"}}
79
+
80
+ with patch("boto3.client", return_value=FakeSSM()) as client_factory:
81
+ assert ssm_config.getenv("DBDatabase") == "ssm-db"
82
+
83
+ client_factory.assert_called_once_with("ssm", region_name="us-west-2")
84
+
85
+
56
86
  def test_getenv_raises_on_missing_when_disabled(monkeypatch):
57
87
  ssm_config.clear_cache()
58
88
  monkeypatch.delenv("VELOCITY_SSM_ENABLED", raising=False)