velocity-python 0.1.45__tar.gz → 0.1.47__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 (192) hide show
  1. {velocity_python-0.1.45/src/velocity_python.egg-info → velocity_python-0.1.47}/PKG-INFO +1 -1
  2. {velocity_python-0.1.45 → velocity_python-0.1.47}/pyproject.toml +1 -1
  3. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/amplify.py +4 -12
  5. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/amplify_build.py +0 -8
  6. velocity_python-0.1.47/src/velocity/aws/ssm_config.py +180 -0
  7. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/postgres/__init__.py +4 -46
  8. {velocity_python-0.1.45 → velocity_python-0.1.47/src/velocity_python.egg-info}/PKG-INFO +1 -1
  9. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity_python.egg-info/SOURCES.txt +1 -0
  10. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_amplify_build.py +13 -1
  11. velocity_python-0.1.47/tests/test_ssm_config.py +132 -0
  12. velocity_python-0.1.45/src/velocity/aws/ssm_config.py +0 -94
  13. {velocity_python-0.1.45 → velocity_python-0.1.47}/LICENSE +0 -0
  14. {velocity_python-0.1.45 → velocity_python-0.1.47}/README.md +0 -0
  15. {velocity_python-0.1.45 → velocity_python-0.1.47}/setup.cfg +0 -0
  16. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/__init__.py +0 -0
  17. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/assets/__init__.py +0 -0
  18. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/assets/backfill.py +0 -0
  19. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/assets/indexing.py +0 -0
  20. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/assets/references.py +0 -0
  21. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/assets/service.py +0 -0
  22. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/assets/usage_index.py +0 -0
  23. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/dirty_pipeline.py +0 -0
  24. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/__init__.py +0 -0
  25. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/base_handler.py +0 -0
  26. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/context.py +0 -0
  27. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/context_factory.py +0 -0
  28. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/exceptions.py +0 -0
  29. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  30. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  31. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  32. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  33. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/perf.py +0 -0
  34. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/response.py +0 -0
  35. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  36. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/s3.py +0 -0
  37. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/tests/__init__.py +0 -0
  38. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  39. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  40. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/aws/tests/test_response.py +0 -0
  41. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/__init__.py +0 -0
  42. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/__init__.py +0 -0
  43. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/async_support.py +0 -0
  44. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/column.py +0 -0
  45. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/database.py +0 -0
  46. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/decorators.py +0 -0
  47. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/engine.py +0 -0
  48. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/result.py +0 -0
  49. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/row.py +0 -0
  50. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/sequence.py +0 -0
  51. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/table.py +0 -0
  52. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/transaction.py +0 -0
  53. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/core/view.py +0 -0
  54. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/exceptions.py +0 -0
  55. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/migrations.py +0 -0
  56. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/__init__.py +0 -0
  57. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/base/__init__.py +0 -0
  58. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/base/initializer.py +0 -0
  59. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/base/operators.py +0 -0
  60. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/base/sql.py +0 -0
  61. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/base/types.py +0 -0
  62. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/mysql/__init__.py +0 -0
  63. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/mysql/operators.py +0 -0
  64. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/mysql/reserved.py +0 -0
  65. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/mysql/sql.py +0 -0
  66. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/mysql/types.py +0 -0
  67. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/postgres/operators.py +0 -0
  68. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/postgres/reserved.py +0 -0
  69. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/postgres/sql.py +0 -0
  70. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/postgres/types.py +0 -0
  71. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  72. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlite/operators.py +0 -0
  73. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  74. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlite/sql.py +0 -0
  75. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlite/types.py +0 -0
  76. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  77. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  78. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  79. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  80. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/sqlserver/types.py +0 -0
  81. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/servers/tablehelper.py +0 -0
  82. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/__init__.py +0 -0
  83. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/common_db_test.py +0 -0
  84. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/__init__.py +0 -0
  85. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/common.py +0 -0
  86. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_column.py +0 -0
  87. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  88. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_database.py +0 -0
  89. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  90. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  91. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  92. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_result.py +0 -0
  93. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_row.py +0 -0
  94. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  95. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  96. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  97. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  98. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  99. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_table.py +0 -0
  100. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  101. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  102. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/sql/__init__.py +0 -0
  103. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/sql/common.py +0 -0
  104. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  105. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  106. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  107. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_db_utils.py +0 -0
  108. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_postgres.py +0 -0
  109. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  110. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  111. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_result_caching.py +0 -0
  112. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  113. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  114. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  115. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  116. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_sql_builder.py +0 -0
  117. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_tablehelper.py +0 -0
  118. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/tests/test_view_helper.py +0 -0
  119. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/db/utils.py +0 -0
  120. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/logging.py +0 -0
  121. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/__init__.py +0 -0
  122. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/conv/__init__.py +0 -0
  123. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/conv/iconv.py +0 -0
  124. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/conv/oconv.py +0 -0
  125. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/db.py +0 -0
  126. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/export.py +0 -0
  127. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/format.py +0 -0
  128. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/mail.py +0 -0
  129. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/merge.py +0 -0
  130. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/pdf.py +0 -0
  131. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/__init__.py +0 -0
  132. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_db.py +0 -0
  133. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_fix.py +0 -0
  134. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_format.py +0 -0
  135. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_iconv.py +0 -0
  136. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_merge.py +0 -0
  137. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_oconv.py +0 -0
  138. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_original_error.py +0 -0
  139. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tests/test_timer.py +0 -0
  140. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/timer.py +0 -0
  141. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/misc/tools.py +0 -0
  142. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/__init__.py +0 -0
  143. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/authorizenet_adapter.py +0 -0
  144. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/authorizenet_mirror.py +0 -0
  145. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/base_adapter.py +0 -0
  146. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/braintree_adapter.py +0 -0
  147. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/braintree_mirror.py +0 -0
  148. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/charge_rules.py +0 -0
  149. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/stripe_adapter.py +0 -0
  150. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity/payment/stripe_mirror.py +0 -0
  151. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  152. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity_python.egg-info/entry_points.txt +0 -0
  153. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity_python.egg-info/requires.txt +0 -0
  154. {velocity_python-0.1.45 → velocity_python-0.1.47}/src/velocity_python.egg-info/top_level.txt +0 -0
  155. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_asset_indexing.py +0 -0
  156. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_asset_references.py +0 -0
  157. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_assets_service.py +0 -0
  158. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_async_support.py +0 -0
  159. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_batch_operations.py +0 -0
  160. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_concurrency_safety.py +0 -0
  161. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_connection_pool.py +0 -0
  162. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_connection_resilience.py +0 -0
  163. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_context_job_descriptions.py +0 -0
  164. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_decorators.py +0 -0
  165. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_dirty_pipeline_fast_path.py +0 -0
  166. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_email_processing.py +0 -0
  167. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_iconv_money_to_cents.py +0 -0
  168. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_lambda_handler.py +0 -0
  169. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_lambda_handler_auth.py +0 -0
  170. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_mixins_import.py +0 -0
  171. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_n_plus_one.py +0 -0
  172. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_observability.py +0 -0
  173. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_payment_authorizenet_adapter.py +0 -0
  174. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_payment_braintree_adapter.py +0 -0
  175. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_payment_braintree_mirror.py +0 -0
  176. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_payment_profile_sorting.py +0 -0
  177. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_payment_stripe_adapter.py +0 -0
  178. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_pdf.py +0 -0
  179. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_prepared_statements.py +0 -0
  180. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_psycopg3_upgrade.py +0 -0
  181. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_query_cache.py +0 -0
  182. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_row_batch_update.py +0 -0
  183. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_row_cache_staleness.py +0 -0
  184. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_row_dirty_tracking.py +0 -0
  185. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_schema_migrations.py +0 -0
  186. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_security_hardening.py +0 -0
  187. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_server_cursor.py +0 -0
  188. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_spreadsheet_functions.py +0 -0
  189. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_sqs_per_record_transactions.py +0 -0
  190. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  191. {velocity_python-0.1.45 → velocity_python-0.1.47}/tests/test_table_alter.py +0 -0
  192. {velocity_python-0.1.45 → velocity_python-0.1.47}/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.45
