openretailscience 0.47.0__tar.gz → 0.48.1__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 (332) hide show
  1. openretailscience-0.48.1/.env_sample +9 -0
  2. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/bigquery-integration.yml +3 -3
  3. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/claude-code-review.yml +5 -2
  4. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/claude.yml +2 -2
  5. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/cloudflare-docs-preview.yml +10 -11
  6. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/gh-page.yml +3 -3
  7. openretailscience-0.48.1/.github/workflows/oracle-integration.yml +46 -0
  8. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/pyspark-integration.yml +3 -3
  9. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/release.yml +20 -12
  10. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/security-audit.yml +6 -6
  11. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/slack-notifications.yml +8 -2
  12. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/workflows/snowflake-integration.yml +3 -3
  13. openretailscience-0.48.1/.github/workflows/sqlserver-integration.yml +64 -0
  14. openretailscience-0.48.1/.github/workflows/test.yml +104 -0
  15. {openretailscience-0.47.0 → openretailscience-0.48.1}/.gitignore +5 -0
  16. {openretailscience-0.47.0 → openretailscience-0.48.1}/.pre-commit-config.yaml +9 -11
  17. {openretailscience-0.47.0 → openretailscience-0.48.1}/CLAUDE.md +18 -1
  18. {openretailscience-0.47.0 → openretailscience-0.48.1}/CONTRIBUTING.md +14 -0
  19. {openretailscience-0.47.0 → openretailscience-0.48.1}/PKG-INFO +28 -10
  20. {openretailscience-0.47.0 → openretailscience-0.48.1}/README.md +25 -8
  21. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/analysis_modules.md +3 -3
  22. openretailscience-0.48.1/docs/api/experimental/clv.md +3 -0
  23. openretailscience-0.48.1/docs/api/experimental/metrics/distribution.md +5 -0
  24. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/examples/retention.ipynb +9 -11
  25. openretailscience-0.48.1/docs/experimental/clv.md +167 -0
  26. {openretailscience-0.47.0/docs → openretailscience-0.48.1/docs/experimental}/metrics.md +6 -2
  27. openretailscience-0.48.1/docs/gallery/index.md +156 -0
  28. openretailscience-0.48.1/docs/gallery/plots/customer_decision_hierarchy.ipynb +249 -0
  29. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/waterfall.ipynb +3 -3
  30. openretailscience-0.48.1/docs/getting_started/agent_skills.md +97 -0
  31. openretailscience-0.48.1/docs/getting_started/connecting_to_data.md +493 -0
  32. openretailscience-0.48.1/docs/getting_started/data_structures.md +274 -0
  33. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/getting_started/options_guide.md +4 -2
  34. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/overrides/home.html +1 -1
  35. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/scripts/regenerate_analysis_modules_svgs.py +5 -7
  36. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/stylesheets/extra.css +95 -0
  37. {openretailscience-0.47.0 → openretailscience-0.48.1}/mkdocs.yml +16 -4
  38. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/SKILL.md +105 -0
  39. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/references/analysis.md +105 -0
  40. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/references/clv.md +128 -0
  41. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/references/configuration.md +113 -0
  42. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/references/plotting.md +87 -0
  43. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_advanced_customization.py +29 -0
  44. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_area.py +79 -0
  45. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_bar.py +98 -0
  46. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_broken_timeline.py +74 -0
  47. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_clv_stats.py +80 -0
  48. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_cohort.py +50 -0
  49. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_cohort_analysis.py +56 -0
  50. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_composite_rank.py +35 -0
  51. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_connecting_to_data.py +167 -0
  52. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_cross_shop.py +43 -0
  53. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_customer_decision_hierarchy.py +108 -0
  54. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_filter_and_label.py +94 -0
  55. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_filter_by_periods.py +36 -0
  56. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_gain_loss.py +109 -0
  57. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_haversine_distance.py +78 -0
  58. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_heatmap.py +40 -0
  59. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_histogram.py +78 -0
  60. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_hml_segmentation.py +70 -0
  61. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_human_format.py +45 -0
  62. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_index.py +82 -0
  63. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_label_by_condition.py +87 -0
  64. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_line.py +56 -0
  65. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_nlr_segmentation.py +70 -0
  66. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_options.py +106 -0
  67. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_overlapping_periods.py +21 -0
  68. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_period_on_period.py +70 -0
  69. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_price.py +83 -0
  70. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_product_association.py +70 -0
  71. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_purchases_per_customer.py +42 -0
  72. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_revenue_tree.py +82 -0
  73. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_rfm_segmentation.py +89 -0
  74. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_scatter.py +103 -0
  75. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_segment_transaction_stats.py +102 -0
  76. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_set_axis_percent.py +68 -0
  77. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_threshold_segmentation.py +96 -0
  78. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_time.py +90 -0
  79. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_tree_diagram.py +115 -0
  80. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_trend_line.py +25 -0
  81. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_venn.py +69 -0
  82. openretailscience-0.48.1/openretailscience/.agents/skills/using-openretailscience/scripts/example_waterfall.py +61 -0
  83. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/cohort.py +59 -9
  84. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/composite_rank.py +4 -5
  85. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/cross_shop.py +6 -4
  86. openretailscience-0.48.1/openretailscience/analysis/customer.py +377 -0
  87. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/product_association.py +6 -7
  88. openretailscience-0.48.1/openretailscience/core/validation.py +349 -0
  89. openretailscience-0.48.1/openretailscience/experimental/__init__.py +4 -0
  90. openretailscience-0.48.1/openretailscience/experimental/clv.py +483 -0
  91. {openretailscience-0.47.0/openretailscience → openretailscience-0.48.1/openretailscience/experimental}/metrics/distribution/acv.py +4 -6
  92. {openretailscience-0.47.0/openretailscience → openretailscience-0.48.1/openretailscience/experimental}/metrics/distribution/pct_of_stores.py +5 -7
  93. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/options.py +33 -16
  94. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/index.py +3 -2
  95. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/price.py +4 -1
  96. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/scatter.py +4 -1
  97. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/styles/graph_utils.py +62 -4
  98. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/styles/styling_helpers.py +376 -77
  99. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/waterfall.py +14 -4
  100. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/segmentation/nlr.py +7 -10
  101. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/segmentation/rfm.py +3 -5
  102. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/segmentation/segstats.py +169 -63
  103. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/segmentation/threshold.py +7 -9
  104. openretailscience-0.48.1/openretailscience/skills.py +417 -0
  105. {openretailscience-0.47.0 → openretailscience-0.48.1}/options_template.toml +5 -0
  106. openretailscience-0.48.1/osv-scanner.toml +9 -0
  107. {openretailscience-0.47.0 → openretailscience-0.48.1}/pyproject.toml +24 -10
  108. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_cohort.py +107 -16
  109. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_composite_rank.py +0 -5
  110. openretailscience-0.48.1/tests/analysis/test_customer.py +522 -0
  111. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/core/test_validation.py +152 -0
  112. {openretailscience-0.47.0/tests → openretailscience-0.48.1/tests/experimental}/metrics/distribution/test_acv.py +2 -2
  113. {openretailscience-0.47.0/tests → openretailscience-0.48.1/tests/experimental}/metrics/distribution/test_pct_of_stores.py +2 -2
  114. {openretailscience-0.47.0/tests → openretailscience-0.48.1/tests/experimental}/metrics/test_base.py +2 -2
  115. openretailscience-0.48.1/tests/experimental/test_clv.py +720 -0
  116. openretailscience-0.48.1/tests/integration/conftest.py +213 -0
  117. openretailscience-0.48.1/tests/integration/docker/README.md +61 -0
  118. openretailscience-0.48.1/tests/integration/docker/docker-compose.oracle.yml +24 -0
  119. openretailscience-0.48.1/tests/integration/docker/docker-compose.sqlserver.yml +23 -0
  120. openretailscience-0.48.1/tests/integration/test_clv_stats.py +133 -0
  121. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/styles/test_chart_chrome.py +231 -15
  122. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/styles/test_graph_utils.py +64 -0
  123. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/styles/test_styling_helper.py +118 -25
  124. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_price.py +15 -0
  125. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_scatter.py +29 -0
  126. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_waterfall.py +36 -1
  127. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/segmentation/test_nlr.py +0 -12
  128. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/segmentation/test_rfm.py +0 -9
  129. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/segmentation/test_segstats.py +353 -438
  130. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/test_options.py +34 -13
  131. openretailscience-0.48.1/tests/test_skills.py +778 -0
  132. {openretailscience-0.47.0 → openretailscience-0.48.1}/uv.lock +612 -587
  133. openretailscience-0.47.0/.claude/commands/review-pr-tests.md +0 -607
  134. openretailscience-0.47.0/.env_sample +0 -9
  135. openretailscience-0.47.0/.github/workflows/test.yml +0 -79
  136. openretailscience-0.47.0/docs/api/metrics/distribution.md +0 -5
  137. openretailscience-0.47.0/docs/gallery/index.md +0 -212
  138. openretailscience-0.47.0/docs/gallery/plots/customer_decision_hierarchy.ipynb +0 -228
  139. openretailscience-0.47.0/openretailscience/analysis/customer.py +0 -223
  140. openretailscience-0.47.0/openretailscience/core/validation.py +0 -153
  141. openretailscience-0.47.0/osv-scanner.toml +0 -19
  142. openretailscience-0.47.0/tests/analysis/test_customer.py +0 -203
  143. openretailscience-0.47.0/tests/integration/conftest.py +0 -47
  144. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  145. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  146. {openretailscience-0.47.0 → openretailscience-0.48.1}/.github/dependabot.yml +0 -0
  147. {openretailscience-0.47.0 → openretailscience-0.48.1}/.markdownlint.json +0 -0
  148. {openretailscience-0.47.0 → openretailscience-0.48.1}/CNAME +0 -0
  149. {openretailscience-0.47.0 → openretailscience-0.48.1}/CODE_OF_CONDUCT.md +0 -0
  150. {openretailscience-0.47.0 → openretailscience-0.48.1}/LICENSE +0 -0
  151. {openretailscience-0.47.0 → openretailscience-0.48.1}/data/transactions.parquet +0 -0
  152. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/cohort.md +0 -0
  153. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/composite_rank.md +0 -0
  154. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/cross_shop.md +0 -0
  155. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/customer.md +0 -0
  156. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/customer_decision_hierarchy.md +0 -0
  157. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/gain_loss.md +0 -0
  158. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/haversine.md +0 -0
  159. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/product_association.md +0 -0
  160. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/analysis/revenue_tree.md +0 -0
  161. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/options.md +0 -0
  162. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/area.md +0 -0
  163. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/bar.md +0 -0
  164. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/broken_timeline.md +0 -0
  165. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/cohort.md +0 -0
  166. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/heatmap.md +0 -0
  167. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/histogram.md +0 -0
  168. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/index.md +0 -0
  169. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/line.md +0 -0
  170. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/period_on_period.md +0 -0
  171. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/price.md +0 -0
  172. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/scatter.md +0 -0
  173. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/styles/graph_utils.md +0 -0
  174. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/styles/styling_helpers.md +0 -0
  175. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/time.md +0 -0
  176. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/venn.md +0 -0
  177. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/plots/waterfall.md +0 -0
  178. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/segmentation/hml.md +0 -0
  179. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/segmentation/nlr.md +0 -0
  180. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/segmentation/rfm.md +0 -0
  181. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/segmentation/segstats.md +0 -0
  182. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/segmentation/threshold.md +0 -0
  183. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/utils/date.md +0 -0
  184. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/utils/filter_and_label.md +0 -0
  185. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/api/utils/label.md +0 -0
  186. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/cohort.svg +0 -0
  187. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/cross_shop.svg +0 -0
  188. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/customer_decision_hierarchy.svg +0 -0
  189. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/days_between_purchases.svg +0 -0
  190. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/gain_loss.svg +0 -0
  191. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/hml_segmentation.svg +0 -0
  192. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/purchases_per_customer.svg +0 -0
  193. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/revenue_tree.svg +0 -0
  194. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/threshold_segmentation.svg +0 -0
  195. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/analysis_modules/transaction_churn.svg +0 -0
  196. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/features/charts.png +0 -0
  197. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/features/cross_shop.png +0 -0
  198. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/area_thumbnail.png +0 -0
  199. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/bar_thumbnail.png +0 -0
  200. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/broken_timeline_thumbnail.png +0 -0
  201. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/cohort_thumbnail.png +0 -0
  202. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/customer_decision_hierarchy_thumbnail.png +0 -0
  203. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/heatmap_thumbnail.png +0 -0
  204. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/histogram_thumbnail.png +0 -0
  205. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/index_thumbnail.png +0 -0
  206. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/line_thumbnail.png +0 -0
  207. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/period_on_period_thumbnail.png +0 -0
  208. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/price_thumbnail.png +0 -0
  209. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/revenue_tree_thumbnail.png +0 -0
  210. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/scatter_thumbnail.png +0 -0
  211. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/time_thumbnail.png +0 -0
  212. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/venn_thumbnail.png +0 -0
  213. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/gallery/waterfall_thumbnail.png +0 -0
  214. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/assets/images/logo.svg +0 -0
  215. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/examples/cross_shop.ipynb +0 -0
  216. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/examples/gain_loss.ipynb +0 -0
  217. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/examples/product_association.ipynb +0 -0
  218. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/examples/revenue_tree.ipynb +0 -0
  219. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/examples/segmentation.ipynb +0 -0
  220. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/area.ipynb +0 -0
  221. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/bar.ipynb +0 -0
  222. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/broken_timeline.ipynb +0 -0
  223. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/cohort.ipynb +0 -0
  224. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/heatmap.ipynb +0 -0
  225. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/histogram.ipynb +0 -0
  226. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/index_plot.ipynb +0 -0
  227. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/line.ipynb +0 -0
  228. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/period_on_period.ipynb +0 -0
  229. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/price.ipynb +0 -0
  230. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/revenue_tree.ipynb +0 -0
  231. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/scatter.ipynb +0 -0
  232. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/time.ipynb +0 -0
  233. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/gallery/plots/venn.ipynb +0 -0
  234. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/getting_started/installation.md +0 -0
  235. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/getting_started/styling_guide.ipynb +0 -0
  236. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/index.md +0 -0
  237. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/javascripts/mathjax.js +0 -0
  238. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/overrides/main.html +0 -0
  239. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/robots.txt +0 -0
  240. {openretailscience-0.47.0 → openretailscience-0.48.1}/docs/scripts/README.md +0 -0
  241. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/__init__.py +0 -0
  242. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/__init__.py +0 -0
  243. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/customer_decision_hierarchy.py +0 -0
  244. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/gain_loss.py +0 -0
  245. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/haversine.py +0 -0
  246. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/analysis/revenue_tree.py +0 -0
  247. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/assets/fonts/Poppins-Bold.ttf +0 -0
  248. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/assets/fonts/Poppins-LightItalic.ttf +0 -0
  249. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/assets/fonts/Poppins-Medium.ttf +0 -0
  250. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/assets/fonts/Poppins-Regular.ttf +0 -0
  251. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/assets/fonts/Poppins-SemiBold.ttf +0 -0
  252. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/constants.py +0 -0
  253. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/core/__init__.py +0 -0
  254. {openretailscience-0.47.0/openretailscience → openretailscience-0.48.1/openretailscience/experimental}/metrics/__init__.py +0 -0
  255. {openretailscience-0.47.0/openretailscience → openretailscience-0.48.1/openretailscience/experimental}/metrics/base.py +0 -0
  256. {openretailscience-0.47.0/openretailscience → openretailscience-0.48.1/openretailscience/experimental}/metrics/distribution/__init__.py +0 -0
  257. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/__init__.py +0 -0
  258. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/area.py +0 -0
  259. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/bar.py +0 -0
  260. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/broken_timeline.py +0 -0
  261. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/cohort.py +0 -0
  262. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/heatmap.py +0 -0
  263. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/histogram.py +0 -0
  264. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/line.py +0 -0
  265. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/period_on_period.py +0 -0
  266. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/styles/__init__.py +0 -0
  267. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/styles/colors.py +0 -0
  268. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/styles/font_utils.py +0 -0
  269. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/styles/trend.py +0 -0
  270. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/time.py +0 -0
  271. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/tree_diagram.py +0 -0
  272. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/plots/venn.py +0 -0
  273. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/py.typed +0 -0
  274. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/segmentation/__init__.py +0 -0
  275. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/segmentation/hml.py +0 -0
  276. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/utils/__init__.py +0 -0
  277. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/utils/date.py +0 -0
  278. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/utils/filter_and_label.py +0 -0
  279. {openretailscience-0.47.0 → openretailscience-0.48.1}/openretailscience/utils/label.py +0 -0
  280. {openretailscience-0.47.0 → openretailscience-0.48.1}/readme_assets/cross_shop_chart.png +0 -0
  281. {openretailscience-0.47.0 → openretailscience-0.48.1}/readme_assets/days_until_next_purchase.png +0 -0
  282. {openretailscience-0.47.0 → openretailscience-0.48.1}/readme_assets/gain_loss_chart.png +0 -0
  283. {openretailscience-0.47.0 → openretailscience-0.48.1}/readme_assets/logo.png +0 -0
  284. {openretailscience-0.47.0 → openretailscience-0.48.1}/readme_assets/logo.svg +0 -0
  285. {openretailscience-0.47.0 → openretailscience-0.48.1}/readme_assets/new_store_cannibalization.png +0 -0
  286. {openretailscience-0.47.0 → openretailscience-0.48.1}/taplo.toml +0 -0
  287. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_cross_shop.py +0 -0
  288. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_customer_decision_hierarchy.py +0 -0
  289. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_gain_loss.py +0 -0
  290. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_haversine.py +0 -0
  291. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_product_association.py +0 -0
  292. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/analysis/test_revenue_tree.py +0 -0
  293. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/core/__init__.py +0 -0
  294. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_cohort_analysis.py +0 -0
  295. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_composite_rank.py +0 -0
  296. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_cross_shop.py +0 -0
  297. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_customer_decision_hierarchy.py +0 -0
  298. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_date.py +0 -0
  299. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_filter_and_label.py +0 -0
  300. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_haversine.py +0 -0
  301. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_hml_segmentation.py +0 -0
  302. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_product_association.py +0 -0
  303. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_revenue_tree.py +0 -0
  304. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_rfm_segmentation.py +0 -0
  305. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_segstats_segmentation.py +0 -0
  306. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/integration/test_threshold_segmentation.py +0 -0
  307. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/styles/test_color.py +0 -0
  308. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/styles/test_font_utils.py +0 -0
  309. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/styles/test_trend.py +0 -0
  310. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_area.py +0 -0
  311. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_bar.py +0 -0
  312. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_broken_timeline.py +0 -0
  313. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_cohort.py +0 -0
  314. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_heatmap.py +0 -0
  315. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_histogram.py +0 -0
  316. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_index.py +0 -0
  317. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_line.py +0 -0
  318. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_period_on_period.py +0 -0
  319. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_styling_options_integration.py +0 -0
  320. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_time.py +0 -0
  321. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_tree_diagram.py +0 -0
  322. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/plots/test_venn.py +0 -0
  323. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/segmentation/test_hml.py +0 -0
  324. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/segmentation/test_threshold.py +0 -0
  325. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/toml_files/corrupt.toml +0 -0
  326. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/toml_files/invalid_option.toml +0 -0
  327. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/toml_files/test_options.toml +0 -0
  328. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/toml_files/valid.toml +0 -0
  329. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/utils/test_date.py +0 -0
  330. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/utils/test_filter_and_label.py +0 -0
  331. {openretailscience-0.47.0 → openretailscience-0.48.1}/tests/utils/test_label.py +0 -0
  332. {openretailscience-0.47.0 → openretailscience-0.48.1}/tox.ini +0 -0
@@ -0,0 +1,9 @@
1
+ GCP_PROJECT_ID=
2
+
3
+ # Snowflake CI Configuration (for integration tests)
4
+ SNOWFLAKE_CI_ACCOUNT=
5
+ SNOWFLAKE_CI_USER=
6
+ SNOWFLAKE_CI_WAREHOUSE=
7
+ SNOWFLAKE_CI_DATABASE=
8
+ SNOWFLAKE_CI_SCHEMA=
9
+ SNOWFLAKE_CI_PRIVATE_KEY_PATH=
@@ -19,16 +19,16 @@ jobs:
19
19
  timeout-minutes: 30
20
20
  steps:
21
21
  - name: Checkout
22
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
22
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
23
  with:
24
24
  persist-credentials: false
25
25
  - name: Setup Python
26
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
26
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
27
27
  with:
28
28
  python-version: "3.11"
29
29
 
30
30
  - name: Install uv
31
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
31
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
32
32
  with:
33
33
  enable-cache: true
34
34
 
@@ -18,6 +18,9 @@ jobs:
18
18
  # github.event.pull_request.user.login == 'new-developer' ||
19
19
  # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
20
20
 
21
+ # Skip automated dependency PRs: Dependabot runs without access to secrets and
22
+ # claude-code-action refuses to run for bot actors, so the job can only ever fail.
23
+ if: github.actor != 'dependabot[bot]'
21
24
  runs-on: ubuntu-latest
