Skip to content

refactor: split outliers.py into a subpackage (#197) - #268

Open
iabaako wants to merge 1 commit into
refactor/197-split-gpschecks-modulefrom
refactor/197-split-outliers-module
Open

refactor: split outliers.py into a subpackage (#197)#268
iabaako wants to merge 1 commit into
refactor/197-split-gpschecks-modulefrom
refactor/197-split-outliers-module

Conversation

@iabaako

@iabaako iabaako commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Pull Request Summary 🚀

What does this PR do? 📝

Splits src/datasure/checks/outliers.py (2,864 lines) into a subpackage, src/datasure/checks/outliers/:

  • models.py — enums, Pydantic settings/result models, TAB_NAME
  • compute.py — pure outlier/constraint computation functions and chart builders (no Streamlit calls)
  • settings_ui.py — just outliers_report_settings
  • report_ui.pyoutliers_report, its report-rendering helpers, and the full column-configuration CRUD group (add/update/delete/validate/format-error/settings-table), which turned out to be called only from outliers_report, not outliers_report_settings, despite settings-sounding names — same pattern found in the two prior splits
  • __init__.py — left empty, matching every other package in this repo

Also eliminates two intra-file duplicates found while splitting:

  • _validate_constraint_settings/_validate_outlier_settings shared an identical try/except/format/return shape → extracted a generic _validate_settings(settings, model_cls, format_error) helper
  • _render_constraint_violations_table/_render_outlier_table shared a near-identical "show more columns" expander/multiselect/save block → extracted _render_display_columns_expander(...)

Tests are mirrored into tests/checks/outliers/{conftest,test_models,test_compute,test_settings_ui,test_report_ui}.py, replacing the 3,528-line tests/checks/test_outliers.py, including the one pre-existing skip (test_stack_empty_dataframe, "Empty DataFrame causes Rust panic in Polars/Streamlit caching") preserved verbatim.

This is the fourth and last of the four splits tracked by #197 (enumerator in #265, backchecks in #266, gpschecks in #267), stacked on top of refactor/197-split-gpschecks-module since that PR is still open.

Why is this change needed? 🤔

Per #197: outliers.py mixed statistical/constraint computation with two distinct Streamlit UI flows (settings vs. report) in one 2,864-line file — the last of the four modules flagged as hard to navigate and review.

How was this implemented? 🛠️

Pure mechanical reorganization — no logic changes, aside from the two documented deduplications above (verified to produce identical output via the existing test suite). Grepped the full src/ tree to confirm only output_view_template.py imports from this module externally, and updated it to import outliers_report directly from datasure.checks.outliers.report_ui. The generated, gitignored output_view_1.py was left untouched, per this repo's convention of never editing generated output views directly.

How to test or reproduce ? 🧪

  1. uv run python -m pytest tests/checks/outliers --cov=datasure.checks.outliers --cov-report=term-missing -q — 228/228 tests pass (exact match to the pre-split count, including the preserved skip), coverage improved from 97.44% to 97.47%
  2. uv run python -m pytest -q -m "not slow" — full suite passes, same 7 pre-existing skips in the same places
  3. Confirm the Outliers & Constraints report page in the app still renders and its settings still save/load correctly

Screenshots (if applicable) 📷

N/A — no UI or behavior changes.

Checklist ✅

  • I have run and tested my changes locally
  • I have limit this PR to less than 1000 lines of code change (if not, explain why) — ~4,700 lines changed, but this is a pure file-move/reorganization plus two small, verified dedup extractions; splitting it into multiple PRs would fragment a single mechanical refactor for no review benefit
  • I have updated/added tests to cover my changes (if applicable)
  • I have updated/added requirements to cover my changes (if applicable)
  • I have run linting and formatting on any code changes (if applicable)
  • I have updated the documentation (README, etc.) accordingly
  • I have reviewed and resolved any merge conflict

🤖 Generated with Claude Code

Splits the 2,864-line checks/outliers.py into models/compute/
settings_ui/report_ui submodules, mirroring the enumerator, backchecks,
and gpschecks splits. __init__.py stays empty per convention;
output_view_template.py now imports outliers_report directly from
datasure.checks.outliers.report_ui.

The full column-config CRUD group (add/update/delete/validate/
format-error/settings-table) turned out to be called only from
outliers_report, not outliers_report_settings, despite settings-sounding
names - moved to report_ui.py, same pattern as the prior two splits.

Also eliminates two intra-file duplicates found while splitting:
_validate_constraint_settings/_validate_outlier_settings share a new
_validate_settings generic Pydantic-validate-and-report helper, and
_render_constraint_violations_table/_render_outlier_table share a new
_render_display_columns_expander. No behavior change.

Tests mirrored into tests/checks/outliers/ with no logic changes;
228/228 tests pass (including the preserved Rust-panic skip), coverage
improved from 97.44% to 97.47%.

This completes all four splits planned in #197.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@iabaako
iabaako requested a review from a team as a code owner August 7, 2026 22:27
@iabaako iabaako linked an issue Aug 7, 2026 that may be closed by this pull request
@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Split oversized check modules (post-1.0)

1 participant