From df61dc29432f04b6857271b460a505ab6dec4aca Mon Sep 17 00:00:00 2001 From: Jan Willhaus Date: Sat, 18 May 2019 18:53:50 +0200 Subject: =?UTF-8?q?Blackify=20=F0=9F=8F=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.py | 60 +++++++------- tests/test_core.py | 225 +++++++++++++++++++++++++---------------------------- warlock/core.py | 8 +- warlock/model.py | 19 ++--- 4 files changed, 149 insertions(+), 163 deletions(-) diff --git a/setup.py b/setup.py index d66d046..2a4ee02 100644 --- a/setup.py +++ b/setup.py @@ -17,46 +17,46 @@ import os def parse_requirements(): - fap = open('requirements.txt', 'r') + fap = open("requirements.txt", "r") raw_req = fap.read() fap.close() - return raw_req.split('\n') + return raw_req.split("\n") def read(fname): - with open(os.path.join(os.path.dirname(__file__), fname), 'r') as fp: + with open(os.path.join(os.path.dirname(__file__), fname), "r") as fp: return fp.read() setuptools.setup( - name='warlock', - version='1.3.0', - description='Python object model built on JSON schema and JSON patch.', - long_description=read('README.md'), - long_description_content_type='text/markdown', - keywords=['JSON schema', 'JSON patch', 'model validation'], - author='Brian Waldon', - author_email='bcwaldon@gmail.com', - maintainer='Jan Willhaus', - maintainer_email='mail@janwillhaus.de', - url='http://github.com/bcwaldon/warlock', - packages=['warlock'], + name="warlock", + version="1.3.0", + description="Python object model built on JSON schema and JSON patch.", + long_description=read("README.md"), + long_description_content_type="text/markdown", + keywords=["JSON schema", "JSON patch", "model validation"], + author="Brian Waldon", + author_email="bcwaldon@gmail.com", + maintainer="Jan Willhaus", + maintainer_email="mail@janwillhaus.de", + url="http://github.com/bcwaldon/warlock", + packages=["warlock"], install_requires=parse_requirements(), - license='Apache-2.0', + license="Apache-2.0", classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Topic :: Software Development :: Libraries :: Python Modules', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Topic :: Software Development :: Libraries :: Python Modules", ], ) diff --git a/tests/test_core.py b/tests/test_core.py index 51c0426..c363950 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -24,48 +24,38 @@ import warlock fixture = { - 'name': 'Country', - 'properties': { - 'name': {'type': 'string'}, - 'population': {'type': 'integer'}, - }, - 'additionalProperties': False, + "name": "Country", + "properties": {"name": {"type": "string"}, "population": {"type": "integer"}}, + "additionalProperties": False, } complex_fixture = { - 'name': 'Mixmaster', - 'properties': { - 'sub': {'type': 'object', - 'properties': {'foo': {'type': 'string'}}} + "name": "Mixmaster", + "properties": { + "sub": {"type": "object", "properties": {"foo": {"type": "string"}}} }, } parent_fixture = { - 'name': 'Parent', - 'properties': { - 'name': {'type': 'string'}, - 'children': {'type': 'array', 'items': [{'type': 'object'}]} + "name": "Parent", + "properties": { + "name": {"type": "string"}, + "children": {"type": "array", "items": [{"type": "object"}]}, }, - 'required': ['name', 'children'] + "required": ["name", "children"], } child_fixture = { - 'name': 'Child', - 'properties': { - 'age': {'type': 'integer'}, - 'mother': {'type': 'object'} - }, - 'required': ['age', 'mother'] + "name": "Child", + "properties": {"age": {"type": "integer"}, "mother": {"type": "object"}}, + "required": ["age", "mother"], } nameless_fixture = { - 'properties': { - 'name': {'type': 'string'}, - 'population': {'type': 'integer'}, - }, - 'additionalProperties': False, + "properties": {"name": {"type": "string"}, "population": {"type": "integer"}}, + "additionalProperties": False, } @@ -76,98 +66,101 @@ class TestCore(unittest.TestCase): def test_class_name_from_unicode_schema_name(self): fixture_copy = copy.deepcopy(fixture) - fixture_copy['name'] = six.text_type(fixture_copy['name']) + fixture_copy["name"] = six.text_type(fixture_copy["name"]) # Can't set class.__name__ to a unicode object, ensure warlock # does some magic to make it possible warlock.model_factory(fixture_copy) def test_invalid_operations(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) # Ensure a valid object was created - self.assertEqual(sweden.name, 'Sweden') + self.assertEqual(sweden.name, "Sweden") self.assertEqual(sweden.population, 9379116) # Specific exceptions should be raised for invalid operations - self.assertRaises(AttributeError, getattr, sweden, 'overlord') + self.assertRaises(AttributeError, getattr, sweden, "overlord") exc = warlock.InvalidOperation - self.assertRaises(exc, setattr, sweden, 'overlord', 'Bears') - self.assertRaises(exc, setattr, sweden, 'name', 5) - self.assertRaises(exc, setattr, sweden, 'population', 'N/A') + self.assertRaises(exc, setattr, sweden, "overlord", "Bears") + self.assertRaises(exc, setattr, sweden, "name", 5) + self.assertRaises(exc, setattr, sweden, "population", "N/A") def test_no_mask_arbitrary_properties(self): fixture_copy = copy.deepcopy(fixture) - fixture_copy['additionalProperties'] = {'type': 'string'} + fixture_copy["additionalProperties"] = {"type": "string"} Country = warlock.model_factory(fixture_copy) # We should still depend on the schema for validation self.assertRaises(ValueError, Country, GDP=56956) # But arbitrary properties should be allowed if they check out - sweden = Country(overlord='Waldon') - sweden.abbreviation = 'SE' + sweden = Country(overlord="Waldon") + sweden.abbreviation = "SE" exc = warlock.InvalidOperation - self.assertRaises(exc, setattr, sweden, 'abbreviation', 0) + self.assertRaises(exc, setattr, sweden, "abbreviation", 0) def test_items(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) - self.assertEqual(set(list(six.iteritems(sweden))), - set([('name', 'Sweden'), ('population', 9379116)])) - self.assertEqual(set(sweden.items()), - set([('name', 'Sweden'), ('population', 9379116)])) + sweden = Country(name="Sweden", population=9379116) + self.assertEqual( + set(list(six.iteritems(sweden))), + set([("name", "Sweden"), ("population", 9379116)]), + ) + self.assertEqual( + set(sweden.items()), set([("name", "Sweden"), ("population", 9379116)]) + ) def test_update(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) exc = warlock.InvalidOperation - self.assertRaises(exc, sweden.update, {'population': 'N/A'}) - self.assertRaises(exc, sweden.update, {'overloard': 'Bears'}) + 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', Country.__name__) + self.assertEqual("Country", Country.__name__) - Country2 = warlock.model_factory(fixture, name='Country2') - self.assertEqual('Country2', Country2.__name__) + Country2 = warlock.model_factory(fixture, name="Country2") + self.assertEqual("Country2", Country2.__name__) nameless = warlock.model_factory(nameless_fixture) - self.assertEqual('Model', nameless.__name__) + self.assertEqual("Model", nameless.__name__) - nameless2 = warlock.model_factory(nameless_fixture, name='Country3') - self.assertEqual('Country3', nameless2.__name__) + nameless2 = warlock.model_factory(nameless_fixture, 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'}) + mike = Mixmaster(sub={"foo": "mike"}) - self.assertEquals('mike', mike.sub['foo']) + self.assertEquals("mike", mike.sub["foo"]) mike_1 = mike.copy() - mike_1['sub']['foo'] = 'james' - self.assertEquals('mike', mike.sub['foo']) + mike_1["sub"]["foo"] = "james" + self.assertEquals("mike", mike.sub["foo"]) mike_2 = dict(six.iteritems(mike)) - mike_2['sub']['foo'] = 'james' - self.assertEquals('mike', mike.sub['foo']) + mike_2["sub"]["foo"] = "james" + self.assertEquals("mike", mike.sub["foo"]) mike_2 = dict(mike.items()) - mike_2['sub']['foo'] = 'james' - self.assertEquals('mike', mike.sub['foo']) + mike_2["sub"]["foo"] = "james" + self.assertEquals("mike", mike.sub["foo"]) mike_3_sub = list(six.itervalues(mike))[0] - mike_3_sub['foo'] = 'james' - self.assertEquals('mike', mike.sub['foo']) + mike_3_sub["foo"] = "james" + self.assertEquals("mike", mike.sub["foo"]) mike_3_sub = list(mike.values())[0] - mike_3_sub['foo'] = 'james' - self.assertEquals('mike', mike.sub['foo']) + mike_3_sub["foo"] = "james" + self.assertEquals("mike", mike.sub["foo"]) def test_forbidden_methods(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) exc = warlock.InvalidOperation self.assertRaises(exc, sweden.clear) self.assertRaises(exc, sweden.pop, 0) @@ -175,97 +168,97 @@ class TestCore(unittest.TestCase): def test_dict_syntax(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) - sweden['name'] = 'Finland' - self.assertEqual('Finland', sweden['name']) + sweden["name"] = "Finland" + self.assertEqual("Finland", sweden["name"]) - del sweden['name'] - self.assertRaises(AttributeError, getattr, sweden, 'name') + del sweden["name"] + self.assertRaises(AttributeError, getattr, sweden, "name") def test_attr_syntax(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) - sweden.name = 'Finland' - self.assertEqual('Finland', sweden.name) + sweden.name = "Finland" + self.assertEqual("Finland", sweden.name) - delattr(sweden, 'name') - self.assertRaises(AttributeError, getattr, sweden, 'name') + delattr(sweden, "name") + self.assertRaises(AttributeError, getattr, sweden, "name") def test_changes(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) self.assertEqual(sweden.changes, {}) - sweden['name'] = 'Finland' - self.assertEqual(sweden.changes, {'name': 'Finland'}) - sweden['name'] = 'Norway' - self.assertEqual(sweden.changes, {'name': 'Norway'}) + sweden["name"] = "Finland" + self.assertEqual(sweden.changes, {"name": "Finland"}) + sweden["name"] = "Norway" + self.assertEqual(sweden.changes, {"name": "Norway"}) def test_patch_no_changes(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) - self.assertEqual(sweden.patch, '[]') + sweden = Country(name="Sweden", population=9379116) + self.assertEqual(sweden.patch, "[]") def test_patch_alter_value(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) - sweden['name'] = 'Finland' + sweden = Country(name="Sweden", population=9379116) + sweden["name"] = "Finland" self.assertEqual( json.loads(sweden.patch), - json.loads( - '[{"path": "/name", "value": "Finland", "op": "replace"}]')) + json.loads('[{"path": "/name", "value": "Finland", "op": "replace"}]'), + ) def test_patch_drop_attribute(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) - del sweden['name'] + sweden = Country(name="Sweden", population=9379116) + del sweden["name"] self.assertEqual( - json.loads(sweden.patch), - json.loads('[{"path": "/name", "op": "remove"}]')) + json.loads(sweden.patch), json.loads('[{"path": "/name", "op": "remove"}]') + ) def test_patch_reduce_operations(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) - sweden['name'] = 'Finland' + sweden["name"] = "Finland" self.assertEqual( json.loads(sweden.patch), - json.loads( - '[{"path": "/name", "value": "Finland", "op": "replace"}]')) + json.loads('[{"path": "/name", "value": "Finland", "op": "replace"}]'), + ) - sweden['name'] = 'Norway' + sweden["name"] = "Norway" self.assertEqual( json.loads(sweden.patch), - json.loads( - '[{"path": "/name", "value": "Norway", "op": "replace"}]')) + json.loads('[{"path": "/name", "value": "Norway", "op": "replace"}]'), + ) def test_patch_multiple_operations(self): Country = warlock.model_factory(fixture) - sweden = Country(name='Sweden', population=9379116) + sweden = Country(name="Sweden", population=9379116) - sweden['name'] = 'Finland' - sweden['population'] = 5387000 + sweden["name"] = "Finland" + sweden["population"] = 5387000 self.assertEqual(len(json.loads(sweden.patch)), 2) patches = json.loads( '[{"path": "/name", "value": "Finland", "op": "replace"}, ' - '{"path": "/population", "value": 5387000, "op": "replace"}]') + '{"path": "/population", "value": 5387000, "op": "replace"}]' + ) for patch in json.loads(sweden.patch): self.assertTrue(patch in patches) def test_resolver(self): from jsonschema import RefResolver + dirname = os.path.dirname(__file__) - schemas_path = 'file://' + os.path.join(dirname, 'schemas/') + schemas_path = "file://" + os.path.join(dirname, "schemas/") resolver = RefResolver(schemas_path, None) - country_schema_file = \ - open(os.path.join(dirname, 'schemas/') + 'country.json') - person_schema_file = \ - open(os.path.join(dirname, 'schemas/') + 'person.json') + country_schema_file = open(os.path.join(dirname, "schemas/") + "country.json") + person_schema_file = open(os.path.join(dirname, "schemas/") + "person.json") country_schema = json.load(country_schema_file) person_schema = json.load(person_schema_file) @@ -275,20 +268,16 @@ class TestCore(unittest.TestCase): england = Country( name="England", population=53865800, - overlord=Person( - title="Queen", - firstname="Elizabeth", - lastname="Windsor" - ) + overlord=Person(title="Queen", firstname="Elizabeth", lastname="Windsor"), ) expected = { - 'name': 'England', - 'population': 53865800, - 'overlord': { - 'title': 'Queen', - 'lastname': 'Windsor', - 'firstname': 'Elizabeth' - } + "name": "England", + "population": 53865800, + "overlord": { + "title": "Queen", + "lastname": "Windsor", + "firstname": "Elizabeth", + }, } self.assertEqual(england, expected) @@ -296,7 +285,7 @@ class TestCore(unittest.TestCase): Parent = warlock.model_factory(parent_fixture) Child = warlock.model_factory(child_fixture) - mom = Parent(name='Abby', children=[]) + mom = Parent(name="Abby", children=[]) teenager = Child(age=15, mother=mom) toddler = Child(age=3, mother=mom) diff --git a/warlock/core.py b/warlock/core.py index c4486c7..621b0a8 100644 --- a/warlock/core.py +++ b/warlock/core.py @@ -30,8 +30,8 @@ def model_factory(schema, resolver=None, base_class=model.Model, name=None): class Model(base_class): def __init__(self, *args, **kwargs): - self.__dict__['schema'] = schema - self.__dict__['resolver'] = resolver + self.__dict__["schema"] = schema + self.__dict__["resolver"] = resolver base_class.__init__(self, *args, **kwargs) if resolver is not None: @@ -39,6 +39,6 @@ def model_factory(schema, resolver=None, base_class=model.Model, name=None): if name is not None: Model.__name__ = name - elif 'name' in schema: - Model.__name__ = str(schema['name']) + elif "name" in schema: + Model.__name__ = str(schema["name"]) return Model diff --git a/warlock/model.py b/warlock/model.py index 602a09a..70fedc4 100644 --- a/warlock/model.py +++ b/warlock/model.py @@ -25,7 +25,6 @@ from . import exceptions class Model(dict): - def __init__(self, *args, **kwargs): # we overload setattr so set this manually d = dict(*args, **kwargs) @@ -37,8 +36,8 @@ class Model(dict): else: dict.__init__(self, d) - self.__dict__['changes'] = {} - self.__dict__['__original__'] = copy.deepcopy(d) + self.__dict__["changes"] = {} + self.__dict__["__original__"] = copy.deepcopy(d) def __setitem__(self, key, value): mutation = dict(self.items()) @@ -46,13 +45,12 @@ class Model(dict): try: self.validate(mutation) except exceptions.ValidationError as exc: - msg = ("Unable to set '%s' to %r. Reason: %s" - % (key, value, str(exc))) + msg = "Unable to set '%s' to %r. Reason: %s" % (key, value, str(exc)) raise exceptions.InvalidOperation(msg) dict.__setitem__(self, key, value) - self.__dict__['changes'][key] = value + self.__dict__["changes"][key] = value def __delitem__(self, key): mutation = dict(self.items()) @@ -60,8 +58,7 @@ class Model(dict): try: self.validate(mutation) except exceptions.ValidationError as exc: - msg = ("Unable to delete attribute '%s'. Reason: %s" - % (key, str(exc))) + msg = "Unable to delete attribute '%s'. Reason: %s" % (key, str(exc)) raise exceptions.InvalidOperation(msg) dict.__delitem__(self, key) @@ -124,15 +121,15 @@ class Model(dict): @property def patch(self): """Return a jsonpatch object representing the delta""" - original = self.__dict__['__original__'] + original = self.__dict__["__original__"] return jsonpatch.make_patch(original, dict(self)).to_string() @property def changes(self): """Dumber version of 'patch' method""" - deprecation_msg = 'Model.changes will be removed in warlock v2' + deprecation_msg = "Model.changes will be removed in warlock v2" warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) - return copy.deepcopy(self.__dict__['changes']) + return copy.deepcopy(self.__dict__["changes"]) def validate(self, obj): """Apply a JSON schema to an object""" -- cgit v1.2.1