Repository: NeuralEnsemble/python-neo

Issue:
Fix tests for quantities 0.16.0
core-tests failing with new version of quantities. We will need to fix.


Discussion:

Patch:
diff --git a/neo/core/analogsignal.py b/neo/core/analogsignal.py
index 79f53440..12edb552 100644
--- a/neo/core/analogsignal.py
+++ b/neo/core/analogsignal.py
@@ -52,7 +52,7 @@ def _new_AnalogSignalArray(
     signal,
     units=None,
     dtype=None,
-    copy=True,
+    copy=None,
     t_start=0 * pq.s,
     sampling_rate=None,
     sampling_period=None,
@@ -180,7 +180,7 @@ class AnalogSignal(BaseSignal):
         signal,
         units=None,
         dtype=None,
-        copy=True,
+        copy=None,
         t_start=0 * pq.s,
         sampling_rate=None,
         sampling_period=None,
@@ -198,8 +198,13 @@ class AnalogSignal(BaseSignal):
 
         __array_finalize__ is called on the new object.
         """
+        if copy is not None:
+            raise ValueError(
+                "`copy` is now deprecated in Neo due to removal in NumPy 2.0 and will be removed in 0.15.0."
+            )
+
         signal = cls._rescale(signal, units=units)
-        obj = pq.Quantity(signal, units=units, dtype=dtype, copy=copy).view(cls)
+        obj = pq.Quantity(signal, units=units, dtype=dtype).view(cls)
 
         if obj.ndim == 1:
             obj.shape = (-1, 1)
@@ -218,7 +223,7 @@ class AnalogSignal(BaseSignal):
         signal,
         units=None,
         dtype=None,
-        copy=True,
+        copy=None,
         t_start=0 * pq.s,
         sampling_rate=None,
         sampling_period=None,
@@ -257,7 +262,7 @@ class AnalogSignal(BaseSignal):
             np.array(self),
             self.units,
             self.dtype,
-            True,
+            None,
             self.t_start,
             self.sampling_rate,
             self.sampling_period,
@@ -547,6 +552,7 @@ class AnalogSignal(BaseSignal):
 
         return new_sig
 
+    # copy in splice is a deepcopy not a numpy copy so we can keep
     def splice(self, signal, copy=False):
         """
         Replace part of the current signal by a new piece of signal.
diff --git a/neo/core/basesignal.py b/neo/core/basesignal.py
index 571a96ed..4ae56d5a 100644
--- a/neo/core/basesignal.py
+++ b/neo/core/basesignal.py
@@ -267,7 +267,7 @@ class BaseSignal(DataObject):
             stack,
             units=self.units,
             dtype=self.dtype,
-            copy=False,
+            copy=None,
             t_start=self.t_start,
             sampling_rate=self.sampling_rate,
             **kwargs,
diff --git a/neo/core/imagesequence.py b/neo/core/imagesequence.py
index d2fbb86c..3da54c8e 100644
--- a/neo/core/imagesequence.py
+++ b/neo/core/imagesequence.py
@@ -70,7 +70,7 @@ class ImageSequence(BaseSignal):
 
     *Optional attributes/properties*:
         :dtype: (numpy dtype or str) Override the dtype of the signal array.
-        :copy: (bool) True by default.
+        :copy: deprecated
 
     Note: Any other additional arguments are assumed to be user-specific
     metadata and stored in :attr:`annotations`.
@@ -103,7 +103,7 @@ class ImageSequence(BaseSignal):
         image_data,
         units=pq.dimensionless,
         dtype=None,
-        copy=True,
+        copy=None,
         t_start=0 * pq.s,
         spatial_scale=None,
         frame_duration=None,
@@ -121,6 +121,12 @@ class ImageSequence(BaseSignal):
 
         __array_finalize__ is called on the new object.
         """
+
+        if copy is not None:
+            raise ValueError(
+                "`copy` is now deprecated in Neo due to removal in NumPy 2.0 and will be removed in 0.15.0."
+            )
+
         if spatial_scale is None:
             raise ValueError("spatial_scale is required")
 
@@ -128,7 +134,7 @@ class ImageSequence(BaseSignal):
         if len(image_data.shape) != 3:
             raise ValueError("list doesn't have the correct number of dimensions")
 
-        obj = pq.Quantity(image_data, units=units, dtype=dtype, copy=copy).view(cls)
+        obj = pq.Quantity(image_data, units=units, dtype=dtype).view(cls)
         obj.segment = None
         # function from analogsignal.py in neo/core directory
         obj.sampling_rate = _get_sampling_rate(sampling_rate, frame_duration)
@@ -144,7 +150,7 @@ class ImageSequence(BaseSignal):
         image_data,
         units=pq.dimensionless,
         dtype=None,
-        copy=True,
+        copy=None,
         t_start=0 * pq.s,
         spatial_scale=None,
         frame_duration=None,
diff --git a/neo/core/irregularlysampledsignal.py b/neo/core/irregularlysampledsignal.py
index b440e561..14d97ae9 100644
--- a/neo/core/irregularlysampledsignal.py
+++ b/neo/core/irregularlysampledsignal.py
@@ -38,7 +38,7 @@ def _new_IrregularlySampledSignal(
     units=None,
     time_units=None,
     dtype=None,
-    copy=True,
+    copy=None,
     name=None,
     file_origin=None,
     description=None,
@@ -93,8 +93,8 @@ class IrregularlySampledSignal(BaseSignal):
     dtype: numpy dtype | string | None, default: None
         Overrides the signal array dtype
         Does not affect the dtype of the times which must be floats
-    copy: bool, default: True
-        Whether copy should be set to True when making the quantity array
+    copy: bool | None, default: None
+        deprecated and no longer used (for NumPy 2.0 support). Will be removed.
     name: str | None, default: None
         An optional label for the dataset
     description: str | None, default: None
@@ -158,7 +158,7 @@ class IrregularlySampledSignal(BaseSignal):
         units=None,
         time_units=None,
         dtype=None,
-        copy=True,
+        copy=None,
         name=None,
         file_origin=None,
         description=None,
@@ -171,6 +171,12 @@ class IrregularlySampledSignal(BaseSignal):
         This is called whenever a new :class:`IrregularlySampledSignal` is
         created from the constructor, but not when slicing.
         """
+
+        if copy is not None:
+            raise ValueError(
+                "`copy` is now deprecated in Neo due to removal in NumPy 2.0 and will be removed in 0.15.0."
+            )
+
         signal = cls._rescale(signal, units=units)
         if time_units is None:
             if hasattr(times, "units"):
@@ -199,7 +205,7 @@ class IrregularlySampledSignal(BaseSignal):
         units=None,
         time_units=None,
         dtype=None,
-        copy=True,
+        copy=None,
         name=None,
         file_origin=None,
         description=None,
@@ -231,7 +237,7 @@ class IrregularlySampledSignal(BaseSignal):
             self.units,
             self.times.units,
             self.dtype,
-            True,
+            None,
             self.name,
             self.file_origin,
             self.description,
@@ -544,6 +550,9 @@ class IrregularlySampledSignal(BaseSignal):
             (the original :class:`IrregularlySampledSignal` is not modified).
         """
         new_sig = deepcopy(self)
+        # As of numpy 2.0/quantities 0.16 we need to copy the array itself
+        # in order to be able to time_shift
+        new_sig.times = self.times.copy()
 
         new_sig.times += t_shift
 
@@ -588,7 +597,7 @@ class IrregularlySampledSignal(BaseSignal):
         merged_annotations = merge_annotations(self.annotations, other.annotations)
         kwargs.update(merged_annotations)
 
-        signal = self.__class__(self.times, stack, units=self.units, dtype=self.dtype, copy=False, **kwargs)
+        signal = self.__class__(self.times, stack, units=self.units, dtype=self.dtype, copy=None, **kwargs)
         signal.segment = self.segment
         signal.array_annotate(**self._merge_array_annotations(other))
 
@@ -681,7 +690,7 @@ class IrregularlySampledSignal(BaseSignal):
             times=new_times[sorting],
             units=self.units,
             dtype=self.dtype,
-            copy=False,
+            copy=None,
             t_start=t_start,
             t_stop=t_stop,
             **kwargs,
diff --git a/neo/core/spiketrain.py b/neo/core/spiketrain.py
index c45b1e65..20b31840 100644
--- a/neo/core/spiketrain.py
+++ b/neo/core/spiketrain.py
@@ -138,7 +138,7 @@ def _new_spiketrain(
     t_stop,
     units=None,
     dtype=None,
-    copy=True,
+    copy=None,
     sampling_rate=1.0 * pq.Hz,
     t_start=0.0 * pq.s,
     waveforms=None,
@@ -158,19 +158,19 @@ def _new_spiketrain(
     if annotations is None:
         annotations = {}
     obj = SpikeTrain(
-        signal,
-        t_stop,
-        units,
-        dtype,
-        copy,
-        sampling_rate,
-        t_start,
-        waveforms,
-        left_sweep,
-        name,
-        file_origin,
-        description,
-        array_annotations,
+        times=signal,
+        t_stop=t_stop,
+        units=units,
+        dtype=dtype,
+        copy=copy,
+        sampling_rate=sampling_rate,
+        t_start=t_start,
+        waveforms=waveforms,
+        left_sweep=left_sweep,
+        name=name,
+        file_origin=file_origin,
+        description=description,
+        array_annotations=array_annotations,
         **annotations,
     )
     obj.segment = segment
@@ -178,7 +178,7 @@ def _new_spiketrain(
     return obj
 
 
-def normalize_times_array(times, units=None, dtype=None, copy=True):
+def normalize_times_array(times, units=None, dtype=None, copy=None):
     """
     Return a quantity array with the correct units.
     There are four scenarios:
@@ -192,6 +192,12 @@ def normalize_times_array(times, units=None, dtype=None, copy=True):
     In scenario C, we rescale the original array to match `units`
     In scenario D, we raise a ValueError
     """
+
+    if copy is not None:
+        raise ValueError(
+            "`copy` is now deprecated in Neo due to removal in NumPy 2.0 and will be removed in 0.15.0."
+            )
+    
     if dtype is None:
         if not hasattr(times, "dtype"):
             dtype = float
@@ -211,20 +217,15 @@ def normalize_times_array(times, units=None, dtype=None, copy=True):
             if times.dimensionality.items() == dim.items():
                 units = None  # units will be taken from times, avoids copying
             else:
-                if not copy:
-                    raise ValueError("cannot rescale and return view")
-                else:
-                    # this is needed because of a bug in python-quantities
-                    # see issue # 65 in python-quantities github
-                    # remove this if it is fixed
-                    times = times.rescale(dim)
+                raise ValueError("cannot rescale and return view")
+                
 
     # check to make sure the units are time
     # this approach is orders of magnitude faster than comparing the
     # reference dimensionality
     if len(dim) != 1 or list(dim.values())[0] != 1 or not isinstance(list(dim.keys())[0], pq.UnitTime):
         ValueError(f"Units have dimensions {dim.simplified}, not [time]")
-    return pq.Quantity(times, units=units, dtype=dtype, copy=copy), dim
+    return pq.Quantity(times, units=units, dtype=dtype,), dim
 
 
 class SpikeTrain(DataObject):
@@ -239,18 +240,16 @@ class SpikeTrain(DataObject):
     times: quantity array 1D | numpy array 1D | list
         The times of each spike.
     t_stop: quantity scalar | numpy scalar |float
-        Time at which the SpikeTrain ended. This will be converted to thesame units as `times`.
+        Time at which the SpikeTrain ended. This will be converted to the same units as `times`.
         This argument is required because it specifies the period of time over which spikes could have occurred.
         Note that :attr:`t_start` is highly recommended for the same reason.
     units: (quantity units) | None, default: None
         Required if `times` is a list or numpy.ndarray`
         Not required if times is a quantities.Quantity
     dtype: numpy dtype | str | None, default: None
-        Overrides the dtype of the times array if given.
-        If None, the dtype of the times is used
-    copy: bool, default: True
-        Whether to copy the times array.
-        Must be True when you request a change of units or dtype.
+        Due to change in `copy` behavior this argument is also deprecated during construction
+    copy: bool, default: None
+        Deprecated in order to support NumPy 2.0 and will be removed.
     sampling_rate: quantity scalar, default: 1.0 pq.Hz
         Number of samples per unit time for the waveforms.
     t_start: quantity scalar | numpy scalar | float
@@ -330,7 +329,7 @@ class SpikeTrain(DataObject):
         t_stop,
         units=None,
         dtype=None,
-        copy=True,
+        copy=None,
         sampling_rate=1.0 * pq.Hz,
         t_start=0.0 * pq.s,
         waveforms=None,
@@ -347,13 +346,17 @@ class SpikeTrain(DataObject):
         This is called whenever a new :class:`SpikeTrain` is created from the
         constructor, but not when slicing.
         """
+        if copy is not None:
+            raise ValueError(
+                "`copy` is now deprecated in Neo due to removal in NumPy 2.0 and will be removed in 0.15.0."
+            )
+
         if len(times) != 0 and waveforms is not None and len(times) != waveforms.shape[0]:
             # len(times)!=0 has been used to workaround a bug occurring during neo import
             raise ValueError("the number of waveforms should be equal to the number of spikes")
 
         if dtype is not None and hasattr(times, "dtype") and times.dtype != dtype:
-            if not copy:
-                raise ValueError("cannot change dtype and return view")
+            raise ValueError("cannot change dtype during construction due to change in copy behavior")
 
             # if t_start.dtype or t_stop.dtype != times.dtype != dtype,
             # _check_time_in_range can have problems, so we set the t_start
@@ -420,7 +423,7 @@ class SpikeTrain(DataObject):
         t_stop,
         units=None,
         dtype=None,
-        copy=True,
+        copy=None,
         sampling_rate=1.0 * pq.Hz,
         t_start=0.0 * pq.s,
         waveforms=None,
@@ -494,7 +497,7 @@ class SpikeTrain(DataObject):
             self.t_stop,
             self.units,
             self.dtype,
-            True,
+            None,
             self.sampling_rate,
             self.t_start,
             self.waveforms,
@@ -738,7 +741,8 @@ class SpikeTrain(DataObject):
         else:
             units = pq.quantity.validate_dimensionality(units)
 
-        new_st = self.__class__(signal, t_start=t_start, t_stop=t_stop, waveforms=waveforms, units=units)
+        signal = deepcopy(signal)
+        new_st = SpikeTrain(signal, t_start=t_start, t_stop=t_stop, waveforms=waveforms, units=units)
         new_st._copy_data_complement(self, deep_copy=deep_copy)
 
         # Note: Array annotations are not copied here, because length of data could change
@@ -798,9 +802,24 @@ class SpikeTrain(DataObject):
             New instance of a :class:`SpikeTrain` object starting at t_shift later than the
             original :class:`SpikeTrain` (the original :class:`SpikeTrain` is not modified).
         """
-        new_st = self.duplicate_with_new_data(
-            signal=self.times.view(pq.Quantity) + t_shift, t_start=self.t_start + t_shift, t_stop=self.t_stop + t_shift
-        )
+        # We need new to make a new SpikeTrain
+        times = self.times.copy() + t_shift
+        t_stop = self.t_stop + t_shift
+        t_start = self.t_start + t_shift
+        new_st = SpikeTrain(
+                times=times,
+                t_stop=t_stop,
+                units=self.unit,
+                sampling_rate=self.sampling_rate,
+                t_start=t_start,
+                waveforms=self.waveforms,
+                left_sweep=self.left_sweep,
+                name=self.name,
+                file_origin=self.file_origin,
+                description=self.description,
+                array_annotations=deepcopy(self.array_annotations),
+                **self.annotations,
+            )
 
         # Here we can safely copy the array annotations since we know that
         # the length of the SpikeTrain does not change.
@@ -845,7 +864,7 @@ class SpikeTrain(DataObject):
             raise MergeError("Cannot merge signal with waveform and signal " "without waveform.")
         stack = np.concatenate([np.asarray(st) for st in all_spiketrains])
         sorting = np.argsort(stack)
-        stack = stack[sorting]
+        sorted_stack = stack[sorting]
 
         kwargs = {}
 
@@ -900,10 +919,10 @@ class SpikeTrain(DataObject):
         kwargs.update(merged_annotations)
 
         train = SpikeTrain(
-            stack,
+            sorted_stack,
             units=self.units,
             dtype=self.dtype,
-            copy=False,
+            copy=None,
             t_start=self.t_start,
             t_stop=self.t_stop,
             sampling_rate=self.sampling_rate,
diff --git a/neo/io/brainwaredamio.py b/neo/io/brainwaredamio.py
index d63234a8..0ac52015 100644
--- a/neo/io/brainwaredamio.py
+++ b/neo/io/brainwaredamio.py
@@ -212,7 +212,7 @@ class BrainwareDamIO(BaseIO):
             t_start=t_start * pq.d,
             file_origin=self._filename,
             sampling_period=1.0 * pq.s,
-            copy=False,
+            copy=None,
         )
         # Note: setting the sampling_period to 1 s is arbitrary
 
diff --git a/neo/io/brainwaresrcio.py b/neo/io/brainwaresrcio.py
index 2a4f9f28..aaa7e69a 100755
--- a/neo/io/brainwaresrcio.py
+++ b/neo/io/brainwaresrcio.py
@@ -455,7 +455,7 @@ class BrainwareSrcIO(BaseIO):
         t_stop=pq.Quantity(1, units=pq.ms, dtype=np.float32),
         waveforms=pq.Quantity([[[]]], dtype=np.int8, units=pq.mV),
         dtype=np.float32,
-        copy=False,
+        copy=None,
         timestamp=_default_datetime,
         respwin=np.array([], dtype=np.int32),
         dama_index=-1,
@@ -541,7 +541,7 @@ class BrainwareSrcIO(BaseIO):
             # get the times of the spiketrains and combine them
             waveforms = [itrain.waveforms for itrain in spiketrains]
             rawtrains = np.array(np.concatenate(spiketrains, axis=1))
-            times = pq.Quantity(rawtrains, units=pq.ms, copy=False)
+            times = pq.Quantity(rawtrains, units=pq.ms)
             lens1 = np.array([wave.shape[1] for wave in waveforms])
             lens2 = np.array([wave.shape[2] for wave in waveforms])
             if lens1.max() != lens1.min() or lens2.max() != lens2.min():
@@ -564,7 +564,7 @@ class BrainwareSrcIO(BaseIO):
             times = np.concatenate(times, axis=0)
 
             # get the times of the SpikeTrains and combine them
-            times = pq.Quantity(times, units=pq.ms, copy=False)
+            times = pq.Quantity(times, units=pq.ms)
 
             # get the waveforms of the SpikeTrains and combine them
             # these should be a 3D array with the first axis being the spike,
@@ -573,7 +573,7 @@ class BrainwareSrcIO(BaseIO):
             waveforms = np.concatenate(waveforms, axis=0)
 
             # extract the trig2 annotation
-            trig2 = pq.Quantity(np.hstack(trig2), units=pq.ms, copy=False)
+            trig2 = pq.Quantity(np.hstack(trig2), units=pq.ms)
 
         if not times.size:
             return self._default_spiketrain.copy()
@@ -581,11 +581,11 @@ class BrainwareSrcIO(BaseIO):
         # get the maximum time
         t_stop = times[-1] * 2.0
 
-        waveforms = pq.Quantity(waveforms, units=pq.mV, copy=False)
+        waveforms = pq.Quantity(waveforms, units=pq.mV)
 
         train = SpikeTrain(
             times=times,
-            copy=False,
+            copy=None,
             t_start=self._default_t_start.copy(),
             t_stop=t_stop,
             file_origin=self._file_origin,
@@ -857,7 +857,7 @@ class BrainwareSrcIO(BaseIO):
             trains = zip(*trains)
 
         # int32 -- SpikeTrain length in ms
-        spiketrainlen = pq.Quantity(np.fromfile(self._fsrc, dtype=np.int32, count=1)[0], units=pq.ms, copy=False)
+        spiketrainlen = pq.Quantity(np.fromfile(self._fsrc, dtype=np.int32, count=1)[0], units=pq.ms)
 
         segments = []
         for train in trains:
@@ -1018,7 +1018,7 @@ class BrainwareSrcIO(BaseIO):
         """
 
         # float32 -- DA conversion clock period in microsec
-        sampling_period = pq.Quantity(np.fromfile(self._fsrc, dtype=np.float32, count=1), units=pq.us, copy=False)[0]
+        sampling_period = pq.Quantity(np.fromfile(self._fsrc, dtype=np.float32, count=1), units=pq.us)[0]
 
         # segment_collection -- this is based off a segment_collection
         segments = self.__read_segment_list()
@@ -1362,7 +1362,7 @@ class BrainwareSrcIO(BaseIO):
         # int32 -- SpikeTrain length in ms
         # int32 * 4 -- response and spon period boundaries
         parts = np.fromfile(self._fsrc, dtype=np.int32, count=5)
-        t_stop = pq.Quantity(parts[0].astype("float32"), units=pq.ms, copy=False)
+        t_stop = pq.Quantity(parts[0].astype("float32"), units=pq.ms)
         respwin = parts[1:]
 
         # (data_obj) -- list of SpikeTrains
diff --git a/neo/io/igorproio.py b/neo/io/igorproio.py
index 71f197d7..661ae436 100644
--- a/neo/io/igorproio.py
+++ b/neo/io/igorproio.py
@@ -174,7 +174,7 @@ class IgorIO(BaseIO):
         signal = AnalogSignal(
             signal,
             units=units,
-            copy=False,
+            copy=None,
             t_start=t_start,
             sampling_period=sampling_period,
             name=name,
diff --git a/neo/io/neurosharectypesio.py b/neo/io/neurosharectypesio.py
index 94935855..282897f9 100644
--- a/neo/io/neurosharectypesio.py
+++ b/neo/io/neurosharectypesio.py
@@ -224,10 +224,10 @@ class NeurosharectypesIO(BaseIO):
                     total_read += pdwContCount.value
 
                 try:
-                    signal = pq.Quantity(pData, units=pAnalogInfo.szUnits.decode(), copy=False)
+                    signal = pq.Quantity(pData, units=pAnalogInfo.szUnits.decode())
                     unit_annotation = None
                 except LookupError:
-                    signal = pq.Quantity(pData, units="dimensionless", copy=False)
+                    signal = pq.Quantity(pData, units="dimensionless")
                     unit_annotation = pAnalogInfo.szUnits.decode()
 
                 # t_start
@@ -292,9 +292,9 @@ class NeurosharectypesIO(BaseIO):
                     waveforms[dwIndex, :, :] = pData[: nsample * nsource].reshape(nsample, nsource).transpose()
 
                 sptr = SpikeTrain(
-                    times=pq.Quantity(times, units="s", copy=False),
+                    times=pq.Quantity(times, units="s"),
                     t_stop=times.max(),
-                    waveforms=pq.Quantity(waveforms, units=str(pdwSegmentInfo.szUnits), copy=False),
+                    waveforms=pq.Quantity(waveforms, units=str(pdwSegmentInfo.szUnits)),
                     left_sweep=nsample / 2.0 / float(pdwSegmentInfo.dSampleRate) * pq.s,
                     sampling_rate=float(pdwSegmentInfo.dSampleRate) * pq.Hz,
                     name=str(entityInfo.szEntityLabel),
diff --git a/neo/io/proxyobjects.py b/neo/io/proxyobjects.py
index 2f3eb0e4..1fb8834a 100644
--- a/neo/io/proxyobjects.py
+++ b/neo/io/proxyobjects.py
@@ -296,7 +296,7 @@ class AnalogSignalProxy(BaseProxy):
         anasig = AnalogSignal(
             sig,
             units=units,
-            copy=False,
+            copy=None,
             t_start=sig_t_start,
             sampling_rate=self.sampling_rate,
             name=name,
@@ -419,11 +419,11 @@ class SpikeTrainProxy(BaseProxy):
                 float_wfs = self._rawio.rescale_waveforms_to_float(
                     raw_wfs, dtype="float32", spike_channel_index=self._spike_channel_index
                 )
-                waveforms = pq.Quantity(float_wfs, units=self._wf_units, dtype="float32", copy=False)
+                waveforms = pq.Quantity(float_wfs, units=self._wf_units, dtype="float32")
             elif magnitude_mode == "raw":
                 # could code also CompundUnit here but it is over killed
                 # so we used dimentionless
-                waveforms = pq.Quantity(raw_wfs, units="", dtype=raw_wfs.dtype, copy=False)
+                waveforms = pq.Quantity(raw_wfs, units="", dtype=raw_wfs.dtype)
         else:
             waveforms = None
 
@@ -433,7 +433,7 @@ class SpikeTrainProxy(BaseProxy):
             units=units,
             dtype=dtype,
             t_start=t_start,
-            copy=False,
+            copy=None,
             sampling_rate=self.sampling_rate,
             waveforms=waveforms,
             left_sweep=self.left_sweep,
diff --git a/pyproject.toml b/pyproject.toml
index 75374cf0..a9230f67 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ classifiers = [
 dependencies = [
     "packaging",
     "numpy>=1.22.4,<2.0.0",
-    "quantities>=0.14.1,<0.16.0"
+    "quantities>=0.16.1"
 ]
 
 [project.urls]


Test patch:
diff --git a/.github/workflows/io-test.yml b/.github/workflows/io-test.yml
index 8522e7e4..c609cc54 100644
--- a/.github/workflows/io-test.yml
+++ b/.github/workflows/io-test.yml
@@ -18,7 +18,7 @@ jobs:
     strategy:
       fail-fast: true
       matrix:
-        python-version: ['3.9', '3.11']
+        python-version: ['3.9', '3.11.9']
     defaults:
       # by default run in bash mode (required for conda usage)
       run:
diff --git a/neo/test/coretest/test_analogsignal.py b/neo/test/coretest/test_analogsignal.py
index 2a230f06..abfbcce2 100644
--- a/neo/test/coretest/test_analogsignal.py
+++ b/neo/test/coretest/test_analogsignal.py
@@ -131,30 +131,6 @@ class TestAnalogSignalConstructor(unittest.TestCase):
         data = np.arange(10.0) * pq.mV
         self.assertRaises(ValueError, AnalogSignal, data, sampling_rate=1 * pq.kHz, sampling_period=5 * pq.s)
 
-    def test__create_with_copy_true_should_return_copy(self):
-        data = np.arange(10.0) * pq.mV
-        rate = 5000 * pq.Hz
-        signal = AnalogSignal(data, copy=True, sampling_rate=rate)
-        data[3] = 99 * pq.mV
-        assert_neo_object_is_compliant(signal)
-        self.assertNotEqual(signal[3, 0], 99 * pq.mV)
-
-    def test__create_with_copy_false_should_return_view(self):
-        data = np.arange(10.0) * pq.mV
-        rate = 5000 * pq.Hz
-        signal = AnalogSignal(data, copy=False, sampling_rate=rate)
-        data[3] = 99 * pq.mV
-        assert_neo_object_is_compliant(signal)
-        self.assertEqual(signal[3, 0], 99 * pq.mV)
-
-    def test__create2D_with_copy_false_should_return_view(self):
-        data = np.arange(10.0) * pq.mV
-        data = data.reshape((5, 2))
-        rate = 5000 * pq.Hz
-        signal = AnalogSignal(data, copy=False, sampling_rate=rate)
-        data[3, 0] = 99 * pq.mV
-        assert_neo_object_is_compliant(signal)
-        self.assertEqual(signal[3, 0], 99 * pq.mV)
 
     def test__create_with_additional_argument(self):
         signal = AnalogSignal(
@@ -1048,6 +1024,7 @@ class TestAnalogSignalArrayMethods(unittest.TestCase):
         assert_array_equal(result.array_annotations["anno2"], np.array(["a"]))
         self.assertIsInstance(result.array_annotations, ArrayDict)
 
+    # splice copy is a deepcopy not a numpy copy still need to test for numpy 2.0
     def test_splice_1channel_with_copy(self):
         signal_for_splicing = AnalogSignal(
             [0.1, 0.1, 0.1],
@@ -1066,6 +1043,7 @@ class TestAnalogSignalArrayMethods(unittest.TestCase):
         assert_array_equal(result.array_annotations["anno2"], np.array(["a"]))
         self.assertIsInstance(result.array_annotations, ArrayDict)
 
+    # splice is a deepcopy still need to test for numpy 2.0
     def test_splice_2channels_inplace(self):
         arr_ann1 = {"index": np.arange(10, 12)}
         arr_ann2 = {"index": np.arange(2), "test": ["a", "b"]}
@@ -1738,8 +1716,9 @@ class TestAnalogSignalCombination(unittest.TestCase):
 
 
 class TestAnalogSignalFunctions(unittest.TestCase):
+
     def test__pickle_1d(self):
-        signal1 = AnalogSignal([1, 2, 3, 4], sampling_period=1 * pq.ms, units=pq.S)
+        signal1 = AnalogSignal(signal=[1, 2, 3, 4], sampling_period=1 * pq.ms, units=pq.S)
         signal1.annotations["index"] = 2
         signal1.array_annotate(**{"anno1": [23], "anno2": ["A"]})
 
@@ -1750,6 +1729,7 @@ class TestAnalogSignalFunctions(unittest.TestCase):
         fobj = open("./pickle", "rb")
         try:
             signal2 = pickle.load(fobj)
+            print(signal2)
         except ValueError:
             signal2 = None
 
@@ -1782,7 +1762,6 @@ class TestAnalogSignalFunctions(unittest.TestCase):
         fobj.close()
         os.remove("./pickle")
 
-
 class TestAnalogSignalSampling(unittest.TestCase):
     def test___get_sampling_rate__period_none_rate_none_ValueError(self):
         sampling_rate = None
diff --git a/neo/test/coretest/test_irregularysampledsignal.py b/neo/test/coretest/test_irregularysampledsignal.py
index 976c9a80..9fde8a57 100644
--- a/neo/test/coretest/test_irregularysampledsignal.py
+++ b/neo/test/coretest/test_irregularysampledsignal.py
@@ -1033,6 +1033,7 @@ class TestIrregularlySampledSignalCombination(unittest.TestCase):
 
 
 class TestAnalogSignalFunctions(unittest.TestCase):
+
     def test__pickle(self):
         signal1 = IrregularlySampledSignal(np.arange(10.0) / 100 * pq.s, np.arange(10.0), units="mV")
 
diff --git a/neo/test/coretest/test_spiketrain.py b/neo/test/coretest/test_spiketrain.py
index 52f249e7..8e5af92a 100644
--- a/neo/test/coretest/test_spiketrain.py
+++ b/neo/test/coretest/test_spiketrain.py
@@ -213,14 +213,7 @@ class TestConstructor(unittest.TestCase):
         self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
         self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
-    def test__create_from_list_set_dtype(self):
-        times = range(10)
-        t_start = 0.0 * pq.s
-        t_stop = 10000.0 * pq.ms
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="ms", dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="ms", dtype="f4")
-
-        dtype = np.float32
+        dtype = np.float64
         units = 1 * pq.ms
         t_start_out = t_start.astype(dtype)
         t_stop_out = t_stop.astype(dtype)
@@ -243,20 +236,6 @@ class TestConstructor(unittest.TestCase):
         self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
         self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
-    def test__create_from_list_no_start_stop_units_set_dtype(self):
-        times = range(10)
-        t_start = 0.0
-        t_stop = 10000.0
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="ms", dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="ms", dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.ms
-        t_start_out = pq.Quantity(t_start, units=units, dtype=dtype)
-        t_stop_out = pq.Quantity(t_stop, units=units, dtype=dtype)
-        st_out = pq.Quantity(times, units=units, dtype=dtype)
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
     def test__create_from_array(self):
         times = np.arange(10)
@@ -288,21 +267,6 @@ class TestConstructor(unittest.TestCase):
         self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
         self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
-    def test__create_from_array_set_dtype(self):
-        times = np.arange(10)
-        t_start = 0.0 * pq.s
-        t_stop = 10000.0 * pq.ms
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.s
-        t_start_out = t_start.astype(dtype)
-        t_stop_out = t_stop.astype(dtype)
-        st_out = times.astype(dtype) * units
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
-
     def test__create_from_array_no_start_stop_units(self):
         times = np.arange(10)
         t_start = 0.0
@@ -333,20 +297,6 @@ class TestConstructor(unittest.TestCase):
         self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
         self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
-    def test__create_from_array_no_start_stop_units_set_dtype(self):
-        times = np.arange(10)
-        t_start = 0.0
-        t_stop = 10000.0
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.s
-        t_start_out = pq.Quantity(t_start, units=units, dtype=dtype)
-        t_stop_out = pq.Quantity(t_stop, units=units, dtype=dtype)
-        st_out = times.astype(dtype) * units
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
     def test__create_from_quantity_array(self):
         times = np.arange(10) * pq.ms
@@ -378,20 +328,6 @@ class TestConstructor(unittest.TestCase):
         self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
         self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
-    def test__create_from_quantity_array_set_dtype(self):
-        times = np.arange(10) * pq.ms
-        t_start = 0.0 * pq.s
-        t_stop = 12.0 * pq.ms
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.ms
-        t_start_out = t_start.astype(dtype)
-        t_stop_out = t_stop.astype(dtype)
-        st_out = times.astype(dtype)
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
     def test__create_from_quantity_array_no_start_stop_units(self):
         times = np.arange(10) * pq.ms
@@ -423,95 +359,6 @@ class TestConstructor(unittest.TestCase):
         self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
         self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
-    def test__create_from_quantity_array_no_start_stop_units_set_dtype(self):
-        times = np.arange(10) * pq.ms
-        t_start = 0.0
-        t_stop = 12.0
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.ms
-        t_start_out = pq.Quantity(t_start, units=units, dtype=dtype)
-        t_stop_out = pq.Quantity(t_stop, units=units, dtype=dtype)
-        st_out = times.astype(dtype)
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
-
-    def test__create_from_quantity_array_units(self):
-        times = np.arange(10) * pq.ms
-        t_start = 0.0 * pq.s
-        t_stop = 12.0 * pq.ms
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s")
-
-        dtype = np.float64
-        units = 1 * pq.s
-        t_start_out = t_start
-        t_stop_out = t_stop
-        st_out = times
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
-
-    def test__create_from_quantity_array_units_with_dtype(self):
-        times = np.arange(10, dtype="f4") * pq.ms
-        t_start = 0.0 * pq.s
-        t_stop = 12.0 * pq.ms
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s")
-
-        dtype = np.float32
-        units = 1 * pq.s
-        t_start_out = t_start.astype(dtype)
-        t_stop_out = t_stop.rescale(units).astype(dtype)
-        st_out = times.rescale(units).astype(dtype)
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
-
-    def test__create_from_quantity_array_units_set_dtype(self):
-        times = np.arange(10) * pq.ms
-        t_start = 0.0 * pq.s
-        t_stop = 12.0 * pq.ms
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.s
-        t_start_out = t_start.astype(dtype)
-        t_stop_out = t_stop.rescale(units).astype(dtype)
-        st_out = times.rescale(units).astype(dtype)
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
-
-    def test__create_from_quantity_array_units_no_start_stop_units(self):
-        times = np.arange(10) * pq.ms
-        t_start = 0.0
-        t_stop = 12.0
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s")
-
-        dtype = np.float64
-        units = 1 * pq.s
-        t_start_out = pq.Quantity(t_start, units=units, dtype=dtype)
-        t_stop_out = pq.Quantity(t_stop, units=units, dtype=dtype)
-        st_out = times
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
-
-    def test__create_from_quantity_units_no_start_stop_units_set_dtype(self):
-        times = np.arange(10) * pq.ms
-        t_start = 0.0
-        t_stop = 12.0
-        train1 = SpikeTrain(times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-        train2 = _new_spiketrain(SpikeTrain, times, t_start=t_start, t_stop=t_stop, units="s", dtype="f4")
-
-        dtype = np.float32
-        units = 1 * pq.s
-        t_start_out = pq.Quantity(t_start, units=units, dtype=dtype)
-        t_stop_out = pq.Quantity(t_stop, units=units, dtype=dtype)
-        st_out = times.rescale(units).astype(dtype)
-        self.result_spike_check(train1, st_out, t_start_out, t_stop_out, dtype, units)
-        self.result_spike_check(train2, st_out, t_start_out, t_stop_out, dtype, units)
 
     def test__create_from_list_without_units_should_raise_ValueError(self):
         times = range(10)
@@ -1267,10 +1114,11 @@ class TestMerge(unittest.TestCase):
         )
         self.assertIsInstance(result.array_annotations, ArrayDict)
 
+    # can't rescale time so need to load milliseconds rather than micro (numpy 2.0)
     def test_merge_multiple(self):
         self.train1.waveforms = None
 
-        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * pq.microsecond)
+        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * 0.1 * pq.millisecond)
         train3.segment = self.train1.segment
         train3.array_annotate(index=np.arange(301, 307))
 
@@ -1317,8 +1165,9 @@ class TestMerge(unittest.TestCase):
             self.assertTrue("array annotations" in str(w[0].message))
         assert_neo_object_is_compliant(result)
 
+    # times need to be same since we can't autoconvert
     def test_merge_multiple_with_waveforms(self):
-        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * pq.microsecond)
+        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * 0.1 * pq.millisecond)
         train3.segment = self.train1.segment
         train3.array_annotate(index=np.arange(301, 307))
         train3.waveforms = self.train1.waveforms / 10
@@ -1380,7 +1229,7 @@ class TestMerge(unittest.TestCase):
         self.assertIsInstance(result.array_annotations, ArrayDict)
 
     def test_rescaling_units(self):
-        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * pq.microsecond)
+        train3 = self.train1.duplicate_with_new_data(signal=(self.train1.times.magnitude/1000) * pq.millisecond)
         train3.segment = self.train1.segment
         train3.array_annotate(**self.arr_ann1)
         # Array annotations merge warning was already tested, can be ignored now
@@ -1411,7 +1260,7 @@ class TestMerge(unittest.TestCase):
         self.train2.description = "desc2"
         self.train2.file_origin = "file2"
 
-        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * pq.microsecond)
+        train3 = self.train1.duplicate_with_new_data(self.train1.times.magnitude * pq.millisecond)
         train3.segment = self.train1.segment
         train3.name = "name3"
         train3.description = "desc3"
