started work on backend
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
from __future__ import nested_scopes, generators, division, absolute_import, with_statement, \
|
||||
print_function, unicode_literals
|
||||
from .utilities.compatibility import backport
|
||||
|
||||
backport() # noqa
|
||||
|
||||
from future.utils import native_str
|
||||
|
||||
from serial.utilities import qualified_name, calling_function_qualified_name
|
||||
from serial.abc.model import Model
|
||||
|
||||
from warnings import warn
|
||||
|
||||
import collections
|
||||
import json as _json
|
||||
from itertools import chain
|
||||
|
||||
import yaml as _yaml
|
||||
|
||||
import serial
|
||||
|
||||
try:
|
||||
import typing
|
||||
except ImportError as e:
|
||||
typing = None
|
||||
|
||||
|
||||
def _object_discrepancies(a, b):
|
||||
# type: (serial.model.Object, serial.model.Object) -> dict
|
||||
discrepancies = {}
|
||||
a_properties = set(serial.meta.read(a).properties.keys())
|
||||
b_properties = set(serial.meta.read(b).properties.keys())
|
||||
for property_ in a_properties | b_properties:
|
||||
try:
|
||||
a_value = getattr(a, property_)
|
||||
except AttributeError:
|
||||
a_value = None
|
||||
try:
|
||||
b_value = getattr(b, property_)
|
||||
except AttributeError:
|
||||
b_value = None
|
||||
if a_value != b_value:
|
||||
discrepancies[property_] = (a_value, b_value)
|
||||
return discrepancies
|
||||
|
||||
|
||||
def json(
|
||||
model_instance, # type: serial.model.Model
|
||||
raise_validation_errors=True, # type: bool
|
||||
):
|
||||
# type: (...) -> None
|
||||
model(
|
||||
model_instance=model_instance,
|
||||
format_='json',
|
||||
raise_validation_errors=raise_validation_errors
|
||||
)
|
||||
|
||||
|
||||
def yaml(
|
||||
model_instance, # type: serial.model.Model
|
||||
raise_validation_errors=True, # type: bool
|
||||
):
|
||||
# type: (...) -> None
|
||||
model(
|
||||
model_instance=model_instance,
|
||||
format_='yaml',
|
||||
raise_validation_errors=raise_validation_errors
|
||||
)
|
||||
|
||||
|
||||
def xml(
|
||||
model_instance, # type: serial.model.Model
|
||||
raise_validation_errors=True, # type: bool
|
||||
):
|
||||
# type: (...) -> None
|
||||
raise NotImplementedError()
|
||||
# model(
|
||||
# model_instance=model_instance,
|
||||
# format_='xml',
|
||||
# raise_validation_errors=raise_validation_errors
|
||||
# )
|
||||
|
||||
|
||||
def model(
|
||||
model_instance, # type: serial.model.Model
|
||||
format_, # type: str
|
||||
raise_validation_errors=True, # type: bool
|
||||
):
|
||||
# type: (...) -> None
|
||||
"""
|
||||
Tests an instance of a `serial.model.Model` sub-class.
|
||||
|
||||
Parameters:
|
||||
|
||||
- model_instance (serial.model.Model):
|
||||
|
||||
An instance of a `serial.model.Model` sub-class.
|
||||
|
||||
- format_ (str):
|
||||
|
||||
The serialization format being tested: 'json', 'yaml' or 'xml'.
|
||||
|
||||
- raise_validation_errors (bool):
|
||||
|
||||
The function `serial.model.validate` verifies that all required attributes are present, as well as any
|
||||
additional validations implemented using the model's validation hooks `after_validate` and/or
|
||||
`before_validate`.
|
||||
|
||||
- If `True`, errors resulting from `serial.model.validate` are raised.
|
||||
|
||||
- If `False`, errors resulting from `serial.model.validate` are expressed only as warnings.
|
||||
"""
|
||||
if not isinstance(model_instance, Model):
|
||||
|
||||
value_representation = repr(model_instance)
|
||||
|
||||
raise TypeError(
|
||||
'`%s` requires an instance of `%s` for the parameter `model_instance`, not%s' % (
|
||||
calling_function_qualified_name(),
|
||||
qualified_name(Model),
|
||||
(
|
||||
(':\n%s' if '\n' in value_representation else ' `%s`') %
|
||||
value_representation
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
serial.meta.format_(model_instance, format_)
|
||||
|
||||
if isinstance(model_instance, serial.model.Object):
|
||||
|
||||
errors = serial.marshal.validate(model_instance, raise_errors=raise_validation_errors)
|
||||
|
||||
if errors:
|
||||
warn('\n' + '\n'.join(errors))
|
||||
|
||||
model_type = type(model_instance)
|
||||
|
||||
string = str(model_instance)
|
||||
|
||||
assert string != ''
|
||||
|
||||
reloaded_model_instance = model_type(string)
|
||||
qualified_model_name = qualified_name(type(model_instance))
|
||||
|
||||
try:
|
||||
|
||||
assert model_instance == reloaded_model_instance
|
||||
|
||||
except AssertionError as e:
|
||||
|
||||
sa = serial.marshal.serialize(model_instance)
|
||||
sb = serial.marshal.serialize(reloaded_model_instance)
|
||||
|
||||
ra = ''.join(l.strip() for l in repr(model_instance).split('\n'))
|
||||
rb = ''.join(l.strip() for l in repr(reloaded_model_instance).split('\n'))
|
||||
|
||||
message = [
|
||||
'Discrepancies were found between the instance of `%s` provided and ' % qualified_model_name +
|
||||
'a serialized/deserialized clone:'
|
||||
]
|
||||
|
||||
if sa != sb:
|
||||
|
||||
message.append(
|
||||
'\n :\n\n %s\n !=\n %s' % (
|
||||
sa,
|
||||
sb
|
||||
)
|
||||
)
|
||||
|
||||
if ra != rb:
|
||||
|
||||
message.append(
|
||||
'\n %s\n !=\n %s\n' % (
|
||||
ra,
|
||||
rb
|
||||
)
|
||||
)
|
||||
|
||||
for k, a_b in _object_discrepancies(model_instance, reloaded_model_instance).items():
|
||||
|
||||
a, b = a_b
|
||||
|
||||
assert a != b
|
||||
|
||||
sa = serial.marshal.serialize(a)
|
||||
sb = serial.marshal.serialize(b)
|
||||
|
||||
if sa != sb:
|
||||
|
||||
message.append(
|
||||
'\n %s().%s:\n\n %s\n %s\n %s' % (
|
||||
qualified_model_name,
|
||||
k,
|
||||
sa,
|
||||
'==' if sa == sb else '!=',
|
||||
sb
|
||||
)
|
||||
)
|
||||
|
||||
ra = ''.join(l.strip() for l in repr(a).split('\n'))
|
||||
rb = ''.join(l.strip() for l in repr(b).split('\n'))
|
||||
|
||||
if ra != rb:
|
||||
|
||||
message.append(
|
||||
'\n %s\n %s\n %s' % (
|
||||
ra,
|
||||
'==' if ra == rb else '!=',
|
||||
rb
|
||||
)
|
||||
)
|
||||
|
||||
e.args = tuple(
|
||||
chain(
|
||||
(e.args[0] + '\n' + '\n'.join(message) if e.args else '\n'.join(message),),
|
||||
e.args[1:] if e.args else tuple()
|
||||
)
|
||||
)
|
||||
|
||||
raise e
|
||||
|
||||
reloaded_string = str(reloaded_model_instance)
|
||||
|
||||
try:
|
||||
assert string == reloaded_string
|
||||
except AssertionError as e:
|
||||
m = '\n%s\n!=\n%s' % (string, reloaded_string)
|
||||
if e.args:
|
||||
e.args = tuple(chain(
|
||||
(e.args[0] + '\n' + m,),
|
||||
e.args[1:]
|
||||
))
|
||||
else:
|
||||
e.args = (m,)
|
||||
raise e
|
||||
|
||||
if format_ == 'json':
|
||||
reloaded_marshalled_data = _json.loads(
|
||||
string,
|
||||
object_hook=collections.OrderedDict,
|
||||
object_pairs_hook=collections.OrderedDict
|
||||
)
|
||||
elif format_ == 'yaml':
|
||||
reloaded_marshalled_data = _yaml.load(string)
|
||||
elif format_ == 'xml':
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
format_representation = repr(format_)
|
||||
raise ValueError(
|
||||
'Valid serialization types for parameter `format_` are "json", "yaml", or "xml'", not" + (
|
||||
(
|
||||
':\n%s' if '\n' in format_representation else ' %s.'
|
||||
) % format_representation
|
||||
)
|
||||
)
|
||||
|
||||
keys = set()
|
||||
|
||||
for property_name, property in serial.meta.read(model_instance).properties.items():
|
||||
|
||||
keys.add(property.name or property_name)
|
||||
property_value = getattr(model_instance, property_name)
|
||||
|
||||
if isinstance(property_value, Model) or (
|
||||
hasattr(property_value, '__iter__') and
|
||||
(not isinstance(property_value, (str, native_str, bytes)))
|
||||
):
|
||||
model(property_value, format_=format_, raise_validation_errors=raise_validation_errors)
|
||||
|
||||
for k in reloaded_marshalled_data.keys():
|
||||
|
||||
if k not in keys:
|
||||
raise KeyError(
|
||||
'"%s" not found in serialized/re-deserialized data: %s' % (
|
||||
k,
|
||||
string
|
||||
)
|
||||
)
|
||||
|
||||
elif isinstance(model_instance, serial.model.Array):
|
||||
|
||||
serial.marshal.validate(model_instance)
|
||||
|
||||
for item in model_instance:
|
||||
|
||||
if isinstance(item, Model) or (
|
||||
hasattr(item, '__iter__') and
|
||||
(not isinstance(item, (str, native_str, bytes)))
|
||||
):
|
||||
model(item, format_=format_, raise_validation_errors=raise_validation_errors)
|
||||
|
||||
elif isinstance(model_instance, serial.model.Dictionary):
|
||||
|
||||
serial.marshal.validate(model_instance)
|
||||
|
||||
for key, value in model_instance.items():
|
||||
|
||||
if isinstance(value, Model) or (
|
||||
hasattr(value, '__iter__') and
|
||||
(not isinstance(value, (str, native_str, bytes)))
|
||||
):
|
||||
model(value, format_=format_, raise_validation_errors=raise_validation_errors)
|
||||
Reference in New Issue
Block a user