velocity-python 0.1.1__tar.gz → 0.1.2__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 (178) hide show
  1. {velocity_python-0.1.1 → velocity_python-0.1.2}/PKG-INFO +12 -6
  2. {velocity_python-0.1.1 → velocity_python-0.1.2}/pyproject.toml +17 -6
  3. velocity_python-0.1.2/src/velocity/__init__.py +17 -0
  4. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/__init__.py +21 -11
  5. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/row.py +43 -5
  6. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/table.py +4 -4
  7. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/export.py +11 -4
  8. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/PKG-INFO +12 -6
  9. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/SOURCES.txt +1 -0
  10. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/requires.txt +15 -4
  11. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_row_batch_update.py +3 -0
  12. velocity_python-0.1.2/tests/test_row_cache_staleness.py +296 -0
  13. velocity_python-0.1.1/src/velocity/__init__.py +0 -8
  14. {velocity_python-0.1.1 → velocity_python-0.1.2}/LICENSE +0 -0
  15. {velocity_python-0.1.1 → velocity_python-0.1.2}/README.md +0 -0
  16. {velocity_python-0.1.1 → velocity_python-0.1.2}/setup.cfg +0 -0
  17. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/__init__.py +0 -0
  18. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/formbuilder/__init__.py +0 -0
  19. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/formbuilder/reshaper.py +0 -0
  20. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/invoices.py +0 -0
  21. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/orders.py +0 -0
  22. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/payments.py +0 -0
  23. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/purchase_orders.py +0 -0
  24. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/__init__.py +0 -0
  25. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/test_email_processing.py +0 -0
  26. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/test_payment_profile_sorting.py +0 -0
  27. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/tests/test_spreadsheet_functions.py +0 -0
  28. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/validators/__init__.py +0 -0
  29. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/app/validators/formbuilder_template.py +0 -0
  30. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/amplify.py +0 -0
  31. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/amplify_build.py +0 -0
  32. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/__init__.py +0 -0
  33. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/base_handler.py +0 -0
  34. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/context.py +0 -0
  35. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/context_factory.py +0 -0
  36. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/exceptions.py +0 -0
  37. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  38. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  39. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  40. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  41. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/perf.py +0 -0
  42. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/response.py +0 -0
  43. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  44. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/__init__.py +0 -0
  45. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  46. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  47. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/aws/tests/test_response.py +0 -0
  48. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/__init__.py +0 -0
  49. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/__init__.py +0 -0
  50. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/column.py +0 -0
  51. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/database.py +0 -0
  52. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/decorators.py +0 -0
  53. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/engine.py +0 -0
  54. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/result.py +0 -0
  55. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/sequence.py +0 -0
  56. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/transaction.py +0 -0
  57. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/core/view.py +0 -0
  58. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/exceptions.py +0 -0
  59. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/__init__.py +0 -0
  60. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/__init__.py +0 -0
  61. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/initializer.py +0 -0
  62. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/operators.py +0 -0
  63. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/sql.py +0 -0
  64. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/base/types.py +0 -0
  65. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/__init__.py +0 -0
  66. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/operators.py +0 -0
  67. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/reserved.py +0 -0
  68. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/sql.py +0 -0
  69. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/mysql/types.py +0 -0
  70. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/__init__.py +0 -0
  71. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/operators.py +0 -0
  72. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/reserved.py +0 -0
  73. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/sql.py +0 -0
  74. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/postgres/types.py +0 -0
  75. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  76. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/operators.py +0 -0
  77. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  78. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/sql.py +0 -0
  79. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlite/types.py +0 -0
  80. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  81. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  82. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  83. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  84. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/sqlserver/types.py +0 -0
  85. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/servers/tablehelper.py +0 -0
  86. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/__init__.py +0 -0
  87. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/common_db_test.py +0 -0
  88. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/__init__.py +0 -0
  89. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/common.py +0 -0
  90. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_column.py +0 -0
  91. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  92. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_database.py +0 -0
  93. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  94. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  95. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  96. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_result.py +0 -0
  97. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_row.py +0 -0
  98. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  99. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  100. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  101. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  102. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  103. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_table.py +0 -0
  104. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  105. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  106. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/__init__.py +0 -0
  107. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/common.py +0 -0
  108. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  109. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  110. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  111. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_db_utils.py +0 -0
  112. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_postgres.py +0 -0
  113. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  114. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  115. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_result_caching.py +0 -0
  116. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  117. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  118. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  119. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  120. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_sql_builder.py +0 -0
  121. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_tablehelper.py +0 -0
  122. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/tests/test_view_helper.py +0 -0
  123. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/db/utils.py +0 -0
  124. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/logging.py +0 -0
  125. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/__init__.py +0 -0
  126. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/conv/__init__.py +0 -0
  127. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/conv/iconv.py +0 -0
  128. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/conv/oconv.py +0 -0
  129. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/db.py +0 -0
  130. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/format.py +0 -0
  131. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/mail.py +0 -0
  132. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/merge.py +0 -0
  133. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/__init__.py +0 -0
  134. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_db.py +0 -0
  135. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_fix.py +0 -0
  136. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_format.py +0 -0
  137. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_iconv.py +0 -0
  138. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_merge.py +0 -0
  139. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_oconv.py +0 -0
  140. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_original_error.py +0 -0
  141. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tests/test_timer.py +0 -0
  142. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/timer.py +0 -0
  143. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/misc/tools.py +0 -0
  144. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/__init__.py +0 -0
  145. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/authorizenet_adapter.py +0 -0
  146. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/base_adapter.py +0 -0
  147. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/braintree_adapter.py +0 -0
  148. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/charge_rules.py +0 -0
  149. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/demo_profiles.py +0 -0
  150. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/profiles.py +0 -0
  151. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/router.py +0 -0
  152. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity/payment/stripe_adapter.py +0 -0
  153. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  154. {velocity_python-0.1.1 → velocity_python-0.1.2}/src/velocity_python.egg-info/top_level.txt +0 -0
  155. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_amplify_build.py +0 -0
  156. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_batch_operations.py +0 -0
  157. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_concurrency_safety.py +0 -0
  158. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_connection_pool.py +0 -0
  159. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_connection_resilience.py +0 -0
  160. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_decorators.py +0 -0
  161. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_formbuilder_reshaper.py +0 -0
  162. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_formbuilder_template_validator.py +0 -0
  163. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_iconv_money_to_cents.py +0 -0
  164. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_lambda_handler.py +0 -0
  165. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_lambda_handler_auth.py +0 -0
  166. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_mixins_import.py +0 -0
  167. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_braintree_adapter.py +0 -0
  168. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_demo_profiles.py +0 -0
  169. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_profiles.py +0 -0
  170. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_router.py +0 -0
  171. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_payment_stripe_adapter.py +0 -0
  172. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_prepared_statements.py +0 -0
  173. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_psycopg3_upgrade.py +0 -0
  174. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_query_cache.py +0 -0
  175. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_sqs_per_record_transactions.py +0 -0
  176. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  177. {velocity_python-0.1.1 → velocity_python-0.1.2}/tests/test_table_alter.py +0 -0
  178. {velocity_python-0.1.1 → velocity_python-0.1.2}/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.1