@@ -1645,127 +1494,62 @@ class TestAttributesAnnotations(unittest.TestCase):
 
 
 class TestChanging(unittest.TestCase):
-    def test_change_with_copy_default(self):
-        # Default is copy = True
-        # Changing spike train does not change data
-        # Data source is quantity
-        data = [3, 4, 5] * pq.s
-        train = SpikeTrain(data, t_stop=100.0)
-        train[0] = 99 * pq.s
-        assert_neo_object_is_compliant(train)
-        self.assertEqual(train[0], 99 * pq.s)
-        self.assertEqual(data[0], 3 * pq.s)
 
-    def test_change_with_copy_false(self):
+
+    # now we test default behavior here so change false to None
+    def test_change_with_default(self):
         # Changing spike train also changes data, because it is a view
         # Data source is quantity
         data = [3, 4, 5] * pq.s
-        train = SpikeTrain(data, copy=False, t_stop=100.0)
+        train = SpikeTrain(data, t_stop=100.0)
         train[0] = 99 * pq.s
         assert_neo_object_is_compliant(train)
         self.assertEqual(train[0], 99 * pq.s)
         self.assertEqual(data[0], 99 * pq.s)
 
-    def test_change_with_copy_false_and_fake_rescale(self):
+    def test_change_with_fake_rescale(self):
         # Changing spike train also changes data, because it is a view
         # Data source is quantity
         data = [3000, 4000, 5000] * pq.ms
         # even though we specify units, it still returns a view
-        train = SpikeTrain(data, units="ms", copy=False, t_stop=100000)
+        train = SpikeTrain(data, units="ms", t_stop=100000)
         train[0] = 99000 * pq.ms
         assert_neo_object_is_compliant(train)
         self.assertEqual(train[0], 99000 * pq.ms)
         self.assertEqual(data[0], 99000 * pq.ms)
 
-    def test_change_with_copy_false_and_rescale_true(self):
+    def test_change_and_rescale_true(self):
         # When rescaling, a view cannot be returned
         # Changing spike train also changes data, because it is a view
         data = [3, 4, 5] * pq.s
-        self.assertRaises(ValueError, SpikeTrain, data, units="ms", copy=False, t_stop=10000)
+        self.assertRaises(ValueError, SpikeTrain, data, units="ms", t_stop=10000)
 
-    def test_init_with_rescale(self):
-        data = [3, 4, 5] * pq.s
-        train = SpikeTrain(data, units="ms", t_stop=6000)
-        assert_neo_object_is_compliant(train)
-        self.assertEqual(train[0], 3000 * pq.ms)
-        self.assertEqual(train._dimensionality, pq.ms._dimensionality)
-        self.assertEqual(train.t_stop, 6000 * pq.ms)
-
-    def test_change_with_copy_true(self):
-        # Changing spike train does not change data
-        # Data source is quantity
-        data = [3, 4, 5] * pq.s
-        train = SpikeTrain(data, copy=True, t_stop=100)
-        train[0] = 99 * pq.s
-        assert_neo_object_is_compliant(train)
-        self.assertEqual(train[0], 99 * pq.s)
-        self.assertEqual(data[0], 3 * pq.s)
 
