Skip to content

Reporter SDK

This page is a compatibility bridge for nested reporter-guide links.

The canonical Reporter SDK documentation lives at Reporter SDK.

Use that page for:

  • the 3.0 authoring contract based on ValidationRunResult
  • the ValidationReporter + RunPresentation workflow
  • guidance on when to_legacy_view() is appropriate
  • SDK templates, builders, mixins, schema helpers, and testing utilities

If you arrived here from the reporters guide, you can also go back to Reporters Guide for the family overview.

from truthound.reporters.sdk import StreamingMixin

class MyReporter(StreamingMixin, ValidationReporter):
    def render(self, data):
        legacy_view = self.present(data).to_legacy_view()
        # Generate in chunks
        for chunk in self.stream_results(legacy_view.results, chunk_size=100):
            yield self.format_chunk(chunk)

    def render_lines(self, data):
        legacy_view = self.present(data).to_legacy_view()
        # Line-by-line streaming
        formatter = lambda r: f"{r.validator_name}: {r.message}"
        return self.render_streaming(legacy_view.results, formatter)

Key Methods:

Method Description
stream_results(results, chunk_size) Chunk iterator
stream_lines(results, formatter) Line iterator
render_streaming(results, formatter) Combine streaming results to string

Builder

@create_reporter Decorator

Convert function to reporter:

from truthound.reporters.sdk import create_reporter

@create_reporter(
    name="simple",
    extension=".txt",
    content_type="text/plain"
)
def render_simple(result, config):
    """Simple text reporter."""
    lines = [
        f"Source: {result.source}",
        f"Status: {'PASS' if result.success else 'FAIL'}",
        f"Issues: {len(result.issues)}",
    ]
    return "\n".join(lines)

# Automatically registered
from truthound.reporters import get_reporter
reporter = get_reporter("simple")

@create_validation_reporter Decorator

Include full ValidationReporter functionality:

from truthound.reporters.sdk import create_validation_reporter
from truthound.reporters.base import ReporterConfig

class MyConfig(ReporterConfig):
    prefix: str = ">"
    include_timestamp: bool = True

@create_validation_reporter(
    name="prefixed",
    extension=".txt",
    config_class=MyConfig
)
def render_prefixed(result, config):
    status = "PASS" if result.success else "FAIL"
    lines = []
    if config.include_timestamp:
        lines.append(f"{config.prefix} Time: {result.run_time}")
    lines.append(f"{config.prefix} Status: {status}")
    return "\n".join(lines)

ReporterBuilder

Fluent builder pattern:

from truthound.reporters.sdk import ReporterBuilder

# ReporterBuilder takes name in constructor
reporter_class = (
    ReporterBuilder("custom")
    .with_extension(".custom")
    .with_content_type("text/plain")
    .with_mixin(FormattingMixin)
    .with_mixin(FilteringMixin)
    .with_renderer(lambda self, data: f"Status: {'PASS' if data.success else 'FAIL'}")
    .build()
)

# Create instance
instance = reporter_class()
output = instance.render(run_result)

Builder Methods:

Method Description
ReporterBuilder(name) Create builder with reporter name
with_extension(ext) Set file extension
with_content_type(type) Set MIME type
with_mixin(mixin_class) Add mixin
with_mixins(*mixins) Add multiple mixins
with_config_class(cls) Specify config class
with_renderer(func) Specify render function (takes self, data as arguments)
with_post_processor(func) Add post-processor function
with_attribute(name, value) Add class attribute
register_as(name) Specify factory registration name
build() Create reporter class

Templates

The SDK provides pre-defined reporter templates.

CSVReporter

from truthound.reporters.sdk import CSVReporter

reporter = CSVReporter(
    delimiter=",",
    include_header=True,
    include_passed=False,
    quoting="minimal"  # minimal, all, none, nonnumeric
)
csv_output = reporter.render(result)

CSVReporterConfig Options:

Option Type Default Description
delimiter str "," Field delimiter
include_header bool True Include header row
include_passed bool False Include passed items
quoting str "minimal" Quoting style
columns list[str] None Columns to include (None=all)

YAMLReporter