3
+ Version: 0.1.2
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
@@ -19,12 +19,16 @@ Classifier: Operating System :: OS Independent
19
19
  Requires-Python: >=3.9
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
- Requires-Dist: boto3>=1.35.0
23
- Requires-Dist: requests>=2.32.0
24
- Requires-Dist: jinja2>=3.1.0
25
- Requires-Dist: xlrd>=2.0.1
26
- Requires-Dist: openpyxl>=3.1.0
27
22
  Requires-Dist: sqlparse>=0.5.0
23
+ Provides-Extra: aws
24
+ Requires-Dist: boto3>=1.35.0; extra == "aws"
25
+ Requires-Dist: requests>=2.32.0; extra == "aws"
26
+ Provides-Extra: excel
27
+ Requires-Dist: openpyxl>=3.1.0; extra == "excel"
28
+ Provides-Extra: templates
29
+ Requires-Dist: jinja2>=3.1.0; extra == "templates"
30
+ Provides-Extra: http
31
+ Requires-Dist: requests>=2.32.0; extra == "http"
28
32
  Provides-Extra: mysql
29
33
  Requires-Dist: mysql-connector-python>=9.0.0; extra == "mysql"
30
34
  Provides-Extra: sqlserver
@@ -34,6 +38,8 @@ Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgres"
34
38
  Provides-Extra: payment