-    def test_change_with_copy_default_and_data_not_quantity(self):
-        # Default is copy = True
-        # Changing spike train does not change data
-        # Data source is array
-        # Array and quantity are tested separately because copy default
-        # is different for these two.
-        data = [3, 4, 5]
-        train = SpikeTrain(data, units="sec", t_stop=100)
-        train[0] = 99 * pq.s
-        assert_neo_object_is_compliant(train)
-        self.assertEqual(train[0], 99 * pq.s)
-        self.assertEqual(data[0], 3 * pq.s)
-
-    def test_change_with_copy_false_and_data_not_quantity(self):
+    def test_change_and_data_not_quantity(self):
         # Changing spike train also changes data, because it is a view
         # Data source is array
         # Array and quantity are tested separately because copy default
         # is different for these two.
         data = np.array([3, 4, 5])
-        train = SpikeTrain(data, units="sec", copy=False, dtype=int, t_stop=101)
+        train = SpikeTrain(data, units="sec", dtype=int, t_stop=101)
         train[0] = 99 * pq.s
         assert_neo_object_is_compliant(train)
         self.assertEqual(train[0], 99 * pq.s)
         self.assertEqual(data[0], 99)
 
-    def test_change_with_copy_false_and_dtype_change(self):
+    def test__dtype_change(self):
         # You cannot change dtype and request a view
         data = np.array([3, 4, 5])
