Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide structured validation error in Python bindings #197

Closed
Stranger6667 opened this issue Apr 29, 2021 · 1 comment · Fixed by #242
Closed

Provide structured validation error in Python bindings #197

Stranger6667 opened this issue Apr 29, 2021 · 1 comment · Fixed by #242

Comments

@Stranger6667
Copy link
Owner

Stranger6667 commented Apr 29, 2021

At the moment, it is not possible to safely define a custom exception class via PyO3 that will expose some Rust struct fields as Python-side instance attributes.

The solution is to add an intermediate Python module that will wrap validate, catch the underlying exception, and re-raise it via a different class.

from . import jsonschema_rs as rs


is_valid = rs.is_valid
JSONSchema = rs.JSONSchema
Draft4 = rs.Draft4
Draft6 = rs.Draft6
Draft7 = rs.Draft7
__build__ = rs.__build__


class ValidationError(ValueError):

    def __init__(self, message, instance_path, instance_path_pointer):
        super().__init__(message)
        self.instance_path = instance_path
        self.instance_path_pointer = instance_path_pointer


ValidationError.__doc__ = rs.ValidationError.__doc__


def validate(schema, instance, draft=None, with_meta_schemas=False):
    try:
        return rs.validate(schema, instance, draft, with_meta_schemas)
    except rs.ValidationError as exc:
        raise ValidationError(
            message=exc.args[0], 
            instance_path=exc.args[1], 
            instance_path_pointer=exc.args[2]
        ) from None

validate.__doc__ = rs.validate.__doc__

I am not sure about attributes - maybe it will be better to follow the same structure as in the ValidationError struct - separate class for instance_path that can be converted to a string or a vector of strings.

This approach implies some overhead, but preliminary tests did not indicate any significant slowdown.

As an extra benefit - it will be possible to specify type annotations for functions created on the python-level, so maybe it worth wrapping is_valid as well.

The snippet above is almost sufficient. Other things:

  • Update raise_on_error in Python bindings code, so it passes a tuple of needed attributes to the bindings-level ValidationError;
  • Update the build system - the resulting Python package should include this code.
@Stranger6667
Copy link
Owner Author

When PyO3/pyo3#1591 gets merged & released, the abovementioned intermediate Python level won't be needed, so it might be better to wait a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant