Skip to content

Commit 03a6b22

Browse files
committed
chore: Restructure ValidationError
Signed-off-by: Dmitry Dygalo <[email protected]>
1 parent 5331aaa commit 03a6b22

File tree

16 files changed

+476
-365
lines changed

16 files changed

+476
-365
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## [Unreleased]
44

5+
### Changed
6+
7+
- **BREAKING**: `ValidationError` fields are private; use `instance()`, `kind()`, `instance_path()`, and `schema_path()` instead of accessing struct fields directly.
8+
9+
### Performance
10+
11+
- `validate` and other APIs returning `Result<_, ValidationError>` are 5–10% faster in some workloads due to the smaller error handle.
12+
513
## [0.36.0] - 2025-11-18
614

715
### Added

MIGRATION.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Migration Guide
22

3+
## Upgrading from 0.36.x to 0.37.0
4+
5+
### `ValidationError` is now opaque
6+
7+
All `ValidationError` fields are private. Replace `error.instance`, `error.instance_path`, `error.schema_path`, and `error.kind` with the corresponding accessor calls:
8+
9+
```rust
10+
let instance = error.instance();
11+
let kind = error.kind();
12+
let instance_path = error.instance_path();
13+
let schema_path = error.schema_path();
14+
```
15+
316
## Upgrading from 0.35.x to 0.36.0
417

518
### Removal of `Validator::apply`, `Output`, and `BasicOutput`

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
2828
// Iterate over errors
2929
for error in validator.iter_errors(&instance) {
3030
eprintln!("Error: {error}");
31-
eprintln!("Location: {}", error.instance_path);
31+
eprintln!("Location: {}", error.instance_path());
3232
}
3333

3434
// Boolean result

crates/jsonschema-py/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Performance
6+
7+
- `jsonschema_rs.validate()` and `Validator.validate()` run 5–10% faster in some workloads thanks to slimmer `ValidationError` objects.
8+
59
## [0.36.0] - 2025-11-18
610

711
### Added

crates/jsonschema-py/src/lib.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ impl ValidationErrorKind {
467467

468468
fn convert_validation_context(
469469
py: Python<'_>,
470-
context: Vec<Vec<jsonschema::error::ValidationError>>,
470+
context: Vec<Vec<jsonschema::error::ValidationError<'static>>>,
471471
mask: Option<&str>,
472472
) -> PyResult<Py<PyList>> {
473473
let mut py_context: Vec<Py<PyList>> = Vec::with_capacity(context.len());
@@ -532,26 +532,25 @@ fn into_validation_error_args(
532532
error.to_string()
533533
};
534534
let verbose_message = to_error_message(&error, message.clone(), mask);
535+
let (instance, kind, instance_path, schema_path) = error.into_parts();
535536
let into_path = |segment: LocationSegment<'_>| match segment {
536537
LocationSegment::Property(property) => {
537538
property.into_pyobject(py).and_then(Py::<PyAny>::try_from)
538539
}
539540
LocationSegment::Index(idx) => idx.into_pyobject(py).and_then(Py::<PyAny>::try_from),
540541
};
541-
let elements = error
542-
.schema_path
542+
let elements = schema_path
543543
.into_iter()
544544
.map(into_path)
545545
.collect::<Result<Vec<_>, _>>()?;
546546
let schema_path = PyList::new(py, elements)?.unbind();
547-
let elements = error
548-
.instance_path
547+
let elements = instance_path
549548
.into_iter()
550549
.map(into_path)
551550
.collect::<Result<Vec<_>, _>>()?;
552551
let instance_path = PyList::new(py, elements)?.unbind();
553-
let kind = ValidationErrorKind::try_new(py, error.kind, mask)?;
554-
let instance = value_to_python(py, error.instance.as_ref())?;
552+
let kind = ValidationErrorKind::try_new(py, kind, mask)?;
553+
let instance = value_to_python(py, instance.as_ref())?;
555554
Ok((
556555
message,
557556
verbose_message,
@@ -758,7 +757,7 @@ fn to_error_message(
758757
}
759758
};
760759

761-
let mut schema_path = error.schema_path.as_str();
760+
let mut schema_path = error.schema_path().as_str();
762761

763762
if let Some((rest, last)) = schema_path.rsplit_once('/') {
764763
message.push(' ');
@@ -774,7 +773,7 @@ fn to_error_message(
774773
message.push('\n');
775774
message.push('\n');
776775
message.push_str("On instance");
777-
for segment in error.instance_path.as_str().split('/').skip(1) {
776+
for segment in error.instance_path().as_str().split('/').skip(1) {
778777
message.push('[');
779778
push_segment(&mut message, segment);
780779
message.push(']');
@@ -785,7 +784,7 @@ fn to_error_message(
785784
message.push_str(mask);
786785
} else {
787786
let mut writer = StringWriter(&mut message);
788-
serde_json::to_writer(&mut writer, &error.instance).expect("Failed to serialize JSON");
787+
serde_json::to_writer(&mut writer, error.instance()).expect("Failed to serialize JSON");
789788
}
790789
message
791790
}
@@ -1549,7 +1548,7 @@ mod meta {
15491548
match result {
15501549
Ok(()) => Ok(true),
15511550
Err(error) => {
1552-
if let jsonschema::error::ValidationErrorKind::Referencing(err) = &error.kind {
1551+
if let jsonschema::error::ValidationErrorKind::Referencing(err) = error.kind() {
15531552
return Err(referencing_error_pyerr(py, err.to_string())?);
15541553
}
15551554
Ok(false)
@@ -1598,7 +1597,7 @@ mod meta {
15981597
match result {
15991598
Ok(()) => Ok(()),
16001599
Err(error) => {
1601-
if let jsonschema::error::ValidationErrorKind::Referencing(err) = &error.kind {
1600+
if let jsonschema::error::ValidationErrorKind::Referencing(err) = error.kind() {
16021601
return Err(referencing_error_pyerr(py, err.to_string())?);
16031602
}
16041603
Err(crate::into_py_err(py, error, None)?)

0 commit comments

Comments
 (0)