-        self.assertRaises(ValueError, SpikeTrain, data, units="sec", copy=False, t_stop=101, dtype=np.float64)
+        self.assertRaises(ValueError, SpikeTrain, data, units="sec", t_stop=101, dtype=np.float64)
 
-    def test_change_with_copy_true_and_data_not_quantity(self):
-        # Changing spike train does not change data
-        # Data source is array
-        # Array and quantity are tested separately because copy default
-        # is different for these two.
-        data = [3, 4, 5]
-        train = SpikeTrain(data, units="sec", copy=True, t_stop=123.4)
-        train[0] = 99 * pq.s
-        assert_neo_object_is_compliant(train)
-        self.assertEqual(train[0], 99 * pq.s)
-        self.assertEqual(data[0], 3)
 
     def test_changing_slice_changes_original_spiketrain(self):
         # If we slice a spiketrain and then change the slice, the
         # original spiketrain should change.
-        # Whether the original data source changes is dependent on the
-        # copy parameter.
-        # This is compatible with both np and quantity default behavior.
-        data = [3, 4, 5] * pq.s
-        train = SpikeTrain(data, copy=True, t_stop=99.9)
-        result = train[1:3]
-        result[0] = 99 * pq.s
-        assert_neo_object_is_compliant(train)
-        self.assertEqual(train[1], 99 * pq.s)
-        self.assertEqual(result[0], 99 * pq.s)
-        self.assertEqual(data[1], 4 * pq.s)
-
-    def test_changing_slice_changes_original_spiketrain_with_copy_false(self):
-        # If we slice a spiketrain and then change the slice, the
-        # original spiketrain should change.
-        # Whether the original data source changes is dependent on the
-        # copy parameter.
+        # Test new default behavior of neo for neo 14.0
         # This is compatible with both np and quantity default behavior.
         data = [3, 4, 5] * pq.s
