velocity-python 0.1.47__tar.gz → 0.1.49__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.47/src/velocity_python.egg-info → velocity_python-0.1.49}/PKG-INFO +1 -1
  2. {velocity_python-0.1.47 → velocity_python-0.1.49}/pyproject.toml +1 -1
  3. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/amplify.py +10 -0
  5. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/amplify_build.py +66 -2
  6. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/context.py +28 -18
  7. {velocity_python-0.1.47 → velocity_python-0.1.49/src/velocity_python.egg-info}/PKG-INFO +1 -1
  8. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_amplify_build.py +30 -0
  9. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_context_job_descriptions.py +61 -0
  10. {velocity_python-0.1.47 → velocity_python-0.1.49}/LICENSE +0 -0
  11. {velocity_python-0.1.47 → velocity_python-0.1.49}/README.md +0 -0
  12. {velocity_python-0.1.47 → velocity_python-0.1.49}/setup.cfg +0 -0
  13. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/__init__.py +0 -0
  14. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/assets/__init__.py +0 -0
  15. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/assets/backfill.py +0 -0
  16. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/assets/indexing.py +0 -0
  17. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/assets/references.py +0 -0
  18. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/assets/service.py +0 -0
  19. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/assets/usage_index.py +0 -0
  20. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/dirty_pipeline.py +0 -0
  21. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/__init__.py +0 -0
  22. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/base_handler.py +0 -0
  23. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/context_factory.py +0 -0
  24. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/exceptions.py +0 -0
  25. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  26. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  27. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  28. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  29. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/perf.py +0 -0
  30. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/response.py +0 -0
  31. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  32. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/s3.py +0 -0
  33. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/ssm_config.py +0 -0
  34. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/tests/__init__.py +0 -0
  35. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  36. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  37. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/aws/tests/test_response.py +0 -0
  38. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/__init__.py +0 -0
  39. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/__init__.py +0 -0
  40. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/async_support.py +0 -0
  41. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/column.py +0 -0
  42. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/database.py +0 -0
  43. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/decorators.py +0 -0
  44. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/engine.py +0 -0
  45. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/result.py +0 -0
  46. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/row.py +0 -0
  47. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/sequence.py +0 -0
  48. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/table.py +0 -0
  49. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/transaction.py +0 -0
  50. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/core/view.py +0 -0
  51. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/exceptions.py +0 -0
  52. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/migrations.py +0 -0
  53. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/__init__.py +0 -0
  54. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/base/__init__.py +0 -0
  55. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/base/initializer.py +0 -0
  56. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/base/operators.py +0 -0
  57. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/base/sql.py +0 -0
  58. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/base/types.py +0 -0
  59. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/mysql/__init__.py +0 -0
  60. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/mysql/operators.py +0 -0
  61. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/mysql/reserved.py +0 -0
  62. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/mysql/sql.py +0 -0
  63. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/mysql/types.py +0 -0
  64. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/postgres/__init__.py +0 -0
  65. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/postgres/operators.py +0 -0
  66. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/postgres/reserved.py +0 -0
  67. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/postgres/sql.py +0 -0
  68. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/postgres/types.py +0 -0
  69. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  70. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlite/operators.py +0 -0
  71. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  72. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlite/sql.py +0 -0
  73. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlite/types.py +0 -0
  74. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  75. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  76. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  77. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  78. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/sqlserver/types.py +0 -0
  79. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/servers/tablehelper.py +0 -0
  80. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/__init__.py +0 -0
  81. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/common_db_test.py +0 -0
  82. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/__init__.py +0 -0
  83. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/common.py +0 -0
  84. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_column.py +0 -0
  85. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  86. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_database.py +0 -0
  87. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  88. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  89. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  90. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_result.py +0 -0
  91. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_row.py +0 -0
  92. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  93. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  94. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  95. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  96. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  97. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_table.py +0 -0
  98. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  99. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  100. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/sql/__init__.py +0 -0
  101. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/sql/common.py +0 -0
  102. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  103. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  104. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  105. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_db_utils.py +0 -0
  106. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_postgres.py +0 -0
  107. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  108. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  109. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_result_caching.py +0 -0
  110. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  111. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  112. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  113. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  114. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_sql_builder.py +0 -0
  115. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_tablehelper.py +0 -0
  116. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/tests/test_view_helper.py +0 -0
  117. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/db/utils.py +0 -0
  118. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/logging.py +0 -0
  119. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/__init__.py +0 -0
  120. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/conv/__init__.py +0 -0
  121. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/conv/iconv.py +0 -0
  122. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/conv/oconv.py +0 -0
  123. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/db.py +0 -0
  124. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/export.py +0 -0
  125. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/format.py +0 -0
  126. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/mail.py +0 -0
  127. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/merge.py +0 -0
  128. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/pdf.py +0 -0
  129. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/__init__.py +0 -0
  130. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_db.py +0 -0
  131. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_fix.py +0 -0
  132. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_format.py +0 -0
  133. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_iconv.py +0 -0
  134. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_merge.py +0 -0
  135. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_oconv.py +0 -0
  136. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_original_error.py +0 -0
  137. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tests/test_timer.py +0 -0
  138. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/timer.py +0 -0
  139. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/misc/tools.py +0 -0
  140. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/__init__.py +0 -0
  141. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/authorizenet_adapter.py +0 -0
  142. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/authorizenet_mirror.py +0 -0
  143. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/base_adapter.py +0 -0
  144. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/braintree_adapter.py +0 -0
  145. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/braintree_mirror.py +0 -0
  146. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/charge_rules.py +0 -0
  147. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/stripe_adapter.py +0 -0
  148. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity/payment/stripe_mirror.py +0 -0
  149. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  150. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  151. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity_python.egg-info/entry_points.txt +0 -0
  152. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity_python.egg-info/requires.txt +0 -0
  153. {velocity_python-0.1.47 → velocity_python-0.1.49}/src/velocity_python.egg-info/top_level.txt +0 -0
  154. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_asset_indexing.py +0 -0
  155. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_asset_references.py +0 -0
  156. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_assets_service.py +0 -0
  157. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_async_support.py +0 -0
  158. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_batch_operations.py +0 -0
  159. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_concurrency_safety.py +0 -0
  160. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_connection_pool.py +0 -0
  161. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_connection_resilience.py +0 -0
  162. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_decorators.py +0 -0
  163. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_dirty_pipeline_fast_path.py +0 -0
  164. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_email_processing.py +0 -0
  165. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_iconv_money_to_cents.py +0 -0
  166. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_lambda_handler.py +0 -0
  167. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_lambda_handler_auth.py +0 -0
  168. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_mixins_import.py +0 -0
  169. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_n_plus_one.py +0 -0
  170. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_observability.py +0 -0
  171. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_payment_authorizenet_adapter.py +0 -0
  172. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_payment_braintree_adapter.py +0 -0
  173. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_payment_braintree_mirror.py +0 -0
  174. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_payment_profile_sorting.py +0 -0
  175. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_payment_stripe_adapter.py +0 -0
  176. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_pdf.py +0 -0
  177. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_prepared_statements.py +0 -0
  178. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_psycopg3_upgrade.py +0 -0
  179. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_query_cache.py +0 -0
  180. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_row_batch_update.py +0 -0
  181. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_row_cache_staleness.py +0 -0
  182. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_row_dirty_tracking.py +0 -0
  183. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_schema_migrations.py +0 -0
  184. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_security_hardening.py +0 -0
  185. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_server_cursor.py +0 -0
  186. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_spreadsheet_functions.py +0 -0
  187. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_sqs_per_record_transactions.py +0 -0
  188. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_ssm_config.py +0 -0
  189. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  190. {velocity_python-0.1.47 → velocity_python-0.1.49}/tests/test_table_alter.py +0 -0
  191. {velocity_python-0.1.47 → velocity_python-0.1.49}/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.47