from truthound.reporters.sdk import YAMLReporter

reporter = YAMLReporter(
    default_flow_style=False,
    indent=2,
    include_passed=False,
    sort_keys=False
)
yaml_output = reporter.render(result)

YAMLReporterConfig Options:

Option Type Default Description
default_flow_style bool False Use flow style
indent int 2 Indentation size
include_passed bool False Include passed items
sort_keys bool False Sort keys

JUnitXMLReporter

JUnit XML format for CI/CD integration:

from truthound.reporters.sdk import JUnitXMLReporter

reporter = JUnitXMLReporter(
    testsuite_name="Truthound Validation",
    include_stdout=True,
    include_properties=True
)
xml_output = reporter.render(result)

JUnitXMLReporterConfig Options:

Option Type Default Description
testsuite_name str "Truthound Validation" Test suite name
include_stdout bool True Include system-out
include_properties bool True Include properties
include_passed bool False Include passed tests

NDJSONReporter

Newline Delimited JSON (for log collection system integration):

from truthound.reporters.sdk import NDJSONReporter

reporter = NDJSONReporter(
    include_metadata=True,
    include_passed=False,
    compact=True
)
ndjson_output = reporter.render(result)

NDJSONReporterConfig Options:

Option Type Default Description
include_metadata bool True Include metadata line
include_passed bool False Include passed items
compact bool True Compact JSON

TableReporter

Text table output:

from truthound.reporters.sdk import TableReporter

reporter = TableReporter(
    style="grid",  # ascii, markdown, grid, simple
    max_width=120,
    include_passed=False
)
table_output = reporter.render(result)

TableReporterConfig Options:

Option Type Default Description
style str "ascii" Table style
max_width int 120 Maximum width
include_passed bool False Include passed items
show_index bool False Show index

Schema Validation

A schema system for output format validation.

Basic Usage

from truthound.reporters.sdk import validate_output, JSONSchema

# Define schema
schema = JSONSchema(
    required_fields=["status", "data_asset", "issues"],
    field_types={
        "status": str,
        "data_asset": str,
        "issues": list,
        "pass_rate": float,
    }
)

# Validate output
result = validate_output(json_output, schema)
if not result.is_valid:
    for error in result.errors:
        print(f"Error: {error.message}")

Schema Types

JSONSchema

from truthound.reporters.sdk import JSONSchema

schema = JSONSchema(
    required_fields=["status", "data_asset"],
    field_types={"status": str, "issues": list},
    allow_extra_fields=True,
    max_depth=10
)

Options:

Option Type Description
required_fields list[str] Required field list
field_types dict[str, type] Field types
allow_extra_fields bool Allow extra fields
max_depth int Maximum nesting depth

XMLSchema

from truthound.reporters.sdk import XMLSchema

schema = XMLSchema(
    root_element="testsuites",
    required_elements=["testsuite", "testcase"],
    required_attributes={"testsuite": ["name", "tests"]},
    validate_dtd=False
)

Options:

Option Type Description
root_element str Root element name
required_elements list[str] Required element list
required_attributes dict[str, list[str]] Required attributes per element
validate_dtd bool Validate DTD

CSVSchema

from truthound.reporters.sdk import CSVSchema

schema = CSVSchema(
    required_columns=["validator", "column", "severity", "message"],
    column_types={"severity": str, "count": int},
    allow_extra_columns=True,
    min_rows=0
)

Options:

Option Type Description
required_columns list[str] Required column list
column_types dict[str, type] Column types
allow_extra_columns bool Allow extra columns
min_rows int Minimum row count

TextSchema

from truthound.reporters.sdk import TextSchema

schema = TextSchema(
    required_patterns=[r"Status:", r"Pass Rate:"],
    forbidden_patterns=[r"ERROR", r"EXCEPTION"],
    max_length=100000,
    encoding="utf-8"
)

Options:

Option Type Description
required_patterns list[str] Required patterns (regex)
forbidden_patterns list[str] Forbidden patterns (regex)
max_length int Maximum character count
encoding str Encoding

Schema Registration and Management

from truthound.reporters.sdk import (
    register_schema,
    get_schema,
    unregister_schema,
    validate_reporter_output,
)

