Metadata-Version: 2.4
Name: ruleframe
Version: 0.1.0
Summary: Declarative DataFrame validation with rule bundles and JsonLogic
Author: Neil Leonard
License: MIT
Project-URL: Homepage, https://github.com/RI-Advisory-Services/ruleframe
Project-URL: Documentation, https://github.com/RI-Advisory-Services/ruleframe/tree/main/docs
Project-URL: Repository, https://github.com/RI-Advisory-Services/ruleframe
Project-URL: Issues, https://github.com/RI-Advisory-Services/ruleframe/issues
Keywords: validation,dataframe,rules,jsonlogic,excel
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas<3.0,>=2.0
Requires-Dist: PyYAML<7.0,>=6.0
Requires-Dist: python-dateutil<3.0,>=2.8
Requires-Dist: python-jsonlogic<1.0.0,>=0.1.0
Provides-Extra: dev
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
Requires-Dist: pytest-cov<6.0,>=5.0; extra == "dev"
Requires-Dist: ruff<1.0.0,>=0.6.0; extra == "dev"
Requires-Dist: mypy<2.0,>=1.10; extra == "dev"
Requires-Dist: openpyxl<4.0,>=3.1; extra == "dev"
Requires-Dist: pandas-stubs<3.0,>=2.2; extra == "dev"
Requires-Dist: types-PyYAML<7.0,>=6.0; extra == "dev"
Requires-Dist: types-python-dateutil<3.0,>=2.8; extra == "dev"
Requires-Dist: build<2.0,>=1.2; extra == "dev"
Requires-Dist: setuptools>=69; extra == "dev"
Requires-Dist: twine<7.0,>=6.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs<2.0,>=1.6; extra == "docs"
Requires-Dist: mkdocs-material<10.0,>=9.5; extra == "docs"
Provides-Extra: jupyter
Requires-Dist: ipykernel<7.0,>=6.29; extra == "jupyter"
Requires-Dist: jupyterlab<5.0,>=4.0; extra == "jupyter"
Requires-Dist: notebook<8.0,>=7.0; extra == "jupyter"
Dynamic: license-file

# RuleFrame

RuleFrame validates pandas DataFrames with readable YAML or JSON rule bundles.

RuleFrame is useful when validation rules need to live outside application code: in files,
database records, admin screens, or workflow configuration. A rule bundle describes the
conditions that should produce findings, and RuleFrame returns both row-level findings and an
annotated DataFrame.

## Status

RuleFrame is in alpha. The core validation API is usable, but public APIs and rule syntax may
change before a stable `1.0.0` release.

## Install

```bash
pip install ruleframe
```

## Quick Start

```python
import pandas as pd

from ruleframe import RuleBundle, validate_dataframe

rules_yaml = """
version: 1
rules:
  - id: active_customer_missing_name
    severity: error
    fail_when:
      all:
        - column: Status
          equals: "Active"
        - column: Customer Name
          is_blank: true
    message: Active customers must have a name.
"""

df = pd.DataFrame(
    {
        "Status": ["Active", "Closed", "Active"],
        "Customer Name": ["", "Grace Hopper", "Ada Lovelace"],
    }
)

bundle = RuleBundle.from_yaml_string(rules_yaml)
result = validate_dataframe(df, bundle)

print(f"{len(result.findings)} finding(s)")
for finding in result.findings:
    print(f"- row {finding.row_index}: [{finding.severity}] {finding.rule_id}")
    print(f"  {finding.message}")

annotated = result.to_annotated_dataframe()
print("\nRows:")
for row_index, row in annotated.iterrows():
    name = row["Customer Name"] or "(missing)"
    message = row["Validation Errors"] or "OK"
    print(f"- row {row_index}: {row['Status']}, {name} -> {message}")
```

Expected output:

```text
1 finding(s)
- row 0: [error] active_customer_missing_name
  Active customers must have a name.

Rows:
- row 0: Active, (missing) -> Active customers must have a name.
- row 1: Closed, Grace Hopper -> OK
- row 2: Active, Ada Lovelace -> OK
```

`validate_dataframe()` returns a `ValidationResult` with:

- `to_findings_dataframe()`: one row per rule finding.
- `to_annotated_dataframe()`: the original DataFrame plus computed columns and a validation
  message column.
- `to_summary_dataframe()`: finding counts grouped by rule and severity.

## Rule Bundles

Rule bundles can be loaded from YAML, JSON, strings, or pre-parsed dictionaries:

```python
from ruleframe import RuleBundle

bundle = RuleBundle.from_yaml("rules.yaml")
bundle = RuleBundle.from_json("rules.json")
bundle = RuleBundle.from_yaml_string(yaml_text)
bundle = RuleBundle.from_json_string(json_text)
bundle = RuleBundle.from_json_dict(data)
```

Rules support boolean nesting, literal comparisons, column-to-column comparisons, date
comparisons, blank checks, membership checks, string containment, ranges, and generated
computed columns.

## Documentation

- [Documentation index](https://github.com/RI-Advisory-Services/ruleframe/tree/main/docs)
- [Rule format](https://github.com/RI-Advisory-Services/ruleframe/blob/main/docs/rules-format.md)
- [Predicates](https://github.com/RI-Advisory-Services/ruleframe/blob/main/docs/predicates.md)
- [Computed columns](https://github.com/RI-Advisory-Services/ruleframe/blob/main/docs/computed-columns.md)
- [Validation results](https://github.com/RI-Advisory-Services/ruleframe/blob/main/docs/validation-results.md)
