association proxies are not json serializable
this can be easily circumvented by simply casting them when needed, e.g. calling json.dumps(list(assoc_list))
.
however, it would be great if these objects were directly serializable. the ORM instrumented objects, InstrumentedList, InstrumentedSet, and InstrumentedDict already achieve this because they respectively subclass list, set, and dict -- the json
package handles them appropriately then.
Comments (8)
-
repo owner -
reporter although i agree it would be good to be ABC-compatible, it would be odd if the Instrumented* objects were non-ABC-style, and the Association* objects were ABC-style.
thus, my vote would be to get the Association* objects working with list/set/dict, then someone (with more ABC expertise) can upgrade both to ABC-style.
-
repo owner well it looks like python json doesn't recognize ABC's anyway. which is of course ridiculous.
-
repo owner many failures. feel free to work on them. patch:
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 045645f..f243b40 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -513,7 +512,7 @@ class _AssociationCollection(object): self.parent._inflate(self) -class _AssociationList(_AssociationCollection): +class _AssociationList(_AssociationCollection, list): """Generic, converting, list-to-list proxy.""" def _create(self, value): @@ -705,7 +704,7 @@ class _AssociationList(_AssociationCollection): _NotProvided = util.symbol('_NotProvided') -class _AssociationDict(_AssociationCollection): +class _AssociationDict(_AssociationCollection, dict): """Generic, converting, dict-to-dict proxy.""" def _create(self, key, value): @@ -853,7 +852,7 @@ class _AssociationDict(_AssociationCollection): del func_name, func -class _AssociationSet(_AssociationCollection): +class _AssociationSet(_AssociationCollection, set): """Generic, converting, set-to-set proxy.""" def _create(self, value):
failures:
=================================== FAILURES =================================== ______________________ CustomSetTest.test_set_comparisons ______________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 484, in test_set_comparisons control.intersection(other)) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/assertions.py", line 180, in eq_ assert a == b, msg or "%r != %r" % (a, b) AssertionError: set([]) != set(['a', 'c', 'b']) _______________________ CustomSetTest.test_set_mutation ________________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 517, in test_set_mutation self.assert_(p.children == control) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/fixtures.py", line 40, in assert_ assert val, msg AssertionError: None ------------------------------- Captured stdout -------------------------------- Test set(['a', 'c', 'b']).update(set(['a', 'c', 'b'])): ('want', "set(['a', 'c', 'b'])") ('got', 'set([])') ______________________ CustomSetTest.test_set_operations _______________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 415, in test_set_operations self.assert_(p1.children == set(['a', 'b', 'c'])) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/fixtures.py", line 40, in assert_ assert val, msg AssertionError: None ______________ DictOfTupleUpdateTest.test_update_multi_elem_dict _______________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 1522, in test_update_multi_elem_dict eq_(a1.elements, {("B", 3): 'elem2', ("C", 4): "elem3"}) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/assertions.py", line 180, in eq_ assert a == b, msg or "%r != %r" % (a, b) AssertionError: {('B', 3): 'elem2', ('C', 4): 'elem3'} != {('B', 3): 'elem2', ('C', 4): 'elem3'} ______________ DictOfTupleUpdateTest.test_update_multi_elem_list _______________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 1532, in test_update_multi_elem_list eq_(a1.elements, {("B", 3): 'elem2', ("C", 4): "elem3"}) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/assertions.py", line 180, in eq_ assert a == b, msg or "%r != %r" % (a, b) AssertionError: {('B', 3): 'elem2', ('C', 4): 'elem3'} != {('B', 3): 'elem2', ('C', 4): 'elem3'} _______________ DictOfTupleUpdateTest.test_update_one_elem_dict ________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 1517, in test_update_one_elem_dict eq_(a1.elements, {("B", 3): 'elem2'}) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/assertions.py", line 180, in eq_ assert a == b, msg or "%r != %r" % (a, b) AssertionError: {('B', 3): 'elem2'} != {('B', 3): 'elem2'} _______________ DictOfTupleUpdateTest.test_update_one_elem_list ________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 1527, in test_update_one_elem_list eq_(a1.elements, {("B", 3): 'elem2'}) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/assertions.py", line 180, in eq_ assert a == b, msg or "%r != %r" % (a, b) AssertionError: {('B', 3): 'elem2'} != {('B', 3): 'elem2'} _____________________ ReconstitutionTest.test_pickle_dict ______________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 1048, in test_pickle_dict assert p.kids == {'c1': 'c1', 'c2': 'c2'} AssertionError: assert {'c2': 'c2', 'c1': 'c1'} == {'c1': 'c1', 'c2': 'c2'} Common items: {'c1': 'c1', 'c2': 'c2'} ______________________ ReconstitutionTest.test_pickle_set ______________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 1033, in test_pickle_set r1 = pickle.loads(pickle.dumps(p)) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps Pickler(file, protocol).dump(obj) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump self.save(obj) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 331, in save self.save_reduce(obj=obj, *rv) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 419, in save_reduce save(state) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save f(self, obj) # Call unbound method with explicit self File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict self._batch_setitems(obj.iteritems()) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 663, in _batch_setitems save(v) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save f(self, obj) # Call unbound method with explicit self File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 562, in save_tuple save(element) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 331, in save self.save_reduce(obj=obj, *rv) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 419, in save_reduce save(state) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save f(self, obj) # Call unbound method with explicit self File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict self._batch_setitems(obj.iteritems()) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 663, in _batch_setitems save(v) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save f(self, obj) # Call unbound method with explicit self File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 748, in save_global (obj, module, name)) PicklingError: Can't pickle <function <lambda> at 0x1043f8b90>: it's not found as sqlalchemy.ext.associationproxy.<lambda> _________________________ SetTest.test_set_comparisons _________________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 484, in test_set_comparisons control.intersection(other)) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/assertions.py", line 180, in eq_ assert a == b, msg or "%r != %r" % (a, b) AssertionError: set([]) != set(['a', 'c', 'b']) __________________________ SetTest.test_set_mutation ___________________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 517, in test_set_mutation self.assert_(p.children == control) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/fixtures.py", line 40, in assert_ assert val, msg AssertionError: None ------------------------------- Captured stdout -------------------------------- Test set(['a', 'c', 'b']).update(set(['a', 'c', 'b'])): ('want', "set(['a', 'c', 'b'])") ('got', 'set([])') _________________________ SetTest.test_set_operations __________________________ Traceback (most recent call last): File "/Users/classic/dev/sqlalchemy/test/ext/test_associationproxy.py", line 415, in test_set_operations self.assert_(p1.children == set(['a', 'b', 'c'])) File "/Users/classic/dev/sqlalchemy/test/../lib/sqlalchemy/testing/fixtures.py", line 40, in assert_ assert val, msg AssertionError: None
-
repo owner - changed milestone to 0.9.xx
-
repo owner - changed milestone to 1.0.xx
-
repo owner - changed milestone to 1.x.xx
-
repo owner - changed status to wontfix
as always, if someone really wants to work on this, feel free. as it stands I have no plans to work with this
- Log in to comment
I'd want to get into the appropriate ABC logic here, rather than a straight list/dict subclass. I've only dealt with ABC's minimally so if someone wants to start off that would help.