Repository: NeuralEnsemble/python-neo

Issue:
Implement deepcopy for all classes
#399 implements `__deepcopy__` for `AnalogSignal` and so fixes #220.

This should also be done for the other Neo classes.

Discussion:

Patch:
diff --git a/neo/core/analogsignal.py b/neo/core/analogsignal.py
index a202fffe..86dcfcae 100644
--- a/neo/core/analogsignal.py
+++ b/neo/core/analogsignal.py
@@ -250,7 +250,7 @@ class AnalogSignal(BaseSignal):
         for k, v in self.__dict__.items():
             try:
                 setattr(new_signal, k, deepcopy(v, memo))
-            except:
+            except TypeError:
                 setattr(new_signal, k, v)
         return new_signal
 
diff --git a/neo/core/epoch.py b/neo/core/epoch.py
index 85cf8117..a20a2f19 100644
--- a/neo/core/epoch.py
+++ b/neo/core/epoch.py
@@ -10,6 +10,7 @@ This module defines :class:`Epoch`, an array of epochs.
 from __future__ import absolute_import, division, print_function
 
 import sys
+from copy import deepcopy
 
 import numpy as np
 import quantities as pq
@@ -189,6 +190,21 @@ class Epoch(BaseNeo, pq.Quantity):
                      "description", "annotations"):
             setattr(self, attr, getattr(other, attr, None))
 
+    def __deepcopy__(self, memo):
+        cls = self.__class__
+        new_ep = cls(times=self.times, durations=self.durations,
+                     labels=self.labels, units=self.units,
+                     name=self.name, description=self.description, 
+                     file_origin=self.file_origin)
+        new_ep.__dict__.update(self.__dict__)
+        memo[id(self)] = new_ep
+        for k, v in self.__dict__.items():
+            try:
+                setattr(new_ep, k, deepcopy(v, memo))
+            except TypeError:
+                setattr(new_ep, k, v)
+        return new_ep
+
     def duplicate_with_new_data(self, signal):
         '''
         Create a new :class:`Epoch` with the same metadata
diff --git a/neo/core/event.py b/neo/core/event.py
index e296357e..d9e5b250 100644
--- a/neo/core/event.py
+++ b/neo/core/event.py
@@ -10,6 +10,7 @@ This module defines :class:`Event`, an array of events.
 from __future__ import absolute_import, division, print_function
 
 import sys
+from copy import deepcopy
 
 import numpy as np
 import quantities as pq
@@ -30,6 +31,7 @@ def _new_event(cls, signal, times = None, labels=None, units=None, name=None,
     e.segment = segment
     return e
 
+
 class Event(BaseNeo, pq.Quantity):
     '''
     Array of events.
@@ -177,6 +179,21 @@ class Event(BaseNeo, pq.Quantity):
                      "annotations"):
             setattr(self, attr, getattr(other, attr, None))
 
+    def __deepcopy__(self, memo):
+        cls = self.__class__
+        new_ev = cls(times=self.times,
+                     labels=self.labels, units=self.units,
+                     name=self.name, description=self.description, 
+                     file_origin=self.file_origin)
+        new_ev.__dict__.update(self.__dict__)
+        memo[id(self)] = new_ev
+        for k, v in self.__dict__.items():
+            try:
+                setattr(new_ev, k, deepcopy(v, memo))
+            except TypeError:
+                setattr(new_ev, k, v)
+        return new_ev
+
     def duplicate_with_new_data(self, signal):
         '''
         Create a new :class:`Event` with the same metadata
diff --git a/neo/core/irregularlysampledsignal.py b/neo/core/irregularlysampledsignal.py
index 8a0df4c0..4a6b9463 100644
--- a/neo/core/irregularlysampledsignal.py
+++ b/neo/core/irregularlysampledsignal.py
@@ -23,6 +23,7 @@ the old object.
 # needed for Python 3 compatibility
 from __future__ import absolute_import, division, print_function
 
+from copy import deepcopy
 import numpy as np
 import quantities as pq
 
@@ -194,6 +195,21 @@ class IrregularlySampledSignal(BaseSignal):
         self.times = getattr(obj, 'times', None)
         return obj
 
+    def __deepcopy__(self, memo):
+        cls = self.__class__
+        new_signal = cls(self.times, np.array(self), units=self.units,
+                         time_units=self.times.units, dtype=self.dtype,
+                         t_start=self.t_start, name=self.name,
+                         file_origin=self.file_origin, description=self.description)
+        new_signal.__dict__.update(self.__dict__)
+        memo[id(self)] = new_signal
+        for k, v in self.__dict__.items():
+            try:
+                setattr(new_signal, k, deepcopy(v, memo))
+            except TypeError:
+                setattr(new_signal, k, v)
+        return new_signal
+
     def __repr__(self):
         '''
         Returns a string representing the :class:`IrregularlySampledSignal`.
diff --git a/neo/core/spiketrain.py b/neo/core/spiketrain.py
index 15ad2124..f3cab166 100644
--- a/neo/core/spiketrain.py
+++ b/neo/core/spiketrain.py
@@ -402,6 +402,22 @@ class SpikeTrain(BaseNeo, pq.Quantity):
         if hasattr(obj, 'lazy_shape'):
             self.lazy_shape = obj.lazy_shape
 
+    def __deepcopy__(self, memo):
+        cls = self.__class__
+        new_st = cls(np.array(self), self.t_stop, units=self.units,
+                     dtype=self.dtype, copy=True, sampling_rate=self.sampling_rate,
+                     t_start=self.t_start, waveforms=self.waveforms, 
+                     left_sweep=self.left_sweep, name=self.name, 
+                     file_origin=self.file_origin, description=self.description)
+        new_st.__dict__.update(self.__dict__)
+        memo[id(self)] = new_st
+        for k, v in self.__dict__.items():
+            try:
+                setattr(new_st, k, copy.deepcopy(v, memo))
+            except TypeError:
+                setattr(new_st, k, v)
+        return new_st
+
     def __repr__(self):
         '''
         Returns a string representing the :class:`SpikeTrain`.
diff --git a/neo/io/igorproio.py b/neo/io/igorproio.py
index 1f8c75f7..7a008a5d 100644
--- a/neo/io/igorproio.py
+++ b/neo/io/igorproio.py
@@ -28,11 +28,10 @@ except ImportError:
 
 class IgorIO(BaseIO):
     """
-    Class for reading Igor Binary Waves (.ibw) written by WaveMetrics’ 
+    Class for reading Igor Binary Waves (.ibw) 
+    or Packed Experiment (.pxp) files written by WaveMetrics’ 
     IGOR Pro software.
 
-    Support for Packed Experiment (.pxp) files is planned.
-
     It requires the `igor` Python package by W. Trevor King.
 
     Usage:


Test patch:
diff --git a/neo/test/coretest/test_block.py b/neo/test/coretest/test_block.py
index 4f93f79b..7e9f0c94 100644
--- a/neo/test/coretest/test_block.py
+++ b/neo/test/coretest/test_block.py
@@ -7,6 +7,7 @@ Tests of the neo.core.block.Block class
 from __future__ import absolute_import, division, print_function
 
 from datetime import datetime
+from copy import deepcopy
 
 import unittest
 
@@ -744,6 +745,10 @@ class TestBlock(unittest.TestCase):
         assert_same_sub_schema(self.units2,
                                self.blk2.list_children_by_class('Unit'))
 
+    def test__deepcopy(self):
+        blk1_copy = deepcopy(self.blk1)
+        assert_same_sub_schema(blk1_copy, self.blk1)
+
 
 if __name__ == "__main__":
     unittest.main()