3
+ Version: 0.1.49
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.47"
7
+ version = "0.1.49"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.47"
1
+ __version__ = version = "0.1.49"
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
@@ -59,6 +60,9 @@ class BackendDeploymentConfig:
59
60
  "WebHooks",
60
61
  )
61
62
  memory_size_by_token: Mapping[str, int] = field(default_factory=dict)
63
+ extra_lambda_policy_statements: Tuple[Mapping[str, Any], ...] = field(
64
+ default_factory=tuple
65
+ )
62
66
  use_reserved_concurrency: bool = True
63
67
 
64
68
  def resolve_queue_name(self, branch: str) -> str:
@@ -75,6 +79,15 @@ class BackendDeploymentConfig:
75
79
  return memory_size
76
80
  return None
77
81
 
82
+ def build_lambda_policy_document(
83
+ self, base_policy_document: Mapping[str, Any]
84
+ ) -> Dict[str, Any]:
85
+ policy_document = dict(base_policy_document)
86
+ statements = list(policy_document.get("Statement", []))
87
+ statements.extend(dict(statement) for statement in self.extra_lambda_policy_statements)
88
+ policy_document["Statement"] = statements
89
+ return policy_document
90
+
78
91
 
79
92
  def _normalize_project_root(project_root: Union[str, Path]) -> Path:
