Repository: jsonpickle/jsonpickle (python)

Issue:
Dictionary subclasses with referencing are encoded/decoded incorrectly
```python
import jsonpickle

class MyDict(dict):
    def __init__(self, obj=None):
        self.obj = obj or object()

d = MyDict()
d["inner"] = MyDict(d.obj)

assert d.obj == d["inner"].obj

json = jsonpickle.encode(d)

d2 = jsonpickle.decode(json)
assert d2.obj == d2["inner"].obj
```

The second assertion fails, because while `d2["inner"].obj` is correctly decoded to an `object`, `d2.obj` is somehow set to `d2["inner"].__dict__`!

```python
>>> d2["inner"].obj
<object object at 0x0000022AEAD35700>
>>> d2.obj
{'obj': <object object at 0x0000022AEAD35700>}
```

The encoded JSON is:
```json
{
  "py/object": "__main__.MyDict",
  "inner": {
    "py/object": "__main__.MyDict",
    "__dict__": {
      "obj": {
        "py/object": "builtins.object"
      }
    }
  },
  "__dict__": {
    "obj": {
      "py/id": 2
    }
  }
}
```

Pull request:
Fix ref-count when pickling dict subclasses
Fixes #453 

Patch:
diff --git a/jsonpickle/pickler.py b/jsonpickle/pickler.py
index ca2b5ad..d2a2f01 100644
--- a/jsonpickle/pickler.py
+++ b/jsonpickle/pickler.py
@@ -775,9 +775,12 @@ class Pickler(object):
 
         # Sub-classes of dict
         if hasattr(obj, '__dict__') and self.unpicklable and obj != obj.__dict__:
-            dict_data = {}
-            self._flatten_dict_obj(obj.__dict__, dict_data)
-            data['__dict__'] = dict_data
+            if self._mkref(obj.__dict__):
+                dict_data = {}
+                self._flatten_dict_obj(obj.__dict__, dict_data)
+                data['__dict__'] = dict_data
+            else:
+                data['__dict__'] = self._getref(obj.__dict__)
 
         return data
 


Test patch:
diff --git a/tests/jsonpickle_test.py b/tests/jsonpickle_test.py
index c2b86fc..6aff2bb 100644
--- a/tests/jsonpickle_test.py
+++ b/tests/jsonpickle_test.py
@@ -727,6 +727,21 @@ class JSONPickleTestCase(SkippableTest):
         self.assertEqual(obj.s, actual.s)
         self.assertEqual(obj.valid, actual.valid)
 
+    def test_dict_subclass_with_references(self):
+        d = UserDict()
+        d.s = 'string'
+        d['s'] = 'test'
+        obj = [d, d, d.__dict__]
+        pickle = jsonpickle.encode(obj)
+        actual = jsonpickle.decode(pickle)
+
+        self.assertEqual(type(actual), list)
+        self.assertEqual(type(actual[0]), UserDict)
+        self.assertEqual(actual[0].s, 'string')
+        self.assertEqual(actual[0]['s'], 'test')
+        self.assertIs(actual[0], actual[1])
+        self.assertIs(actual[0].__dict__, actual[2])
+
     def test_list_of_objects(self):
         """Test that objects in lists are referenced correctly"""
         a = Thing('a')