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

Fix incorrect schema dict for arrays, rename Schema.schema to jsonschema_dict #30

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fixed incorrect schema dict for arrays, renamed schema method to json…
…schema_dict for clarity, documented Schema class
jtv8 committed May 22, 2020
commit bdb0740403df020d121ff2a3869c46dd4f97afbe
43 changes: 43 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -198,6 +198,49 @@ bases of Person::
.. autoclass:: wysdom.ReadsYAML
:members:


Internals
=========

Schema objects
--------------

.. autoclass:: wysdom.Schema
:members:

Base schemas
............

The following schemas define simple atomic schemas
(defined in the subpackage `wysdom.base_schema`):

=============== ==================================================================
Name Description
=============== ==================================================================
Schema abstract base class
SchemaType abstract base class for any schema with the "type" directive
SchemaAnything any valid JSON will be accepted
SchemaConst a string constant
SchemaNone a null value
SchemaPrimitive a primitive variable
=============== ==================================================================

Object schemas
..............

The following schemas define complex schemas which reference other schemas
(defined in the subpackage `wysdom.object_schema`):

=============== ==================================================================
Name Description
=============== ==================================================================
SchemaAnyOf Any of the permitted schemas supplied
SchemaArray An array (corresponding to a Python list)
SchemaObject An object with named properties
SchemaDict An object with dynamic properties (corresponding to a Python dict)
=============== ==================================================================


Indices and tables
==================

45 changes: 45 additions & 0 deletions features/dict.feature
Original file line number Diff line number Diff line change
@@ -29,6 +29,50 @@ Feature: Test JSON DOM objects
}
example = dict_module.Person(example_dict_input)
example_dict_output = example.to_builtin()
expected_schema = {
"additionalProperties": False,
"properties": {
"first_name": {"type": "string"},
"last_name": {"type": "string"},
"current_address": {
"additionalProperties": False,
"properties": {
"city": {"type": "string"},
"first_line": {"type": "string"},
"postal_code": {"type": "integer"},
"second_line": {"type": "string"}
},
"type": "object"
},
"previous_addresses": {
"array": {
"items": {
"additionalProperties": False,
"properties": {
"city": {"type": "string"},
"first_line": {"type": "string"},
"postal_code": {"type": "integer"},
"second_line": {"type": "string"}
},
"type": "object"
}
}
},
"vehicles": {
"properties": {},
"additionalProperties": {
"properties": {
"color": {"type": "string"},
"description": {"type": "string"}
},
"additionalProperties": False,
"type": "object"
},
"type": "object"
}
},
"type": "object"
}
"""
Then the following statements are true:
"""
@@ -63,6 +107,7 @@ Feature: Test JSON DOM objects
document(example["vehicles"]["eabf04"]) is example
key(example["vehicles"]["eabf04"]) == "eabf04"
schema(example).is_valid(example_dict_input)
schema(example).jsonschema_dict == expected_schema
example_dict_output == example_dict_input
"""

37 changes: 34 additions & 3 deletions wysdom/base_schema/Schema.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
from abc import ABC, abstractmethod
from typing import Any, Dict, Tuple

from ..exceptions import ValidationError
from jsonschema.validators import validator_for


class Schema(ABC):
"""
Abstract base class for JSON schemas. Objects of type `Schema` can be used to generate
jsonschema-compatible dictionaries, and to validate potential input data against those
schemas.

Objects of type `Schema` are also callable, and when called will create DOM objects or
primitive Python object containing the data that is supplied to them.
"""

@abstractmethod
def __call__(
self,
value: Any,
dom_info: Tuple = None
) -> Any:
return value
"""
Return either a DOM object or primitive Python object containing the data
supplied in `value`, if `value` is a valid instance of this schema.

:return: A DOM object or primitive Python object containing the data in `value`
"""
if self.is_valid(value):
return value
else:
raise ValidationError(
f"The supplied value does not conform to this schema: {value}"
)

@property
@abstractmethod
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
"""
Compile this schema as a jsonschema-compatible dictionary.

:return: A jsonschema-compatible dictionary
"""
return {}

def is_valid(self, value: Any) -> bool:
return validator_for(self.schema)(self.schema).is_valid(value)
"""
Determine whether a given object conforms to this schema.

:param value: An object to test for validity against this schema
:return: True if the object is valid, otherwise False
"""
return validator_for(self.jsonschema_dict)(self.jsonschema_dict).is_valid(value)
2 changes: 1 addition & 1 deletion wysdom/base_schema/SchemaAnything.py
Original file line number Diff line number Diff line change
@@ -13,5 +13,5 @@ def __call__(
return value

@property
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
return {}
2 changes: 1 addition & 1 deletion wysdom/base_schema/SchemaConst.py
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ def __call__(
return self.value

@property
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
return {
"const": self.value
}
2 changes: 1 addition & 1 deletion wysdom/base_schema/SchemaType.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ def type_name(self) -> str:
pass

@property
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
return {"type": self.type_name}


4 changes: 2 additions & 2 deletions wysdom/object_schema/SchemaAnyOf.py
Original file line number Diff line number Diff line change
@@ -36,10 +36,10 @@ def __call__(
return valid_schemas[0](value, dom_info)

@property
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
return {
'anyOf': [
allowed_schema.schema
allowed_schema.jsonschema_dict
for allowed_schema in self.allowed_schemas
]
}
4 changes: 2 additions & 2 deletions wysdom/object_schema/SchemaArray.py
Original file line number Diff line number Diff line change
@@ -28,9 +28,9 @@ def __call__(
)

@property
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
return {
"array": {
"items": self.items
"items": self.items.jsonschema_dict
}
}
8 changes: 4 additions & 4 deletions wysdom/object_schema/SchemaObject.py
Original file line number Diff line number Diff line change
@@ -29,15 +29,15 @@ def __call__(
return self.object_type(value, dom_info)

@property
def schema(self) -> Dict[str, Any]:
def jsonschema_dict(self) -> Dict[str, Any]:
return {
**super().schema,
**super().jsonschema_dict,
'properties': {
k: v.schema
k: v.jsonschema_dict
for k, v in self.properties.items()
},
"additionalProperties": (
self.additional_properties.schema
self.additional_properties.jsonschema_dict
if isinstance(self.additional_properties, Schema)
else self.additional_properties
)