From 4b58d04be635a430c6e24666ac43c92fbd79af73 Mon Sep 17 00:00:00 2001 From: Jauhien Piatlicki Date: Sat, 18 Apr 2015 19:21:21 +0200 Subject: [g_sorcery/serialization] fix serialization for collections --- g_sorcery/g_collections.py | 13 +++++++----- g_sorcery/serialization.py | 15 +++++++++----- tests/serializable.py | 38 +++++++++++++++++++++++++++++++++++ tests/test_FileBSON.py | 40 ++++++++++++------------------------- tests/test_FileJSON.py | 50 ++++++++++++++++------------------------------ tests/test_PackageDB.py | 11 +++++++--- 6 files changed, 94 insertions(+), 73 deletions(-) create mode 100644 tests/serializable.py diff --git a/g_sorcery/g_collections.py b/g_sorcery/g_collections.py index b28db6a..b9f3d06 100644 --- a/g_sorcery/g_collections.py +++ b/g_sorcery/g_collections.py @@ -4,14 +4,14 @@ """ g_collections.py ~~~~~~~~~~~~~~~~ - + Customized classes of standard python data types for use withing g-sorcery for custom formatted string output substitution in our ebuild templates and classes for storing information about packages and dependencies. - + :copyright: (c) 2013 by Brian Dolbec - :copyright: (c) 2013 by Jauhien Piatlicki + :copyright: (c) 2013-2015 by Jauhien Piatlicki :license: GPL-2, see LICENSE for more details. """ @@ -52,7 +52,7 @@ class serializable_elist(object): """ __slots__ = ('data') - + def __init__(self, iterable=None, separator=' '): ''' iterable: initialize from iterable's items @@ -60,6 +60,9 @@ class serializable_elist(object): ''' self.data = elist(iterable or [], separator) + def __eq__(self, other): + return self.data == other.data + def __iter__(self): return iter(self.data) @@ -122,7 +125,7 @@ class Dependency(object): def __init__(self, category, package, version="", operator=""): atom_str = operator + category + "/" + package - if version: + if version: atom_str += "-" + str(version) object.__setattr__(self, "atom", portage.dep.Atom(atom_str)) object.__setattr__(self, "category", category) diff --git a/g_sorcery/serialization.py b/g_sorcery/serialization.py index 3a7704b..b5d71f3 100644 --- a/g_sorcery/serialization.py +++ b/g_sorcery/serialization.py @@ -14,6 +14,8 @@ import json import importlib +from .compatibility import basestring + def step_to_raw_serializable(obj): """ Make one step of convertion of object @@ -40,19 +42,22 @@ def to_raw_serializable(obj): Convert object to the raw serializable type. Logic is the same as in the standard json encoder. """ - if isinstance(obj, str) \ + if isinstance(obj, basestring) \ or obj is None \ or obj is True \ or obj is False \ or isinstance(obj, int) \ - or isinstance(obj, float) \ - or isinstance(obj, (list, tuple)) \ - or isinstance(obj, dict): + or isinstance(obj, float): return obj + elif isinstance(obj, dict): + return {k: to_raw_serializable(v) for k, v in obj.items()} + elif isinstance(obj, (list, tuple)): + return [to_raw_serializable(item) for item in obj] + else: sobj = step_to_raw_serializable(obj) if not sobj: - raise TypeError('Non serializable object: ', sobj) + raise TypeError('Non serializable object: ', obj) return to_raw_serializable(sobj) diff --git a/tests/serializable.py b/tests/serializable.py new file mode 100644 index 0000000..1d3981e --- /dev/null +++ b/tests/serializable.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + serializable.py + ~~~~~~~~~~~~~~~ + + test classes for serialization + + :copyright: (c) 2013-2015 by Jauhien Piatlicki + :license: GPL-2, see LICENSE for more details. +""" + +class NonSerializableClass(object): + pass + + +class SerializableClass(object): + + __slots__ = ("field1", "field2") + + def __init__(self, field1, field2): + self.field1 = field1 + self.field2 = field2 + + def __eq__(self, other): + return self.field1 == other.field1 \ + and self.field2 == other.field2 + + def serialize(self): + return {"field1": self.field1, "field2": self.field2} + + +class DeserializableClass(SerializableClass): + + @classmethod + def deserialize(cls, value): + return DeserializableClass(value["field1"], value["field2"]) diff --git a/tests/test_FileBSON.py b/tests/test_FileBSON.py index ff2a7b3..1bf1b7d 100644 --- a/tests/test_FileBSON.py +++ b/tests/test_FileBSON.py @@ -14,7 +14,10 @@ import os import unittest +from g_sorcery.g_collections import serializable_elist + from tests.base import BaseTest +from tests.serializable import NonSerializableClass, SerializableClass, DeserializableClass BSON_INSTALLED = False @@ -24,33 +27,6 @@ try: except ImportError as e: pass -class NonSerializableClass(object): - pass - - -class SerializableClass(object): - - __slots__ = ("field1", "field2") - - def __init__(self, field1, field2): - self.field1 = field1 - self.field2 = field2 - - def __eq__(self, other): - return self.field1 == other.field1 \ - and self.field2 == other.field2 - - def serialize(self): - return {"field1": self.field1, "field2": self.field2} - - -class DeserializableClass(SerializableClass): - - @classmethod - def deserialize(cls, value): - return DeserializableClass(value["field1"], value["field2"]) - - if BSON_INSTALLED: class TestFileJSON(BaseTest): @@ -82,11 +58,21 @@ if BSON_INSTALLED: content_r = fj.read() self.assertEqual(content, content_r) + def test_deserializable_collection(self): + fj = FileBSON(self.directory, self.name, []) + content1 = DeserializableClass("1", "2") + content2 = DeserializableClass("3", "4") + content = serializable_elist([content1, content2]) + fj.write(content) + content_r = fj.read() + self.assertEqual(content, content_r) + def suite(): suite = unittest.TestSuite() suite.addTest(TestFileJSON('test_write_read')) suite.addTest(TestFileJSON('test_serializable')) suite.addTest(TestFileJSON('test_deserializable')) + suite.addTest(TestFileJSON('test_deserializable_collection')) return suite else: diff --git a/tests/test_FileJSON.py b/tests/test_FileJSON.py index 5bda353..f9ab032 100644 --- a/tests/test_FileJSON.py +++ b/tests/test_FileJSON.py @@ -4,10 +4,10 @@ """ test_FileJSON.py ~~~~~~~~~~~~~~~~ - + FileJSON test suite - - :copyright: (c) 2013 by Jauhien Piatlicki + + :copyright: (c) 2013-2015 by Jauhien Piatlicki :license: GPL-2, see LICENSE for more details. """ @@ -17,36 +17,10 @@ import unittest from g_sorcery.fileutils import FileJSON from g_sorcery.exceptions import FileJSONError +from g_sorcery.g_collections import serializable_elist from tests.base import BaseTest - - -class NonSerializableClass(object): - pass - - -class SerializableClass(object): - - __slots__ = ("field1", "field2") - - def __init__(self, field1, field2): - self.field1 = field1 - self.field2 = field2 - - def __eq__(self, other): - return self.field1 == other.field1 \ - and self.field2 == other.field2 - - def serialize(self): - return {"field1": self.field1, "field2": self.field2} - - -class DeserializableClass(SerializableClass): - - @classmethod - def deserialize(cls, value): - return DeserializableClass(value["field1"], value["field2"]) - +from tests.serializable import NonSerializableClass, SerializableClass, DeserializableClass class TestFileJSON(BaseTest): def setUp(self): @@ -54,7 +28,7 @@ class TestFileJSON(BaseTest): self.directory = os.path.join(self.tempdir.name, 'tst') self.name = 'tst.json' self.path = os.path.join(self.directory, self.name) - + def test_read_nonexistent(self): fj = FileJSON(self.directory, self.name, []) content = fj.read() @@ -99,7 +73,16 @@ class TestFileJSON(BaseTest): fj.write(content) content_r = fj.read() self.assertEqual(content, content_r) - + + def test_deserializable_collection(self): + fj = FileJSON(self.directory, self.name, []) + content1 = DeserializableClass("1", "2") + content2 = DeserializableClass("3", "4") + content = serializable_elist([content1, content2]) + fj.write(content) + content_r = fj.read() + self.assertEqual(content, content_r) + def suite(): suite = unittest.TestSuite() suite.addTest(TestFileJSON('test_read_nonexistent')) @@ -109,4 +92,5 @@ def suite(): suite.addTest(TestFileJSON('test_write_read')) suite.addTest(TestFileJSON('test_serializable')) suite.addTest(TestFileJSON('test_deserializable')) + suite.addTest(TestFileJSON('test_deserializable_collection')) return suite diff --git a/tests/test_PackageDB.py b/tests/test_PackageDB.py index 221be00..179cc32 100644 --- a/tests/test_PackageDB.py +++ b/tests/test_PackageDB.py @@ -18,10 +18,11 @@ import unittest from g_sorcery.compatibility import TemporaryDirectory from g_sorcery.db_layout import JSON_FILE_SUFFIX, BSON_FILE_SUFFIX from g_sorcery.exceptions import IntegrityError, InvalidKeyError, SyncError -from g_sorcery.g_collections import Package +from g_sorcery.g_collections import Package, serializable_elist from g_sorcery.package_db import PackageDB from tests.base import BaseTest +from tests.serializable import DeserializableClass from tests.server import Server SUPPORTED_FILE_FORMATS = [JSON_FILE_SUFFIX] @@ -50,8 +51,12 @@ class TestPackageDB(BaseTest): orig_db = PackageDB(orig_path, preferred_category_format=fmt) orig_db.add_category("app-test1") orig_db.add_category("app-test2") - ebuild_data = {"test1": "tst1", "test2": "tst2"} - common_data = {"common1": "cmn1", "common2": "cmn2"} + ebuild_data = {"test1": "tst1", "test2": "tst2", + "test3": serializable_elist([DeserializableClass("1", "2"), + DeserializableClass("3", "4")])} + common_data = {"common1": "cmn1", "common2": "cmn2", + "common3": serializable_elist([DeserializableClass("c1", "c2"), + DeserializableClass("c3", "c4")])} packages = [Package("app-test1", "test", "1"), Package("app-test1", "test", "2"), Package("app-test1", "test1", "1"), Package("app-test2", "test2", "1")] for package in packages: -- cgit v1.2.3-65-gdbad