velocity-python 0.1.28__tar.gz → 0.1.29__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 (187) hide show
  1. {velocity_python-0.1.28/src/velocity_python.egg-info → velocity_python-0.1.29}/PKG-INFO +5 -1
  2. {velocity_python-0.1.28 → velocity_python-0.1.29}/pyproject.toml +7 -1
  3. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/data_service.py +165 -6
  5. {velocity_python-0.1.28 → velocity_python-0.1.29/src/velocity_python.egg-info}/PKG-INFO +5 -1
  6. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity_python.egg-info/requires.txt +6 -0
  7. {velocity_python-0.1.28 → velocity_python-0.1.29}/LICENSE +0 -0
  8. {velocity_python-0.1.28 → velocity_python-0.1.29}/README.md +0 -0
  9. {velocity_python-0.1.28 → velocity_python-0.1.29}/setup.cfg +0 -0
  10. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/__init__.py +0 -0
  11. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/amplify.py +0 -0
  12. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/amplify_build.py +0 -0
  13. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/assets/__init__.py +0 -0
  14. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/assets/backfill.py +0 -0
  15. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/assets/indexing.py +0 -0
  16. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/assets/references.py +0 -0
  17. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/assets/service.py +0 -0
  18. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/assets/usage_index.py +0 -0
  19. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/dirty_pipeline.py +0 -0
  20. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/__init__.py +0 -0
  21. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/base_handler.py +0 -0
  22. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/context.py +0 -0
  23. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/context_factory.py +0 -0
  24. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/exceptions.py +0 -0
  25. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  26. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  27. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  28. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/perf.py +0 -0
  29. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/response.py +0 -0
  30. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  31. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/s3.py +0 -0
  32. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/ssm_config.py +0 -0
  33. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/tests/__init__.py +0 -0
  34. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  35. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  36. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/aws/tests/test_response.py +0 -0
  37. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/__init__.py +0 -0
  38. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/__init__.py +0 -0
  39. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/async_support.py +0 -0
  40. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/column.py +0 -0
  41. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/database.py +0 -0
  42. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/decorators.py +0 -0
  43. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/engine.py +0 -0
  44. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/result.py +0 -0
  45. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/row.py +0 -0
  46. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/sequence.py +0 -0
  47. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/table.py +0 -0
  48. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/transaction.py +0 -0
  49. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/core/view.py +0 -0
  50. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/exceptions.py +0 -0
  51. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/migrations.py +0 -0
  52. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/__init__.py +0 -0
  53. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/base/__init__.py +0 -0
  54. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/base/initializer.py +0 -0
  55. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/base/operators.py +0 -0
  56. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/base/sql.py +0 -0
  57. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/base/types.py +0 -0
  58. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/__init__.py +0 -0
  59. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/operators.py +0 -0
  60. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/reserved.py +0 -0
  61. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/sql.py +0 -0
  62. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/mysql/types.py +0 -0
  63. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/__init__.py +0 -0
  64. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/operators.py +0 -0
  65. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/reserved.py +0 -0
  66. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/sql.py +0 -0
  67. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/postgres/types.py +0 -0
  68. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  69. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/operators.py +0 -0
  70. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  71. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/sql.py +0 -0
  72. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlite/types.py +0 -0
  73. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  74. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  75. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  76. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  77. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/sqlserver/types.py +0 -0
  78. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/servers/tablehelper.py +0 -0
  79. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/__init__.py +0 -0
  80. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/common_db_test.py +0 -0
  81. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/__init__.py +0 -0
  82. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/common.py +0 -0
  83. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_column.py +0 -0
  84. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  85. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_database.py +0 -0
  86. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  87. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  88. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  89. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_result.py +0 -0
  90. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_row.py +0 -0
  91. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  92. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  93. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  94. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  95. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  96. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_table.py +0 -0
  97. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  98. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  99. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/sql/__init__.py +0 -0
  100. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/sql/common.py +0 -0
  101. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  102. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  103. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  104. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_db_utils.py +0 -0
  105. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_postgres.py +0 -0
  106. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  107. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  108. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_result_caching.py +0 -0
  109. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  110. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  111. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  112. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  113. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_sql_builder.py +0 -0
  114. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_tablehelper.py +0 -0
  115. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/tests/test_view_helper.py +0 -0
  116. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/db/utils.py +0 -0
  117. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/logging.py +0 -0
  118. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/__init__.py +0 -0
  119. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/conv/__init__.py +0 -0
  120. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/conv/iconv.py +0 -0
  121. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/conv/oconv.py +0 -0
  122. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/db.py +0 -0
  123. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/export.py +0 -0
  124. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/format.py +0 -0
  125. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/mail.py +0 -0
  126. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/merge.py +0 -0
  127. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/pdf.py +0 -0
  128. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/__init__.py +0 -0
  129. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_db.py +0 -0
  130. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_fix.py +0 -0
  131. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_format.py +0 -0
  132. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_iconv.py +0 -0
  133. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_merge.py +0 -0
  134. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_oconv.py +0 -0
  135. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_original_error.py +0 -0
  136. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tests/test_timer.py +0 -0
  137. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/timer.py +0 -0
  138. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/misc/tools.py +0 -0
  139. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/__init__.py +0 -0
  140. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/authorizenet_adapter.py +0 -0
  141. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/authorizenet_mirror.py +0 -0
  142. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/base_adapter.py +0 -0
  143. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/braintree_adapter.py +0 -0
  144. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/braintree_mirror.py +0 -0
  145. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/charge_rules.py +0 -0
  146. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/stripe_adapter.py +0 -0
  147. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity/payment/stripe_mirror.py +0 -0
  148. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity_python.egg-info/SOURCES.txt +0 -0
  149. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  150. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity_python.egg-info/entry_points.txt +0 -0
  151. {velocity_python-0.1.28 → velocity_python-0.1.29}/src/velocity_python.egg-info/top_level.txt +0 -0
  152. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_amplify_build.py +0 -0
  153. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_asset_indexing.py +0 -0
  154. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_asset_references.py +0 -0
  155. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_assets_service.py +0 -0
  156. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_async_support.py +0 -0
  157. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_batch_operations.py +0 -0
  158. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_concurrency_safety.py +0 -0
  159. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_connection_pool.py +0 -0
  160. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_connection_resilience.py +0 -0
  161. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_decorators.py +0 -0
  162. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_dirty_pipeline_fast_path.py +0 -0
  163. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_email_processing.py +0 -0
  164. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_iconv_money_to_cents.py +0 -0
  165. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_lambda_handler.py +0 -0
  166. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_lambda_handler_auth.py +0 -0
  167. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_mixins_import.py +0 -0
  168. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_n_plus_one.py +0 -0
  169. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_observability.py +0 -0
  170. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_payment_authorizenet_adapter.py +0 -0
  171. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_payment_braintree_adapter.py +0 -0
  172. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_payment_profile_sorting.py +0 -0
  173. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_payment_stripe_adapter.py +0 -0
  174. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_pdf.py +0 -0
  175. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_prepared_statements.py +0 -0
  176. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_psycopg3_upgrade.py +0 -0
  177. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_query_cache.py +0 -0
  178. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_row_batch_update.py +0 -0
  179. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_row_cache_staleness.py +0 -0
  180. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_row_dirty_tracking.py +0 -0
  181. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_schema_migrations.py +0 -0
  182. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_security_hardening.py +0 -0
  183. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_spreadsheet_functions.py +0 -0
  184. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_sqs_per_record_transactions.py +0 -0
  185. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  186. {velocity_python-0.1.28 → velocity_python-0.1.29}/tests/test_table_alter.py +0 -0
  187. {velocity_python-0.1.28 → velocity_python-0.1.29}/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.28
