Validator¶
The Validator class is the primary interface for data validation.
Overview¶
from pycharter import Validator
# Create from contract file
validator = Validator.from_file("user_contract.yaml")
# Validate data
result = validator.validate({"name": "Alice", "age": 30})
if result.is_valid:
print(f"Valid: {result.data}")
else:
print(f"Errors: {result.errors}")
API Reference¶
Validator
¶
Validator(
contract: ContractMetadata
| dict[str, Any]
| DataContract,
*,
strict: bool = False,
coerce: bool = True,
strict_types: bool | None = None,
include_quality: bool = False,
metrics: MetricsCollector | None = None,
state_rules: dict[str, Any] | None = None,
)
Generic Validator that performs validation from contract artifacts.
Construct directly from an in-memory contract (a ContractMetadata,
a contract dict, or a :class:DataContract), or use one of the
from_* classmethods (from_file, from_dir, from_dict,
from_store). Then call validate() or validate_batch() on
data dicts.
Thread safety
A Validator is immutable after construction — the Pydantic
model is compiled once in __init__ and never mutated by
validation calls. validate(), validate_batch(), and
validate_for_state() are safe to call concurrently from
multiple threads on one shared instance. One caveat: an attached
metrics collector receives results from every thread, so its
store must itself be thread-safe (the bundled
InMemoryMetricsStore is).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
contract
|
ContractMetadata | dict[str, Any] | DataContract
|
The contract source — a |
required |
strict
|
bool
|
If True, validation errors raise instead of being
captured in the result. This governs error handling, not
typing — see |
False
|
coerce
|
bool
|
If True (default), the contract's |
True
|
strict_types
|
bool | None
|
If True, the generated model runs in Pydantic's
strict mode, so a value of the wrong JSON type is rejected
instead of converted — Leave it off for ingest, where a CSV's |
None
|
include_quality
|
bool
|
If True, validation results include quality metrics by default. |
False
|
metrics
|
MetricsCollector | None
|
Optional |
None
|
state_rules
|
dict[str, Any] | None
|
Optional mapping from state names to override
dicts, consumed by |
None
|
Raises:
| Type | Description |
|---|---|
CoercionOperationNotFoundError
|
If |
Source code in src/pycharter/runtime_validator/_engine.py
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | |
model
property
¶
The generated Pydantic model.
Raises:
| Type | Description |
|---|---|
ValueError
|
If model not initialized. |
from_file
classmethod
¶
from_file(path: str | Path, **kwargs: Any) -> Validator
Create a validator from a single contract file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Path to a contract file (YAML/JSON). |
required |
**kwargs
|
Any
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Validator
|
A configured :class: |
Source code in src/pycharter/runtime_validator/_engine.py
from_dir
classmethod
¶
from_dir(path: str | Path, **kwargs: Any) -> Validator
Create a validator from a directory of contract files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Directory containing |
required |
**kwargs
|
Any
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Validator
|
A configured :class: |
Source code in src/pycharter/runtime_validator/_engine.py
from_dict
classmethod
¶
from_dict(
config: dict[str, Any], **kwargs: Any
) -> Validator
Create a validator from a contract dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Full artifact dict ( |
required |
**kwargs
|
Any
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Validator
|
A configured :class: |
Source code in src/pycharter/runtime_validator/_engine.py
from_store
classmethod
¶
from_store(
ref: StoreRef | str,
*,
store: ContractStoreClient,
namespace: str | None = None,
**kwargs: Any,
) -> Validator
Create a validator from a contract in a contract store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ref
|
StoreRef | str
|
A :class: |
required |
store
|
ContractStoreClient
|
The :class: |
required |
namespace
|
str | None
|
Exact contract namespace. |
None
|
**kwargs
|
Any
|
Forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Validator
|
A configured :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the contract is not found in the store. |
Source code in src/pycharter/runtime_validator/_engine.py
validate
¶
validate(
data: dict[str, Any],
strict: bool | None = None,
include_quality: bool | None = None,
) -> ValidationResult
Validate a single data record against the contract.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict[str, Any]
|
Data dictionary to validate. |
required |
strict
|
bool | None
|
If True, raise exceptions on validation errors. Defaults to the configured setting or False. |
None
|
include_quality
|
bool | None
|
If True, include quality metrics in result. Defaults to the configured setting or False. |
None
|
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult object. |
Source code in src/pycharter/runtime_validator/_engine.py
validate_batch
¶
validate_batch(
data_list: list[dict[str, Any]],
strict: bool | None = None,
include_quality: bool | None = None,
) -> list[ValidationResult]
Validate a batch of data records against the contract.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_list
|
list[dict[str, Any]]
|
List of data dictionaries to validate. |
required |
strict
|
bool | None
|
If True, stop on first validation error. Defaults to the configured setting or False. |
None
|
include_quality
|
bool | None
|
If True, include quality metrics in results. Defaults to the configured setting or False. |
None
|
Returns:
| Type | Description |
|---|---|
list[ValidationResult]
|
List of ValidationResult objects. |
Source code in src/pycharter/runtime_validator/_engine.py
json_schema
¶
Return the complete schema (with rules merged).
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Complete schema dictionary. |
Constructor and Factory Methods¶
Direct construction¶
Construct directly from an in-memory contract — a DataContract, a contract
dict, or a ContractMetadata:
from pycharter import Validator, build_contract_from_store
contract = build_contract_from_store(store, "user", "1.0.0")
validator = Validator(contract) # DataContract, dict, or ContractMetadata
result = validator.validate(data)
Configuration options are keyword-only:
strict and strict_types are different things
strict controls error handling — whether a validation failure raises
instead of being returned in the result. It predates Pydantic's own
strict and is unrelated to it.
strict_types controls typing — whether a value of the wrong JSON type
is rejected instead of converted.
coerce is a third, separate thing: it toggles the contract's declared
coercion_rules. Setting coerce=False does not stop Pydantic from
converting types.
from_file¶
Create validator from a single contract file:
from_dir¶
Create from a directory containing schema.yaml, coercion_rules.yaml, validation_rules.yaml:
from_dict¶
Create from a contract dictionary (full artifact dict or a bare JSON Schema document):
validator = Validator.from_dict(
{
"json_schema": {"type": "object", "properties": {...}},
"coercion_rules": {...},
"validation_rules": {...},
}
)
from_store¶
Create a validator from a contract stored by name and version, addressed with
a StoreRef:
from pycharter import Validator, PostgresContractStore
from pycharter.shared.refs import StoreRef
store = PostgresContractStore("postgresql://...")
store.connect()
validator = Validator.from_store(StoreRef("user", "1.0.0"), store=store)
result = validator.validate(data)
store.disconnect()
ValidationResult¶
ValidationResult
¶
ValidationResult(
is_valid: bool,
data: BaseModel | None = None,
errors: list[str] | None = None,
quality: QualityMetrics | None = None,
diagnostics: list[FieldDiagnostic] | None = None,
state: str | None = None,
trigger: str | None = None,
entity_id: str | None = None,
contract_name: str | None = None,
)
Result of a validation operation.
Attributes:
| Name | Type | Description |
|---|---|---|
is_valid |
Whether validation passed |
|
data |
Validated data (Pydantic model instance) if valid |
|
errors |
List of human-readable validation error messages if invalid |
|
diagnostics |
Structured per-field diagnostics if invalid |
|
quality |
Optional quality metrics |
Source code in src/pycharter/runtime_validator/validator_core.py
Examples¶
Single Validation¶
result = validator.validate({"name": "Alice", "email": "alice@example.com", "age": 30})
if result.is_valid:
user = result.data # Pydantic model instance
print(user.name)
else:
for error in result.errors:
print(f"{error['loc']}: {error['msg']}")
Batch Validation¶
records = [
{"name": "Alice", "email": "alice@example.com"},
{"name": "", "email": "invalid"}, # Invalid
{"name": "Charlie", "email": "charlie@example.com"},
]
results = validator.validate_batch(records)
valid_records = [r.data for r in results if r.is_valid]
print(f"Valid: {len(valid_records)}/{len(records)}")
Strict Mode (raise instead of return)¶
from pydantic import ValidationError
try:
result = validator.validate(data, strict=True)
# If we get here, data is valid
except ValidationError as e:
print(f"Validation failed: {e}")
Strict Types (reject wrong types instead of converting)¶
By default a contract validates leniently: "10.5" satisfies a number field,
because Pydantic converts it. That is the right behaviour for ingest — a
CSV's "10.5" really is that float, and rejecting it would be wrong.
It is the wrong behaviour for verification, where the producer emitting a
string instead of a number is exactly what you are validating to catch. Turn on
strict_types for that case:
lenient = Validator(contract)
lenient.validate({"total": "10.5"}).is_valid # True — converted
strict = Validator(contract, strict_types=True)
strict.validate({"total": "10.5"}).is_valid # False — float_type
strict.validate({"total": 10.5}).is_valid # True
It applies to nested objects and array items too, so a nested field cannot slip through while the record it belongs to is being graded strictly.
Declare it on the contract when strictness is a property of the data rather
than of one call site — whether a field tolerates "10.5" usually belongs to
the contract, not to whoever happens to be validating against it:
format_version: "1"
strict_types: true
json_schema:
version: "1.0.0"
type: object
properties:
total: { type: number }
required: [total]
A strict_types argument overrides the contract's flag; absent from both, the
lenient default applies, so existing contracts are unaffected.
Getting the Model¶
# Access the generated Pydantic model
UserModel = validator.model
# Use it directly
user = UserModel(name="Alice", email="alice@example.com")
# Export schema
print(UserModel.model_json_schema())
Convenience Functions¶
get_model_from_contract¶
Generate a Pydantic model from a contract (file path, DataContract, dict, or
ContractMetadata) without keeping a Validator around:
from pycharter import get_model_from_contract
UserModel = get_model_from_contract("contract.yaml")
UserModel = get_model_from_contract(contract_dict) # DataContract or dict
get_model_from_store¶
Generate a Pydantic model from a contract in the contract store (by name and version):
See Also¶
- Validate a pandas DataFrame —
validate_dataframe(df, contract, on_error=...), the one-call façade overValidator.validate_batchwith quarantine/fail/warn behaviour. - Validate a file from the shell —
the
pycharter validateCLI verb (exit-code CI gate). - Contracts Tutorial
- Custom Validators Guide
- Pydantic Generator
- Glossary