Featuresmith Icon
Featuresmith
  • Docs
  • SDK
  • CLI
  • Examples
  • Roadmap
v0.4.0
Documentation

Getting Started

  • Introduction
  • Installation
  • Quick Start
  • Tutorial Notebooks
  • Benchmarks
  • Development Setup
  • Contributing

Core Concepts

  • Architecture Overview
  • Dataset Layer
  • Connectors
  • Profiling Engine
  • Rule Engine
  • Dataset Review Engine
  • ML Readiness Score
  • Target Leakage Detection
  • Dataset Diff Engine
  • Target Column Concept
  • Mental Model & Workflow
  • Interpreting Findings
  • Workflow Cheat Sheet
  • Beginner Glossary

Python SDK

  • load()
  • profile()
  • analyze()
  • review()
  • diff()
  • score()
  • plan()
  • Dataset
  • Data Models
  • Profile Models
  • Rule & Finding Models
  • Review Models
  • Score Models
  • Leakage Models
  • Diff Models
  • Exceptions
  • Plugins

CLI Reference

  • analyze
  • review
  • diff
  • score
  • plan
  • Configuration

Guides

  • CI/CD Integration
  • Custom Rules
  • Writing Plugins

Resources

  • Release Notes
  • FAQ
  • Troubleshooting
DocsGuide

Getting Started

  • Introduction
  • Installation
  • Quick Start
  • Tutorial Notebooks
  • Benchmarks
  • Development Setup
  • Contributing

Core Concepts

  • Architecture Overview
  • Dataset Layer
  • Connectors
  • Profiling Engine
  • Rule Engine
  • Dataset Review Engine
  • ML Readiness Score
  • Target Leakage Detection
  • Dataset Diff Engine
  • Target Column Concept
  • Mental Model & Workflow
  • Interpreting Findings
  • Workflow Cheat Sheet
  • Beginner Glossary

Python SDK

  • load()
  • profile()
  • analyze()
  • review()
  • diff()
  • score()
  • plan()
  • Dataset
  • Data Models
  • Profile Models
  • Rule & Finding Models
  • Review Models
  • Score Models
  • Leakage Models
  • Diff Models
  • Exceptions
  • Plugins

CLI Reference

  • analyze
  • review
  • diff
  • score
  • plan
  • Configuration

Guides

  • CI/CD Integration
  • Custom Rules
  • Writing Plugins

Resources

  • Release Notes
  • FAQ
  • Troubleshooting
HomeDocsCustom Rules Guide

Guides

Custom Rules Guide

Learn how to write custom deterministic data quality validation rules

Featuresmith is fully extensible. You can add your own deterministic rules by extending the BaseRule interface and registering them with the Rule Engine.

The BaseRule Interface

All rules must extend BaseRule and implement the following properties and method:

  • id: A unique dotted identifier (e.g., statistical.zero_variance).
  • name: A short human-readable rule title.
  • description: What the rule flags.
  • category: The group category (quality, statistical, or leakage).
  • severity: The default finding severity as a string ("info", "warning", or "critical").
  • enabled_by_default: Whether the rule runs by default in the engine.
  • evaluate(profile: ProfileResult) -> list[RuleFinding]: The core audit logic.

Custom Rule Implementation

Here is a complete rule that flags numeric columns with zero standard deviation (constant-value columns), using the real BaseRule API and the NumericProfile output of the profiling engine:

python
1from featuresmith.core.profile_result import ProfileResult
2from featuresmith.core.rule_finding import RuleFinding
3from featuresmith.rules.base import BaseRule
4
5
6class ZeroVarianceRule(BaseRule):
7 """Custom rule to detect numeric columns with zero variance."""
8
9 @property
10 def id(self) -> str:
11 return "statistical.zero_variance"
12
13 @property
14 def name(self) -> str:
15 return "Zero Variance Columns"
16
17 @property
18 def description(self) -> str:
19 return "Flags numeric columns whose standard deviation is zero."
20
21 @property
22 def category(self) -> str:
23 return "statistical"
24
25 @property
26 def severity(self) -> str:
27 return "warning"
28
29 @property
30 def enabled_by_default(self) -> bool:
31 return True
32
33 def evaluate(self, profile: ProfileResult) -> list[RuleFinding]:
34 findings: list[RuleFinding] = []
35 for col_name, num_prof in profile.numeric_profiles.items():
36 if num_prof.std_dev == 0.0:
37 findings.append(
38 RuleFinding(
39 rule_id=self.id,
40 rule_name=self.name,
41 category=self.category,
42 severity=self.severity,
43 column_name=col_name,
44 title=f"Zero variance in column '{col_name}'",
45 description=(
46 f"Column '{col_name}' has a standard deviation "
47 f"of 0.0 (no variance)."
48 ),
49 evidence={
50 "std_dev": num_prof.std_dev,
51 "unique_count": num_prof.unique_count,
52 },
53 confidence=1.0,
54 )
55 )
56 return findings

Evaluating Custom Rules

You can run the rule directly against a computed profile:

python
1import featuresmith as fs
2
3dataset = fs.load("data.csv")
4profile = fs.profile(dataset)
5
6rule = ZeroVarianceRule()
7findings = rule.evaluate(profile)
8
9for finding in findings:
10 print(f"[{finding.severity}] {finding.title} in {finding.column_name}")

To run your custom rule inside the Rule Engine (for example alongside the built-ins through fs.analyze()), register it in a RuleRegistry and pass the registry to a RuleEngine:

python
1from featuresmith.rules.engine import RuleEngine
2from featuresmith.rules.registry import RuleRegistry, default_registry
3
4# Start from the built-in rules and add your custom rule
5registry = RuleRegistry([*default_registry().list_rules(), ZeroVarianceRule()])
6engine = RuleEngine(registry=registry)
7
8result = engine.run(
9 profile,
10 target_column="churn",
11 enabled_rules=["statistical.zero_variance"],
12)
13
14print(f"Executed {len(result.executed_rules)} rule(s): {result.executed_rules}")
15print(f"Failed: {result.failed_rules}")

Explore

  • Quick Start
  • Python SDK
  • CLI Reference
  • Examples
Featuresmith Icon
Featuresmith

Open-source data profiling and validation for Python engineers.

Documentation

  • Introduction
  • Quick Start
  • Python SDK
  • CLI Reference

Community

  • GitHub
  • Discussions
  • Issues
  • Contributing

Project

  • Roadmap
  • Release status
  • Benchmarks
  • Changelog
  • Examples

Legal

  • Apache 2.0 License
  • Code of Conduct
  • Security

© 2026 Featuresmith Contributors. Released under the Apache 2.0 License.

Built by Aditya Gangwani in the open.