# Register schema
register_schema("my_format", schema)

# Get schema
my_schema = get_schema("my_format")

# Remove schema
unregister_schema("my_format")

# Auto-validate reporter output
is_valid = validate_reporter_output("json", json_output)

Schema Inference and Merging

from truthound.reporters.sdk import infer_schema, merge_schemas

# Infer schema from sample data
inferred = infer_schema(sample_output, format="json")

# Merge multiple schemas
merged = merge_schemas([schema1, schema2], strategy="union")

Testing Utilities

Utilities for reporter testing.

Mock Data Generation

create_mock_result

from truthound.reporters.sdk import create_mock_result

# Default mock result
result = create_mock_result()

# Custom settings
result = create_mock_result(
    data_asset="test_data.csv",
    status="failure",
    pass_rate=0.75,
    issue_count=5,
    severity_distribution={"critical": 2, "high": 2, "medium": 1}
)

Parameters:

Parameter Type Default Description
data_asset str "test_data.csv" Data asset name
status str "failure" Validation status
pass_rate float 0.8 Pass rate
issue_count int 3 Issue count
severity_distribution dict None Issues per severity

MockResultBuilder

Fluent builder pattern:

from truthound.reporters.sdk import MockResultBuilder

result = (
    MockResultBuilder()
    .with_data_asset("orders.parquet")
    .with_status("failure")
    .with_pass_rate(0.65)
    .add_issue(
        validator="NullValidator",
        column="email",
        severity="critical",
        message="Found 10 null values"
    )
    .add_issue(
        validator="RangeValidator",
        column="age",
        severity="high",
        message="5 values out of range"
    )
    .with_run_time("2024-01-15T10:30:45")
    .build()
)

Builder Methods:

Method Description
with_data_asset(name) Set data asset name
with_status(status) Set validation status
with_pass_rate(rate) Set pass rate
with_run_time(time) Set run time
add_issue(...) Add issue
add_issues(issues) Add multiple issues
build() Create MockValidationResult

create_mock_results

Generate multiple results:

from truthound.reporters.sdk import create_mock_results

# Generate 5 random results
results = create_mock_results(count=5)

# Various status distributions
results = create_mock_results(
    count=10,
    status_distribution={"success": 0.7, "failure": 0.3}
)

Assertion Functions

General Validation

from truthound.reporters.sdk import assert_valid_output

# Auto-detect and validate output format
assert_valid_output(output, format="json")
assert_valid_output(output, format="xml")
assert_valid_output(output, format="csv")

JSON Validation

from truthound.reporters.sdk import assert_json_valid

# Basic JSON validation
assert_json_valid(json_output)

# Validate with schema
assert_json_valid(json_output, schema=my_schema)

# Validate required fields
assert_json_valid(json_output, required_fields=["status", "issues"])

XML Validation

from truthound.reporters.sdk import assert_xml_valid

# Basic XML validation
assert_xml_valid(xml_output)

# Validate root element
assert_xml_valid(xml_output, root_element="testsuites")

# Validate with XSD schema
assert_xml_valid(xml_output, xsd_path="schema.xsd")

CSV Validation

from truthound.reporters.sdk import assert_csv_valid

# Basic CSV validation
assert_csv_valid(csv_output)

# Validate columns
assert_csv_valid(
    csv_output,
    required_columns=["validator", "column", "severity"],
    min_rows=1
)

Pattern Matching

from truthound.reporters.sdk import assert_contains_patterns

assert_contains_patterns(
    output,
    patterns=[
        r"Status: (success|failure)",
        r"Pass Rate: \d+\.\d+%",
        r"Total Issues: \d+"
    ]
)

ReporterTestCase

Base class for test cases:

from truthound.reporters.sdk import ReporterTestCase
from truthound.reporters import get_reporter