3
+ Version: 0.1.29
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
@@ -27,6 +27,10 @@ Requires-Dist: boto3>=1.35.0; extra == "aws"
27
27
  Requires-Dist: requests>=2.32.0; extra == "aws"
28
28
  Provides-Extra: excel
29
29
  Requires-Dist: openpyxl>=3.1.0; extra == "excel"
30
+ Provides-Extra: parquet
31
+ Requires-Dist: pyarrow>=15.0.0; extra == "parquet"
32
+ Provides-Extra: ods
33
+ Requires-Dist: odfpy>=1.4.0; extra == "ods"
30
34
  Provides-Extra: templates
31
35
  Requires-Dist: jinja2>=3.1.0; extra == "templates"
32
36
  Provides-Extra: pdf
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "velocity-python"
7
- version = "0.1.28"
7
+ version = "0.1.29"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -45,6 +45,12 @@ aws = [
45
45
  excel = [
46
46
  "openpyxl>=3.1.0",
47
47
  ]
48
+ parquet = [
49
+ "pyarrow>=15.0.0",
50
+ ]
51
+ ods = [
52
+ "odfpy>=1.4.0",
53
+ ]
48
54
  templates = [
49
55
  "jinja2>=3.1.0",
50
56
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.28"
1
+ __version__ = version = "0.1.29"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -6,11 +6,14 @@ that uses velocity.db for database access.
6
6
  """
7
7
 
8
8
  import base64
9
+ import csv
9
10
  import datetime
10
11
  import importlib
12
+ import json
11
13
  import logging
12
14
  import re
13
- from io import BytesIO
15
+ import xml.etree.ElementTree as ET
16
+ from io import BytesIO, StringIO
14
17
 
15
18
  from velocity.aws import dirty_pipeline
16
19
  from velocity.misc import export
@@ -333,7 +336,8 @@ class DataServiceMixin:
333
336
  "message": message,
334
337
  "missing": missing,
335
338
  }
336
- if result_format == "excel":
339
+ _file_export_formats_early = {"excel", "csv", "tsv", "json", "jsonl", "xml", "html", "markdown", "xlsx", "parquet", "ods"}
340
+ if result_format in _file_export_formats_early:
337
341
  return {
338
342
  "headers": payload.get("headers", []),
339
343
  "rows": [],
@@ -354,7 +358,10 @@ class DataServiceMixin:
354
358
  swallowed_error = getattr(tx, "_last_return_default_error", None)
355
359
  if swallowed_error:
356
360
  tx._last_return_default_error = None
357
- if result_format == "excel":
361
+
362
+ _file_export_formats = {"excel", "csv", "tsv", "json", "jsonl", "xml", "html", "markdown", "xlsx", "parquet", "ods"}
363
+
364
+ if result_format in _file_export_formats:
358
365
  data = {
359
366
  "headers": payload.get(
360
367
  "headers", [x.replace("_", " ").title() for x in result.headers]
@@ -373,7 +380,7 @@ class DataServiceMixin:
373
380
 
374
381
  # If the DB call failed but was swallowed (return_default), surface a reason.
375
382
  # Common symptoms are empty rows + null SQL.
376
- if swallowed_error and result_format == "excel":
383
+ if swallowed_error and result_format in _file_export_formats:
377
384
  error_message = swallowed_error.get("message") or "Unknown database error"
378
385
  context.response().toast(
379
386
  f"Query failed for '{obj}': {error_message.splitlines()[0]}",
@@ -575,6 +582,143 @@ class DataServiceMixin:
575
582
  #
576
583
  # Payload parameters
577
584
 
585
+ # ---------------------------------------------------------------------------
586
+ # Export format helpers
587
+ # ---------------------------------------------------------------------------
588
+
589
+ @staticmethod
590
+ def _safe_xml_tag(name):
591
+ """Sanitise a column name so it is a valid XML element name."""
592
+ tag = re.sub(r"[^a-zA-Z0-9_.-]", "_", str(name))
593
+ if tag and tag[0].isdigit():
594
+ tag = "_" + tag
595
+ return tag or "_col"
596
+
597
+ @classmethod
598
+ def _build_export_buffer(cls, result_format, headers, rows, filename_base):
599
+ """
600
+ Build a (bytes_buffer, filename, mime_type) tuple for the given
601
+ result_format. Returns None if the format is not handled here.
602
+ """
603
+ if result_format == "csv":
604
+ buf = StringIO()
605
+ writer = csv.writer(buf)
606
+ writer.writerow(headers)
607
+ writer.writerows(rows)
608
+ return buf.getvalue().encode("utf-8"), f"{filename_base}.csv", "text/csv"
609
+
610
+ if result_format == "tsv":
611
+ buf = StringIO()
612
+ writer = csv.writer(buf, delimiter="\t")
613
+ writer.writerow(headers)
614
+ writer.writerows(rows)
615
+ return buf.getvalue().encode("utf-8"), f"{filename_base}.tsv", "text/tab-separated-values"
616
+
617
+ if result_format == "json":
618
+ data = [dict(zip(headers, row)) for row in rows]
619
+ return json.dumps(data, default=str).encode("utf-8"), f"{filename_base}.json", "application/json"
620
+
621
+ if result_format == "jsonl":
622
+ lines = [json.dumps(dict(zip(headers, row)), default=str) for row in rows]
623
+ return "\n".join(lines).encode("utf-8"), f"{filename_base}.jsonl", "application/x-ndjson"
624
+
625
+ if result_format == "xml":
626
+ root = ET.Element("rows")
627
+ for row in rows:
628
+ row_el = ET.SubElement(root, "row")
629
+ for header, value in zip(headers, row):
630
+ col_el = ET.SubElement(row_el, cls._safe_xml_tag(header))
631
+ col_el.text = "" if value is None else str(value)
632
+ xml_bytes = ET.tostring(root, encoding="unicode").encode("utf-8")
633
+ return xml_bytes, f"{filename_base}.xml", "application/xml"
634
+
635
+ if result_format == "html":
636
+ th_cells = "".join(f"<th>{h}</th>" for h in headers)
637
+ tr_rows = "".join(
638
+ "<tr>" + "".join(f"<td>{'' if v is None else str(v)}</td>" for v in row) + "</tr>"
639
+ for row in rows
640
+ )
641
+ html = (
642
+ f"<!DOCTYPE html><html><head><meta charset='utf-8'></head>"
643
+ f"<body><table border='1'><thead><tr>{th_cells}</tr></thead>"
644
+ f"<tbody>{tr_rows}</tbody></table></body></html>"
645
+ )
646
+ return html.encode("utf-8"), f"{filename_base}.html", "text/html"
647
+
648
+ if result_format == "markdown":
649
+ header_row = "| " + " | ".join(str(h) for h in headers) + " |"
650
+ separator = "| " + " | ".join("---" for _ in headers) + " |"
651
+ data_rows = [
652
+ "| " + " | ".join("" if v is None else str(v) for v in row) + " |"
653
+ for row in rows
654
+ ]
655
+ md = "\n".join([header_row, separator] + data_rows)
656
+ return md.encode("utf-8"), f"{filename_base}.md", "text/markdown"
657
+
658
+ if result_format == "xlsx":
659
+ try:
660
+ from openpyxl import Workbook
661
+ except ImportError:
662
+ raise ImportError("openpyxl is required for xlsx export (install velocity-python[excel])")
663
+ wb = Workbook()
664
+ ws = wb.active
665
+ ws.append(list(headers))
666
+ for row in rows:
667
+ ws.append(list(row))
668
+ buf = BytesIO()
669
+ wb.save(buf)
670
+ return (
671
+ buf.getvalue(),
672
+ f"{filename_base}.xlsx",
673
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
674
+ )
675
+
676
+ if result_format == "parquet":
677
+ try:
678
+ import pyarrow as pa
679
+ import pyarrow.parquet as pq
680
+ except ImportError:
681
+ raise ImportError("pyarrow is required for parquet export (install velocity-python[parquet])")
682
+ table = pa.table({h: [row[i] for row in rows] for i, h in enumerate(headers)})
683
+ buf = BytesIO()
684
+ pq.write_table(table, buf)
685
+ return buf.getvalue(), f"{filename_base}.parquet", "application/octet-stream"
686
+
687
+ if result_format == "ods":
688
+ try:
689
+ from odf.opendocument import OpenDocumentSpreadsheet
690
+ from odf.table import Table, TableRow, TableCell
691
+ from odf.text import P
692
+ except ImportError:
693
+ raise ImportError("odfpy is required for ods export (install velocity-python[ods])")
694
+ doc = OpenDocumentSpreadsheet()
695
+ sheet = Table(name="Sheet1")
696
+ doc.spreadsheet.addElement(sheet)
697
+ header_row_el = TableRow()
698
+ for h in headers:
699
+ cell = TableCell()
700
+ cell.addElement(P(text=str(h)))
701
+ header_row_el.addElement(cell)
702
+ sheet.addElement(header_row_el)
703
+ for row in rows:
704
+ tr = TableRow()
705
+ for v in row:
706
+ cell = TableCell()
707
+ cell.addElement(P(text="" if v is None else str(v)))
708
+ tr.addElement(cell)
709
+ sheet.addElement(tr)
710
+ buf = BytesIO()
711
+ doc.save(buf)
712
+ return (
713
+ buf.getvalue(),
714
+ f"{filename_base}.ods",
715
+ "application/vnd.oasis.opendocument.spreadsheet",
716
+ )
717
+
718
+ return None
719
+
720
+ # ---------------------------------------------------------------------------
721
+
578
722
  def OnActionQuery(self, tx, context):
579
723
  payload = context.payload()
580
724
 
@@ -586,8 +730,10 @@ class DataServiceMixin:
586
730
  if not table:
587
731
  raise ValueError("Parameter 'obj' cannot be empty")
588
732
 
733
+ result_format = payload.get("result_format")
589
734
  data = self.query_hook(tx, table, payload, context)
590
- if payload.get("result_format") == "excel":
735
+
736
+ if result_format == "excel":
591
737
  filebuffer = BytesIO()
592
738
  export.create_spreadsheet(data["headers"], data["rows"], filebuffer)
593
739
  context.response().file_download(
@@ -598,7 +744,20 @@ class DataServiceMixin:
598
744
  )
599
745
  return
600
746
 
601
- if payload.get("result_format") == "raw":
747
+ if result_format in ("csv", "tsv", "json", "jsonl", "xml", "html", "markdown", "xlsx", "parquet", "ods"):
748
+ filename_base = payload.get("filename_base") or table
749
+ built = self._build_export_buffer(result_format, data.get("headers", []), data.get("rows", []), filename_base)
750
+ if built is not None:
751
+ file_bytes, filename, _mime = built
752
+ context.response().file_download(
753
+ {
754
+ "filename": filename,
755
+ "data": base64.b64encode(file_bytes).decode(),
756
+ }
757
+ )
758
+ return
759
+
760
+ if result_format == "raw":
602
761
  context.response().set_body(data)
603
762
  else:
604
763
  context.response().set_table(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.28
3
+ Version: 0.1.29
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
@@ -27,6 +27,10 @@ Requires-Dist: boto3>=1.35.0; extra == "aws"
27
27
  Requires-Dist: requests>=2.32.0; extra == "aws"
28
28
  Provides-Extra: excel
29
29
  Requires-Dist: openpyxl>=3.1.0; extra == "excel"
30
+ Provides-Extra: parquet
31
+ Requires-Dist: pyarrow>=15.0.0; extra == "parquet"
32
+ Provides-Extra: ods
33
+ Requires-Dist: odfpy>=1.4.0; extra == "ods"
30
34
  Provides-Extra: templates
31
35
  Requires-Dist: jinja2>=3.1.0; extra == "templates"
32
36
  Provides-Extra: pdf
@@ -29,6 +29,12 @@ requests>=2.32.0
29
29
  [mysql]
30
30
  mysql-connector-python>=9.0.0
31
31
 
32
+ [ods]
33
+ odfpy>=1.4.0
34
+
35
+ [parquet]
36
+ pyarrow>=15.0.0
37
+
32
38
  [payment]
33
39
  stripe>=12.0.0
34
40
  braintree>=4.30.0