velocity-python 0.1.35__tar.gz → 0.1.37__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 (189) hide show
  1. {velocity_python-0.1.35/src/velocity_python.egg-info → velocity_python-0.1.37}/PKG-INFO +1 -1
  2. {velocity_python-0.1.35 → velocity_python-0.1.37}/pyproject.toml +1 -1
  3. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/__init__.py +1 -1
  4. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/braintree_mirror.py +66 -9
  5. {velocity_python-0.1.35 → velocity_python-0.1.37/src/velocity_python.egg-info}/PKG-INFO +1 -1
  6. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity_python.egg-info/SOURCES.txt +1 -0
  7. velocity_python-0.1.37/tests/test_payment_braintree_mirror.py +130 -0
  8. {velocity_python-0.1.35 → velocity_python-0.1.37}/LICENSE +0 -0
  9. {velocity_python-0.1.35 → velocity_python-0.1.37}/README.md +0 -0
  10. {velocity_python-0.1.35 → velocity_python-0.1.37}/setup.cfg +0 -0
  11. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/__init__.py +0 -0
  12. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/amplify.py +0 -0
  13. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/amplify_build.py +0 -0
  14. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/assets/__init__.py +0 -0
  15. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/assets/backfill.py +0 -0
  16. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/assets/indexing.py +0 -0
  17. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/assets/references.py +0 -0
  18. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/assets/service.py +0 -0
  19. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/assets/usage_index.py +0 -0
  20. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/dirty_pipeline.py +0 -0
  21. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/__init__.py +0 -0
  22. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/base_handler.py +0 -0
  23. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/context.py +0 -0
  24. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/context_factory.py +0 -0
  25. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/exceptions.py +0 -0
  26. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/lambda_handler.py +0 -0
  27. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/mixins/__init__.py +0 -0
  28. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/mixins/data_service.py +0 -0
  29. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/mixins/web_handler.py +0 -0
  30. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/perf.py +0 -0
  31. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/response.py +0 -0
  32. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  33. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/s3.py +0 -0
  34. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/ssm_config.py +0 -0
  35. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/tests/__init__.py +0 -0
  36. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/tests/test_base_handler_error_response.py +0 -0
  37. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/tests/test_lambda_handler_json_serialization.py +0 -0
  38. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/aws/tests/test_response.py +0 -0
  39. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/__init__.py +0 -0
  40. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/__init__.py +0 -0
  41. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/async_support.py +0 -0
  42. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/column.py +0 -0
  43. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/database.py +0 -0
  44. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/decorators.py +0 -0
  45. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/engine.py +0 -0
  46. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/result.py +0 -0
  47. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/row.py +0 -0
  48. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/sequence.py +0 -0
  49. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/table.py +0 -0
  50. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/transaction.py +0 -0
  51. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/core/view.py +0 -0
  52. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/exceptions.py +0 -0
  53. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/migrations.py +0 -0
  54. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/__init__.py +0 -0
  55. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/base/__init__.py +0 -0
  56. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/base/initializer.py +0 -0
  57. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/base/operators.py +0 -0
  58. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/base/sql.py +0 -0
  59. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/base/types.py +0 -0
  60. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/mysql/__init__.py +0 -0
  61. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/mysql/operators.py +0 -0
  62. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/mysql/reserved.py +0 -0
  63. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/mysql/sql.py +0 -0
  64. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/mysql/types.py +0 -0
  65. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/postgres/__init__.py +0 -0
  66. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/postgres/operators.py +0 -0
  67. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/postgres/reserved.py +0 -0
  68. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/postgres/sql.py +0 -0
  69. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/postgres/types.py +0 -0
  70. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlite/__init__.py +0 -0
  71. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlite/operators.py +0 -0
  72. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlite/reserved.py +0 -0
  73. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlite/sql.py +0 -0
  74. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlite/types.py +0 -0
  75. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlserver/__init__.py +0 -0
  76. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlserver/operators.py +0 -0
  77. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlserver/reserved.py +0 -0
  78. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlserver/sql.py +0 -0
  79. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/sqlserver/types.py +0 -0
  80. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/servers/tablehelper.py +0 -0
  81. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/__init__.py +0 -0
  82. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/common_db_test.py +0 -0
  83. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/__init__.py +0 -0
  84. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/common.py +0 -0
  85. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_column.py +0 -0
  86. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_connections.py +0 -0
  87. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_database.py +0 -0
  88. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_engine.py +0 -0
  89. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_general_usage.py +0 -0
  90. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_imports.py +0 -0
  91. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_result.py +0 -0
  92. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_row.py +0 -0
  93. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_row_comprehensive.py +0 -0
  94. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_schema_locking.py +0 -0
  95. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_schema_locking_unit.py +0 -0
  96. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_sequence.py +0 -0
  97. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_sql_comprehensive.py +0 -0
  98. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_table.py +0 -0
  99. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_table_comprehensive.py +0 -0
  100. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/postgres/test_transaction.py +0 -0
  101. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/sql/__init__.py +0 -0
  102. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/sql/common.py +0 -0
  103. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/sql/test_postgres_select_advanced.py +0 -0
  104. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/sql/test_postgres_select_variances.py +0 -0
  105. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_cursor_rowcount_fix.py +0 -0
  106. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_db_utils.py +0 -0
  107. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_postgres.py +0 -0
  108. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_postgres_unchanged.py +0 -0
  109. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_process_error_robustness.py +0 -0
  110. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_result_caching.py +0 -0
  111. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_result_sql_aware.py +0 -0
  112. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_row_get_missing_column.py +0 -0
  113. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_schema_locking_initializers.py +0 -0
  114. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_schema_locking_simple.py +0 -0
  115. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_sql_builder.py +0 -0
  116. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_tablehelper.py +0 -0
  117. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/tests/test_view_helper.py +0 -0
  118. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/db/utils.py +0 -0
  119. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/logging.py +0 -0
  120. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/__init__.py +0 -0
  121. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/conv/__init__.py +0 -0
  122. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/conv/iconv.py +0 -0
  123. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/conv/oconv.py +0 -0
  124. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/db.py +0 -0
  125. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/export.py +0 -0
  126. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/format.py +0 -0
  127. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/mail.py +0 -0
  128. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/merge.py +0 -0
  129. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/pdf.py +0 -0
  130. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/__init__.py +0 -0
  131. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_db.py +0 -0
  132. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_fix.py +0 -0
  133. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_format.py +0 -0
  134. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_iconv.py +0 -0
  135. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_merge.py +0 -0
  136. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_oconv.py +0 -0
  137. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_original_error.py +0 -0
  138. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tests/test_timer.py +0 -0
  139. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/timer.py +0 -0
  140. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/misc/tools.py +0 -0
  141. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/__init__.py +0 -0
  142. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/authorizenet_adapter.py +0 -0
  143. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/authorizenet_mirror.py +0 -0
  144. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/base_adapter.py +0 -0
  145. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/braintree_adapter.py +0 -0
  146. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/charge_rules.py +0 -0
  147. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/stripe_adapter.py +0 -0
  148. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity/payment/stripe_mirror.py +0 -0
  149. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  150. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity_python.egg-info/entry_points.txt +0 -0
  151. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity_python.egg-info/requires.txt +0 -0
  152. {velocity_python-0.1.35 → velocity_python-0.1.37}/src/velocity_python.egg-info/top_level.txt +0 -0
  153. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_amplify_build.py +0 -0
  154. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_asset_indexing.py +0 -0
  155. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_asset_references.py +0 -0
  156. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_assets_service.py +0 -0
  157. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_async_support.py +0 -0
  158. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_batch_operations.py +0 -0
  159. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_concurrency_safety.py +0 -0
  160. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_connection_pool.py +0 -0
  161. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_connection_resilience.py +0 -0
  162. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_decorators.py +0 -0
  163. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_dirty_pipeline_fast_path.py +0 -0
  164. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_email_processing.py +0 -0
  165. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_iconv_money_to_cents.py +0 -0
  166. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_lambda_handler.py +0 -0
  167. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_lambda_handler_auth.py +0 -0
  168. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_mixins_import.py +0 -0
  169. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_n_plus_one.py +0 -0
  170. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_observability.py +0 -0
  171. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_payment_authorizenet_adapter.py +0 -0
  172. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_payment_braintree_adapter.py +0 -0
  173. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_payment_profile_sorting.py +0 -0
  174. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_payment_stripe_adapter.py +0 -0
  175. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_pdf.py +0 -0
  176. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_prepared_statements.py +0 -0
  177. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_psycopg3_upgrade.py +0 -0
  178. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_query_cache.py +0 -0
  179. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_row_batch_update.py +0 -0
  180. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_row_cache_staleness.py +0 -0
  181. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_row_dirty_tracking.py +0 -0
  182. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_schema_migrations.py +0 -0
  183. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_security_hardening.py +0 -0
  184. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_server_cursor.py +0 -0
  185. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_spreadsheet_functions.py +0 -0
  186. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_sqs_per_record_transactions.py +0 -0
  187. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_sys_modified_count_postgres_demo.py +0 -0
  188. {velocity_python-0.1.35 → velocity_python-0.1.37}/tests/test_table_alter.py +0 -0
  189. {velocity_python-0.1.35 → velocity_python-0.1.37}/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.35