35
39
  Requires-Dist: stripe>=12.0.0; extra == "payment"
36
40
  Requires-Dist: braintree>=4.30.0; extra == "payment"
41
+ Provides-Extra: all
42
+ Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
37
43
  Provides-Extra: dev
38
44
  Requires-Dist: pytest>=8.0.0; extra == "dev"
39
45
  Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -26,11 +26,6 @@ classifiers = [
26
26
  "Operating System :: OS Independent",
27
27
  ]
28
28
  dependencies = [
29
- "boto3>=1.35.0",
30
- "requests>=2.32.0",
31
- "jinja2>=3.1.0",
32
- "xlrd>=2.0.1",
33
- "openpyxl>=3.1.0",
34
29
  "sqlparse>=0.5.0"
35
30
  ]
36
31
 
@@ -38,6 +33,19 @@ dependencies = [
38
33
  Homepage = "https://codeclubs.org/projects/velocity"
39
34
 
40
35
  [project.optional-dependencies]
36
+ aws = [
37
+ "boto3>=1.35.0",
38
+ "requests>=2.32.0",
39
+ ]
40
+ excel = [
41
+ "openpyxl>=3.1.0",
42
+ ]
43
+ templates = [
44
+ "jinja2>=3.1.0",
45
+ ]
46
+ http = [
47
+ "requests>=2.32.0",
48
+ ]
41
49
  mysql = [
42
50
  "mysql-connector-python>=9.0.0",
43
51
  ]
@@ -51,6 +59,9 @@ payment = [
51
59
  "stripe>=12.0.0",
52
60
  "braintree>=4.30.0",
53
61
  ]
62
+ all = [
63
+ "velocity-python[postgres,aws,excel,templates,http,payment]",
64
+ ]
54
65
  dev = [
55
66
  "pytest>=8.0.0",
56
67
  "pytest-cov>=6.0.0",
@@ -0,0 +1,17 @@
1
+ __version__ = version = "0.1.2"
2
+
3
+ import importlib as _importlib
4
+
5
+ from . import db
6
+ from . import misc
7
+ from . import app
8
+
9
+ __all__ = ["aws", "db", "misc", "app"]
10
+
11
+ _LAZY_SUBMODULES = {"aws"}
12
+
13
+
14
+ def __getattr__(name: str):
15
+ if name in _LAZY_SUBMODULES:
16
+ return _importlib.import_module(f".{name}", __name__)
17
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -1,15 +1,5 @@
1
+ import importlib as _importlib
1
2
  import os
2
- import requests
3
-
4
- from velocity.aws.amplify import AmplifyProject
5
- from velocity.aws.amplify_build import (
6
- BackendDeploymentConfig,
7
- build_environment_variables,
8
- get_amplify_app_id_and_branch,
9
- initialize_build_environment,
10
- run_backend_deployment,
11
- update_lambda_layers_to_latest,
12
- )
13
3
 
14
4
  DEBUG = (os.environ.get("ENV") != "production") or (os.environ.get("DEBUG") == "Y")
15
5
 
@@ -23,11 +13,31 @@ class AWS(object):
23
13
  # Get AWS EC2 Instance ID. Must run this from the EC2 instance itself to get the ID
24
14
  @staticmethod
25
15
  def instance_id(cls):
16
+ import requests
26
17
  response = requests.get("http://169.254.169.254/latest/meta-data/instance-id")
27
18
  instance_id = response.text
28
19
  return instance_id
29
20
 
30
21
 
22
+ # Lazy-load heavy modules (boto3-dependent) on first access
23
+ _LAZY_ATTRS = {
24
+ "AmplifyProject": "velocity.aws.amplify",
25
+ "BackendDeploymentConfig": "velocity.aws.amplify_build",
26
+ "build_environment_variables": "velocity.aws.amplify_build",
27
+ "get_amplify_app_id_and_branch": "velocity.aws.amplify_build",
28
+ "initialize_build_environment": "velocity.aws.amplify_build",
29
+ "run_backend_deployment": "velocity.aws.amplify_build",
30
+ "update_lambda_layers_to_latest": "velocity.aws.amplify_build",
31
+ }
32
+
33
+
34
+ def __getattr__(name: str):
35
+ if name in _LAZY_ATTRS:
36
+ module = _importlib.import_module(_LAZY_ATTRS[name])
37
+ return getattr(module, name)
38
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
39
+
40
+
31
41
  __all__ = [
32
42
  "AmplifyProject",
33
43
  "AWS",
@@ -1,4 +1,5 @@
1
1
  import pprint
2
+ import time as _time
2
3
  import warnings
3
4
  from collections.abc import MutableMapping
4
5
  from velocity.db.exceptions import DbColumnMissingError
@@ -8,6 +9,7 @@ from velocity.db.exceptions import DbColumnMissingError
8
9
  # intercepted by __getattr__ / __setattr__.
9
10
  _INTERNAL_ATTRS = frozenset({
10
11
  "table", "pk", "_cache", "_column_set", "_batching", "_pending",
12
+ "_cache_ttl", "_cache_time", "_no_cache",
11
13
  })
12
14
 
13
15
 
@@ -23,7 +25,7 @@ class Row(MutableMapping):
23
25
  write-through (immediate UPDATE) and also update the local cache.
24
26
  """
25
27
 
26
- def __init__(self, table, key, lock=None):
28
+ def __init__(self, table, key, lock=None, cache_ttl=None, no_cache=False):
27
29
  if isinstance(table, str):
28
30
  raise Exception("Table parameter must be a `table` instance.")
29
31
  object.__setattr__(self, "table", table)
@@ -43,6 +45,9 @@ class Row(MutableMapping):
43
45
  object.__setattr__(self, "_column_set", None)
44
46
  object.__setattr__(self, "_batching", False)
45
47
  object.__setattr__(self, "_pending", {})
48
+ object.__setattr__(self, "_cache_ttl", cache_ttl)
49
+ object.__setattr__(self, "_cache_time", None)
50
+ object.__setattr__(self, "_no_cache", no_cache)
46
51
  if lock:
47
52
  self.lock()
48
53
 
@@ -51,10 +56,20 @@ class Row(MutableMapping):
51
56
  # ------------------------------------------------------------------
52
57
 
53
58
  def _ensure_cache(self):
54
- """Populate the local cache from the database if not yet loaded."""
59
+ """Populate the local cache from the database if not yet loaded or expired."""
60
+ if self._no_cache:
61
+ # Always fetch fresh — never store in cache
62
+ data = self.table.select(where=self.pk).as_dict().one()
63
+ return data or {}
64
+ if self._cache is not None and self._cache_ttl is not None:
65
+ elapsed = _time.monotonic() - (self._cache_time or 0)
66
+ if elapsed > self._cache_ttl:
67
+ object.__setattr__(self, "_cache", None)
68
+ object.__setattr__(self, "_column_set", None)
55
69
  if self._cache is None:
56
70
  data = self.table.select(where=self.pk).as_dict().one()
57
71
  object.__setattr__(self, "_cache", data or {})
72
+ object.__setattr__(self, "_cache_time", _time.monotonic())
58
73
  return self._cache
59
74
 
60
75
  def _column_names_lower(self):
@@ -232,9 +247,9 @@ class Row(MutableMapping):
232
247
  data.update(kwds)
233
248
  if data:
234
249
  self.table.update_or_insert(data, pk=self.pk)
235
- if self._cache is not None:
236
- self._cache.update(data)
237
- object.__setattr__(self, "_column_set", None)
250
+ # Invalidate cache so trigger-computed columns are re-fetched
251
+ object.__setattr__(self, "_cache", None)
252
+ object.__setattr__(self, "_column_set", None)
238
253
  return self
239
254
 
240
255
  def copy(self, lock=None):
@@ -366,6 +381,29 @@ class Row(MutableMapping):
366
381
  self.table.select(where=self.pk, lock=True)
367
382
  return self
368
383
 
384
+ def with_lock(self):
385
+ """SELECT ... FOR UPDATE and clear the cache so the next read is fresh.
386
+
387
+ Returns self for chaining::
388
+
389
+ row = row.with_lock()
390
+ balance = row["balance"] # guaranteed fresh, locked
391
+ """
392
+ self.table.select(where=self.pk, lock=True)
393
+ object.__setattr__(self, "_cache", None)
394
+ object.__setattr__(self, "_column_set", None)
395
+ return self
396
+
397
+ def no_cache(self):
398
+ """Return a new Row that never caches — every read hits the database.
399
+
400
+ Useful for critical-path reads where staleness is unacceptable::
401
+
402
+ fresh_row = row.no_cache()
403
+ balance = fresh_row["balance"] # always from DB
404
+ """
405
+ return Row(self.table, self.pk, no_cache=True)
406
+
369
407
  def notBlank(self, key, failobj=None):
370
408
  """
371
409
  Returns the value if it is not blank, else failobj.
@@ -400,13 +400,13 @@ class Table:
400
400
  """
401
401
  return Column(self, name)
402
402
 
403
- def row(self, key=None, lock=None):
403
+ def row(self, key=None, lock=None, cache_ttl=None, no_cache=False):
404
404
  """
405
405
  Retrieves a Row instance for the given primary key or conditions dict. If `key` is None, returns a new row.
406
406
  """
407
407
  if key is None:
408
408
  return self.new(lock=lock)
409
- return Row(self, key, lock=lock)
409
+ return Row(self, key, lock=lock, cache_ttl=cache_ttl, no_cache=no_cache)
410
410
 
411
411
  def dict(self, key):
412
412
  """
@@ -415,14 +415,14 @@ class Table:
415
415
  r = self.find(key)
416
416
  return r.to_dict() if r else {}
417
417
 
418
- def rows(self, where=None, orderby=None, qty=None, lock=None, skip_locked=None):
418
+ def rows(self, where=None, orderby=None, qty=None, lock=None, skip_locked=None, cache_ttl=None, no_cache=False):
419
419
  """
420
420
  Generator that yields Row objects matching `where`, up to `qty`.
421
421
  """
422
422
  for key in self.ids(
423
423
  where=where, orderby=orderby, qty=qty, lock=lock, skip_locked=skip_locked
424
424
  ):
425
- yield Row(self, key, lock=lock)
425
+ yield Row(self, key, lock=lock, cache_ttl=cache_ttl, no_cache=no_cache)
426
426
 
427
427
  def ids(
428
428
  self,
@@ -1,13 +1,15 @@
1
+ from __future__ import annotations
2
+
1
3
  from datetime import date, datetime, time, timedelta
2
4
  from decimal import Decimal
3
5
  from io import BytesIO
4
- from typing import Dict, List
6
+ from typing import TYPE_CHECKING, Dict, List
5
7
  import base64
6
8
  import re
7
9
 
8
- import openpyxl
9
- from openpyxl.styles import Alignment, Border, Font, NamedStyle, Side
10
- from openpyxl.utils import get_column_letter
10
+ if TYPE_CHECKING: # pragma: no cover
11
+ import openpyxl
12
+ from openpyxl.styles import NamedStyle
11
13
 
12
14
 
13
15
  NUMBER_FORMAT_RE = re.compile(r"[#0?][#0?,]*(?:\.[#0?]+)?")
@@ -107,6 +109,8 @@ def _display_value(cell) -> str:
107
109
 
108
110
  def autosize_columns(ws, fixed: Dict[str, float] | None = None):
109
111
  """Autosize columns in the worksheet based on content length."""
112
+ from openpyxl.utils import get_column_letter
113
+
110
114
  fixed = fixed or {}
111
115
  for col in ws.columns:
112
116
  max_length = 0
@@ -135,6 +139,9 @@ def create_spreadsheet(
135
139
  auto_size: bool = True,
136
140
  ):
137
141
  """Create an Excel spreadsheet with specified headers, rows, and styles."""
142
+ import openpyxl
143
+ from openpyxl.styles import Alignment, Border, Font, NamedStyle, Side
144
+
138
145
  styles = styles or {}
139
146
  merge = merge or []
140
147
  formats = formats or {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.1
3
+ Version: 0.1.2
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
@@ -19,12 +19,16 @@ Classifier: Operating System :: OS Independent
19
19
  Requires-Python: >=3.9
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
- Requires-Dist: boto3>=1.35.0
23
- Requires-Dist: requests>=2.32.0
24
- Requires-Dist: jinja2>=3.1.0
25
- Requires-Dist: xlrd>=2.0.1
26
- Requires-Dist: openpyxl>=3.1.0
27
22
  Requires-Dist: sqlparse>=0.5.0
23
+ Provides-Extra: aws
24
+ Requires-Dist: boto3>=1.35.0; extra == "aws"
25
+ Requires-Dist: requests>=2.32.0; extra == "aws"
26
+ Provides-Extra: excel
27
+ Requires-Dist: openpyxl>=3.1.0; extra == "excel"
28
+ Provides-Extra: templates
29
+ Requires-Dist: jinja2>=3.1.0; extra == "templates"
30
+ Provides-Extra: http
31
+ Requires-Dist: requests>=2.32.0; extra == "http"
28
32
  Provides-Extra: mysql
29
33
  Requires-Dist: mysql-connector-python>=9.0.0; extra == "mysql"
30
34
  Provides-Extra: sqlserver
@@ -34,6 +38,8 @@ Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgres"
34
38
  Provides-Extra: payment
35
39
  Requires-Dist: stripe>=12.0.0; extra == "payment"
36
40
  Requires-Dist: braintree>=4.30.0; extra == "payment"
41
+ Provides-Extra: all
42
+ Requires-Dist: velocity-python[aws,excel,http,payment,postgres,templates]; extra == "all"
37
43
  Provides-Extra: dev
38
44
  Requires-Dist: pytest>=8.0.0; extra == "dev"
39
45
  Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
@@ -168,6 +168,7 @@ tests/test_prepared_statements.py
168
168
  tests/test_psycopg3_upgrade.py
169
169
  tests/test_query_cache.py
170
170
  tests/test_row_batch_update.py
171
+ tests/test_row_cache_staleness.py
171
172
  tests/test_sqs_per_record_transactions.py
172
173
  tests/test_sys_modified_count_postgres_demo.py
173
174
  tests/test_table_alter.py
@@ -1,9 +1,11 @@
1
+ sqlparse>=0.5.0
2
+
3
+ [all]
4
+ velocity-python[aws,excel,http,payment,postgres,templates]
5
+
6
+ [aws]
1
7
  boto3>=1.35.0
2
8
  requests>=2.32.0
3
- jinja2>=3.1.0
4
- xlrd>=2.0.1
5
- openpyxl>=3.1.0
6
- sqlparse>=0.5.0
7
9
 
8
10
  [dev]
9
11
  pytest>=8.0.0
@@ -17,6 +19,12 @@ pre-commit>=4.0.0
17
19
  sphinx>=8.0.0
18
20
  sphinx-rtd-theme>=3.0.0
19
21
 
22
+ [excel]
23
+ openpyxl>=3.1.0
24
+
25
+ [http]
26
+ requests>=2.32.0
27
+
20
28
  [mysql]
21
29
  mysql-connector-python>=9.0.0
22
30
 
@@ -30,6 +38,9 @@ psycopg[binary]>=3.2.0
30
38
  [sqlserver]
31
39
  python-tds>=1.15.0
32
40
 
41
+ [templates]
42
+ jinja2>=3.1.0
43
+
33
44
  [test]
34
45
  pytest>=8.0.0
35
46
  pytest-cov>=6.0.0
@@ -26,6 +26,9 @@ def _make_row(cache=None, pk=None):
26
26
  object.__setattr__(row, "_column_set", None)
27
27
  object.__setattr__(row, "_batching", False)
28
28
  object.__setattr__(row, "_pending", {})
29
+ object.__setattr__(row, "_cache_ttl", None)
30
+ object.__setattr__(row, "_cache_time", None)
31
+ object.__setattr__(row, "_no_cache", False)
29
32
  return row
30
33
 
31
34