class TestMyReporter(ReporterTestCase):
    reporter_name = "my_format"

    def test_basic_render(self):
        """Basic rendering test."""
        reporter = get_reporter(self.reporter_name)
        result = self.create_sample_result()

        output = reporter.render(result)

        self.assert_output_valid(output)
        self.assertIn("Status:", output)

    def test_empty_issues(self):
        """Test with no issues."""
        result = self.create_result_with_no_issues()
        output = self.render(result)

        self.assert_output_valid(output)

    def test_edge_cases(self):
        """Edge case tests."""
        for edge_case in self.get_edge_cases():
            with self.subTest(edge_case=edge_case.name):
                output = self.render(edge_case.data)
                self.assert_output_valid(output)

Provided Methods:

Method Description
create_sample_result() Create standard sample result
create_result_with_no_issues() Create result with no issues
create_result_with_many_issues(n) Create result with n issues
get_edge_cases() Return edge case list
render(result) Render with reporter
assert_output_valid(output) Validate output

Test Data Generation

from truthound.reporters.sdk import (
    create_sample_data,
    create_edge_case_data,
    create_stress_test_data,
)

# Standard sample data
sample = create_sample_data()

# Edge case data
edge_cases = create_edge_case_data()
# Returns: empty_result, single_issue, max_severity, unicode_content, ...

# Stress test data
stress = create_stress_test_data(
    issue_count=10000,
    validator_count=100
)

Output Capture and Benchmarking

capture_output

from truthound.reporters.sdk import capture_output

# Capture stdout/stderr
with capture_output() as captured:
    reporter.print(result)

print(f"Stdout: {captured.stdout}")
print(f"Stderr: {captured.stderr}")

benchmark_reporter

from truthound.reporters.sdk import benchmark_reporter, BenchmarkResult

# Benchmark reporter performance
result: BenchmarkResult = benchmark_reporter(
    reporter=get_reporter("json"),
    data=create_stress_test_data(issue_count=1000),
    iterations=100
)

print(f"Mean time: {result.mean_time:.4f}s")
print(f"Std dev: {result.std_dev:.4f}s")
print(f"Min time: {result.min_time:.4f}s")
print(f"Max time: {result.max_time:.4f}s")
print(f"Throughput: {result.throughput:.2f} ops/sec")

BenchmarkResult Fields:

Field Type Description
mean_time float Mean execution time (seconds)
std_dev float Standard deviation
min_time float Minimum execution time
max_time float Maximum execution time
throughput float Throughput per second
iterations int Iteration count

Custom Reporter Registration

Register with Decorator

from truthound.reporters import register_reporter
from truthound.reporters.base import ValidationReporter, ReporterConfig

@register_reporter("my_custom")
class MyCustomReporter(ValidationReporter[ReporterConfig]):
    name = "my_custom"
    file_extension = ".custom"

    def render(self, run_result):
        presentation = self.present(run_result)
        return f"Custom: {presentation.status}"

Manual Registration

from truthound.reporters.factory import register_reporter

register_reporter("my_custom", MyCustomReporter)

# Usage
reporter = get_reporter("my_custom")

API Reference

SDK Exports

from truthound.reporters.sdk import (
    # Mixins
    FormattingMixin,
    AggregationMixin,
    FilteringMixin,
    SerializationMixin,
    TemplatingMixin,
    StreamingMixin,

    # Builder
    ReporterBuilder,
    create_reporter,
    create_validation_reporter,

    # Templates
    CSVReporter,
    YAMLReporter,
    JUnitXMLReporter,
    NDJSONReporter,
    TableReporter,

    # Schema
    ReportSchema,
    JSONSchema,
    XMLSchema,
    CSVSchema,
    TextSchema,
    ValidationResult,
    ValidationError,
    SchemaError,
    validate_output,
    register_schema,
    get_schema,
    unregister_schema,
    validate_reporter_output,
    infer_schema,
    merge_schemas,

    # Testing
    ReporterTestCase,
    create_mock_result,
    create_mock_results,
    create_mock_validator_result,
    MockResultBuilder,
    MockValidationResult,
    MockValidatorResult,
    assert_valid_output,
    assert_json_valid,
    assert_xml_valid,
    assert_csv_valid,
    assert_contains_patterns,
    create_sample_data,
    create_edge_case_data,
    create_stress_test_data,
    capture_output,
    benchmark_reporter,
    BenchmarkResult,
)