22
25
  permissions:
23
26
  contents: read
@@ -27,14 +30,14 @@ jobs:
27
30
 
28
31
  steps:
29
32
  - name: Checkout repository
30
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
33
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
31
34
  with:
32
35
  fetch-depth: 1
33
36
  persist-credentials: false
34
37
 
35
38
  - name: Run Claude Code Review
36
39
  id: claude-review
37
- uses: anthropics/claude-code-action@787c5a0ce96a9a6cfb050ea0c8f4c05f2447c251 # v1.0.133
40
+ uses: anthropics/claude-code-action@b76a0776ae74036e77cd11018083743453d7ad35 # v1.0.179
38
41
  with:
39
42
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
40
43
  track_progress: true
@@ -85,7 +85,7 @@ jobs:
85
85
 
86
86
  - name: Checkout repository
87
87
  if: steps.check_permissions.outputs.has_permission == 'true'
88
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
88
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
89
89
  with:
90
90
  fetch-depth: 1
91
91
  persist-credentials: false
@@ -93,7 +93,7 @@ jobs:
93
93
  - name: Run Claude Code
94
94
  if: steps.check_permissions.outputs.has_permission == 'true'
95
95
  id: claude
96
- uses: anthropics/claude-code-action@787c5a0ce96a9a6cfb050ea0c8f4c05f2447c251 # v1.0.133
96
+ uses: anthropics/claude-code-action@b76a0776ae74036e77cd11018083743453d7ad35 # v1.0.179
97
97
  with:
98
98
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
99
99
 
@@ -22,24 +22,25 @@ jobs:
22
22
 
23
23
  steps:
24
24
  - name: Checkout repository
25
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
26
  with:
27
27
  persist-credentials: false
28
28
  - name: Setup Python
29
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
29
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
30
30
  with:
31
31
  python-version: "3.11"
32
32
 
33
33
  - name: Install uv
34
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
34
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
35
35
  with:
36
- enable-cache: true
36
+ # Disabled: a shared cache feeding the preview deploy is a poisoning vector.
37
+ enable-cache: "false"
37
38
 
38
39
  - name: Install Dependencies
39
40
  run: uv sync --locked
40
41
 
41
42
  - name: Build docs
42
- run: uv run mkdocs build
43
+ run: uv run mkdocs build --strict
43
44
 
44
45
  - name: Verify build output
45
46
  run: |
@@ -51,14 +52,12 @@ jobs:
51
52
 
52
53
  - name: Publish to Cloudflare Pages
53
54
  id: cloudflare-deploy
54
- uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # v1.5.0
55
+ uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
55
56
  with:
56
57
  apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
57
58
  accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
58
- projectName: openretailscience-docs
59
- directory: site
60
59
  gitHubToken: ${{ secrets.GITHUB_TOKEN }}
61
- branch: ${{ github.head_ref || github.ref_name }}
60
+ command: pages deploy site --project-name=openretailscience-docs --branch=${{ github.head_ref || github.ref_name }}
62
61
 
63
62
  - name: Find existing comment
64
63
  if: github.event_name == 'pull_request'
@@ -81,8 +80,8 @@ jobs:
81
80
 
82
81
  ✅ Preview deployed successfully!
83
82
 
84
- **Preview URL:** ${{ steps.cloudflare-deploy.outputs.url }}
85
- **Deployment ID:** ${{ steps.cloudflare-deploy.outputs.id }}
83
+ **Preview URL:** ${{ steps.cloudflare-deploy.outputs.deployment-url }}
84
+ **Deployment ID:** ${{ steps.cloudflare-deploy.outputs.pages-deployment-id }}
86
85
 
87
86
  ---
88
87
  *This preview will be updated automatically when you push new changes to this PR.*
@@ -20,15 +20,15 @@ jobs:
20
20
  timeout-minutes: 15
21
21
  steps:
22
22
  - name: Checkout
23
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
23
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
24
  with:
25
25
  persist-credentials: false
26
26
  - name: Setup Python
27
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
27
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
28
28
  with:
29
29
  python-version: "3.11"
30
30
  - name: Install uv
31
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
31
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
32
32
  with:
33
33
  enable-cache: true
34
34
  - name: Install Dependencies
@@ -0,0 +1,46 @@
1
+ name: Oracle Integration Tests
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ workflow_call:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ integration-tests:
12
+ name: Run Oracle Integration Tests
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 30
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
18
+ with:
19
+ persist-credentials: false
20
+ - name: Setup Python
21
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
22
+ with:
23
+ python-version: "3.11"
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
27
+ with:
28
+ enable-cache: true
29
+
30
+ - name: Install Dependencies
31
+ run: |
32
+ uv sync --locked
33
+
34
+ # Oracle 23ai Free (the supported LTS); the Compose file pins the gvenzl image.
35
+ - name: Start Oracle
36
+ run: |
37
+ docker compose -f tests/integration/docker/docker-compose.oracle.yml up -d --wait --wait-timeout 600
38
+
39
+ - name: Run Integration Tests
40
+ run: |
41
+ uv run pytest tests/integration -k "oracle" -v
42
+
43
+ - name: Stop Oracle
44
+ if: always()
45
+ run: |
46
+ docker compose -f tests/integration/docker/docker-compose.oracle.yml down -v
@@ -14,16 +14,16 @@ jobs:
14
14
  timeout-minutes: 30
15
15
  steps:
16
16
  - name: Checkout
17
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
17
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
18
18
  with:
19
19
  persist-credentials: false
20
20
  - name: Setup Python
21
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
21
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
22
22
  with:
23
23
  python-version: "3.11"
24
24
 
25
25
  - name: Install uv
26
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
26
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
27
27
  with:
28
28
  enable-cache: true
29
29
 
@@ -22,15 +22,15 @@ jobs:
22
22
  timeout-minutes: 10
23
23
  steps:
24
24
  - name: Checkout
25
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
26
  with:
27
27
  persist-credentials: false
28
28
  - name: Setup Python
29
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
29
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
30
30
  with:
31
31
  python-version: "3.11"
32
32
  - name: Install uv
33
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
33
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
34
34
  with:
35
35
  enable-cache: true
36
36
  - name: Install dependencies
@@ -68,6 +68,14 @@ jobs:
68
68
  SNOWFLAKE_CI_DATABASE: ${{ secrets.SNOWFLAKE_CI_DATABASE }}
69
69
  SNOWFLAKE_CI_SCHEMA: ${{ secrets.SNOWFLAKE_CI_SCHEMA }}
70
70
 
71
+ sqlserver-integration-tests:
72
+ name: SQL Server Integration Tests
73
+ uses: ./.github/workflows/sqlserver-integration.yml
74
+
75
+ oracle-integration-tests:
76
+ name: Oracle Integration Tests
77
+ uses: ./.github/workflows/oracle-integration.yml
78
+
71
79
  multi-python-tests:
72
80
  name: Multi-Python Version Tests
73
81
  runs-on: ubuntu-latest
@@ -78,15 +86,15 @@ jobs:
78
86
  python-version: ["3.10", "3.11", "3.12", "3.13"]
79
87
  steps:
80
88
  - name: Checkout code
81
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
89
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
82
90
  with:
83
91
  persist-credentials: false
84
92
  - name: Set up Python ${{ matrix.python-version }}
85
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
93
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
86
94
  with:
87
95
  python-version: ${{ matrix.python-version }}
88
96
  - name: Install uv
89
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
97
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
90
98
  with:
91
99
  enable-cache: true
92
100
  - name: Install dependencies
@@ -100,7 +108,7 @@ jobs:
100
108
  name: Build
101
109
  runs-on: ubuntu-latest
102
110
  timeout-minutes: 15
103
- needs: [security-audit, pre-commit, bigquery-integration-tests, pyspark-integration-tests, snowflake-integration-tests, multi-python-tests]
111
+ needs: [security-audit, pre-commit, bigquery-integration-tests, pyspark-integration-tests, snowflake-integration-tests, sqlserver-integration-tests, oracle-integration-tests, multi-python-tests]
104
112
  permissions:
105
113
  contents: write
106
114
  id-token: write
@@ -112,13 +120,13 @@ jobs:
112
120
  # tag, so it requires the GITHUB_TOKEN persisted by actions/checkout. Only
113
121
  # dist/ is uploaded as an artifact, not .git/, so the token is not exposed.
114
122
  - name: Checkout # zizmor: ignore[artipacked]
115
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
123
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
116
124
  - name: Setup Python
117
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
125
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
118
126
  with:
119
127
  python-version: "3.11"
120
128
  - name: Install uv
121
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
129
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
122
130
  with:
123
131
  enable-cache: true
124
132
  - name: Install Dependencies
@@ -147,7 +155,7 @@ jobs:
147
155
  - name: Build package
148
156
  run: uv build
149
157
  - name: Attest build provenance
150
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
158
+ uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
151
159
  with:
152
160
  subject-path: "dist/*"
153
161
  - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -185,7 +193,7 @@ jobs:
185
193
  name: build
186
194
  path: dist
187
195
  - name: Publish package distributions to PyPI
188
- uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
196
+ uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
189
197
  with:
190
198
  attestations: true
191
199
  deploy-docs:
@@ -12,8 +12,10 @@ name: Security Audit
12
12
  #
13
13
  # On pull requests the scan runs only when dependencies or this workflow change,
14
14
  # and is advisory (results still post to code scanning); pushes to main (same
15
- # path filter) refresh the default-branch code-scanning state, and scheduled
16
- # runs, manual dispatches, and release calls are hard gates.
15
+ # path filter) refresh the default-branch code-scanning state, and manual
16
+ # dispatches and release calls are hard gates. Detection of newly-disclosed CVEs
17
+ # against already-pinned dependencies (with no repo change) is left to Dependabot
18
+ # alerts and security updates, so no scheduled scan is needed here.
17
19
 
18
20
  on:
19
21
  pull_request:
@@ -30,8 +32,6 @@ on:
30
32
  - "pyproject.toml"
31
33
  - "osv-scanner.toml"
32
34
  - ".github/workflows/security-audit.yml"
33
- schedule:
34
- - cron: "0 6 * * 1" # Mondays 06:00 UTC
35
35
  workflow_dispatch:
36
36
  workflow_call:
37
37
 
@@ -51,7 +51,7 @@ jobs:
51
51
  security-events: write # upload SARIF to code scanning
52
52
  steps:
53
53
  - name: Checkout
54
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
54
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
55
55
  with:
56
56
  persist-credentials: false
57
57
  - name: Run OSV-Scanner
@@ -69,7 +69,7 @@ jobs:
69
69
  # than erroring and being swallowed by continue-on-error.