80
93
  return Path(project_root).resolve()
@@ -271,9 +284,54 @@ def _serialize_policy_document(policy_document: Any) -> str:
271
284
  return json.dumps(policy_document)
272
285
 
273
286
 
287
+ def _normalize_policy_document(policy_document: Any) -> Any:
288
+ if not isinstance(policy_document, str):
289
+ return policy_document
290
+ try:
291
+ return json.loads(unquote(policy_document))
292
+ except json.JSONDecodeError:
293
+ return json.loads(policy_document)
294
+
295
+
296
+ def _sync_managed_policy_document(iam_client, policy_arn: str, policy_document: Any) -> None:
297
+ policy = retryable_call(iam_client.get_policy, PolicyArn=policy_arn)["Policy"]
298
+ current_version = retryable_call(
299
+ iam_client.get_policy_version,
300
+ PolicyArn=policy_arn,
301
+ VersionId=policy["DefaultVersionId"],
302
+ )["PolicyVersion"]
303
+
304
+ current_document = _normalize_policy_document(current_version["Document"])
305
+ desired_document = _normalize_policy_document(policy_document)
306
+ if json.dumps(current_document, sort_keys=True) == json.dumps(desired_document, sort_keys=True):
307
+ return
308
+
309
+ versions = retryable_call(iam_client.list_policy_versions, PolicyArn=policy_arn)["Versions"]
310
+ nondefault_versions = sorted(
311
+ (version for version in versions if not version["IsDefaultVersion"]),
312
+ key=lambda version: version["CreateDate"],
313
+ )
314
+ if len(versions) >= 5 and nondefault_versions:
315
+ retryable_call(
316
+ iam_client.delete_policy_version,
317
+ PolicyArn=policy_arn,
318
+ VersionId=nondefault_versions[0]["VersionId"],
319
+ )
320
+
321
+ print(f"Updating policy {policy['PolicyName']}")
322
+ retryable_call(
323
+ iam_client.create_policy_version,
324
+ PolicyArn=policy_arn,
325
+ PolicyDocument=_serialize_policy_document(desired_document),
326
+ SetAsDefault=True,
327
+ )
328
+ time.sleep(10)
329
+
330
+
274
331
  def ensure_lambda_policies_and_attach(
275
332
  app: AmplifyProject,
276
333
  function: Mapping[str, str],
334
+ config: Optional[BackendDeploymentConfig] = None,
277
335
  iam_client=None,
278
336
  ) -> None:
279
337
  if iam_client is None:
@@ -291,11 +349,15 @@ def ensure_lambda_policies_and_attach(
291
349
  ],
292
350
  }
293
351
 
