openretailscience 0.46.0__tar.gz → 0.47.0__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.
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/dependabot.yml +15 -0
- openretailscience-0.47.0/.github/workflows/bigquery-integration.yml +48 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/claude-code-review.yml +3 -2
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/claude.yml +5 -4
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/cloudflare-docs-preview.yml +13 -12
- openretailscience-0.47.0/.github/workflows/gh-page.yml +46 -0
- openretailscience-0.47.0/.github/workflows/pyspark-integration.yml +36 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/release.yml +80 -102
- openretailscience-0.47.0/.github/workflows/security-audit.yml +86 -0
- openretailscience-0.47.0/.github/workflows/slack-notifications.yml +104 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/snowflake-integration.yml +30 -40
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/test.yml +23 -19
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.pre-commit-config.yaml +4 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/CLAUDE.md +3 -2
- {openretailscience-0.46.0 → openretailscience-0.47.0}/PKG-INFO +3 -4
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/getting_started/options_guide.md +1 -1
- openretailscience-0.47.0/openretailscience/__init__.py +1 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/cohort.py +5 -10
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/composite_rank.py +19 -82
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/cross_shop.py +3 -6
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/customer.py +4 -18
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/customer_decision_hierarchy.py +2 -4
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/gain_loss.py +5 -5
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/product_association.py +3 -6
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/revenue_tree.py +8 -22
- openretailscience-0.47.0/openretailscience/core/__init__.py +1 -0
- openretailscience-0.47.0/openretailscience/core/validation.py +153 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/metrics/distribution/acv.py +5 -7
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/metrics/distribution/pct_of_stores.py +9 -8
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/bar.py +31 -28
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/broken_timeline.py +19 -43
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/index.py +15 -17
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/line.py +16 -13
- openretailscience-0.47.0/openretailscience/plots/styles/graph_utils.py +423 -0
- openretailscience-0.47.0/openretailscience/plots/styles/trend.py +506 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/waterfall.py +5 -9
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/segmentation/nlr.py +19 -17
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/segmentation/rfm.py +8 -10
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/segmentation/segstats.py +20 -26
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/segmentation/threshold.py +5 -12
- openretailscience-0.47.0/openretailscience/utils/__init__.py +0 -0
- openretailscience-0.47.0/osv-scanner.toml +19 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/pyproject.toml +7 -7
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_cohort.py +10 -7
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_composite_rank.py +25 -21
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_cross_shop.py +2 -2
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_customer_decision_hierarchy.py +24 -25
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_gain_loss.py +1 -1
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_revenue_tree.py +14 -12
- openretailscience-0.47.0/tests/core/__init__.py +0 -0
- openretailscience-0.47.0/tests/core/test_validation.py +179 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/metrics/distribution/test_acv.py +4 -4
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/metrics/distribution/test_pct_of_stores.py +1 -1
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/styles/test_chart_chrome.py +34 -35
- openretailscience-0.47.0/tests/plots/styles/test_graph_utils.py +363 -0
- openretailscience-0.47.0/tests/plots/styles/test_trend.py +625 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_bar.py +34 -7
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_broken_timeline.py +33 -22
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_index.py +47 -1
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_line.py +15 -2
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/segmentation/test_nlr.py +22 -11
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/segmentation/test_rfm.py +122 -68
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/segmentation/test_segstats.py +21 -1
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/segmentation/test_threshold.py +1 -1
- {openretailscience-0.46.0 → openretailscience-0.47.0}/uv.lock +1613 -1605
- openretailscience-0.46.0/.github/workflows/bigquery-integration.yml +0 -67
- openretailscience-0.46.0/.github/workflows/gh-page.yml +0 -45
- openretailscience-0.46.0/.github/workflows/pyspark-integration.yml +0 -63
- openretailscience-0.46.0/.github/workflows/slack-notifications.yml +0 -103
- openretailscience-0.46.0/openretailscience/__init__.py +0 -3
- openretailscience-0.46.0/openretailscience/plots/styles/graph_utils.py +0 -923
- openretailscience-0.46.0/openretailscience/plugin.py +0 -238
- openretailscience-0.46.0/openretailscience/utils/validation.py +0 -45
- openretailscience-0.46.0/tests/plots/styles/test_graph_utils.py +0 -979
- openretailscience-0.46.0/tests/test_plugin.py +0 -367
- openretailscience-0.46.0/tests/utils/test_validation.py +0 -87
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.claude/commands/review-pr-tests.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.env_sample +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.gitignore +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/.markdownlint.json +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/CNAME +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/CODE_OF_CONDUCT.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/CONTRIBUTING.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/LICENSE +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/README.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/data/transactions.parquet +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/analysis_modules.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/cohort.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/composite_rank.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/cross_shop.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/customer.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/customer_decision_hierarchy.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/gain_loss.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/haversine.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/product_association.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/analysis/revenue_tree.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/metrics/distribution.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/options.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/area.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/bar.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/broken_timeline.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/cohort.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/heatmap.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/histogram.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/index.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/line.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/period_on_period.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/price.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/scatter.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/styles/graph_utils.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/styles/styling_helpers.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/time.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/venn.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/plots/waterfall.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/segmentation/hml.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/segmentation/nlr.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/segmentation/rfm.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/segmentation/segstats.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/segmentation/threshold.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/utils/date.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/utils/filter_and_label.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/api/utils/label.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/cohort.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/cross_shop.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/customer_decision_hierarchy.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/days_between_purchases.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/gain_loss.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/hml_segmentation.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/purchases_per_customer.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/revenue_tree.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/threshold_segmentation.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/analysis_modules/transaction_churn.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/features/charts.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/features/cross_shop.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/area_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/bar_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/broken_timeline_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/cohort_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/customer_decision_hierarchy_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/heatmap_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/histogram_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/index_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/line_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/period_on_period_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/price_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/revenue_tree_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/scatter_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/time_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/venn_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/gallery/waterfall_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/assets/images/logo.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/examples/cross_shop.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/examples/gain_loss.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/examples/product_association.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/examples/retention.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/examples/revenue_tree.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/examples/segmentation.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/index.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/area.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/bar.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/broken_timeline.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/cohort.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/customer_decision_hierarchy.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/heatmap.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/histogram.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/index_plot.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/line.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/period_on_period.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/price.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/revenue_tree.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/scatter.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/time.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/venn.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/gallery/plots/waterfall.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/getting_started/installation.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/getting_started/styling_guide.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/index.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/javascripts/mathjax.js +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/metrics.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/overrides/home.html +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/overrides/main.html +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/robots.txt +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/scripts/README.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/scripts/regenerate_analysis_modules_svgs.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/docs/stylesheets/extra.css +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/mkdocs.yml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/analysis/haversine.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/assets/fonts/Poppins-Bold.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/assets/fonts/Poppins-LightItalic.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/assets/fonts/Poppins-Medium.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/assets/fonts/Poppins-Regular.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/assets/fonts/Poppins-SemiBold.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/constants.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/metrics/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/metrics/base.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/metrics/distribution/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/options.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/area.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/cohort.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/heatmap.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/histogram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/period_on_period.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/price.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/scatter.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/styles/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/styles/colors.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/styles/font_utils.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/styles/styling_helpers.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/time.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/tree_diagram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/plots/venn.py +0 -0
- /openretailscience-0.46.0/openretailscience/segmentation/__init__.py → /openretailscience-0.47.0/openretailscience/py.typed +0 -0
- {openretailscience-0.46.0/openretailscience/utils → openretailscience-0.47.0/openretailscience/segmentation}/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/segmentation/hml.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/utils/date.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/utils/filter_and_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/openretailscience/utils/label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/options_template.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/readme_assets/cross_shop_chart.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/readme_assets/days_until_next_purchase.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/readme_assets/gain_loss_chart.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/readme_assets/logo.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/readme_assets/logo.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/readme_assets/new_store_cannibalization.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/taplo.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_customer.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_haversine.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/analysis/test_product_association.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/conftest.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_cohort_analysis.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_composite_rank.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_cross_shop.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_customer_decision_hierarchy.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_date.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_filter_and_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_haversine.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_hml_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_product_association.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_revenue_tree.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_rfm_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_segstats_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/integration/test_threshold_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/metrics/test_base.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/styles/test_color.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/styles/test_font_utils.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/styles/test_styling_helper.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_area.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_cohort.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_heatmap.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_histogram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_period_on_period.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_price.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_scatter.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_styling_options_integration.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_time.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_tree_diagram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_venn.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/plots/test_waterfall.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/segmentation/test_hml.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/test_options.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/toml_files/corrupt.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/toml_files/invalid_option.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/toml_files/test_options.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/toml_files/valid.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/utils/test_date.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/utils/test_filter_and_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tests/utils/test_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.47.0}/tox.ini +0 -0
|
@@ -5,6 +5,8 @@ updates:
|
|
|
5
5
|
schedule:
|
|
6
6
|
interval: "weekly"
|
|
7
7
|
open-pull-requests-limit: 5
|
|
8
|
+
cooldown:
|
|
9
|
+
default-days: 7
|
|
8
10
|
commit-message:
|
|
9
11
|
prefix: "chore(deps)"
|
|
10
12
|
prefix-development: "chore(deps-dev)"
|
|
@@ -13,3 +15,16 @@ updates:
|
|
|
13
15
|
dependency-type: "production"
|
|
14
16
|
development-dependencies:
|
|
15
17
|
dependency-type: "development"
|
|
18
|
+
|
|
19
|
+
- package-ecosystem: "github-actions"
|
|
20
|
+
directory: "/"
|
|
21
|
+
schedule:
|
|
22
|
+
interval: "weekly"
|
|
23
|
+
open-pull-requests-limit: 5
|
|
24
|
+
cooldown:
|
|
25
|
+
default-days: 7
|
|
26
|
+
commit-message:
|
|
27
|
+
prefix: "chore(deps)"
|
|
28
|
+
groups:
|
|
29
|
+
actions-minor-patch:
|
|
30
|
+
update-types: ["minor", "patch"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: BigQuery Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
secrets:
|
|
7
|
+
GCP_SA_KEY:
|
|
8
|
+
required: true
|
|
9
|
+
GCP_PROJECT_ID:
|
|
10
|
+
required: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
integration-tests:
|
|
17
|
+
name: Run BigQuery Integration Tests
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 30
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
- name: Setup Python
|
|
26
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.11"
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Install Dependencies
|
|
36
|
+
run: |
|
|
37
|
+
uv sync --locked
|
|
38
|
+
|
|
39
|
+
- name: Set up GCP Authentication
|
|
40
|
+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
|
|
41
|
+
with:
|
|
42
|
+
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
|
43
|
+
|
|
44
|
+
- name: Run Integration Tests
|
|
45
|
+
env:
|
|
46
|
+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
|
|
47
|
+
run: |
|
|
48
|
+
uv run pytest tests/integration -k "bigquery" -v
|
{openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/claude-code-review.yml
RENAMED
|
@@ -27,13 +27,14 @@ jobs:
|
|
|
27
27
|
|
|
28
28
|
steps:
|
|
29
29
|
- name: Checkout repository
|
|
30
|
-
uses: actions/checkout@
|
|
30
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
31
31
|
with:
|
|
32
32
|
fetch-depth: 1
|
|
33
|
+
persist-credentials: false
|
|
33
34
|
|
|
34
35
|
- name: Run Claude Code Review
|
|
35
36
|
id: claude-review
|
|
36
|
-
uses: anthropics/claude-code-action@v1
|
|
37
|
+
uses: anthropics/claude-code-action@787c5a0ce96a9a6cfb050ea0c8f4c05f2447c251 # v1.0.133
|
|
37
38
|
with:
|
|
38
39
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
39
40
|
track_progress: true
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
steps:
|
|
28
28
|
- name: Check user permissions
|
|
29
29
|
id: check_permissions
|
|
30
|
-
uses: actions/github-script@
|
|
30
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
31
31
|
with:
|
|
32
32
|
script: |
|
|
33
33
|
let actor;
|
|
@@ -60,7 +60,7 @@ jobs:
|
|
|
60
60
|
|
|
61
61
|
- name: Comment on permission denied
|
|
62
62
|
if: steps.check_permissions.outputs.has_permission == 'false'
|
|
63
|
-
uses: actions/github-script@
|
|
63
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
64
64
|
with:
|
|
65
65
|
script: |
|
|
66
66
|
let issueNumber;
|
|
@@ -85,14 +85,15 @@ jobs:
|
|
|
85
85
|
|
|
86
86
|
- name: Checkout repository
|
|
87
87
|
if: steps.check_permissions.outputs.has_permission == 'true'
|
|
88
|
-
uses: actions/checkout@
|
|
88
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
89
89
|
with:
|
|
90
90
|
fetch-depth: 1
|
|
91
|
+
persist-credentials: false
|
|
91
92
|
|
|
92
93
|
- name: Run Claude Code
|
|
93
94
|
if: steps.check_permissions.outputs.has_permission == 'true'
|
|
94
95
|
id: claude
|
|
95
|
-
uses: anthropics/claude-code-action@v1
|
|
96
|
+
uses: anthropics/claude-code-action@787c5a0ce96a9a6cfb050ea0c8f4c05f2447c251 # v1.0.133
|
|
96
97
|
with:
|
|
97
98
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
98
99
|
|
{openretailscience-0.46.0 → openretailscience-0.47.0}/.github/workflows/cloudflare-docs-preview.yml
RENAMED
|
@@ -22,20 +22,21 @@ jobs:
|
|
|
22
22
|
|
|
23
23
|
steps:
|
|
24
24
|
- name: Checkout repository
|
|
25
|
-
uses: actions/checkout@
|
|
26
|
-
|
|
25
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
27
28
|
- name: Setup Python
|
|
28
|
-
uses: actions/setup-python@
|
|
29
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
29
30
|
with:
|
|
30
31
|
python-version: "3.11"
|
|
31
32
|
|
|
32
|
-
- name: Install uv
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
- name: Install uv
|
|
34
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
35
|
+
with:
|
|
36
|
+
enable-cache: true
|
|
36
37
|
|
|
37
38
|
- name: Install Dependencies
|
|
38
|
-
run: uv sync
|
|
39
|
+
run: uv sync --locked
|
|
39
40
|
|
|
40
41
|
- name: Build docs
|
|
41
42
|
run: uv run mkdocs build
|
|
@@ -50,7 +51,7 @@ jobs:
|
|
|
50
51
|
|
|
51
52
|
- name: Publish to Cloudflare Pages
|
|
52
53
|
id: cloudflare-deploy
|
|
53
|
-
uses: cloudflare/pages-action@v1
|
|
54
|
+
uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # v1.5.0
|
|
54
55
|
with:
|
|
55
56
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
56
57
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
@@ -61,7 +62,7 @@ jobs:
|
|
|
61
62
|
|
|
62
63
|
- name: Find existing comment
|
|
63
64
|
if: github.event_name == 'pull_request'
|
|
64
|
-
uses: peter-evans/find-comment@
|
|
65
|
+
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
|
|
65
66
|
id: find-comment
|
|
66
67
|
with:
|
|
67
68
|
issue-number: ${{ github.event.pull_request.number }}
|
|
@@ -70,7 +71,7 @@ jobs:
|
|
|
70
71
|
|
|
71
72
|
- name: Create or update deployment comment
|
|
72
73
|
if: github.event_name == 'pull_request'
|
|
73
|
-
uses: peter-evans/create-or-update-comment@
|
|
74
|
+
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
|
|
74
75
|
with:
|
|
75
76
|
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
|
76
77
|
issue-number: ${{ github.event.pull_request.number }}
|
|
@@ -88,7 +89,7 @@ jobs:
|
|
|
88
89
|
|
|
89
90
|
- name: Comment on deployment failure
|
|
90
91
|
if: failure() && github.event_name == 'pull_request'
|
|
91
|
-
uses: actions/github-script@
|
|
92
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
92
93
|
with:
|
|
93
94
|
script: |
|
|
94
95
|
github.rest.issues.createComment({
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Page Deploy
|
|
2
|
+
on:
|
|
3
|
+
workflow_call:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
pages: write
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: "pages"
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
jobs:
|
|
15
|
+
docs:
|
|
16
|
+
environment:
|
|
17
|
+
name: github-pages
|
|
18
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 15
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
- name: Setup Python
|
|
27
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.11"
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
- name: Install Dependencies
|
|
35
|
+
run: uv sync --locked
|
|
36
|
+
- name: Build docs
|
|
37
|
+
run: uv run mkdocs build
|
|
38
|
+
- name: Setup Pages
|
|
39
|
+
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
40
|
+
- name: Upload artifact
|
|
41
|
+
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
42
|
+
with:
|
|
43
|
+
path: "site/"
|
|
44
|
+
- name: Deploy to GitHub Pages
|
|
45
|
+
id: deployment
|
|
46
|
+
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: PySpark 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 PySpark Integration Tests
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 30
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
18
|
+
with:
|
|
19
|
+
persist-credentials: false
|
|
20
|
+
- name: Setup Python
|
|
21
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
|
|
30
|
+
- name: Install Dependencies
|
|
31
|
+
run: |
|
|
32
|
+
uv sync --locked
|
|
33
|
+
|
|
34
|
+
- name: Run Integration Tests
|
|
35
|
+
run: |
|
|
36
|
+
uv run pytest tests/integration -k "pyspark" -v
|
|
@@ -11,9 +11,7 @@ on:
|
|
|
11
11
|
- minor
|
|
12
12
|
- patch
|
|
13
13
|
permissions:
|
|
14
|
-
contents:
|
|
15
|
-
deployments: write
|
|
16
|
-
packages: write
|
|
14
|
+
contents: read
|
|
17
15
|
concurrency:
|
|
18
16
|
group: "release"
|
|
19
17
|
cancel-in-progress: false
|
|
@@ -21,92 +19,79 @@ jobs:
|
|
|
21
19
|
pre-commit:
|
|
22
20
|
name: Pre-Commit Checks
|
|
23
21
|
runs-on: ubuntu-latest
|
|
22
|
+
timeout-minutes: 10
|
|
24
23
|
steps:
|
|
25
24
|
- name: Checkout
|
|
26
|
-
uses: actions/checkout@
|
|
25
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
27
28
|
- name: Setup Python
|
|
28
|
-
uses: actions/setup-python@
|
|
29
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
29
30
|
with:
|
|
30
31
|
python-version: "3.11"
|
|
31
|
-
- name: Install
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
run: uv run pip install pre-commit
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
34
|
+
with:
|
|
35
|
+
enable-cache: true
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: uv sync --locked
|
|
38
38
|
- name: Run Pre-commit
|
|
39
|
-
run: pre-commit run --all-files
|
|
39
|
+
run: uv run pre-commit run --all-files
|
|
40
|
+
|
|
41
|
+
security-audit:
|
|
42
|
+
name: Dependency Security Audit
|
|
43
|
+
uses: ./.github/workflows/security-audit.yml
|
|
44
|
+
permissions:
|
|
45
|
+
contents: read
|
|
46
|
+
security-events: write
|
|
40
47
|
|
|
41
48
|
bigquery-integration-tests:
|
|
42
49
|
name: BigQuery Integration Tests
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- name: Setup Python
|
|
48
|
-
uses: actions/setup-python@v5
|
|
49
|
-
with:
|
|
50
|
-
python-version: "3.11"
|
|
51
|
-
- name: Install uv Package
|
|
52
|
-
run: |
|
|
53
|
-
pip install --upgrade pip
|
|
54
|
-
pip install uv==0.5.30
|
|
55
|
-
- name: Install Dependencies
|
|
56
|
-
run: |
|
|
57
|
-
uv sync
|
|
58
|
-
- name: Set up GCP Authentication
|
|
59
|
-
uses: google-github-actions/auth@v2
|
|
60
|
-
with:
|
|
61
|
-
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
|
62
|
-
- name: Run BigQuery Integration Tests
|
|
63
|
-
env:
|
|
64
|
-
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
|
|
65
|
-
run: |
|
|
66
|
-
uv run pytest tests/integration -k "bigquery" -v
|
|
50
|
+
uses: ./.github/workflows/bigquery-integration.yml
|
|
51
|
+
secrets:
|
|
52
|
+
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
|
|
53
|
+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
|
|
67
54
|
|
|
68
55
|
pyspark-integration-tests:
|
|
69
56
|
name: PySpark Integration Tests
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
run: |
|
|
84
|
-
uv sync
|
|
85
|
-
- name: Run PySpark Integration Tests
|
|
86
|
-
run: |
|
|
87
|
-
uv run pytest tests/integration -k "pyspark" -v
|
|
57
|
+
uses: ./.github/workflows/pyspark-integration.yml
|
|
58
|
+
|
|
59
|
+
snowflake-integration-tests:
|
|
60
|
+
name: Snowflake Integration Tests
|
|
61
|
+
uses: ./.github/workflows/snowflake-integration.yml
|
|
62
|
+
secrets:
|
|
63
|
+
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
|
|
64
|
+
GCP_INFRA_PROJECT_ID: ${{ secrets.GCP_INFRA_PROJECT_ID }}
|
|
65
|
+
SNOWFLAKE_CI_ACCOUNT: ${{ secrets.SNOWFLAKE_CI_ACCOUNT }}
|
|
66
|
+
SNOWFLAKE_CI_USER: ${{ secrets.SNOWFLAKE_CI_USER }}
|
|
67
|
+
SNOWFLAKE_CI_WAREHOUSE: ${{ secrets.SNOWFLAKE_CI_WAREHOUSE }}
|
|
68
|
+
SNOWFLAKE_CI_DATABASE: ${{ secrets.SNOWFLAKE_CI_DATABASE }}
|
|
69
|
+
SNOWFLAKE_CI_SCHEMA: ${{ secrets.SNOWFLAKE_CI_SCHEMA }}
|
|
88
70
|
|
|
89
71
|
multi-python-tests:
|
|
90
72
|
name: Multi-Python Version Tests
|
|
91
73
|
runs-on: ubuntu-latest
|
|
74
|
+
timeout-minutes: 20
|
|
92
75
|
strategy:
|
|
93
76
|
fail-fast: false
|
|
94
77
|
matrix:
|
|
95
78
|
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
96
79
|
steps:
|
|
97
80
|
- name: Checkout code
|
|
98
|
-
uses: actions/checkout@
|
|
81
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
82
|
+
with:
|
|
83
|
+
persist-credentials: false
|
|
99
84
|
- name: Set up Python ${{ matrix.python-version }}
|
|
100
|
-
uses: actions/setup-python@
|
|
85
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
101
86
|
with:
|
|
102
87
|
python-version: ${{ matrix.python-version }}
|
|
103
|
-
- name: Install
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
88
|
+
- name: Install uv
|
|
89
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
90
|
+
with:
|
|
91
|
+
enable-cache: true
|
|
107
92
|
- name: Install dependencies
|
|
108
93
|
run: |
|
|
109
|
-
uv sync
|
|
94
|
+
uv sync --locked
|
|
110
95
|
- name: Run tests (excluding integration)
|
|
111
96
|
run: |
|
|
112
97
|
uv run pytest tests/ --ignore=tests/integration --tb=short -v
|
|
@@ -114,23 +99,30 @@ jobs:
|
|
|
114
99
|
build:
|
|
115
100
|
name: Build
|
|
116
101
|
runs-on: ubuntu-latest
|
|
117
|
-
|
|
102
|
+
timeout-minutes: 15
|
|
103
|
+
needs: [security-audit, pre-commit, bigquery-integration-tests, pyspark-integration-tests, snowflake-integration-tests, multi-python-tests]
|
|
104
|
+
permissions:
|
|
105
|
+
contents: write
|
|
106
|
+
id-token: write
|
|
107
|
+
attestations: write
|
|
118
108
|
env:
|
|
119
109
|
CI_COMMIT_MESSAGE: Continuous Integration Version Bump ${{ inputs.release }}
|
|
120
110
|
steps:
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
# zizmor: ignore[artipacked] this job pushes the version-bump commit and
|
|
112
|
+
# tag, so it requires the GITHUB_TOKEN persisted by actions/checkout. Only
|
|
113
|
+
# dist/ is uploaded as an artifact, not .git/, so the token is not exposed.
|
|
114
|
+
- name: Checkout # zizmor: ignore[artipacked]
|
|
115
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
123
116
|
- name: Setup Python
|
|
124
|
-
uses: actions/setup-python@
|
|
117
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
125
118
|
with:
|
|
126
119
|
python-version: "3.11"
|
|
127
|
-
- name: Install uv
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
pip install uv==0.5.30
|
|
120
|
+
- name: Install uv
|
|
121
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
122
|
+
with:
|
|
123
|
+
enable-cache: true
|
|
132
124
|
- name: Install Dependencies
|
|
133
|
-
run: uv sync --group dev
|
|
125
|
+
run: uv sync --locked --group dev
|
|
134
126
|
- name: Bump Version
|
|
135
127
|
run: |
|
|
136
128
|
uv run python - <<EOF
|
|
@@ -153,8 +145,12 @@ jobs:
|
|
|
153
145
|
EOF
|
|
154
146
|
echo "RELEASE_TAG=$(uv run python -c 'from tomlkit.toml_file import TOMLFile; print(TOMLFile("pyproject.toml").read()["project"]["version"])')" >> $GITHUB_ENV
|
|
155
147
|
- name: Build package
|
|
156
|
-
run:
|
|
157
|
-
-
|
|
148
|
+
run: uv build
|
|
149
|
+
- name: Attest build provenance
|
|
150
|
+
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
|
|
151
|
+
with:
|
|
152
|
+
subject-path: "dist/*"
|
|
153
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
158
154
|
with:
|
|
159
155
|
name: build
|
|
160
156
|
path: dist/
|
|
@@ -164,38 +160,19 @@ jobs:
|
|
|
164
160
|
git config user.name 'github-actions[bot]'
|
|
165
161
|
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
|
166
162
|
git add pyproject.toml
|
|
167
|
-
git commit -m "$
|
|
163
|
+
git commit -m "$CI_COMMIT_MESSAGE"
|
|
168
164
|
git push
|
|
169
165
|
echo "Tagging new version: $RELEASE_TAG"
|
|
170
166
|
git tag -a "$RELEASE_TAG" -m "Auto-generated tag"
|
|
171
167
|
git push origin "$RELEASE_TAG"
|
|
172
|
-
- name:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
script: |
|
|
177
|
-
if (!process.env.RELEASE_TAG) {
|
|
178
|
-
core.setFailed("The environment variable RELEASE_TAG is not defined.");
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
try {
|
|
182
|
-
const response = await github.rest.repos.createRelease({
|
|
183
|
-
draft: false,
|
|
184
|
-
generate_release_notes: true,
|
|
185
|
-
name: process.env.RELEASE_TAG,
|
|
186
|
-
owner: context.repo.owner,
|
|
187
|
-
prerelease: false,
|
|
188
|
-
repo: context.repo.repo,
|
|
189
|
-
tag_name: process.env.RELEASE_TAG,
|
|
190
|
-
});
|
|
191
|
-
core.exportVariable('RELEASE_ID', response.data.id);
|
|
192
|
-
core.exportVariable('RELEASE_UPLOAD_URL', response.data.upload_url);
|
|
193
|
-
} catch (error) {
|
|
194
|
-
core.setFailed(error.message);
|
|
195
|
-
}
|
|
168
|
+
- name: Create release
|
|
169
|
+
env:
|
|
170
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
171
|
+
run: gh release create "$RELEASE_TAG" --generate-notes
|
|
196
172
|
pypi-publish:
|
|
197
173
|
name: Upload release to PyPI
|
|
198
174
|
runs-on: ubuntu-latest
|
|
175
|
+
timeout-minutes: 10
|
|
199
176
|
needs: build
|
|
200
177
|
environment:
|
|
201
178
|
name: production
|
|
@@ -203,13 +180,14 @@ jobs:
|
|
|
203
180
|
permissions:
|
|
204
181
|
id-token: write
|
|
205
182
|
steps:
|
|
206
|
-
- uses: actions/download-artifact@
|
|
183
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
207
184
|
with:
|
|
208
185
|
name: build
|
|
209
186
|
path: dist
|
|
210
187
|
- name: Publish package distributions to PyPI
|
|
211
|
-
uses: pypa/gh-action-pypi-publish@
|
|
212
|
-
|
|
188
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
189
|
+
with:
|
|
190
|
+
attestations: true
|
|
213
191
|
deploy-docs:
|
|
214
192
|
name: Deploy Documentation
|
|
215
193
|
needs: pypi-publish
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: Security Audit
|
|
2
|
+
|
|
3
|
+
# Scans the resolved dependency lockfile (uv.lock) for known vulnerabilities
|
|
4
|
+
# using OSV-Scanner. Because it reads uv.lock statically, it audits every pinned
|
|
5
|
+
# version across all supported Python versions (3.10-3.13) and platforms.
|
|
6
|
+
# Results are uploaded to GitHub code scanning (Security tab) as SARIF, so a
|
|
7
|
+
# newly-disclosed CVE in a pinned dependency surfaces as a failing check and a
|
|
8
|
+
# code-scanning alert rather than a passive Dependabot alert.
|
|
9
|
+
#
|
|
10
|
+
# Suppressions (each with a rationale, and an ignoreUntil expiry where a fix may
|
|
11
|
+
# yet appear) live in osv-scanner.toml at the repo root.
|
|
12
|
+
#
|
|
13
|
+
# On pull requests the scan runs only when dependencies or this workflow change,
|
|
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.
|
|
17
|
+
|
|
18
|
+
on:
|
|
19
|
+
pull_request:
|
|
20
|
+
types: [opened, synchronize]
|
|
21
|
+
paths:
|
|
22
|
+
- "uv.lock"
|
|
23
|
+
- "pyproject.toml"
|
|
24
|
+
- "osv-scanner.toml"
|
|
25
|
+
- ".github/workflows/security-audit.yml"
|
|
26
|
+
push:
|
|
27
|
+
branches: [main]
|
|
28
|
+
paths:
|
|
29
|
+
- "uv.lock"
|
|
30
|
+
- "pyproject.toml"
|
|
31
|
+
- "osv-scanner.toml"
|
|
32
|
+
- ".github/workflows/security-audit.yml"
|
|
33
|
+
schedule:
|
|
34
|
+
- cron: "0 6 * * 1" # Mondays 06:00 UTC
|
|
35
|
+
workflow_dispatch:
|
|
36
|
+
workflow_call:
|
|
37
|
+
|
|
38
|
+
permissions: {}
|
|
39
|
+
|
|
40
|
+
concurrency:
|
|
41
|
+
group: "security-audit-${{ github.ref }}-${{ github.event_name }}"
|
|
42
|
+
cancel-in-progress: true
|
|
43
|
+
|
|
44
|
+
jobs:
|
|
45
|
+
osv-scan:
|
|
46
|
+
name: OSV-Scanner (uv.lock)
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
timeout-minutes: 10
|
|
49
|
+
permissions:
|
|
50
|
+
contents: read
|
|
51
|
+
security-events: write # upload SARIF to code scanning
|
|
52
|
+
steps:
|
|
53
|
+
- name: Checkout
|
|
54
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
55
|
+
with:
|
|
56
|
+
persist-credentials: false
|
|
57
|
+
- name: Run OSV-Scanner
|
|
58
|
+
id: osv
|
|
59
|
+
continue-on-error: true # gate is enforced explicitly below, after SARIF upload
|
|
60
|
+
uses: google/osv-scanner-action/osv-scanner-action@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8
|
|
61
|
+
with:
|
|
62
|
+
scan-args: |-
|
|
63
|
+
--config=osv-scanner.toml
|
|
64
|
+
--format=sarif
|
|
65
|
+
--output=results.sarif
|
|
66
|
+
--lockfile=uv.lock
|
|
67
|
+
- name: Upload results to code scanning
|
|
68
|
+
# Skip cleanly if the scanner errored before writing the SARIF, rather
|
|
69
|
+
# than erroring and being swallowed by continue-on-error.
|
|
70
|
+
if: always() && hashFiles('results.sarif') != ''
|
|
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
|
|
73
|
+
with:
|
|
74
|
+
sarif_file: results.sarif
|
|
75
|
+
category: osv-scanner
|
|
76
|
+
- name: Enforce gate
|
|
77
|
+
# Pull requests are advisory only (results still post to code scanning);
|
|
78
|
+
# every other trigger is a hard gate. Fail closed: block unless the scan
|
|
79
|
+
# completed successfully, so a failed, errored, or skipped scan never
|
|
80
|
+
# passes the gate. !cancelled() (rather than always()) avoids marking a
|
|
81
|
+
# concurrency-superseded run as failed; a real timeout still blocks
|
|
82
|
+
# downstream via the job's needs dependency.
|
|
83
|
+
if: ${{ !cancelled() && github.event_name != 'pull_request' && steps.osv.outcome != 'success' }}
|
|
84
|
+
run: |
|
|
85
|
+
echo "::error::OSV-Scanner did not complete cleanly (vulnerabilities found or scan failed) — see the SARIF results in the Security tab."
|
|
86
|
+
exit 1
|