3
+ Version: 0.1.37
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.35"
7
+ version = "0.1.37"
8
8
  authors = [
9
9
  { name="Velocity Team", email="info@codeclubs.org" },
10
10
  ]
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.1.35"
1
+ __version__ = version = "0.1.37"
2
2
 
3
3
  import importlib as _importlib
4
4
 
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from datetime import datetime, timezone
3
- from typing import Any, Dict, Optional
3
+ from typing import Any, Dict, Optional, Set
4
4
 
5
5
 
6
6
  SUCCESS_STATUSES = {
@@ -19,19 +19,61 @@ def _get_value(data: Any, key: str, default: Any = None) -> Any:
19
19
  return getattr(data, key, default)
20
20
 
21
21
 
22
- def _to_jsonable(value: Any) -> Any:
22
+ def _recursive_marker(value: Any) -> str:
23
+ return f"<recursive:{type(value).__name__}>"
24
+
25
+
26
+ def _attribute_getter_fields(value: Any):
27
+ fields = getattr(value, "_setattrs", None)
28
+ if not isinstance(fields, (list, tuple, set)):
29
+ return None
30
+ return [str(field) for field in fields if not str(field).startswith("_")]
31
+
32
+
33
+ def _to_jsonable(value: Any, _stack: Optional[Set[int]] = None) -> Any:
23
34
  if value is None or isinstance(value, (str, int, float, bool)):
24
35
  return value
36
+ if _stack is None:
37
+ _stack = set()
38
+
39
+ value_id = id(value)
40
+ if value_id in _stack:
41
+ return _recursive_marker(value)
42
+
25
43
  if isinstance(value, dict):
26
- return {str(key): _to_jsonable(item) for key, item in value.items()}
44
+ _stack.add(value_id)
45
+ try:
46
+ return {
47
+ str(key): _to_jsonable(item, _stack) for key, item in value.items()
48
+ }
49
+ finally:
50
+ _stack.remove(value_id)
27
51
  if isinstance(value, (list, tuple, set)):
28
- return [_to_jsonable(item) for item in value]
52
+ _stack.add(value_id)
53
+ try:
54
+ return [_to_jsonable(item, _stack) for item in value]
55
+ finally:
56
+ _stack.remove(value_id)
57
+ attribute_fields = _attribute_getter_fields(value)
58
+ if attribute_fields is not None:
59
+ _stack.add(value_id)
60
+ try:
61
+ return {
62
+ key: _to_jsonable(getattr(value, key, None), _stack)
63
+ for key in attribute_fields
64
+ }
65
+ finally:
66
+ _stack.remove(value_id)
29
67
  if hasattr(value, "__dict__"):
30
- return {
31
- str(key): _to_jsonable(item)
32
- for key, item in vars(value).items()
33
- if not str(key).startswith("_")
34
- }
68
+ _stack.add(value_id)
69
+ try:
70
+ return {
71
+ str(key): _to_jsonable(item, _stack)
72
+ for key, item in vars(value).items()
73
+ if not str(key).startswith("_")
74
+ }
75
+ finally:
76
+ _stack.remove(value_id)
35
77
  return str(value)
36
78
 
37
79
 
@@ -56,10 +98,25 @@ def _table(tx, table_name: str):
56
98
  return table
57
99
 
58
100
 
101
+ def _filtered_payload_for_table(table, payload: Dict[str, Any]) -> Dict[str, Any]:
102
+ try:
103
+ existing_columns = {
104
+ str(column).lower() for column in (table.sys_columns() or [])
105
+ }
106
+ except Exception:
107
+ return payload
108
+ if not existing_columns:
109
+ return payload
110
+ return {
111
+ key: value for key, value in payload.items() if str(key).lower() in existing_columns
112
+ }
113
+
114
+
59
115
  def _upsert(tx, table_name: str, payload: Dict[str, Any], key: Dict[str, Any]):
60
116
  table = _table(tx, table_name)
61
117
  if not table:
62
118
  return None
119
+ payload = _filtered_payload_for_table(table, payload)
63
120
  table.upsert(payload, key)
64
121
  return payload
65
122
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.1.35
3
+ Version: 0.1.37
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
@@ -167,6 +167,7 @@ tests/test_n_plus_one.py
167
167
  tests/test_observability.py
168
168
  tests/test_payment_authorizenet_adapter.py
169
169
  tests/test_payment_braintree_adapter.py
170
+ tests/test_payment_braintree_mirror.py
170
171
  tests/test_payment_profile_sorting.py
171
172
  tests/test_payment_stripe_adapter.py
172
173
  tests/test_pdf.py
@@ -0,0 +1,130 @@
1
+ import json
2
+
3
+ from velocity.payment.braintree_mirror import upsert_braintree_transaction_record
4
+
5
+
6
+ class FakeTable:
7
+ def __init__(self):
8
+ self.upserts = []
9
+
10
+ def exists(self):
11
+ return True
12
+
13
+ def upsert(self, payload, key):
14
+ self.upserts.append((payload, key))
15
+
16
+
17
+ class ColumnAwareTable(FakeTable):
18
+ def __init__(self, columns):
19
+ super().__init__()
20
+ self._columns = columns
21
+
22
+ def sys_columns(self):
23
+ return list(self._columns)
24
+
25
+
26
+ class FakeTx:
27
+ def __init__(self):
28
+ self._table = FakeTable()
29
+
30
+ def table(self, table_name):
31
+ assert table_name == "braintree_transaction"
32
+ return self._table
33
+
34
+
35
+ class ColumnAwareTx(FakeTx):
36
+ def __init__(self, columns):
37
+ self._table = ColumnAwareTable(columns)
38
+
39
+
40
+ class RecursiveTransaction:
41
+ def __init__(self):
42
+ self.id = "txn_recursive"
43
+ self.status = "submitted_for_settlement"
44
+ self.amount = "10.50"
45
+ self.custom_fields = {"client_id": "client_1"}
46
+ self.credit_card_details = None
47
+ self.paypal_details = None
48
+ self.customer_details = None
49
+ self.billing_details = None
50
+ self.child = self
51
+
52
+
53
+ class GatewayInternal:
54
+ def __init__(self):
55
+ self.configuration = {"private_key": "secret"}
56
+
57
+
58
+ class AttributeGetterStyleTransaction:
59
+ def __init__(self):
60
+ self._setattrs = [
61
+ "id",
62
+ "status",
63
+ "amount",
64
+ "custom_fields",
65
+ "credit_card_details",
66
+ "paypal_details",
67
+ "customer_details",
68
+ "billing_details",
69
+ "child",
70
+ ]
71
+ self.id = "txn_gateway_trimmed"
72
+ self.status = "submitted_for_settlement"
73
+ self.amount = "42.00"
74
+ self.custom_fields = {"client_id": "client_2"}
75
+ self.credit_card_details = None
76
+ self.paypal_details = None
77
+ self.customer_details = None
78
+ self.billing_details = None
79
+ self.child = self
80
+ self.gateway = GatewayInternal()
81
+
82
+
83
+ def test_upsert_braintree_transaction_record_handles_recursive_objects():
84
+ tx = FakeTx()
85
+ transaction = RecursiveTransaction()
86
+
87
+ payload = upsert_braintree_transaction_record(tx, transaction)
88
+
89
+ assert payload is not None
90
+ assert payload["braintree_id"] == "txn_recursive"
91
+ raw_response = json.loads(payload["raw_response"])
92
+ assert raw_response["id"] == "txn_recursive"
93
+ assert raw_response["child"] == "<recursive:RecursiveTransaction>"
94
+ assert tx._table.upserts
95
+
96
+
97
+ def test_upsert_braintree_transaction_record_skips_gateway_internals():
98
+ tx = FakeTx()
99
+ transaction = AttributeGetterStyleTransaction()
100
+
101
+ payload = upsert_braintree_transaction_record(tx, transaction)
102
+
103
+ assert payload is not None
104
+ raw_response = json.loads(payload["raw_response"])
105
+ assert raw_response["id"] == "txn_gateway_trimmed"
106
+ assert raw_response["child"] == "<recursive:AttributeGetterStyleTransaction>"
107
+ assert "gateway" not in raw_response
108
+ assert tx._table.upserts
109
+
110
+
111
+ def test_upsert_braintree_transaction_record_omits_missing_columns():
112
+ tx = ColumnAwareTx(
113
+ [
114
+ "braintree_id",
115
+ "status",
116
+ "amount",
117
+ "amount_attempted",
118
+ "authorized_amount",
119
+ "payment_ok",
120
+ ]
121
+ )
122
+ transaction = RecursiveTransaction()
123
+
124
+ payload = upsert_braintree_transaction_record(tx, transaction)
125
+
126
+ assert payload is not None
127
+ assert payload["braintree_id"] == "txn_recursive"
128
+ assert "raw_response" not in payload
129
+ assert "update_source" not in payload
130
+ assert tx._table.upserts