70
70
  if: always() && hashFiles('results.sarif') != ''
71
71
  continue-on-error: true # never let SARIF upload (e.g. missing perms) break the gate
72
- uses: github/codeql-action/upload-sarif@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1
72
+ uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
73
73
  with:
74
74
  sarif_file: results.sarif
75
75
  category: osv-scanner
@@ -11,9 +11,12 @@ on:
11
11
  - "Tests"
12
12
  - "PyPi Package Deploy"
13
13
  - "Page Deploy"
14
+ - "Security Audit"
14
15
  - "BigQuery Integration Tests"
15
16
  - "PySpark Integration Tests"
16
17
  - "Snowflake Integration Tests"
18
+ - "SQL Server Integration Tests"
19
+ - "Oracle Integration Tests"
17
20
  types: [completed]
18
21
 
19
22
  permissions: {}
@@ -49,7 +52,10 @@ jobs:
49
52
  --arg event "$EVENT_NAME" \
50
53
  --arg author "$AUTHOR_NAME" \
51
54
  --arg message "$COMMIT_MESSAGE" \
52
- '{
55
+ '# Slack 400s if a section text exceeds 3000 chars. Slice in jq, not bash:
56
+ # bash slices bytes under a C locale and can split a codepoint.
57
+ ($message | if length > 2000 then .[0:2000] + "\n…(truncated)" else . end) as $commit_message
58
+ | {
53
59
  attachments: [{
54
60
  color: "danger",
55
61
  fallback: "Workflow failure notification",
@@ -76,7 +82,7 @@ jobs:
76
82
  },
77
83
  {
78
84
  type: "section",
79
- text: {type: "mrkdwn", text: ("*Commit Message:*\n```" + $message + "```")}
85
+ text: {type: "mrkdwn", text: ("*Commit Message:*\n```" + $commit_message + "```")}
80
86
  },
81
87
  {
82
88
  type: "actions",
@@ -29,16 +29,16 @@ jobs:
29
29
  timeout-minutes: 30
30
30
  steps:
31
31
  - name: Checkout
32
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
32
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33
33
  with:
34
34
  persist-credentials: false
35
35
  - name: Setup Python
36
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
36
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
37
37
  with:
38
38
  python-version: "3.11"
39
39
 
40
40
  - name: Install uv
41
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
41
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
42
42
  with:
43
43
  enable-cache: true
44
44
 
@@ -0,0 +1,64 @@
1
+ name: SQL Server Integration Tests
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ workflow_call:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ integration-tests:
12
+ name: Run SQL Server Integration Tests
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 30
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ mssql-image:
19
+ - mcr.microsoft.com/mssql/server:2022-latest
20
+ - mcr.microsoft.com/mssql/server:2025-latest
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
+ with:
25
+ persist-credentials: false
26
+ - name: Setup Python
27
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
28
+ with:
29
+ python-version: "3.11"
30
+
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
33
+ with:
34
+ enable-cache: true
35
+
36
+ - name: Install Dependencies
37
+ run: |
38
+ uv sync --locked
39
+
40
+ - name: Install Microsoft ODBC Driver 18
41
+ run: |
42
+ set -euo pipefail
43
+ curl -fsSL https://packages.microsoft.com/keys/microsoft.asc \
44
+ | sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/microsoft-prod.gpg
45
+ source /etc/os-release
46
+ echo "deb [arch=amd64,arm64,armhf signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/ubuntu/${VERSION_ID}/prod ${VERSION_CODENAME} main" \
47
+ | sudo tee /etc/apt/sources.list.d/mssql-release.list
48
+ sudo apt-get update
49
+ sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc unixodbc-dev
50
+
51
+ - name: Start SQL Server (${{ matrix.mssql-image }})
52
+ env:
53
+ MSSQL_IMAGE: ${{ matrix.mssql-image }}
54
+ run: |
55
+ docker compose -f tests/integration/docker/docker-compose.sqlserver.yml up -d --wait --wait-timeout 300
56
+
57
+ - name: Run Integration Tests
58
+ run: |
59
+ uv run pytest tests/integration -k "mssql" -v
60
+
61
+ - name: Stop SQL Server
62
+ if: always()
63
+ run: |
64
+ docker compose -f tests/integration/docker/docker-compose.sqlserver.yml down -v
@@ -0,0 +1,104 @@
1
+ name: Tests
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize]
6
+ push:
7
+ branches: [main]
8
+
9
+ permissions: {}
10
+
11
+ concurrency:
12
+ group: "test-${{ github.ref }}"
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ pre-commit:
17
+ name: Pre-Commit
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: Checkout
21
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ with:
23
+ persist-credentials: false
24
+ - name: Setup Python
25
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
26
+ with:
27
+ python-version: "3.11"
28
+ - name: Install uv
29
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
30
+ with:
31
+ enable-cache: true
32
+ - name: Install dependencies
33
+ run: uv sync --locked
34
+ - name: Run Pre-commit
35
+ run: uv run pre-commit run --all-files
36
+ - name: Pre-import Codecov uploader signing key
37
+ if: github.event_name == 'pull_request' && github.actor != 'dependabot[bot]'
38
+ # Workaround for codecov/codecov-action#1876: the uploader intermittently
39
+ # fails to fetch its own verification key, producing "Can't check signature:
40
+ # No public key" and failing the job under fail_ci_if_error. Pre-seed Codecov's
41
+ # public key (codecovsecops, fingerprint 2703 4E7F DB85 0E0B BC2C 62FF 806B B28A
42
+ # ED77 9869) so the wrapper's check succeeds even when its own fetch flakes. The
43
+ # observed wrapper verifies against the default keyring (`gpg --verify`), so that
44
+ # import is the one that fixes this failure; trustedkeys.gpg is also seeded for
45
+ # the documented gpgv path. The fetched key's fingerprint is checked against the
46
+ # expected value BEFORE import, so a DNS hijack or tampered keybase response is
47
+ # never installed into a trusted keyring. Best-effort: never fails the build, so a
48
+ # fetch outage or fingerprint mismatch just falls back to the uploader's own check.
49
+ run: |
50
+ set +e
51
+ expected="27034E7FDB850E0BBC2C62FF806BB28AED779869"
52
+ curl -fsSL https://keybase.io/codecovsecops/pgp_keys.asc -o codecov.asc
53
+ if gpg --show-keys --with-colons codecov.asc 2>/dev/null | grep -q ":${expected}:"; then
54
+ gpg --batch --import codecov.asc
55
+ gpg --batch --no-default-keyring --keyring trustedkeys.gpg --import codecov.asc
56
+ else
57
+ echo "WARNING: Codecov signing key not verified (fetch failed or fingerprint mismatch) – skipping pre-import"
58
+ fi
59
+ rm -f codecov.asc
60
+ exit 0
61
+ - name: Upload coverage to Codecov
62
+ if: github.event_name == 'pull_request' && github.actor != 'dependabot[bot]'
63
+ uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
64
+ with:
65
+ token: ${{ secrets.CODECOV_TOKEN }}
66
+ fail_ci_if_error: true
67
+
68
+ # Note: This job also exists in release.yml as a final quality gate before publishing.
69
+ # While it may seem redundant, it serves as a safety check in case of misconfiguration.
70
+ test-matrix:
71
+ name: Test Python ${{ matrix.python-version }}
72
+ runs-on: ubuntu-latest
73
+ if: github.event_name == 'push'
74
+ continue-on-error: ${{ matrix.experimental }}
75
+ strategy:
76
+ fail-fast: false
77
+ matrix:
78
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
79
+ experimental: [false]
80
+
81
+ steps:
82
+ - name: Checkout code
83
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
84
+ with:
85
+ persist-credentials: false
86
+ - name: Set up Python ${{ matrix.python-version }}
87
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
88
+ with:
89
+ python-version: ${{ matrix.python-version }}
90
+
91
+ - name: Install uv
92
+ uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
93
+ with:
94
+ enable-cache: true
95
+
96
+ - name: Install dependencies
97
+ run: |
98
+ uv sync --locked
99
+
100
+ - name: Run tests
101
+ run: |
102
+ uv run pytest tests/ --ignore=tests/integration --tb=short -v
103
+ env:
104
+ PYTHONDONTWRITEBYTECODE: 1
@@ -142,3 +142,8 @@ cython_debug/
142
142
 
143
143
  .claude-review
144
144
  .claude/scheduled_tasks.lock
145
+
146
+ # Local Spark artifacts (created by pyspark integration tests)
147
+ spark-warehouse/
148
+ metastore_db/
149
+ derby.log
@@ -1,35 +1,33 @@
1
1
  repos:
2
2
  - repo: https://github.com/compilerla/conventional-pre-commit
3
- rev: v3.2.0
3
+ rev: v4.4.0
4
4
  hooks:
5
5
  - id: conventional-pre-commit
6
6
  stages: [commit-msg]
7
7
  args: []
8
8
  - repo: https://github.com/astral-sh/ruff-pre-commit
9
- rev: "v0.11.0"
9
+ rev: "v0.15.17"
10
10
  hooks:
11
- - id: ruff
11
+ - id: ruff-check
12
12
  args: ["--fix"]
13
13
  - id: ruff-format
14
14
  - repo: https://github.com/pre-commit/pre-commit-hooks
15
- rev: v5.0.0
15
+ rev: v6.0.0
16
16
  hooks:
17
17
  - id: trailing-whitespace
18
18
  - id: end-of-file-fixer
19
19
  exclude: '\.svg$'
20
- - id: fix-encoding-pragma
21
- args: [--remove]
22
20
  - id: check-yaml
23
21
  - id: debug-statements
24
22
  language_version: python3
25
23
  - repo: https://github.com/kynan/nbstripout
26
- rev: 0.5.0
24
+ rev: 0.9.1
27
25
  hooks:
28
26
  - id: nbstripout
29
27
  files: \.(ipynb)$
30
- args: [--keep-output, --strip-empty-cells]
31
- - repo: https://github.com/nikaro/taplo-pre-commit
32
- rev: 0.1.1
28
+ args: [--keep-output, --drop-empty-cells]
29
+ - repo: https://github.com/ComPWA/taplo-pre-commit
30
+ rev: v0.9.3
33
31
  hooks:
34
32
  - id: taplo-format
35
33
  name: Format TOML files
@@ -40,7 +38,7 @@ repos:
40
38
  args: ["--config", "taplo.toml"]
41
39
  exclude: ^tests/toml_files/corrupt.toml$
42
40
  - repo: https://github.com/igorshubovych/markdownlint-cli
43
- rev: v0.38.0
41
+ rev: v0.48.0
44
42
  hooks:
45
43
  - id: markdownlint
46
44
  args: ["--config", ".markdownlint.json"]