Repository: pydata/xarray
Issue: Unable to load pickle Dataset that was picked with cPickle

```
import cPickle as pickle
import xray
import numpy as np
import pandas as pd

foo_values = np.random.RandomState(0).rand(3,4)
times = pd.date_range('2001-02-03', periods=3)
ds = xray.Dataset({'time': ('time', times), 'foo': (['time', 'space'], foo_values)})

with open('mypickle.pkl', 'w') as f:
    pickle.dump(ds, f)

with open('mypickle.pkl') as f:
    myds = pickle.load(f)

myds
```

This code results in:
`<repr(<xray.dataset.Dataset at 0x7f95a3290d90>) failed: AttributeError: mapping>`


Changed files:
test/test_dataset.py, xray/utils.py

diff --git a/test/test_dataset.py b/test/test_dataset.py
index 0b6906925..337f3904b 100644
--- a/test/test_dataset.py
+++ b/test/test_dataset.py
@@ -651,6 +651,8 @@ class TestDataset(TestCase):
         data = create_test_data()
         roundtripped = pickle.loads(pickle.dumps(data))
         self.assertDatasetIdentical(data, roundtripped)
+        # regression test for #167:
+        self.assertEqual(data.dimensions, roundtripped.dimensions)
 
     def test_lazy_load(self):
         store = InaccessibleVariableDataStore()
diff --git a/xray/utils.py b/xray/utils.py
index 566afa7de..167baba8b 100644
--- a/xray/utils.py
+++ b/xray/utils.py
@@ -215,7 +215,18 @@ def ordered_dict_intersection(first_dict, second_dict, compat=equivalent):
     return new_dict
 
 
-class Frozen(Mapping):
+class SingleSlotPickleMixin(object):
+    """Mixin class to add the ability to pickle objects whose state is defined
+    by a single __slots__ attribute. Only necessary under Python 2.
+    """
+    def __getstate__(self):
+        return getattr(self, self.__slots__[0])
+
+    def __setstate__(self, state):
+        setattr(self, self.__slots__[0], state)
+
+
+class Frozen(Mapping, SingleSlotPickleMixin):
     """Wrapper around an object implementing the mapping interface to make it
     immutable. If you really want to modify the mapping, the mutable version is
     saved under the `mapping` attribute.
@@ -240,16 +251,12 @@ class Frozen(Mapping):
     def __repr__(self):
         return '%s(%r)' % (type(self).__name__, self.mapping)
 
-    if not PY3:
-        def __getstate__(self):
-            return self.__dict__
-
 
 def FrozenOrderedDict(*args, **kwargs):
     return Frozen(OrderedDict(*args, **kwargs))
 
 
-class SortedKeysDict(MutableMapping):
+class SortedKeysDict(MutableMapping, SingleSlotPickleMixin):
     """An wrapper for dictionary-like objects that always iterates over its
     items in sorted order by key but is otherwise equivalent to the underlying
     mapping.
@@ -283,12 +290,8 @@ class SortedKeysDict(MutableMapping):
     def copy(self):
         return type(self)(self.mapping.copy())
 
-    if not PY3:
-        def __getstate__(self):
-            return self.__dict__
-
 
-class ChainMap(MutableMapping):
+class ChainMap(MutableMapping, SingleSlotPickleMixin):
     """Partial backport of collections.ChainMap from Python>=3.3
 
     Don't return this from any public APIs, since some of the public methods
@@ -319,10 +322,6 @@ class ChainMap(MutableMapping):
     def __len__(self):
         raise NotImplementedError
 
-    if not PY3:
-        def __getstate__(self):
-            return self.__dict__
-
 
 class NDArrayMixin(object):
     """Mixin class for making wrappers of N-dimensional arrays that conform to