summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Johnson <david.johnson@oerc.ox.ac.uk>2016-06-25 10:46:42 -0700
committerBrian Waldon <brian@waldon.cc>2016-06-25 10:49:15 -0700
commit64a771d151a5defb9bca82042f2c78d513b33aa9 (patch)
tree6564e9d7d5afd866a469198778c7e7683c26b797
parent9d89de02df78a5315ec9e75145eb4a6578c05598 (diff)
downloadwarlock-64a771d151a5defb9bca82042f2c78d513b33aa9.tar.gz
Allow a resolver to be set on the Model
-rw-r--r--test/schemas/country.json10
-rw-r--r--test/schemas/person.json10
-rw-r--r--test/test_core.py98
-rw-r--r--warlock/core.py7
-rw-r--r--warlock/model.py5
5 files changed, 112 insertions, 18 deletions
diff --git a/test/schemas/country.json b/test/schemas/country.json
new file mode 100644
index 0000000..730eb0d
--- /dev/null
+++ b/test/schemas/country.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "name": "Country",
+ "properties": {
+ "name": {"type": "string"},
+ "population": {"type": "integer"},
+ "overlord": { "$ref": "person.json#" }
+ },
+ "additionalProperties": false
+} \ No newline at end of file
diff --git a/test/schemas/person.json b/test/schemas/person.json
new file mode 100644
index 0000000..e517a53
--- /dev/null
+++ b/test/schemas/person.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "name": "Person",
+ "type" : "object",
+ "properties": {
+ "title": { "type": "string" },
+ "firstname": { "type": "string" },
+ "lastname": { "type": "string" }
+ }
+} \ No newline at end of file
diff --git a/test/test_core.py b/test/test_core.py
index 21ceca1..90983de 100644
--- a/test/test_core.py
+++ b/test/test_core.py
@@ -14,6 +14,7 @@
import copy
import unittest
+import os
import json
@@ -40,6 +41,24 @@ complex_fixture = {
},
}
+parent_fixture = {
+ 'name': 'Parent',
+ 'properties': {
+ 'name': {'type': 'string'},
+ 'children': {'type': 'array', 'items': [{'type': 'object'}]}
+ },
+ 'required': ['name', 'children']
+}
+
+child_fixture = {
+ 'name': 'Child',
+ 'properties': {
+ 'age': {'type':'integer'},
+ 'mother': {'type': 'object'}
+ },
+ 'required': ['age', 'mother']
+}
+
nameless_fixture = {
'properties': {
@@ -105,46 +124,46 @@ class TestCore(unittest.TestCase):
exc = warlock.InvalidOperation
self.assertRaises(exc, sweden.update, {'population': 'N/A'})
self.assertRaises(exc, sweden.update, {'overloard': 'Bears'})
-
+
def test_naming(self):
Country = warlock.model_factory(fixture)
- self.assertEqual(Country.__name__, 'Country')
-
+ self.assertEqual('Country', Country.__name__)
+
Country2 = warlock.model_factory(fixture, name='Country2')
- self.assertEqual(Country2.__name__, 'Country2')
-
+ self.assertEqual('Country2', Country2.__name__)
+
nameless = warlock.model_factory(nameless_fixture)
- self.assertEqual(nameless.__name__, 'Model')
-
+ self.assertEqual('Model', nameless.__name__)
+
nameless2 = warlock.model_factory(nameless_fixture, name='Country3')
- self.assertEqual(nameless2.__name__, 'Country3')
+ self.assertEqual('Country3', nameless2.__name__)
def test_deepcopy(self):
"""Make sure we aren't leaking references."""
Mixmaster = warlock.model_factory(complex_fixture)
mike = Mixmaster(sub={'foo': 'mike'})
- self.assertEquals(mike.sub['foo'], 'mike')
+ self.assertEquals('mike', mike.sub['foo'])
mike_1 = mike.copy()
mike_1['sub']['foo'] = 'james'
- self.assertEquals(mike.sub['foo'], 'mike')
+ self.assertEquals('mike', mike.sub['foo'])
mike_2 = dict(six.iteritems(mike))
mike_2['sub']['foo'] = 'james'
- self.assertEquals(mike.sub['foo'], 'mike')
+ self.assertEquals('mike', mike.sub['foo'])
mike_2 = dict(mike.items())
mike_2['sub']['foo'] = 'james'
- self.assertEquals(mike.sub['foo'], 'mike')
+ self.assertEquals('mike', mike.sub['foo'])
mike_3_sub = list(six.itervalues(mike))[0]
mike_3_sub['foo'] = 'james'
- self.assertEquals(mike.sub['foo'], 'mike')
+ self.assertEquals('mike', mike.sub['foo'])
mike_3_sub = list(mike.values())[0]
mike_3_sub['foo'] = 'james'
- self.assertEquals(mike.sub['foo'], 'mike')
+ self.assertEquals('mike', mike.sub['foo'])
def test_forbidden_methods(self):
Country = warlock.model_factory(fixture)
@@ -159,7 +178,7 @@ class TestCore(unittest.TestCase):
sweden = Country(name='Sweden', population=9379116)
sweden['name'] = 'Finland'
- self.assertEqual(sweden['name'], 'Finland')
+ self.assertEqual('Finland', sweden['name'])
del sweden['name']
self.assertRaises(AttributeError, getattr, sweden, 'name')
@@ -169,7 +188,7 @@ class TestCore(unittest.TestCase):
sweden = Country(name='Sweden', population=9379116)
sweden.name = 'Finland'
- self.assertEqual(sweden.name, 'Finland')
+ self.assertEqual('Finland', sweden.name)
delattr(sweden, 'name')
self.assertRaises(AttributeError, getattr, sweden, 'name')
@@ -236,3 +255,50 @@ class TestCore(unittest.TestCase):
for patch in json.loads(sweden.patch):
self.assertTrue(patch in patches)
+
+ def test_resolver(self):
+ from jsonschema import RefResolver
+ schemas_path = 'file://' + os.path.join(os.path.dirname(__file__), 'schemas/')
+ resolver = RefResolver(schemas_path, None)
+
+ country_schema_file = open(os.path.join(os.path.dirname(__file__), 'schemas/') + 'country.json')
+ person_schema_file = open(os.path.join(os.path.dirname(__file__), 'schemas/') + 'person.json')
+
+ country_schema = json.load(country_schema_file)
+ person_schema = json.load(person_schema_file)
+ Country = warlock.model_factory(country_schema, resolver)
+ Person = warlock.model_factory(person_schema, resolver)
+
+ england = Country(
+ name="England",
+ population=53865800,
+ overlord=Person(
+ title="Queen",
+ firstname="Elizabeth",
+ lastname="Windsor"
+ )
+ )
+ expected = {
+ 'name': 'England',
+ 'population': 53865800,
+ 'overlord': {
+ 'title': 'Queen',
+ 'lastname': 'Windsor',
+ 'firstname': 'Elizabeth'
+ }
+ }
+ self.assertEqual(england, expected)
+
+ def test_recursive_models(self):
+ Parent = warlock.model_factory(parent_fixture)
+ Child = warlock.model_factory(child_fixture)
+
+ mom = Parent(name='Abby', children=[])
+
+ teenager = Child(age=15, mother=mom)
+ toddler = Child(age=3, mother=mom)
+
+ mom.children = [teenager, toddler]
+
+ self.assertEqual(mom.children[0].age, 15)
+ self.assertEqual(mom.children[1].age, 3)
diff --git a/warlock/core.py b/warlock/core.py
index affdaa9..c4486c7 100644
--- a/warlock/core.py
+++ b/warlock/core.py
@@ -19,19 +19,24 @@ import copy
from . import model
-def model_factory(schema, base_class=model.Model, name=None):
+def model_factory(schema, resolver=None, base_class=model.Model, name=None):
"""Generate a model class based on the provided JSON Schema
:param schema: dict representing valid JSON schema
:param name: A name to give the class, if `name` is not in `schema`
"""
schema = copy.deepcopy(schema)
+ resolver = resolver
class Model(base_class):
def __init__(self, *args, **kwargs):
self.__dict__['schema'] = schema
+ self.__dict__['resolver'] = resolver
base_class.__init__(self, *args, **kwargs)
+ if resolver is not None:
+ Model.resolver = resolver
+
if name is not None:
Model.__name__ = name
elif 'name' in schema:
diff --git a/warlock/model.py b/warlock/model.py
index 666128c..1fe2606 100644
--- a/warlock/model.py
+++ b/warlock/model.py
@@ -137,6 +137,9 @@ class Model(dict):
def validate(self, obj):
"""Apply a JSON schema to an object"""
try:
- jsonschema.validate(obj, self.schema)
+ if self.resolver is not None:
+ jsonschema.validate(obj, self.schema, resolver=self.resolver)
+ else:
+ jsonschema.validate(obj, self.schema)
except jsonschema.ValidationError as exc:
raise exceptions.ValidationError(str(exc))