-        train = SpikeTrain(data, copy=False, t_stop=100.0)
+        train = SpikeTrain(data, t_stop=100.0)
         result = train[1:3]
         result[0] = 99 * pq.s
         assert_neo_object_is_compliant(train)
@@ -1776,7 +1560,7 @@ class TestChanging(unittest.TestCase):
 
     def test__changing_spiketime_should_check_time_in_range(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         assert_neo_object_is_compliant(train)
         self.assertRaises(ValueError, train.__setitem__, 0, 10.1 * pq.ms)
         self.assertRaises(ValueError, train.__setitem__, 1, 5.0 * pq.s)
@@ -1785,19 +1569,19 @@ class TestChanging(unittest.TestCase):
 
     def test__changing_multiple_spiketimes(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         train[:] = [7, 8, 9] * pq.ms
         assert_neo_object_is_compliant(train)
         assert_arrays_equal(train, np.array([7, 8, 9]))
 
     def test__changing_multiple_spiketimes_should_check_time_in_range(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         assert_neo_object_is_compliant(train)
 
     def test__adding_time_scalar(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         assert_neo_object_is_compliant(train)
         # t_start and t_stop are also changed
         self.assertEqual((train + 10 * pq.ms).t_start, 10.5 * pq.ms)
@@ -1808,7 +1592,7 @@ class TestChanging(unittest.TestCase):
 
     def test__adding_time_array(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         assert_neo_object_is_compliant(train)
         delta = [-2, 2, 4] * pq.ms
         assert_arrays_equal(train + delta, np.array([1, 6, 9]) * pq.ms)
@@ -1825,13 +1609,13 @@ class TestChanging(unittest.TestCase):
 
     def test__adding_two_spike_trains(self):
         data = [3, 4, 5] * pq.ms
-        train1 = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
-        train2 = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train1 = SpikeTrain(data, t_start=0.5, t_stop=10.0)
+        train2 = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         self.assertRaises(TypeError, train1.__add__, train2)
 
     def test__subtracting_time_scalar(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         assert_neo_object_is_compliant(train)
         # t_start and t_stop are also changed
         self.assertEqual((train - 1 * pq.ms).t_start, -0.5 * pq.ms)
@@ -1841,7 +1625,7 @@ class TestChanging(unittest.TestCase):
 
     def test__subtracting_time_array(self):
         data = [3, 4, 5] * pq.ms
-        train = SpikeTrain(data, copy=False, t_start=0.5, t_stop=10.0)
+        train = SpikeTrain(data, t_start=0.5, t_stop=10.0)
         assert_neo_object_is_compliant(train)
         delta = [2, 1, -2] * pq.ms
         self.assertIsInstance(train - delta, SpikeTrain)
@@ -1856,9 +1640,9 @@ class TestChanging(unittest.TestCase):
         self.assertEqual((train - delta).t_stop, 11 * pq.ms)
 
     def test__subtracting_two_spike_trains(self):
-        train1 = SpikeTrain([3, 4, 5] * pq.ms, copy=False, t_start=0.5, t_stop=10.0)
-        train2 = SpikeTrain([4, 5, 6] * pq.ms, copy=False, t_start=0.5, t_stop=10.0)
-        train3 = SpikeTrain([3, 4, 5, 6] * pq.ms, copy=False, t_start=0.5, t_stop=10.0)
+        train1 = SpikeTrain([3, 4, 5] * pq.ms, t_start=0.5, t_stop=10.0)
+        train2 = SpikeTrain([4, 5, 6] * pq.ms, t_start=0.5, t_stop=10.0)
+        train3 = SpikeTrain([3, 4, 5, 6] * pq.ms, t_start=0.5, t_stop=10.0)
         self.assertRaises(TypeError, train1.__sub__, train3)
         self.assertRaises(TypeError, train3.__sub__, train1)
         self.assertIsInstance(train1 - train2, pq.Quantity)
@@ -2064,135 +1848,7 @@ class TestPropertiesMethods(unittest.TestCase):
 
 
 class TestMiscellaneous(unittest.TestCase):
-    def test__different_dtype_for_t_start_and_array(self):
-        data = np.array([0, 9.9999999], dtype=np.float64) * pq.s
-        data16 = data.astype(np.float16)
-        data32 = data.astype(np.float32)
-        data64 = data.astype(np.float64)
-        t_start = data[0]
-        t_stop = data[1]
-        t_start16 = data[0].astype(dtype=np.float16)
-        t_stop16 = data[1].astype(dtype=np.float16)
-        t_start32 = data[0].astype(dtype=np.float32)
-        t_stop32 = data[1].astype(dtype=np.float32)
-        t_start64 = data[0].astype(dtype=np.float64)
-        t_stop64 = data[1].astype(dtype=np.float64)
-        t_start_custom = 0.0
-        t_stop_custom = 10.0
-        t_start_custom16 = np.array(t_start_custom, dtype=np.float16)
-        t_stop_custom16 = np.array(t_stop_custom, dtype=np.float16)
-        t_start_custom32 = np.array(t_start_custom, dtype=np.float32)
-        t_stop_custom32 = np.array(t_stop_custom, dtype=np.float32)
-        t_start_custom64 = np.array(t_start_custom, dtype=np.float64)
-        t_stop_custom64 = np.array(t_stop_custom, dtype=np.float64)
-
-        # This is OK.
-        train = SpikeTrain(data64, copy=True, t_start=t_start, t_stop=t_stop)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data16, copy=True, t_start=t_start, t_stop=t_stop, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start, t_stop=t_stop, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start, t_stop=t_stop, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start, t_stop=t_stop, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start16, t_stop=t_stop16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start16, t_stop=t_stop16, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start16, t_stop=t_stop16, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start16, t_stop=t_stop16, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start32, t_stop=t_stop32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start32, t_stop=t_stop32, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start32, t_stop=t_stop32, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start32, t_stop=t_stop32, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start64, t_stop=t_stop64, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start64, t_stop=t_stop64, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom, t_stop=t_stop_custom)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start_custom, t_stop=t_stop_custom, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom16, t_stop=t_stop_custom16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom16, t_stop=t_stop_custom16, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom16, t_stop=t_stop_custom16, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom16, t_stop=t_stop_custom16, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom32, t_stop=t_stop_custom32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom32, t_stop=t_stop_custom32, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom32, t_stop=t_stop_custom32, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom32, t_stop=t_stop_custom32, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom64, t_stop=t_stop_custom64)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom64, t_stop=t_stop_custom64, dtype=np.float16)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom64, t_stop=t_stop_custom64, dtype=np.float32)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start_custom64, t_stop=t_stop_custom64, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        # This use to bug - see ticket #38
-        train = SpikeTrain(data16, copy=True, t_start=t_start, t_stop=t_stop)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data16, copy=True, t_start=t_start, t_stop=t_stop, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start, t_stop=t_stop)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start, t_stop=t_stop, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
-        train = SpikeTrain(data32, copy=True, t_start=t_start64, t_stop=t_stop64)
-        assert_neo_object_is_compliant(train)
-        train = SpikeTrain(data32, copy=True, t_start=t_start64, t_stop=t_stop64, dtype=np.float64)
-        assert_neo_object_is_compliant(train)
-
+    
     def test_as_array(self):
         data = np.arange(10.0)
         st = SpikeTrain(data, t_stop=10.0, units="ms")
diff --git a/neo/test/iotest/test_brainwaresrcio.py b/neo/test/iotest/test_brainwaresrcio.py
index f87e5938..a4d67880 100644
--- a/neo/test/iotest/test_brainwaresrcio.py
+++ b/neo/test/iotest/test_brainwaresrcio.py
@@ -251,7 +251,7 @@ def proc_src_condition_unit_repetition(sweep, damaIndex, timeStamp, sweepLen, si
         timestamp=timeStamp,
         dama_index=damaIndex,
         side=side,
-        copy=True,
+        copy=None,
         respwin=respWin,
         waveforms=waveforms,
         file_origin=filename,