From b94f48abd5d00e5037991f61eef72ff38a43f608 Mon Sep 17 00:00:00 2001 From: maskedsyntax Date: Tue, 20 Oct 2026 21:27:45 +0530 Subject: [PATCH 1/4] feat: ship the 0.2 production gate Treat critical findings as training blockers, share one column-role model across checks, and escape dataset text in HTML reports. --- .github/workflows/ci.yml | 14 +- .github/workflows/release.yml | 13 +- CHANGELOG.md | 16 + CONTRIBUTING.md | 2 +- README.md | 48 ++- SECURITY.md | 7 +- hashprep/__init__.py | 2 +- hashprep/checks/__init__.py | 1 + hashprep/checks/columns.py | 3 +- hashprep/checks/core.py | 4 + hashprep/checks/correlations.py | 11 +- hashprep/checks/distribution.py | 5 +- hashprep/checks/drift.py | 81 ++++- hashprep/checks/leakage.py | 200 ++++++----- hashprep/checks/missing_values.py | 25 +- hashprep/checks/mutual_info.py | 4 + hashprep/checks/outliers.py | 25 +- hashprep/checks/roles.py | 33 ++ hashprep/checks/statistical_tests.py | 27 +- hashprep/config.py | 6 + hashprep/core/analyzer.py | 104 ++++-- hashprep/interfaces/cli/main.py | 242 +++++++------ hashprep/preparers/codegen.py | 6 +- hashprep/preparers/pipeline_builder.py | 117 ++++-- hashprep/preparers/strategies/base.py | 10 +- hashprep/preparers/strategies/column_ops.py | 2 +- hashprep/preparers/strategies/encoding.py | 17 +- hashprep/preparers/strategies/imputation.py | 7 +- hashprep/preparers/strategies/outlier.py | 37 +- hashprep/preparers/strategies/scaling.py | 11 +- .../preparers/strategies/transformation.py | 8 +- hashprep/reports/base.py | 11 + hashprep/reports/generators.py | 12 +- hashprep/reports/html.py | 6 +- hashprep/reports/pdf.py | 7 +- hashprep/utils/type_inference.py | 129 +++++-- pyproject.toml | 17 +- tests/test_cli.py | 26 +- tests/test_code_execution.py | 19 + tests/test_config_loader.py | 4 +- tests/test_gate.py | 142 ++++++++ tests/test_library_api.py | 22 +- tests/test_release.py | 339 ++++++++++++++++++ uv.lock | 154 +++++++- web/src/lib/components/Hero.svelte | 4 +- 45 files changed, 1507 insertions(+), 473 deletions(-) create mode 100644 hashprep/checks/roles.py create mode 100644 tests/test_gate.py create mode 100644 tests/test_release.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81d639f..07e2c35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 @@ -23,7 +23,7 @@ jobs: run: uv python install ${{ matrix.python-version }} - name: Install dependencies - run: uv sync --dev + run: uv sync --group dev --all-extras - name: Run tests run: uv run pytest tests/ -v --tb=short @@ -40,7 +40,7 @@ jobs: run: uv python install 3.12 - name: Install dependencies - run: uv sync --dev + run: uv sync --group dev --all-extras - name: Run ruff check run: uv run ruff check . @@ -65,6 +65,14 @@ jobs: - name: Check build artifacts run: uvx twine check dist/* + - name: Smoke test the core wheel + run: | + uv venv /tmp/hashprep-smoke + uv pip install --python /tmp/hashprep-smoke/bin/python dist/*.whl + status=0 + /tmp/hashprep-smoke/bin/hashprep scan datasets/train.csv --target Survived --preset gate --fail-on critical --json || status=$? + test "$status" -eq 2 + web-check: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b452be0..0b87d2a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,10 +25,14 @@ jobs: - name: Build package run: uv build + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/* + - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - # with: - # repository-url: https://upload.pypi.org/legacy/ # Optional: defaults to PyPI github-release: runs-on: ubuntu-latest @@ -37,6 +41,11 @@ jobs: contents: write steps: - uses: actions/checkout@v4 + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: dist + path: dist - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b95fc1..b651b7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.0] - 2026-10-20 + +### Breaking +- `critical` means a training blocker. Non-normality is always a warning. Drift is critical only when the shift is large, not merely when the p-value is small. +- `DatasetAnalyzer` and `hashprep scan` / `details` default to the `gate` preset. `hashprep report` defaults to `profile`. Pass `preset="profile"` or `--preset profile` for the previous full catalogue. +- Sampling is off unless `--sample-size` or `auto_sample=True` is set. +- `scan --json` now uses `schema_version`, `critical_count`, `warning_count`, `total_issues`, `issues`, and `sampling_info`. `details --json` prints the same object. +- F-statistic leakage thresholds are ignored. Leakage uses correlation, bias-corrected Cramér's V, or correlation ratio. +- Plots, HTML, and PDF require `pip install "hashprep[reports]"`. Parquet requires `pip install "hashprep[parquet]"`. + +### Added +- Column roles (`target`, `identifier`, `boolean`, `categorical`, `numeric`, `datetime`, `text`) shared by every check. +- `--preset`, `--fail-on`, and Parquet input. +- `statistic` and `effect_size` on each issue. +- Generated code escapes column names. Sklearn steps with the same transformation are grouped. Outlier clipping is a real pre-pipeline function. + ## [0.1.0] - 2026-05-22 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41d8778..9e1c482 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ source .venv/bin/activate ### Install in development mode ```bash -uv sync --extra dev +uv sync --group dev --all-extras ``` - + - +

@@ -27,15 +27,15 @@ > [!NOTE] -> HashPrep 0.2.0 is the production gate release. `critical` means "do not train this table as-is." +> Tablint 0.1.0b1 is the first public beta. `critical` means "do not train this table as-is." ## Overview -**HashPrep** is a Python library for intelligent dataset profiling and debugging that acts as a comprehensive pre-training quality assurance tool for machine learning projects. +**Tablint** is a Python library for intelligent dataset profiling and debugging that acts as a comprehensive pre-training quality assurance tool for machine learning projects. Think of it as **"Pandas Profiling + PyLint for datasets"**, designed specifically for machine learning workflows. It catches critical dataset issues before they derail your ML pipeline, explains the problems, and suggests context-aware fixes. -If you want, HashPrep can even apply those fixes for you automatically. +If you want, Tablint can even apply those fixes for you automatically. --- @@ -57,7 +57,7 @@ Key features include: ### Using pip ```bash -pip install hashprep +pip install tablint ``` ### Using uv (recommended) @@ -65,29 +65,29 @@ pip install hashprep # Install uv if you haven't already curl -LsSf https://astral.sh/uv/install.sh | sh -# Install hashprep -uv pip install hashprep +# Install tablint +uv pip install tablint # Or for development from source -git clone https://github.com/cachevector/hashprep.git -cd hashprep +git clone https://github.com/cachevector/tablint.git +cd tablint uv sync ``` -After installation, the `hashprep` command will be available directly in your terminal. +After installation, the `tablint` command will be available directly in your terminal. --- ## Usage -HashPrep can be used both as a **command-line tool** and as a **Python library**. +Tablint can be used both as a **command-line tool** and as a **Python library**. ### CLI Usage #### 1. Quick Scan Get a quick summary of critical issues in your terminal. ```bash -hashprep scan dataset.csv +tablint scan dataset.csv ``` **Options:** @@ -106,29 +106,29 @@ hashprep scan dataset.csv **Example:** ```bash # Block a training job when the table is not trainable -hashprep scan train.csv --target Survived --preset gate --fail-on critical +tablint scan train.csv --target Survived --preset gate --fail-on critical # Quick scan with JSON output -hashprep scan dataset.csv --json --quiet +tablint scan dataset.csv --json --quiet ``` #### 2. Detailed Analysis Get comprehensive details about all detected issues. ```bash -hashprep details dataset.csv +tablint details dataset.csv ``` **Options:** Same as `scan` command (including `--config`) **Example:** ```bash -hashprep details train.csv --target Survived +tablint details train.csv --target Survived ``` #### 3. Generate Reports Generate comprehensive reports in multiple formats with visualizations. ```bash -hashprep report dataset.csv --format html --theme minimal +tablint report dataset.csv --format html --theme minimal ``` **Options:** @@ -149,36 +149,36 @@ hashprep report dataset.csv --format html --theme minimal **Examples:** ```bash # Generate HTML report with minimal theme -hashprep report dataset.csv --format html --theme minimal --full +tablint report dataset.csv --format html --theme minimal --full # Generate PDF report without visualizations (faster) -hashprep report dataset.csv --format pdf --no-visualizations +tablint report dataset.csv --format pdf --no-visualizations # Generate report with automatic fix scripts -hashprep report dataset.csv --with-code +tablint report dataset.csv --with-code # Generate report with custom output path -hashprep report dataset.csv --format html --output my_reports/analysis.html +tablint report dataset.csv --format html --output my_reports/analysis.html # This creates: -# - dataset_hashprep_report.md (or .html/.pdf/.json) -# - dataset_hashprep_report_fixes.py (pandas script) -# - dataset_hashprep_report_pipeline.py (sklearn pipeline) +# - dataset_tablint_report.md (or .html/.pdf/.json) +# - dataset_tablint_report_fixes.py (pandas script) +# - dataset_tablint_report_pipeline.py (sklearn pipeline) # Compare two datasets for drift detection -hashprep report train.csv --comparison test.csv --format html +tablint report train.csv --comparison test.csv --format html ``` #### 4. List Available Checks -Discover all data quality checks that HashPrep can perform. +Discover all data quality checks that Tablint can perform. ```bash -hashprep checks +tablint checks ``` #### 5. Version -Check HashPrep version. +Check Tablint version. ```bash -hashprep version +tablint version ``` #### Available Checks @@ -221,7 +221,7 @@ hashprep version #### Basic Analysis ```python import pandas as pd -from hashprep import DatasetAnalyzer +from tablint import DatasetAnalyzer # Load your dataset df = pd.read_csv("dataset.csv") @@ -286,7 +286,7 @@ summary = analyzer.analyze() #### Generate Reports Programmatically ```python -from hashprep.reports import generate_report +from tablint.reports import generate_report # Analyze dataset analyzer = DatasetAnalyzer(df, include_plots=True) @@ -328,10 +328,10 @@ generate_report( #### Generate Fix Scripts ```python -from hashprep.checks.core import Issue -from hashprep.preparers.codegen import CodeGenerator -from hashprep.preparers.pipeline_builder import PipelineBuilder -from hashprep.preparers.suggestions import SuggestionProvider +from tablint.checks.core import Issue +from tablint.preparers.codegen import CodeGenerator +from tablint.preparers.pipeline_builder import PipelineBuilder +from tablint.preparers.suggestions import SuggestionProvider # After running analysis analyzer = DatasetAnalyzer(df, target_col='target') @@ -364,17 +364,17 @@ with open('pipeline.py', 'w') as f: #### Load Config from File ```python -from hashprep.utils.config_loader import load_config -from hashprep import DatasetAnalyzer +from tablint.utils.config_loader import load_config +from tablint import DatasetAnalyzer # Load thresholds from YAML, TOML, or JSON -config = load_config("hashprep.yaml") # or .toml / .json +config = load_config("tablint.yaml") # or .toml / .json analyzer = DatasetAnalyzer(df, config=config) summary = analyzer.analyze() ``` -Example `hashprep.yaml`: +Example `tablint.yaml`: ```yaml missing_values: warning: 0.3 @@ -389,7 +389,7 @@ Only the keys you specify are overridden; all others fall back to defaults. #### Custom Sampling ```python -from hashprep.utils.sampling import SamplingConfig +from tablint.utils.sampling import SamplingConfig # Configure sampling for large datasets sampling_config = SamplingConfig(max_rows=10000) @@ -411,7 +411,7 @@ if 'sampling_info' in summary: ## Production gate -`DatasetAnalyzer` defaults to the `gate` preset. `hashprep report` defaults to `profile`. +`DatasetAnalyzer` defaults to the `gate` preset. `tablint report` defaults to `profile`. `critical` is reserved for defects that should stop a training job: an empty table, an all-null column, missingness at or above the critical threshold, infinite values, duplicate rows above the critical ratio, a column identical or nearly identical to the target, and drift whose effect size is large. Skew, non-normality, ordinary correlation with the target, and zero-inflation of a binary target are warnings, and most of them run only in the `profile` preset. @@ -424,14 +424,14 @@ Stable keys in `analyze()` and in `scan --json` / `details --json`: `summaries` and plots are best-effort and can change without a major version. ```bash -hashprep scan train.csv --target Survived --preset gate --fail-on critical --json +tablint scan train.csv --target Survived --preset gate --fail-on critical --json ``` Exit 2 when `--fail-on` matches. A job that only checks the exit code should pass `--fail-on critical`. ### Limitations -- Input is CSV, or Parquet when `hashprep[parquet]` is installed. HTML, PDF, and plots need `hashprep[reports]`. +- Input is CSV, or Parquet when `tablint[parquet]` is installed. HTML, PDF, and plots need `tablint[reports]`. - Leakage means near-deterministic association with the target, not a proof that a column was built from the label. - Sampling is off unless you pass `--sample-size` or `auto_sample=True`. Checks then describe the analyzed frame, which is the full table by default. - Generated pandas code learns fill values from the frame you pass. Pass the training split, or fit the generated sklearn pipeline on that split. @@ -446,7 +446,7 @@ This project is licensed under the [**MIT License**](./LICENSE). ## Contributing -We welcome contributions from the community to make HashPrep better! +We welcome contributions from the community to make Tablint better! Before you get started, please: diff --git a/RELEASE_TODO.md b/RELEASE_TODO.md index 5c3bb49..b0620ea 100644 --- a/RELEASE_TODO.md +++ b/RELEASE_TODO.md @@ -1,10 +1,10 @@ -# HashPrep Official Release TODO +# Tablint Official Release TODO ## Release Scope - [x] Decide the official version target, likely `0.1.0` unless the release should signal `1.0.0`. - [x] Freeze public API expectations for `DatasetAnalyzer`. -- [x] Freeze public API expectations for `HashPrepConfig`. +- [x] Freeze public API expectations for `TablintConfig`. - [x] Freeze public API expectations for `load_config`. - [x] Freeze public API expectations for `generate_report`. - [x] Freeze CLI behavior for `scan`, `details`, `report`, and `version`. @@ -65,11 +65,11 @@ ### Strongly Recommended -- [x] Add an `--output` option to `hashprep report`. -- [x] Allow `hashprep report data.csv --format html --output reports/data.html`. -- [x] Add machine-readable JSON output for `hashprep details`. -- [x] Add check discovery through a command such as `hashprep checks`. -- [x] Alternatively add check discovery through an option such as `hashprep scan --list-checks`. +- [x] Add an `--output` option to `tablint report`. +- [x] Allow `tablint report data.csv --format html --output reports/data.html`. +- [x] Add machine-readable JSON output for `tablint details`. +- [x] Add check discovery through a command such as `tablint checks`. +- [x] Alternatively add check discovery through an option such as `tablint scan --list-checks`. - [x] Document why issues are classified as `critical` versus `warning`. - [x] Review whether PDF/reporting dependencies should move to optional extras in a future release. - [x] Document any dependency-extra plan if it is deferred. @@ -84,7 +84,7 @@ ## Packaging -- [x] Update `hashprep/__init__.py` from `0.1.0b3` to the official release version. +- [x] Update `tablint/__init__.py` from `0.1.0b3` to the official release version. - [x] Update the beta note in `README.md`. - [x] Update the beta support table in `SECURITY.md`. - [x] Add or verify PyPI classifiers in `pyproject.toml`. @@ -96,10 +96,10 @@ - [x] Build wheel distribution. - [x] Inspect built package artifacts. - [x] Install the built wheel in a clean environment. -- [x] Smoke test `import hashprep` from the built wheel. -- [x] Smoke test `hashprep version` from the built wheel. -- [x] Smoke test `hashprep scan datasets/train.csv` from the built wheel. -- [x] Smoke test `hashprep report datasets/train.csv --format html` from the built wheel. +- [x] Smoke test `import tablint` from the built wheel. +- [x] Smoke test `tablint version` from the built wheel. +- [x] Smoke test `tablint scan datasets/train.csv` from the built wheel. +- [x] Smoke test `tablint report datasets/train.csv --format html` from the built wheel. - [x] Confirm `MANIFEST.in` excludes dev/demo files intentionally. - [x] Confirm `MANIFEST.in` includes all runtime files needed by reports and templates. @@ -165,15 +165,15 @@ - [x] Tag the release, for example `v0.1.0`. - [x] Publish to PyPI. - [x] Create GitHub release with release notes. -- [x] Verify public install with `pip install hashprep`. -- [x] Verify public CLI with `hashprep version`. +- [x] Verify public install with `pip install tablint`. +- [x] Verify public CLI with `tablint version`. - [x] Announce the release as the first stable release after alpha and beta. ## Known Immediate Gaps - [x] Version is still `0.1.0b3`. - [x] `README.md` still says beta. -- [x] Website hero still says beta and shows `hashprep-0.1.0b3`. +- [x] Website hero still says beta and shows `tablint-0.1.0b3`. - [x] `SECURITY.md` only describes beta support. - [x] `CHANGELOG.md` is not present. - [x] CI does not currently build or check publish artifacts. diff --git a/SECURITY.md b/SECURITY.md index aa7882e..3c900f6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,18 +6,17 @@ Only the latest minor release is supported for security updates. | Version | Supported | | ---------- | ------------------ | -| `0.2.x` | :white_check_mark: | -| `0.1.0` | :x: | -| `< 0.1.0` | :x: | +| `0.1.0b1` | :white_check_mark: | +| `< 0.1.0b1`| :x: | ## Reporting a Vulnerability -If you believe you have found a security vulnerability in hashprep (the Python package, the CLI, or the documentation website under `web/`), **please do not open a public GitHub issue**. +If you believe you have found a security vulnerability in tablint (the Python package, the CLI, or the documentation website under `web/`), **please do not open a public GitHub issue**. Instead, report it privately through one of the following channels: -- **GitHub Private Vulnerability Reporting** — preferred. Open a report at . -- **Email** — `aftaab@aftaab.xyz` with the subject line `hashprep security report`. +- **GitHub Private Vulnerability Reporting** — preferred. Open a report at . +- **Email** — `aftaab@aftaab.xyz` with the subject line `tablint security report`. Please include as much of the following as you can: @@ -36,12 +35,12 @@ Please include as much of the following as you can: In scope: -- The `hashprep` Python package and CLI. +- The `tablint` Python package and CLI. - The documentation site in `web/`. - Build, packaging, and release tooling in this repository. Out of scope: -- Vulnerabilities in third-party dependencies — please report those upstream. If a dependency issue affects hashprep users, we still appreciate a heads-up so we can bump the pinned version. +- Vulnerabilities in third-party dependencies — please report those upstream. If a dependency issue affects tablint users, we still appreciate a heads-up so we can bump the pinned version. - Issues that require physical access to a user's machine or already-compromised environments. - Denial of service caused by passing intentionally malformed datasets far outside the documented usage (e.g., multi-TB crafted inputs on a laptop). diff --git a/docs/assets/hashprep-dark.svg b/docs/assets/tablint-dark.svg similarity index 100% rename from docs/assets/hashprep-dark.svg rename to docs/assets/tablint-dark.svg diff --git a/docs/assets/hashprep-light-bg.svg b/docs/assets/tablint-light-bg.svg similarity index 100% rename from docs/assets/hashprep-light-bg.svg rename to docs/assets/tablint-light-bg.svg diff --git a/docs/assets/hashprep-light.svg b/docs/assets/tablint-light.svg similarity index 100% rename from docs/assets/hashprep-light.svg rename to docs/assets/tablint-light.svg diff --git a/docs/assets/hashprep-wobg.svg b/docs/assets/tablint-wobg.svg similarity index 100% rename from docs/assets/hashprep-wobg.svg rename to docs/assets/tablint-wobg.svg diff --git a/examples/reports/train_hashprep_report.html b/examples/reports/train_tablint_report.html similarity index 99% rename from examples/reports/train_hashprep_report.html rename to examples/reports/train_tablint_report.html index 3246499..2b1f694 100644 --- a/examples/reports/train_hashprep_report.html +++ b/examples/reports/train_tablint_report.html @@ -4,7 +4,7 @@ - HashPrep Quality Report [NEO] + Tablint Quality Report [NEO] @@ -23,7 +23,7 @@

-

HashPrep // Report

+

Tablint // Report

VERSION: 0.1.0a4

@@ -2846,13 +2846,13 @@

Tail (last 5 r
- *** HashPrep ::: Dataset Debugger *** + *** Tablint ::: Dataset Debugger ***

@@ -114,7 +114,7 @@ def _minimal_template(self):
- HashPrep + Tablint v{{ version }}
@@ -279,7 +279,7 @@ def _minimal_template(self):
Software version
-
hashprep v{{ version }}
+
tablint v{{ version }}
{% if not pdf_mode %} @@ -676,7 +676,7 @@ def _minimal_template(self):
-

Built with HashPrep

+

Built with Tablint

@@ -730,7 +730,7 @@ def _neubrutalism_template(self):
-

HashPrep // Report

+

Tablint // Report

VERSION: {{ version }}

@@ -1170,7 +1170,7 @@ def _neubrutalism_template(self): {% endif %}
- *** HashPrep ::: Dataset Debugger *** + *** Tablint ::: Dataset Debugger ***
@@ -1182,7 +1182,7 @@ def _neubrutalism_template(self): const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; - a.download = 'hashprep_config.json'; + a.download = 'tablint_config.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); diff --git a/hashprep/reports/json.py b/tablint/reports/json.py similarity index 98% rename from hashprep/reports/json.py rename to tablint/reports/json.py index ec9b92a..79b6035 100644 --- a/hashprep/reports/json.py +++ b/tablint/reports/json.py @@ -3,7 +3,7 @@ import numpy as np -import hashprep +import tablint def json_numpy_handler(obj): @@ -24,7 +24,7 @@ def generate(self, summary, full=False, output_file=None): report: dict = { "metadata": { "generated": datetime.now().isoformat(), - "version": hashprep.__version__, + "version": tablint.__version__, }, "dataset_overview": { "statistics": { diff --git a/hashprep/reports/markdown.py b/tablint/reports/markdown.py similarity index 98% rename from hashprep/reports/markdown.py rename to tablint/reports/markdown.py index 1af75c4..d09b028 100644 --- a/hashprep/reports/markdown.py +++ b/tablint/reports/markdown.py @@ -3,7 +3,7 @@ import pandas as pd -import hashprep +import tablint from ..utils.logging import get_logger from .base import BaseReport @@ -60,7 +60,7 @@ def generate(self, summary, full=False, output_file=None): content += f"| Analysis started | {analysis_started[:19] if analysis_started != 'N/A' else 'N/A'} |\n" content += f"| Analysis finished | {analysis_finished[:19] if analysis_finished != 'N/A' else 'N/A'} |\n" content += f"| Duration | {reproduction_info.get('duration_seconds', 0)} seconds |\n" - content += f"| Software version | hashprep v{hashprep.__version__} |\n\n" + content += f"| Software version | tablint v{tablint.__version__} |\n\n" if full: img_dir = None @@ -241,7 +241,7 @@ def generate(self, summary, full=False, output_file=None): content += "### Tail (last 5 rows)\n\n" content += pd.DataFrame(summary["summaries"]["tail"]).to_markdown(index=False) + "\n\n" - content += "\n---\nGenerated by HashPrep\n" + content += "\n---\nGenerated by Tablint\n" if output_file: with open(output_file, "w") as f: diff --git a/hashprep/reports/pdf.py b/tablint/reports/pdf.py similarity index 99% rename from hashprep/reports/pdf.py rename to tablint/reports/pdf.py index 47cd743..4b9ceef 100644 --- a/hashprep/reports/pdf.py +++ b/tablint/reports/pdf.py @@ -3,7 +3,7 @@ import pandas as pd from weasyprint import HTML -import hashprep +import tablint from .base import BaseReport, render_html @@ -40,7 +40,7 @@ def generate(self, summary, full=False, output_file=None, **kwargs): "analysis_started": reproduction_info.get("analysis_started", ""), "analysis_finished": reproduction_info.get("analysis_finished", ""), "duration_seconds": reproduction_info.get("duration_seconds", 0), - "version": hashprep.__version__, + "version": tablint.__version__, "full": full, "head_table": head_df.to_html(index=False, border=0), "tail_table": tail_df.to_html(index=False, border=0), @@ -268,7 +268,7 @@ def _get_template(self):
-

HashPrep Report

+

Tablint Report

v{{ version }}
{{ critical_count }} Critical @@ -332,7 +332,7 @@ def _get_template(self):
Software version
-
hashprep v{{ version }}
+
tablint v{{ version }}
@@ -611,6 +611,6 @@ def _get_template(self):
{{ tail_table | safe }}
{% endif %} - + """ diff --git a/hashprep/summaries/__init__.py b/tablint/summaries/__init__.py similarity index 100% rename from hashprep/summaries/__init__.py rename to tablint/summaries/__init__.py diff --git a/hashprep/summaries/dataset.py b/tablint/summaries/dataset.py similarity index 97% rename from hashprep/summaries/dataset.py rename to tablint/summaries/dataset.py index 92ae295..98ac9bf 100644 --- a/hashprep/summaries/dataset.py +++ b/tablint/summaries/dataset.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd -import hashprep +import tablint def get_dataset_preview(df): @@ -82,5 +82,5 @@ def add_reproduction_info(df: pd.DataFrame) -> dict: dataset_hash = hashlib.md5(pd.util.hash_pandas_object(df, index=True).values).hexdigest() return { "dataset_hash": dataset_hash, - "software_version": hashprep.__version__, + "software_version": tablint.__version__, } diff --git a/hashprep/summaries/interactions.py b/tablint/summaries/interactions.py similarity index 100% rename from hashprep/summaries/interactions.py rename to tablint/summaries/interactions.py diff --git a/hashprep/summaries/missing.py b/tablint/summaries/missing.py similarity index 100% rename from hashprep/summaries/missing.py rename to tablint/summaries/missing.py diff --git a/hashprep/summaries/mutual_info.py b/tablint/summaries/mutual_info.py similarity index 100% rename from hashprep/summaries/mutual_info.py rename to tablint/summaries/mutual_info.py diff --git a/hashprep/summaries/variables.py b/tablint/summaries/variables.py similarity index 100% rename from hashprep/summaries/variables.py rename to tablint/summaries/variables.py diff --git a/hashprep/utils/config_loader.py b/tablint/utils/config_loader.py similarity index 87% rename from hashprep/utils/config_loader.py rename to tablint/utils/config_loader.py index 9c19f6c..5269230 100644 --- a/hashprep/utils/config_loader.py +++ b/tablint/utils/config_loader.py @@ -1,15 +1,15 @@ -"""Load HashPrepConfig from YAML, TOML, or JSON files.""" +"""Load TablintConfig from YAML, TOML, or JSON files.""" from __future__ import annotations import json from pathlib import Path -from ..config import HashPrepConfig, config_from_dict +from ..config import TablintConfig, config_from_dict -def load_config(path: str | Path) -> HashPrepConfig: - """Load a HashPrepConfig from a YAML (.yaml/.yml), TOML (.toml), or JSON (.json) file. +def load_config(path: str | Path) -> TablintConfig: + """Load a TablintConfig from a YAML (.yaml/.yml), TOML (.toml), or JSON (.json) file. Only keys present in the file are overridden; all others fall back to defaults. """ diff --git a/hashprep/utils/logging.py b/tablint/utils/logging.py similarity index 66% rename from hashprep/utils/logging.py rename to tablint/utils/logging.py index 7c0efb8..2f71060 100644 --- a/hashprep/utils/logging.py +++ b/tablint/utils/logging.py @@ -1,4 +1,4 @@ -"""Structured logging for HashPrep. +"""Structured logging for Tablint. Provides a package-level logger that callers can use via get_logger(). By default, logs at WARNING level so end users don't see noise. @@ -7,22 +7,22 @@ import logging -LOGGER_NAME = "hashprep" +LOGGER_NAME = "tablint" def get_logger(module_name: str = "") -> logging.Logger: - """Get a logger scoped to a hashprep submodule. + """Get a logger scoped to a tablint submodule. Args: module_name: Dot-separated submodule path (e.g. "checks.correlations"). - If empty, returns the root hashprep logger. + If empty, returns the root tablint logger. """ name = f"{LOGGER_NAME}.{module_name}" if module_name else LOGGER_NAME return logging.getLogger(name) -# Configure root hashprep logger with NullHandler (library best practice). -# This prevents "No handlers could be found" warnings when hashprep is used +# Configure root tablint logger with NullHandler (library best practice). +# This prevents "No handlers could be found" warnings when tablint is used # as a library. End users or the CLI can attach their own handlers. _root_logger = logging.getLogger(LOGGER_NAME) _root_logger.addHandler(logging.NullHandler()) diff --git a/hashprep/utils/sampling.py b/tablint/utils/sampling.py similarity index 100% rename from hashprep/utils/sampling.py rename to tablint/utils/sampling.py diff --git a/hashprep/utils/type_inference.py b/tablint/utils/type_inference.py similarity index 95% rename from hashprep/utils/type_inference.py rename to tablint/utils/type_inference.py index 3569786..79e17c6 100644 --- a/hashprep/utils/type_inference.py +++ b/tablint/utils/type_inference.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd -from ..config import DEFAULT_CONFIG, HashPrepConfig +from ..config import DEFAULT_CONFIG, TablintConfig _TYPE_TO_ROLE = { "Numeric": "numeric", @@ -15,7 +15,7 @@ } -def _type_config(config: HashPrepConfig | None): +def _type_config(config: TablintConfig | None): cfg = config or DEFAULT_CONFIG return cfg, cfg.type_inference, cfg.datetime @@ -48,7 +48,7 @@ def _is_boolean_text(series: pd.Series, mappings: dict) -> bool: return bool(sample.isin(list(mappings)).all()) -def infer_types(df: pd.DataFrame, config: HashPrepConfig | None = None) -> dict[str, str]: +def infer_types(df: pd.DataFrame, config: TablintConfig | None = None) -> dict[str, str]: """ Infer semantic types per ydata logic. Returns: {col: 'Numeric' | 'Categorical' | 'Text' | 'DateTime' | 'Boolean' | 'Unsupported'} @@ -101,7 +101,7 @@ def infer_roles( df: pd.DataFrame, column_types: dict[str, str], target_col: str | None = None, - config: HashPrepConfig | None = None, + config: TablintConfig | None = None, ) -> dict[str, str]: """Classify each column for checks. diff --git a/tests/test.py b/tests/test.py index 81b023c..2a80350 100755 --- a/tests/test.py +++ b/tests/test.py @@ -2,8 +2,8 @@ import pandas as pd -import hashprep -from hashprep import DatasetAnalyzer +import tablint +from tablint import DatasetAnalyzer TARGET_COLUMN = "Survived" VALID_CHECKS = DatasetAnalyzer.ALL_CHECKS @@ -17,7 +17,7 @@ critical = [i for i in issues if i["severity"] == "critical"] warnings = [i for i in issues if i["severity"] == "warning"] -print(hashprep.__version__) +print(tablint.__version__) print(issues) print(critical) print(warnings) diff --git a/tests/test_cli.py b/tests/test_cli.py index a4a769b..5bba96d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,5 +1,5 @@ """ -Comprehensive tests for HashPrep CLI commands. +Comprehensive tests for Tablint CLI commands. """ import json @@ -16,7 +16,7 @@ def has_pdf_deps(): # Probe in a child process. A broken WeasyPrint/Pango install can abort # the interpreter, which a try/except in this process cannot catch. probe = subprocess.run( - [sys.executable, "-c", "from hashprep.reports.pdf import PdfReport; PdfReport()"], + [sys.executable, "-c", "from tablint.reports.pdf import PdfReport; PdfReport()"], capture_output=True, ) return probe.returncode == 0 @@ -40,7 +40,7 @@ def temp_output_dir(): def run_cli(args, cwd=None): """Helper to run CLI commands.""" - cmd = [sys.executable, "-m", "hashprep.interfaces.cli.main", *args] + cmd = [sys.executable, "-m", "tablint.interfaces.cli.main", *args] if cwd is None: cwd = Path(__file__).parent.parent result = subprocess.run(cmd, capture_output=True, text=True, cwd=cwd) @@ -48,7 +48,7 @@ def run_cli(args, cwd=None): class TestCLIScan: - """Test 'hashprep scan' command.""" + """Test 'tablint scan' command.""" def test_scan_basic(self, titanic_csv): """Test basic scan command.""" @@ -109,7 +109,7 @@ def test_scan_with_sampling(self, titanic_csv): class TestCLIDetails: - """Test 'hashprep details' command.""" + """Test 'tablint details' command.""" def test_details_basic(self, titanic_csv): """Test basic details command.""" @@ -136,7 +136,7 @@ def test_details_specific_checks(self, titanic_csv): class TestCLIReport: - """Test 'hashprep report' command.""" + """Test 'tablint report' command.""" def test_report_markdown(self, titanic_csv, temp_output_dir): """Test Markdown report generation.""" @@ -144,10 +144,10 @@ def test_report_markdown(self, titanic_csv, temp_output_dir): assert result.returncode == 0 assert "Report saved to:" in result.stdout - assert "train_hashprep_report.md" in result.stdout + assert "train_tablint_report.md" in result.stdout # Check file was created - report_file = os.path.join(temp_output_dir, "train_hashprep_report.md") + report_file = os.path.join(temp_output_dir, "train_tablint_report.md") assert os.path.exists(report_file) def test_report_json(self, titanic_csv, temp_output_dir): @@ -155,10 +155,10 @@ def test_report_json(self, titanic_csv, temp_output_dir): result = run_cli(["report", titanic_csv, "--format", "json"], cwd=temp_output_dir) assert result.returncode == 0 - assert "train_hashprep_report.json" in result.stdout + assert "train_tablint_report.json" in result.stdout # Verify JSON is valid - report_file = os.path.join(temp_output_dir, "train_hashprep_report.json") + report_file = os.path.join(temp_output_dir, "train_tablint_report.json") assert os.path.exists(report_file) with open(report_file) as f: data = json.load(f) @@ -172,9 +172,9 @@ def test_report_html_minimal(self, titanic_csv, temp_output_dir): ) assert result.returncode == 0 - assert "train_hashprep_report.html" in result.stdout + assert "train_tablint_report.html" in result.stdout - report_file = os.path.join(temp_output_dir, "train_hashprep_report.html") + report_file = os.path.join(temp_output_dir, "train_tablint_report.html") assert os.path.exists(report_file) def test_report_html_neubrutalism(self, titanic_csv, temp_output_dir): @@ -184,7 +184,7 @@ def test_report_html_neubrutalism(self, titanic_csv, temp_output_dir): ) assert result.returncode == 0 - assert "train_hashprep_report.html" in result.stdout + assert "train_tablint_report.html" in result.stdout @skip_pdf def test_report_pdf(self, titanic_csv, temp_output_dir): @@ -192,9 +192,9 @@ def test_report_pdf(self, titanic_csv, temp_output_dir): result = run_cli(["report", titanic_csv, "--format", "pdf", "--full"], cwd=temp_output_dir) assert result.returncode == 0 - assert "train_hashprep_report.pdf" in result.stdout + assert "train_tablint_report.pdf" in result.stdout - report_file = os.path.join(temp_output_dir, "train_hashprep_report.pdf") + report_file = os.path.join(temp_output_dir, "train_tablint_report.pdf") assert os.path.exists(report_file) # Check PDF magic number with open(report_file, "rb") as f: @@ -209,8 +209,8 @@ def test_report_with_code_generation(self, titanic_csv, temp_output_dir): assert "pipeline script saved" in result.stdout # Check files were created - assert os.path.exists(os.path.join(temp_output_dir, "train_hashprep_report_fixes.py")) - assert os.path.exists(os.path.join(temp_output_dir, "train_hashprep_report_pipeline.py")) + assert os.path.exists(os.path.join(temp_output_dir, "train_tablint_report_fixes.py")) + assert os.path.exists(os.path.join(temp_output_dir, "train_tablint_report_pipeline.py")) def test_report_no_visualizations(self, titanic_csv, temp_output_dir): """Test report without visualizations.""" @@ -241,14 +241,14 @@ def test_report_specific_checks(self, titanic_csv, temp_output_dir): class TestCLIVersion: - """Test 'hashprep version' command.""" + """Test 'tablint version' command.""" def test_version(self): """Test version command.""" result = run_cli(["version"]) assert result.returncode == 0 - assert "hashprep" in result.stdout.lower() + assert "tablint" in result.stdout.lower() # Should show version number assert any(char.isdigit() for char in result.stdout) @@ -345,9 +345,9 @@ def test_ml_workflow_with_target(self, titanic_csv, temp_output_dir): ) assert result.returncode == 0 - assert os.path.exists(os.path.join(temp_output_dir, "train_hashprep_report.html")) - assert os.path.exists(os.path.join(temp_output_dir, "train_hashprep_report_fixes.py")) - assert os.path.exists(os.path.join(temp_output_dir, "train_hashprep_report_pipeline.py")) + assert os.path.exists(os.path.join(temp_output_dir, "train_tablint_report.html")) + assert os.path.exists(os.path.join(temp_output_dir, "train_tablint_report_fixes.py")) + assert os.path.exists(os.path.join(temp_output_dir, "train_tablint_report_pipeline.py")) if __name__ == "__main__": diff --git a/tests/test_code_execution.py b/tests/test_code_execution.py index 6b9ccbd..c3abef3 100644 --- a/tests/test_code_execution.py +++ b/tests/test_code_execution.py @@ -2,15 +2,15 @@ import pandas as pd import pytest -from hashprep.preparers.codegen import CodeGenerator -from hashprep.preparers.models import ( +from tablint.preparers.codegen import CodeGenerator +from tablint.preparers.models import ( EncodeMethod, FixSuggestion, FixType, ImputeMethod, ScaleMethod, ) -from hashprep.preparers.pipeline_builder import PipelineBuilder +from tablint.preparers.pipeline_builder import PipelineBuilder def test_hostile_column_name_does_not_execute_injected_code(capfd): diff --git a/tests/test_codegen.py b/tests/test_codegen.py index 2cc8776..7a52811 100644 --- a/tests/test_codegen.py +++ b/tests/test_codegen.py @@ -1,7 +1,7 @@ """Tests for code generation module.""" -from hashprep.preparers.codegen import CodeGenerator -from hashprep.preparers.models import ( +from tablint.preparers.codegen import CodeGenerator +from tablint.preparers.models import ( EncodeMethod, FixSuggestion, FixType, diff --git a/tests/test_config_loader.py b/tests/test_config_loader.py index 350a2a9..290b298 100644 --- a/tests/test_config_loader.py +++ b/tests/test_config_loader.py @@ -7,8 +7,8 @@ import pandas as pd import pytest -from hashprep import DatasetAnalyzer, HashPrepConfig, load_config -from hashprep.config import DEFAULT_CONFIG, config_from_dict +from tablint import DatasetAnalyzer, TablintConfig, load_config +from tablint.config import DEFAULT_CONFIG, config_from_dict # --------------------------------------------------------------------------- # config_from_dict @@ -53,9 +53,9 @@ def test_unknown_nested_keys_are_ignored(self): with pytest.raises(ValueError, match="Unknown configuration key"): config_from_dict({"outliers": {"z_score": 3.0, "nonexistent": 99}}) - def test_returns_hashprepconfig_instance(self): + def test_returns_tablintconfig_instance(self): cfg = config_from_dict({}) - assert isinstance(cfg, HashPrepConfig) + assert isinstance(cfg, TablintConfig) def test_result_is_frozen(self): cfg = config_from_dict({"outliers": {"z_score": 2.0}}) diff --git a/tests/test_datetime.py b/tests/test_datetime.py index e282b07..5a971df 100644 --- a/tests/test_datetime.py +++ b/tests/test_datetime.py @@ -3,14 +3,14 @@ import numpy as np import pandas as pd -from hashprep import DatasetAnalyzer -from hashprep.checks.datetime_checks import ( +from tablint import DatasetAnalyzer +from tablint.checks.datetime_checks import ( _check_datetime_future_dates, _check_datetime_gaps, _check_datetime_monotonicity, ) -from hashprep.summaries.variables import _summarize_datetime -from hashprep.utils.type_inference import infer_types +from tablint.summaries.variables import _summarize_datetime +from tablint.utils.type_inference import infer_types # --------------------------------------------------------------------------- # Type inference @@ -67,7 +67,7 @@ class _FakeAnalyzer: """Minimal stand-in for DatasetAnalyzer used in unit tests.""" def __init__(self, df, column_types): - from hashprep.config import DEFAULT_CONFIG + from tablint.config import DEFAULT_CONFIG self.df = df self.column_types = column_types diff --git a/tests/test_drift.py b/tests/test_drift.py index 1401a1a..98e8dae 100644 --- a/tests/test_drift.py +++ b/tests/test_drift.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd -from hashprep.checks.drift import check_drift +from tablint.checks.drift import check_drift class TestNumericDrift: diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py index 71cf1cb..52cacb4 100644 --- a/tests/test_edge_cases.py +++ b/tests/test_edge_cases.py @@ -3,8 +3,8 @@ import numpy as np import pandas as pd -from hashprep import DatasetAnalyzer -from hashprep.checks.drift import check_drift +from tablint import DatasetAnalyzer +from tablint.checks.drift import check_drift class TestEmptyDataframes: diff --git a/tests/test_gate.py b/tests/test_gate.py index 9194a62..3102d93 100644 --- a/tests/test_gate.py +++ b/tests/test_gate.py @@ -7,8 +7,8 @@ import pandas as pd from click.testing import CliRunner -from hashprep import DatasetAnalyzer -from hashprep.interfaces.cli.main import _json_payload, cli +from tablint import DatasetAnalyzer +from tablint.interfaces.cli.main import _json_payload, cli TITANIC = Path(__file__).parent.parent / "datasets" / "train.csv" diff --git a/tests/test_library_api.py b/tests/test_library_api.py index 0b9375d..ab511dc 100644 --- a/tests/test_library_api.py +++ b/tests/test_library_api.py @@ -1,5 +1,5 @@ """ -Comprehensive tests for HashPrep library API usage. +Comprehensive tests for Tablint library API usage. Tests all features when used as a Python library. """ @@ -12,16 +12,16 @@ import pandas as pd import pytest -from hashprep import DatasetAnalyzer -from hashprep.reports import generate_report -from hashprep.utils.sampling import SamplingConfig +from tablint import DatasetAnalyzer +from tablint.reports import generate_report +from tablint.utils.sampling import SamplingConfig def has_pdf_deps(): # Probe in a child process. A broken WeasyPrint/Pango install can abort # the interpreter, which a try/except in this process cannot catch. probe = subprocess.run( - [sys.executable, "-c", "from hashprep.reports.pdf import PdfReport; PdfReport()"], + [sys.executable, "-c", "from tablint.reports.pdf import PdfReport; PdfReport()"], capture_output=True, ) return probe.returncode == 0 @@ -205,7 +205,7 @@ def test_html_report_minimal(self, sample_dataframe): with open(output_file) as f: content = f.read() assert "=5.0.0" }, "bin": "bin/svelte-check" }, "sha512-uBkz96ElE3G4pt9E1Tw0xvBfIUQkeH794kDQZdAUk795UVMr+NJZpuFSS62vcmO/DuSalK83LyOwhgWq8YGU1Q=="], @@ -218,10 +226,20 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + "vite": ["vite@6.4.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4enwjFfi4IwtEh0w+jPzpLVOFQiPHmmzPxcHXQOyEur47o6u0jE573DmGpjA+7irXoMLYRZD5ZaFUEneS3abPg=="], "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" } }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], + + "@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "esrap/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "is-reference/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "magic-string/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], } } diff --git a/web/package-lock.json b/web/package-lock.json index 356700d..f6939e5 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,11 +1,11 @@ { - "name": "hashprep-website", + "name": "tablint-website", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "hashprep-website", + "name": "tablint-website", "version": "1.0.0", "devDependencies": { "@sveltejs/adapter-static": "^3.0.0", diff --git a/web/package.json b/web/package.json index 0223275..e3557a0 100644 --- a/web/package.json +++ b/web/package.json @@ -1,5 +1,5 @@ { - "name": "hashprep-website", + "name": "tablint-website", "version": "1.0.0", "private": true, "type": "module", diff --git a/web/src/app.css b/web/src/app.css index f7eafb3..eec61ff 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -1,5 +1,5 @@ /* ============================================ - HashPrep Design System + Tablint Design System Primary accent: #b16286 (rose/mauve from logo) Typography: Epilogue (300-600) + DM Mono (300-500) ============================================ */ diff --git a/web/src/app.html b/web/src/app.html index 070ae8f..d12a77c 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -4,7 +4,7 @@ - + - diff --git a/web/src/lib/components/Navbar.svelte b/web/src/lib/components/Navbar.svelte index 84f885c..bbcecae 100644 --- a/web/src/lib/components/Navbar.svelte +++ b/web/src/lib/components/Navbar.svelte @@ -8,7 +8,7 @@ { label: 'Features', href: '/#features' }, { label: 'How It Works', href: '/#how-it-works' }, { label: 'Docs', href: '/docs' }, - { label: 'GitHub', href: 'https://github.com/cachevector/hashprep' } + { label: 'GitHub', href: 'https://github.com/cachevector/tablint' } ]; function closeMobile() { diff --git a/web/src/lib/theme.svelte.ts b/web/src/lib/theme.svelte.ts index 2e6f7d2..9c1fe38 100644 --- a/web/src/lib/theme.svelte.ts +++ b/web/src/lib/theme.svelte.ts @@ -27,7 +27,7 @@ function getSystemTheme(): Theme { function getStoredPreference(): 'light' | 'dark' | 'system' { if (!browser) return 'system'; - return (safeLocalStorage('get', 'hashprep-theme') as 'light' | 'dark' | 'system') || 'system'; + return (safeLocalStorage('get', 'tablint-theme') as 'light' | 'dark' | 'system') || 'system'; } let preference = $state<'light' | 'dark' | 'system'>(getStoredPreference()); @@ -47,7 +47,7 @@ function apply(t: Theme) { function setPreference(pref: 'light' | 'dark' | 'system') { preference = pref; if (browser) { - safeLocalStorage('set', 'hashprep-theme', pref); + safeLocalStorage('set', 'tablint-theme', pref); } apply(pref === 'system' ? getSystemTheme() : pref); } diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 41d439f..78df4b1 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -12,7 +12,7 @@ - HashPrep — Dataset Profiler & Debugger for Machine Learning + Tablint — Dataset Profiler & Debugger for Machine Learning {@render children()} diff --git a/web/src/routes/docs/+page.svelte b/web/src/routes/docs/+page.svelte index 13a93a2..952940d 100644 --- a/web/src/routes/docs/+page.svelte +++ b/web/src/routes/docs/+page.svelte @@ -9,9 +9,9 @@
Documentation
-

Learn HashPrep in minutes, not hours.

+

Learn Tablint in minutes, not hours.

- A focused guide to installing, running, and integrating HashPrep into your ML workflows. Built to match the + A focused guide to installing, running, and integrating Tablint into your ML workflows. Built to match the minimal, calm UI of the rest of the site.

@@ -42,7 +42,7 @@

Overview

- HashPrep is a dataset profiler and debugger for machine learning. Think of it as + Tablint is a dataset profiler and debugger for machine learning. Think of it as “Pandas Profiling + a linter for datasets” that runs before you train.

@@ -56,7 +56,7 @@

Installation

Using pip

-
pip install hashprep
+
pip install tablint
@@ -64,17 +64,17 @@
# Install uv (if needed)
 curl -LsSf https://astral.sh/uv/install.sh | sh
 
-# Install HashPrep
-uv pip install hashprep
+# Install Tablint
+uv pip install tablint
 
 # Or from source
-git clone https://github.com/cachevector/hashprep.git
-cd hashprep
+git clone https://github.com/cachevector/tablint.git
+cd tablint
 uv sync

- After installation, the hashprep command is available directly in your terminal. + After installation, the tablint command is available directly in your terminal.

@@ -83,7 +83,7 @@

1. Run a quick scan

Get a concise summary of dataset issues in your terminal.

-
hashprep scan dataset.csv
+
tablint scan dataset.csv
@@ -98,7 +98,7 @@

Example

-
hashprep scan train.csv \
+              
tablint scan train.csv \
   --target Survived \
   --checks outliers,high_missing_values,class_imbalance
@@ -106,8 +106,8 @@

2. Detailed analysis

-

Drill into every issue HashPrep found.

-
hashprep details train.csv --target Survived
+

Drill into every issue Tablint found.

+
tablint details train.csv --target Survived
@@ -117,7 +117,7 @@

Basic analysis

import pandas as pd
-from hashprep import DatasetAnalyzer
+from tablint import DatasetAnalyzer
 
 df = pd.read_csv("dataset.csv")
 
@@ -154,7 +154,7 @@ summary = analyzer.analyze()

Generate a report from the CLI

-
hashprep report dataset.csv --format html --theme minimal
+
tablint report dataset.csv --format html --theme minimal

Reports can be exported as md, json, html, or pdf, using the --format flag. Use --with-code to generate @@ -164,8 +164,8 @@ summary = analyzer.analyze()

Generate reports from Python

-
from hashprep import DatasetAnalyzer
-from hashprep.reports import generate_report
+            
from tablint import DatasetAnalyzer
+from tablint.reports import generate_report
 
 analyzer = DatasetAnalyzer(df, include_plots=True)
 summary = analyzer.analyze()
@@ -174,7 +174,7 @@ generate_report(
     summary,
     format="html",
     full=True,
-    output_file="dataset_hashprep_report.html",
+    output_file="dataset_tablint_report.html",
     theme="minimal",
 )
@@ -184,12 +184,12 @@ generate_report(

CLI reference

-

hashprep scan

+

tablint scan

Run a quick scan and print a compact summary of issues to the terminal. Ideal for a fast health check during development.

-
hashprep scan dataset.csv --target Survived
+
tablint scan dataset.csv --target Survived
  • --target COLUMN — target column for ML checks (class imbalance, leakage, etc.)
  • --checks LIST — comma-separated list of checks to run
  • @@ -203,12 +203,12 @@ generate_report(
-

hashprep details

+

tablint details

Produce a verbose, line-by-line description of each issue in the dataset, with statistics and recommendations.

-
hashprep details dataset.csv --target Survived
+
tablint details dataset.csv --target Survived

Accepts the same options as scan (including --comparison and --config) and is best used when you are actively debugging a dataset or deciding which columns to drop or transform. @@ -216,12 +216,12 @@ generate_report(

-

hashprep report

+

tablint report

Generate a full report in HTML, PDF, Markdown, or JSON. Reports contain summaries, plots, and (optionally) auto-generated Python code.

-
hashprep report dataset.csv --format html --theme minimal --with-code
+
tablint report dataset.csv --format html --theme minimal --with-code