velocity-python 0.1.23__tar.gz → 0.1.24__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 (172) hide show
  1. {velocity_python-0.1.23/src/velocity_python.egg-info → velocity_python-0.1.24}/PKG-INFO +1 -1
  2. {velocity_python-0.1.23 → velocity_python-0.1.24}/pyproject.toml +1 -1
  3. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/__init__.py +1 -1
  4. velocity_python-0.1.24/src/velocity/aws/ssm_config.py +94 -0
  5. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/postgres/__init__.py +14 -13
  6. {velocity_python-0.1.23 → velocity_python-0.1.24/src/velocity_python.egg-info}/PKG-INFO +1 -1
  7. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity_python.egg-info/SOURCES.txt +1 -0
  8. {velocity_python-0.1.23 → velocity_python-0.1.24}/LICENSE +0 -0
  9. {velocity_python-0.1.23 → velocity_python-0.1.24}/README.md +0 -0
  10. {velocity_python-0.1.23 → velocity_python-0.1.24}/setup.cfg +0 -0
  11. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/__init__.py +0 -0
  12. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/amplify.py +0 -0
  13. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/amplify_build.py +0 -0
  14. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/__init__.py +0 -0
  15. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/base_handler.py +0 -0
  16. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/context.py +0 -0
  17. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/context_factory.py +0 -0
  18. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/exceptions.py +0 -0
  19. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  20. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  21. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  22. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  23. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/perf.py +0 -0
  24. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/response.py +0 -0
  25. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  26. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/s3.py +0 -0
  27. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/tests/__init__.py +0 -0
  28. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  29. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  30. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/aws/tests/test_response.py +0 -0
  31. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/__init__.py +0 -0
  32. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/__init__.py +0 -0
  33. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/async_support.py +0 -0
  34. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/column.py +0 -0
  35. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/database.py +0 -0
  36. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/decorators.py +0 -0
  37. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/engine.py +0 -0
  38. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/result.py +0 -0
  39. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/row.py +0 -0
  40. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/sequence.py +0 -0
  41. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/table.py +0 -0
  42. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/transaction.py +0 -0
  43. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/core/view.py +0 -0
  44. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/exceptions.py +0 -0
  45. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/migrations.py +0 -0
  46. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/__init__.py +0 -0
  47. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/base/__init__.py +0 -0
  48. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/base/initializer.py +0 -0
  49. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/base/operators.py +0 -0
  50. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/base/sql.py +0 -0
  51. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/base/types.py +0 -0
  52. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/mysql/__init__.py +0 -0
  53. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/mysql/operators.py +0 -0
  54. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/mysql/reserved.py +0 -0
  55. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/mysql/sql.py +0 -0
  56. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/mysql/types.py +0 -0
  57. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/postgres/operators.py +0 -0
  58. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/postgres/reserved.py +0 -0
  59. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/postgres/sql.py +0 -0
  60. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/postgres/types.py +0 -0
  61. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  62. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlite/operators.py +0 -0
  63. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  64. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlite/sql.py +0 -0
  65. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlite/types.py +0 -0
  66. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  67. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  68. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  69. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  70. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/sqlserver/types.py +0 -0
  71. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/servers/tablehelper.py +0 -0
  72. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/__init__.py +0 -0
  73. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/common_db_test.py +0 -0
  74. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/__init__.py +0 -0
  75. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/common.py +0 -0
  76. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_column.py +0 -0
  77. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  78. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_database.py +0 -0
  79. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  80. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  81. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  82. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_result.py +0 -0
  83. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_row.py +0 -0
  84. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  85. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  86. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  87. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  88. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  89. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_table.py +0 -0
  90. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  91. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  92. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/sql/__init__.py +0 -0
  93. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/sql/common.py +0 -0
  94. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  95. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  96. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  97. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_db_utils.py +0 -0
  98. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_postgres.py +0 -0
  99. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  100. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  101. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_result_caching.py +0 -0
  102. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  103. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  104. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  105. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  106. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_sql_builder.py +0 -0
  107. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_tablehelper.py +0 -0
  108. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/tests/test_view_helper.py +0 -0
  109. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/db/utils.py +0 -0
  110. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/logging.py +0 -0
  111. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/__init__.py +0 -0
  112. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/conv/__init__.py +0 -0
  113. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/conv/iconv.py +0 -0
  114. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/conv/oconv.py +0 -0
  115. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/db.py +0 -0
  116. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/export.py +0 -0
  117. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/format.py +0 -0
  118. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/mail.py +0 -0
  119. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/merge.py +0 -0
  120. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/pdf.py +0 -0
  121. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/__init__.py +0 -0
  122. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_db.py +0 -0
  123. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_fix.py +0 -0
  124. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_format.py +0 -0
  125. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_iconv.py +0 -0
  126. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_merge.py +0 -0
  127. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_oconv.py +0 -0
  128. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_original_error.py +0 -0
  129. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tests/test_timer.py +0 -0
  130. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/timer.py +0 -0
  131. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/misc/tools.py +0 -0
  132. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/payment/__init__.py +0 -0
  133. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/payment/authorizenet_adapter.py +0 -0
  134. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/payment/base_adapter.py +0 -0
  135. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/payment/braintree_adapter.py +0 -0
  136. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/payment/charge_rules.py +0 -0
  137. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity/payment/stripe_adapter.py +0 -0
  138. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  139. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity_python.egg-info/entry_points.txt +0 -0
  140. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity_python.egg-info/requires.txt +0 -0
  141. {velocity_python-0.1.23 → velocity_python-0.1.24}/src/velocity_python.egg-info/top_level.txt +0 -0
  142. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_amplify_build.py +0 -0
  143. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_async_support.py +0 -0
  144. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_batch_operations.py +0 -0
  145. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_concurrency_safety.py +0 -0
  146. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_connection_pool.py +0 -0
  147. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_connection_resilience.py +0 -0
  148. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_decorators.py +0 -0
  149. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_email_processing.py +0 -0
  150. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_iconv_money_to_cents.py +0 -0
  151. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_lambda_handler.py +0 -0
  152. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_lambda_handler_auth.py +0 -0
  153. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_mixins_import.py +0 -0
  154. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_n_plus_one.py +0 -0
  155. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_observability.py +0 -0
  156. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_payment_braintree_adapter.py +0 -0
  157. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_payment_profile_sorting.py +0 -0
  158. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_payment_stripe_adapter.py +0 -0
  159. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_pdf.py +0 -0
  160. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_prepared_statements.py +0 -0
  161. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_psycopg3_upgrade.py +0 -0
  162. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_query_cache.py +0 -0
  163. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_row_batch_update.py +0 -0
  164. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_row_cache_staleness.py +0 -0
  165. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_row_dirty_tracking.py +0 -0
  166. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_schema_migrations.py +0 -0
  167. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_security_hardening.py +0 -0
  168. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_spreadsheet_functions.py +0 -0
  169. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_sqs_per_record_transactions.py +0 -0
  170. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  171. {velocity_python-0.1.23 → velocity_python-0.1.24}/tests/test_table_alter.py +0 -0
  172. {velocity_python-0.1.23 → velocity_python-0.1.24}/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.23