352
+ lambda_vpc_policy = app.get_lambda_vpc_policy_template()
353
+ if config is not None:
354
+ lambda_vpc_policy = config.build_lambda_policy_document(lambda_vpc_policy)
355
+
294
356
  required_policies = [
295
357
  (
296
358
  "lambda-vpc-execution",
297
359
  f"arn:aws:iam::{account_id}:policy/lambda-vpc-execution",
298
- app.get_lambda_vpc_policy_template(),
360
+ lambda_vpc_policy,
299
361
  ),
300
362
  (
301
363
  "lambda-layer-access",
@@ -318,6 +380,8 @@ def ensure_lambda_policies_and_attach(
318
380
  PolicyDocument=_serialize_policy_document(policy_doc),
319
381
  )
320
382
  time.sleep(10)
383
+ else:
384
+ _sync_managed_policy_document(iam_client, policy_arn, policy_doc)
321
385
 
322
386
  role_name = function["Role"].split("/")[-1]
323
387
  attached_policies = retryable_call(
@@ -462,7 +526,7 @@ def run_backend_deployment(
462
526
  else:
463
527
  queue_producers.append(function)
464
528
 
465
- ensure_lambda_policies_and_attach(app, function)
529
+ ensure_lambda_policies_and_attach(app, function, config=config)
466
530
 
467
531
  timeout_value = config.resolve_timeout(function_name)
468
532
  memory_value = config.resolve_memory_size(function_name)
@@ -12,6 +12,10 @@ 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
16
+ from velocity.aws.ssm_config import get_project_name as config_get_project_name
17
+ from velocity.aws.ssm_config import get_region as config_get_region
18
+ from velocity.aws.ssm_config import get_stage as config_get_stage
15
19
  from velocity.logging import get_logger
16
20
 
17
21
  engine = velocity.db.postgres.initialize()
@@ -21,6 +25,25 @@ cognito_client = boto3.client("cognito-idp")
21
25
  logger = get_logger("velocity.aws.handlers.context")
22
26
 
23
27
 
28
+ def _get_work_queue_name() -> str:
29
+ queue_name = str(config_getenv("SqsWorkQueue", "") or "").strip()
30
+ if not queue_name:
31
+ raise KeyError("SqsWorkQueue")
32
+ return queue_name
33
+
34
+
35
+ def _get_controls_vars() -> dict:
36
+ return {
37
+ "USER_BRANCH": config_get_stage(),
38
+ "AWS_JOB_ID": os.environ.get("AWS_JOB_ID"),
39
+ "LOGLEVEL": config_getenv("LOGLEVEL"),
40
+ "USER_REGION": config_get_region(),
41
+ "ProjectName": config_get_project_name(),
42
+ "DBDatabase": config_getenv("DBDatabase"),
43
+ "BUILD_DATETIME": config_getenv("BUILD_DATETIME"),
44
+ }
45
+
46
+
24
47
  @engine.transaction
25
48
  class Context:
26
49
 
@@ -372,7 +395,7 @@ class Context:
372
395
  batch_id = str(uuid.uuid4())
373
396
  results = {"batch_id": batch_id}
374
397
  queue = boto3.resource("sqs").get_queue_by_name(
375
- QueueName=os.environ["SqsWorkQueue"]
398
+ QueueName=_get_work_queue_name()
376
399
  )
377
400
  if isinstance(payload, dict):
378
401
  payload = [payload]
@@ -423,11 +446,11 @@ class Context:
423
446
 
424
447
  def _is_production(self):
425
448
  """Return True when running in production environment."""
426
- return os.environ.get("USER_BRANCH", "").lower() == "production"
449
+ return str(config_get_stage("") or "").lower() == "production"
427
450
 
428
451
  def get_environment(self):
429
452
  """Return the current USER_BRANCH value (defaults to demo)."""
430
- return os.environ.get("USER_BRANCH", "demo")
453
+ return config_get_stage("demo")
431
454
 
432
455
  def get_current_lambda_layers(self):
433
456
  """Return details about the Lambda layers attached to the running function."""
@@ -459,21 +482,8 @@ class Context:
459
482
  return []
460
483
 
461
484
  def get_pass_through_vars(self, tx):
462
- """Return environment and layer information for controls.vars."""
463
- vars = dict(
464
- [
465
- (x, os.environ.get(x))
466
- for x in [
467
- "USER_BRANCH",
468
- "AWS_JOB_ID",
469
- "LOGLEVEL",
470
- "USER_REGION",
471
- "ProjectName",
472
- "DBDatabase",
473
- "BUILD_DATETIME",
474
- ]
475
- ]
476
- )
485
+ """Return runtime and config information for controls.vars."""
486
+ vars = _get_controls_vars()
477
487
 
478
488
  temp = {"controls": {"vars": vars}}
479
489
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.47
3
+ Version: 0.1.49
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
@@ -74,6 +74,36 @@ def test_backend_deployment_config_resolves_queue_timeout_and_memory_size():
74
74
  assert config.resolve_memory_size("ClientUtility-demo") is None
75
75
 
76
76
 
77
+ def test_backend_deployment_config_merges_extra_lambda_policy_statements():
78
+ config = BackendDeploymentConfig(
79
+ queue_name_template="clients-queue-{branch}",
80
+ extra_lambda_policy_statements=(
81
+ {
82
+ "Effect": "Allow",
83
+ "Action": ["ssm:PutParameter"],
84
+ "Resource": "*",
85
+ },
86
+ ),
87
+ )
88
+
89
+ base_policy = {
90
+ "Version": "2012-10-17",
91
+ "Statement": [
92
+ {
93
+ "Effect": "Allow",
94
+ "Action": ["ssm:GetParameter"],
95
+ "Resource": "*",
96
+ }
97
+ ],
98
+ }
99
+
100
+ merged = config.build_lambda_policy_document(base_policy)
101
+
102
+ assert len(merged["Statement"]) == 2
103
+ assert merged["Statement"][0]["Action"] == ["ssm:GetParameter"]
104
+ assert merged["Statement"][1]["Action"] == ["ssm:PutParameter"]
105
+
106
+
77
107
  def test_build_environment_variables_reads_project_metadata(tmp_path, monkeypatch):
78
108
  amplify_dir = tmp_path / "amplify" / "backend"
79
109
  amplify_dir.mkdir(parents=True)
@@ -87,6 +87,67 @@ class TestQueueJobDescriptions(unittest.TestCase):
87
87
  self.assertEqual(1, len(fake_context.jobs))
88
88
  self.assertIsNone(fake_context.jobs[0]["description"])
89
89
 
90
+ def test_get_pass_through_vars_uses_ssm_aware_runtime_helpers(self):
91
+ fake_context = _FakeContext()
92
+
93
+ def _fake_config_getenv(key, default=None, **kwargs):
94
+ values = {
95
+ "LOGLEVEL": "INFO",
96
+ "DBDatabase": "cc_demo",
97
+ "BUILD_DATETIME": "05/28/2026 11:00PM",
98
+ }
99
+ return values.get(key, default)
100
+
101
+ with patch.dict(
102
+ handler_context.os.environ,
103
+ {"AWS_JOB_ID": "job-123"},
104
+ clear=False,
105
+ ), patch.object(
106
+ handler_context,
107
+ "config_get_stage",
108
+ return_value="demo",
109
+ ), patch.object(
110
+ handler_context,
111
+ "config_get_region",
112
+ return_value="us-east-1",
113
+ ), patch.object(
114
+ handler_context,
115
+ "config_get_project_name",
116
+ return_value="BackOffice",
117
+ ), patch.object(
118
+ handler_context,
119
+ "config_getenv",
120
+ side_effect=_fake_config_getenv,
121
+ ):
122
+ result = handler_context.Context.get_pass_through_vars.__wrapped__(
123
+ fake_context,
124
+ tx=None,
125
+ )
126
+
127
+ self.assertEqual(
128
+ {
129
+ "USER_BRANCH": "demo",
130
+ "AWS_JOB_ID": "job-123",
131
+ "LOGLEVEL": "INFO",
132
+ "USER_REGION": "us-east-1",
133
+ "ProjectName": "BackOffice",
134
+ "DBDatabase": "cc_demo",
135
+ "BUILD_DATETIME": "05/28/2026 11:00PM",
136
+ },
137
+ result["controls"]["vars"],
138
+ )
139
+
140
+ def test_environment_helpers_use_stage_alias_resolution(self):
141
+ fake_context = _FakeContext()
142
+
143
+ with patch.object(
144
+ handler_context,
145
+ "config_get_stage",
146
+ side_effect=["production", "demo"],
147
+ ):
148
+ self.assertTrue(handler_context.Context._is_production(fake_context))
149
+ self.assertEqual("demo", handler_context.Context.get_environment(fake_context))
150
+
90
151
 
91
152
  if __name__ == "__main__":
92
153
  unittest.main()