3
+ Version: 0.1.47
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.45"
7
+ version = "0.1.47"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.45"
1
+ __version__ = version = "0.1.47"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -446,18 +446,10 @@ class AmplifyProject:
446
446
  )
447
447
 
448
448
  def sync(self, branch):
449
- print(
450
- f"\n🚀 Syncing environment variables for app '{self.app_id}' and environment '{branch}'..."
451
- )
452
- env_vars = self.get_merged_env_vars(branch)
453
-
454
- print(f"\n🔧 Applying {len(env_vars)} environment variables...")
455
- for function_name in self.list_lambda_functions_filtered(branch):
456
- print(f"➡️ Updating Lambda function: {function_name}")
457
- self.update_lambda_function(function_name, env_vars)
458
-
459
- print(
460
- "✅ Environment variables successfully applied to matching Lambda functions.\n"
449
+ raise RuntimeError(
450
+ "AmplifyProject.sync() is retired. Lambda environment variables are no "
451
+ "longer copied from Amplify configuration. Use SSM-backed runtime "
452
+ "configuration instead."
461
453
  )
462
454
 
463
455
 
@@ -450,13 +450,6 @@ def run_backend_deployment(
450
450
  queue_handler = None
451
451
  queue_producers = []
452
452
  pending_logging = []
453
-
454
- env_vars = build_environment_variables(
455
- app,
456
- branch,
457
- queue_name,
458
- project_root=project_root,
459
- )
460
453
  subnet_ids = list(config.subnet_ids) if config.subnet_ids else None
461
454
  security_group_ids = (
462
455
  list(config.security_group_ids) if config.security_group_ids else None
@@ -491,7 +484,6 @@ def run_backend_deployment(
491
484
  )
492
485
  app.update_lambda_function(
493
486
  function_name=function_name,
494
- merge_env_vars=env_vars,
495
487
  timeout=timeout_value,
496
488
  memory_size=memory_value,
497
489
  subnet_ids=subnet_ids,
@@ -0,0 +1,180 @@
1
+ """
2
+ SSM-backed configuration with environment-variable fallback.
3
+
4
+ ``getenv(key)`` reads from SSM at::
5
+
6
+ /{ProjectName}/{stage}/{key}
7
+
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.
15
+
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
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import logging
23
+ import os
24
+ from typing import Optional
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ _LAMBDA_PROJECT_SUFFIXES = (
29
+ 'QueueHandler',
30
+ 'Scheduler',
31
+ 'WebHooks',
32
+ 'Public',
33
+ 'Events',
34
+ 'Data',
35
+ )
36
+
37
+ # Per-process cache: key → value (str) or sentinel _MISS.
38
+ _MISS = object()
39
+ _cache: dict[str, object] = {}
40
+
41
+ # Lazily evaluated once per process.
42
+ _SSM_ENABLED: bool | None = None
43
+
44
+
45
+ def _is_enabled() -> bool:
46
+ global _SSM_ENABLED
47
+ if _SSM_ENABLED is None:
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())
53
+ return _SSM_ENABLED
54
+
55
+
56
+ def _first_nonempty_env(*keys: str) -> str | None:
57
+ for key in keys:
58
+ value = os.environ.get(key)
59
+ if value is None:
60
+ continue
61
+ value = value.strip()
62
+ if value:
63
+ return value
64
+ return None
65
+
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
+
100
+ def get_project_name(default: Optional[str] = None) -> Optional[str]:
101
+ return _first_nonempty_env('ProjectName') or _infer_project_name_from_lambda_name() or default
102
+
103
+
104
+ def get_stage(default: Optional[str] = None) -> Optional[str]:
105
+ return _first_nonempty_env('AppStage', 'ENV', 'USER_BRANCH', 'AWS_BRANCH') or default
106
+
107
+
108
+ def get_region(default: Optional[str] = 'us-east-1') -> Optional[str]:
109
+ return _first_nonempty_env('AWS_REGION', 'REGION', 'USER_REGION') or default
110
+
111
+
112
+ def _ssm_prefix() -> str | None:
113
+ """Return '/{ProjectName}/{stage}' or None if either component is missing."""
114
+ project = get_project_name()
115
+ stage = get_stage()
116
+ if project and stage:
117
+ return f'/{project}/{stage}'
118
+ return None
119
+
120
+
121
+ def _fetch(key: str) -> str | None:
122
+ """Single SSM GetParameter call; returns value or None on any failure."""
123
+ prefix = _ssm_prefix()
124
+ if prefix is None:
125
+ return None
126
+ param_name = f'{prefix}/{key}'
127
+ try:
128
+ import boto3
129
+ ssm = boto3.client('ssm', region_name=get_region('us-east-1'))
130
+ resp = ssm.get_parameter(Name=param_name, WithDecryption=True)
131
+ return resp['Parameter']['Value']
132
+ except Exception as exc:
133
+ logger.debug('SSM miss for %s: %s', param_name, exc)
134
+ return None
135
+
136
+
137
+ def getenv(
138
+ key: str,
139
+ default: Optional[str] = None,
140
+ *,
141
+ raise_on_missing: bool = False,
142
+ ) -> Optional[str]:
143
+ """
144
+ Read a config value, checking SSM before ``os.environ``.
145
+
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
+
151
+ All other cases fall straight through to ``os.environ``.
152
+
153
+ Results are cached per process so SSM is queried at most once per key
154
+ per Lambda cold start.
155
+
156
+ When ``raise_on_missing`` is true, this raises ``KeyError`` if neither
157
+ SSM nor ``os.environ`` contains a non-empty value for the requested key.
158
+ In that mode, the provided default is ignored.
159
+ """
160
+ if _is_enabled():
161
+ if key not in _cache:
162
+ value = _fetch(key)
163
+ _cache[key] = value if value is not None else _MISS
164
+ cached = _cache[key]
165
+ if cached is not _MISS:
166
+ if raise_on_missing and cached == "":
167
+ raise KeyError(f'{key} not found in SSM or environment')
168
+ return cached # type: ignore[return-value]
169
+
170
+ value = os.environ.get(key, default)
171
+ if raise_on_missing and value in (None, ""):
172
+ raise KeyError(f'{key} not found in SSM or environment')
173
+ return value
174
+
175
+
176
+ def clear_cache() -> None:
177
+ """Clear the SSM cache (useful in tests)."""
178
+ _cache.clear()
179
+ global _SSM_ENABLED
180
+ _SSM_ENABLED = None
@@ -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.45
3
+ Version: 0.1.47
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
@@ -183,6 +183,7 @@ tests/test_security_hardening.py
183
183
  tests/test_server_cursor.py
184
184
  tests/test_spreadsheet_functions.py
185
185
  tests/test_sqs_per_record_transactions.py
186
+ tests/test_ssm_config.py
186
187
  tests/test_sys_modified_count_postgres_demo.py
187
188
  tests/test_table_alter.py
188
189
  tests/test_where_clause_validation.py
@@ -1,3 +1,6 @@
1
+ import pytest
2
+
3
+ from velocity.aws.amplify import AmplifyProject
1
4
  from velocity.aws.amplify_build import (
2
5
  BackendDeploymentConfig,
3
6
  build_environment_variables,
@@ -144,7 +147,16 @@ def test_run_backend_deployment_refreshes_lambda_layers(monkeypatch, tmp_path):
144
147
  assert app.updated_functions[0]["function_name"] == "ClientEvents-demo"
145
148
  assert app.updated_functions[0]["timeout"] == 60
146
149
  assert app.updated_functions[0]["memory_size"] == 512
150
+ assert "merge_env_vars" not in app.updated_functions[0]
147
151
  assert app.updated_functions[0]["layers"] == [
148
152
  "arn:aws:lambda:us-east-1:741671896925:layer:py-lib-support:240",
149
153
  "arn:aws:lambda:us-east-1:741671896925:layer:py-lib-accounting:34",
150
- ]
154
+ ]
155
+
156
+
157
+ def test_amplify_project_sync_is_retired():
158
+ app = AmplifyProject.__new__(AmplifyProject)
159
+ app.app_id = "app-123"
160
+
161
+ with pytest.raises(RuntimeError, match=r"AmplifyProject\.sync\(\) is retired"):
162
+ app.sync("demo")
@@ -0,0 +1,132 @@
1
+ from unittest.mock import patch
2
+
3
+ import pytest
4
+
5
+ from velocity.aws import ssm_config
6
+
7
+
8
+ def test_get_stage_prefers_app_stage_then_aliases(monkeypatch):
9
+ ssm_config.clear_cache()
10
+ monkeypatch.setenv("AWS_BRANCH", "production")
11
+ monkeypatch.setenv("USER_BRANCH", "demo")
12
+ monkeypatch.setenv("ENV", "sandbox")
13
+ monkeypatch.setenv("AppStage", "stage")
14
+
15
+ assert ssm_config.get_stage() == "stage"
16
+
17
+
18
+ def test_ssm_prefix_uses_aws_branch_when_env_missing(monkeypatch):
19
+ ssm_config.clear_cache()
20
+ monkeypatch.setenv("ProjectName", "Client")
21
+ monkeypatch.delenv("ENV", raising=False)
22
+ monkeypatch.delenv("USER_BRANCH", raising=False)
23
+ monkeypatch.setenv("AWS_BRANCH", "production")
24
+
25
+ assert ssm_config._ssm_prefix() == "/Client/production"
26
+
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
+
37
+ def test_getenv_falls_back_to_environment_when_disabled(monkeypatch):
38
+ ssm_config.clear_cache()
39
+ monkeypatch.delenv("VELOCITY_SSM_ENABLED", raising=False)
40
+ monkeypatch.setenv("StripeSecretKey", "env-secret")
41
+
42
+ assert ssm_config.getenv("StripeSecretKey") == "env-secret"
43
+
44
+
45
+ def test_getenv_reads_ssm_with_region_aliases(monkeypatch):
46
+ ssm_config.clear_cache()
47
+ monkeypatch.setenv("VELOCITY_SSM_ENABLED", "true")
48
+ monkeypatch.setenv("ProjectName", "Client")
49
+ monkeypatch.setenv("AWS_BRANCH", "production")
50
+ monkeypatch.setenv("AWS_REGION", "us-west-2")
51
+ monkeypatch.setenv("StripeSecretKey", "env-secret")
52
+
53
+ class FakeSSM:
54
+ def get_parameter(self, Name, WithDecryption):
55
+ assert Name == "/Client/production/StripeSecretKey"
56
+ assert WithDecryption is True
57
+ return {"Parameter": {"Value": "ssm-secret"}}
58
+
59
+ with patch("boto3.client", return_value=FakeSSM()) as client_factory:
60
+ assert ssm_config.getenv("StripeSecretKey") == "ssm-secret"
61
+
62
+ client_factory.assert_called_once_with("ssm", region_name="us-west-2")
63
+
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
+
86
+ def test_getenv_raises_on_missing_when_disabled(monkeypatch):
87
+ ssm_config.clear_cache()
88
+ monkeypatch.delenv("VELOCITY_SSM_ENABLED", raising=False)
89
+ monkeypatch.delenv("MissingKey", raising=False)
90
+
91
+ with pytest.raises(KeyError, match="MissingKey"):
92
+ ssm_config.getenv("MissingKey", raise_on_missing=True)
93
+
94
+
95
+ def test_getenv_raises_on_missing_after_ssm_miss(monkeypatch):
96
+ ssm_config.clear_cache()
97
+ monkeypatch.setenv("VELOCITY_SSM_ENABLED", "true")
98
+ monkeypatch.setenv("ProjectName", "Client")
99
+ monkeypatch.setenv("AWS_BRANCH", "production")
100
+ monkeypatch.delenv("MissingKey", raising=False)
101
+
102
+ class FakeSSM:
103
+ def get_parameter(self, Name, WithDecryption):
104
+ raise Exception("missing")
105
+
106
+ with patch("boto3.client", return_value=FakeSSM()):
107
+ with pytest.raises(KeyError, match="MissingKey"):
108
+ ssm_config.getenv("MissingKey", raise_on_missing=True)
109
+
110
+
111
+ def test_getenv_raises_on_empty_environment_value(monkeypatch):
112
+ ssm_config.clear_cache()
113
+ monkeypatch.delenv("VELOCITY_SSM_ENABLED", raising=False)
114
+ monkeypatch.setenv("MissingKey", "")
115
+
116
+ with pytest.raises(KeyError, match="MissingKey"):
117
+ ssm_config.getenv("MissingKey", raise_on_missing=True)
118
+
119
+
120
+ def test_getenv_raises_on_empty_ssm_value(monkeypatch):
121
+ ssm_config.clear_cache()
122
+ monkeypatch.setenv("VELOCITY_SSM_ENABLED", "true")
123
+ monkeypatch.setenv("ProjectName", "Client")
124
+ monkeypatch.setenv("AWS_BRANCH", "production")
125
+
126
+ class FakeSSM:
127
+ def get_parameter(self, Name, WithDecryption):
128
+ return {"Parameter": {"Value": ""}}
129
+
130
+ with patch("boto3.client", return_value=FakeSSM()):
131
+ with pytest.raises(KeyError, match="MissingKey"):
132
+ ssm_config.getenv("MissingKey", raise_on_missing=True)
@@ -1,94 +0,0 @@
1
- """
2
- SSM-backed configuration with environment-variable fallback.
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::
8
-
9
- /{ProjectName}/{ENV}/{key}
10
-
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.
14
-
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).
18
- """
19
-
20
- from __future__ import annotations
21
-
22
- import logging
23
- import os
24
- from typing import Optional
25
-
26
- logger = logging.getLogger(__name__)
27
-
28
- # Per-process cache: key → value (str) or sentinel _MISS.
29
- _MISS = object()
30
- _cache: dict[str, object] = {}
31
-
32
- # Lazily evaluated once per process.
33
- _SSM_ENABLED: bool | None = None
34
-
35
-
36
- def _is_enabled() -> bool:
37
- global _SSM_ENABLED
38
- if _SSM_ENABLED is None:
39
- _SSM_ENABLED = os.environ.get('VELOCITY_SSM_ENABLED', '').lower() in ('1', 'true', 'yes')
40
- return _SSM_ENABLED
41
-
42
-
43
- def _ssm_prefix() -> str | None:
44
- """Return '/{ProjectName}/{ENV}' or None if either var is missing."""
45
- project = os.environ.get('ProjectName')
46
- env = os.environ.get('ENV')
47
- if project and env:
48
- return f'/{project}/{env}'
49
- return None
50
-
51
-
52
- def _fetch(key: str) -> str | None:
53
- """Single SSM GetParameter call; returns value or None on any failure."""
54
- prefix = _ssm_prefix()
55
- if prefix is None:
56
- return None
57
- param_name = f'{prefix}/{key}'
58
- try:
59
- import boto3
60
- ssm = boto3.client('ssm', region_name=os.environ.get('REGION', 'us-east-1'))
61
- resp = ssm.get_parameter(Name=param_name, WithDecryption=True)
62
- return resp['Parameter']['Value']
63
- except Exception as exc:
64
- logger.debug('SSM miss for %s: %s', param_name, exc)
65
- return None
66
-
67
-
68
- def getenv(key: str, default: Optional[str] = None) -> Optional[str]:
69
- """
70
- Read a config value, checking SSM before ``os.environ``.
71
-
72
- SSM is only consulted when ``VELOCITY_SSM_ENABLED=true`` is set in the
73
- Lambda environment *and* both ``ProjectName`` and ``ENV`` are present.
74
- All other cases fall straight through to ``os.environ``.
75
-
76
- Results are cached per process so SSM is queried at most once per key
77
- per Lambda cold start.
78
- """
79
- if _is_enabled():
80
- if key not in _cache:
81
- value = _fetch(key)
82
- _cache[key] = value if value is not None else _MISS
83
- cached = _cache[key]
84
- if cached is not _MISS:
85
- return cached # type: ignore[return-value]
86
-
87
- return os.environ.get(key, default)
88
-
89
-
90
- def clear_cache() -> None:
91
- """Clear the SSM cache (useful in tests)."""
92
- _cache.clear()
93
- global _SSM_ENABLED
94
- _SSM_ENABLED = None