Repository: mila-udem/fuel (python)

Issue:
Is IndexableDataset.__getattr__ interfering with pickling?
Here's a small example exhibiting the issue:

``` python
>>> import pickle
>>> from fuel.datasets import IndexableDataset
>>> dataset = IndexableDataset({'features': [[0, 0], [1, 1]]})
>>> dataset = pickle.loads(pickle.dumps(dataset))
TypeError: argument of type 'NoneType' is not iterable
```

Removing the `__getattr__` method solves the issue, but I'm not familiar enough with pickling to determine whether this is a coincidence or not.

Pull request:
Fix unpickling bug in IndexableDataset
Fixes #183.

Patch:
diff --git a/fuel/datasets/base.py b/fuel/datasets/base.py
index 42f7de8..1ca7175 100644
--- a/fuel/datasets/base.py
+++ b/fuel/datasets/base.py
@@ -361,6 +361,13 @@ class IndexableDataset(Dataset):
             return self.indexables[self.sources.index(attr)]
         raise AttributeError
 
+    # Without explicitly defining a trivial __setstate__ method,
+    # the __getattribute__ method would call the __getattr__ method,
+    # which would raise an AttributeError. This causes problems
+    # when unpickling.
+    def __setstate__(self, dict):
+        self.__dict__ = dict
+
     @property
     def num_examples(self):
         return len(self.indexables[0])


Test patch:
diff --git a/tests/test_datasets.py b/tests/test_datasets.py
index 3294974..f9e42aa 100644
--- a/tests/test_datasets.py
+++ b/tests/test_datasets.py
@@ -3,7 +3,7 @@ from collections import OrderedDict
 import numpy
 from numpy.testing import assert_raises, assert_equal
 from picklable_itertools import repeat
-from six.moves import zip, range
+from six.moves import zip, range, cPickle
 
 from fuel.datasets import Dataset, IterableDataset, IndexableDataset
 from fuel.streams import DataStream
@@ -117,6 +117,9 @@ class TestIndexableDataset(object):
         assert_raises(
             ValueError, IndexableDataset([1, 2, 3]).get_data, None, None)
 
+    def test_pickling(self):
+        cPickle.loads(cPickle.dumps(IndexableDataset({'a': (1, 2)})))
+
     def test_batch_iteration_scheme_with_lists(self):
         """Batch schemes should work with more than ndarrays."""
         data = IndexableDataset(OrderedDict([('foo', list(range(50))),