summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Chisholm <matt@theory.org>2014-07-27 12:15:36 +0200
committerMatt Chisholm <matt@theory.org>2014-08-09 11:03:10 +0200
commit88f7ec6a0efe68305d5d1ee429565c1778ec6a87 (patch)
tree53b251f8dedad6e0ee48fd5c27c81eff9e18cfaa
parent35551841c522d8eb20f8e20243a5510de9d95dfc (diff)
downloadsqlalchemy-88f7ec6a0efe68305d5d1ee429565c1778ec6a87.tar.gz
fix MutableDict.coerce
If a class inherited from MutableDict (say, for instance, to add an update() method), coerce() would give back an instance of MutableDict instead of an instance of the derived class.
-rw-r--r--lib/sqlalchemy/ext/mutable.py6
-rw-r--r--test/ext/test_mutable.py53
2 files changed, 56 insertions, 3 deletions
diff --git a/lib/sqlalchemy/ext/mutable.py b/lib/sqlalchemy/ext/mutable.py
index 7469bcbda..1a4568f23 100644
--- a/lib/sqlalchemy/ext/mutable.py
+++ b/lib/sqlalchemy/ext/mutable.py
@@ -627,10 +627,10 @@ class MutableDict(Mutable, dict):
@classmethod
def coerce(cls, key, value):
- """Convert plain dictionary to MutableDict."""
- if not isinstance(value, MutableDict):
+ """Convert plain dictionary to instance of this class."""
+ if not isinstance(value, cls):
if isinstance(value, dict):
- return MutableDict(value)
+ return cls(value)
return Mutable.coerce(key, value)
else:
return value
diff --git a/test/ext/test_mutable.py b/test/ext/test_mutable.py
index 32b3e11dd..e81b91d93 100644
--- a/test/ext/test_mutable.py
+++ b/test/ext/test_mutable.py
@@ -299,6 +299,59 @@ class MutableAssociationScalarJSONTest(_MutableDictTestBase, fixtures.MappedTest
)
+class CustomMutableAssociationScalarJSONTest(_MutableDictTestBase, fixtures.MappedTest):
+
+ CustomMutableDict = None
+
+ @classmethod
+ def _type_fixture(cls):
+ if not(getattr(cls, 'CustomMutableDict')):
+ MutableDict = super(CustomMutableAssociationScalarJSONTest, cls)._type_fixture()
+ class CustomMutableDict(MutableDict):
+ pass
+ cls.CustomMutableDict = CustomMutableDict
+ return cls.CustomMutableDict
+
+ @classmethod
+ def define_tables(cls, metadata):
+ import json
+
+ class JSONEncodedDict(TypeDecorator):
+ impl = VARCHAR(50)
+
+ def process_bind_param(self, value, dialect):
+ if value is not None:
+ value = json.dumps(value)
+
+ return value
+
+ def process_result_value(self, value, dialect):
+ if value is not None:
+ value = json.loads(value)
+ return value
+
+ CustomMutableDict = cls._type_fixture()
+ CustomMutableDict.associate_with(JSONEncodedDict)
+
+ Table('foo', metadata,
+ Column('id', Integer, primary_key=True,
+ test_needs_autoincrement=True),
+ Column('data', JSONEncodedDict),
+ Column('unrelated_data', String(50))
+ )
+
+ def test_pickle_parent(self):
+ # Picklers don't know how to pickle CustomMutableDict, but we aren't testing that here
+ pass
+
+ def test_coerce(self):
+ sess = Session()
+ f1 = Foo(data={'a': 'b'})
+ sess.add(f1)
+ sess.flush()
+ eq_(type(f1.data), self._type_fixture())
+
+
class _CompositeTestBase(object):
@classmethod
def define_tables(cls, metadata):