3
+ Version: 0.1.24
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.23"
7
+ version = "0.1.24"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.23"
1
+ __version__ = version = "0.1.24"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -0,0 +1,94 @@
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
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  from ..base.initializer import BaseInitializer
3
3
  from velocity.db.core import engine
4
+ from velocity.aws.ssm_config import getenv as _getenv
4
5
 
5
6
 
6
7
  # Default TCP keepalive settings for PostgreSQL connections.
@@ -41,14 +42,14 @@ class PostgreSQLInitializer(BaseInitializer):
41
42
 
42
43
  from .sql import SQL
43
44
 
44
- # Base configuration from environment
45
+ # Base configuration from environment / SSM
45
46
  # psycopg v3 uses libpq param names; 'dbname' not 'database'.
46
47
  base_config = {
47
- "dbname": os.environ.get("DBDatabase"),
48
- "host": os.environ.get("DBHost"),
49
- "port": os.environ.get("DBPort"),
50
- "user": os.environ.get("DBUser"),
51
- "password": os.environ.get("DBPassword"),
48
+ "dbname": _getenv("DBDatabase"),
49
+ "host": _getenv("DBHost"),
50
+ "port": _getenv("DBPort"),
51
+ "user": _getenv("DBUser"),
52
+ "password": _getenv("DBPassword"),
52
53
  }
53
54
 
54
55
  # Remove None values
@@ -65,7 +66,7 @@ class PostgreSQLInitializer(BaseInitializer):
65
66
 
66
67
  # SSL mode — default to "prefer" so connections upgrade when the
67
68
  # server supports TLS but don't fail when it doesn't.
68
- ssl_mode = os.environ.get("VELOCITY_SSL_MODE")
69
+ ssl_mode = _getenv("VELOCITY_SSL_MODE")
69
70
  if ssl_mode:
70
71
  final_config.setdefault("sslmode", ssl_mode)
71
72
 
@@ -108,11 +109,11 @@ def initialize(config=None, schema_locked=False, **kwargs):
108
109
  from .sql import SQL
109
110
 
110
111
  konfig = {
111
- "dbname": os.environ["DBDatabase"],
112
- "host": os.environ["DBHost"],
113
- "port": os.environ["DBPort"],
114
- "user": os.environ["DBUser"],
115
- "password": os.environ["DBPassword"],
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"],
116
117
  }
117
118
  konfig.update(config or {})
118
119
  konfig.update(kwargs)
@@ -122,7 +123,7 @@ def initialize(config=None, schema_locked=False, **kwargs):
122
123
  konfig.setdefault(key, default_val)
123
124
 
124
125
  # SSL mode.
125
- ssl_mode = os.environ.get("VELOCITY_SSL_MODE")
126
+ ssl_mode = _getenv("VELOCITY_SSL_MODE")
126
127
  if ssl_mode:
127
128
  konfig.setdefault("sslmode", ssl_mode)
128
129
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.23
3
+ Version: 0.1.24
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
@@ -7,6 +7,7 @@ src/velocity/aws/__init__.py
7
7
  src/velocity/aws/amplify.py
8
8
  src/velocity/aws/amplify_build.py
9
9
  src/velocity/aws/s3.py
10
+ src/velocity/aws/ssm_config.py
10
11
  src/velocity/aws/handlers/__init__.py
11
12
  src/velocity/aws/handlers/base_handler.py
12
13
  src/velocity/aws/handlers/context.py