Repository: spinnakermanchester/spynnaker
Issue: get_data clear does not clear previous segments

Population.get_data(...Clear=True) removes data from the current sqlite3 database 

It however does not affect either
- previous sqlite3 databases no longer used after a reset (in current master only hard ones)
- data held in memory from previous segments



Changed files:
spynnaker/pyNN/utilities/neo_buffer_database.py, spynnaker_integration_tests/test_various/test_clear.py, spynnaker/pyNN/models/recorder.py

diff --git a/spynnaker/pyNN/models/recorder.py b/spynnaker/pyNN/models/recorder.py
index 7fbe85cd50..35e98aafff 100644
--- a/spynnaker/pyNN/models/recorder.py
+++ b/spynnaker/pyNN/models/recorder.py
@@ -61,10 +61,7 @@ class Recorder(object):
         return self.__write_to_files_indicators
 
     def record(self, variables, to_file, sampling_interval, indexes):
-        """ Same as record but without non-standard PyNN warning
-
-        This method is non-standard PyNN and is intended only to be called by
-        record in a Population, View or Assembly
+        """ Turns on (or off) recording
 
         :param variables: either a single variable name or a list of variable
             names. For a given celltype class, ``celltype.recordable`` contains
@@ -102,23 +99,40 @@ class Recorder(object):
         elif isinstance(variables, str):
             # handle special case of 'all'
             if variables == "all":
-                warn_once(
-                    logger, 'record("all") is non-standard PyNN, and '
-                    'therefore may not be portable to other simulators.')
-
-                # iterate though all possible recordings for this vertex
-                for variable in self.__vertex.get_recordable_variables():
-                    self.turn_on_record(
-                        variable, sampling_interval, to_file, indexes)
+                self.__turn_on_all_record(sampling_interval, to_file, indexes)
             else:
                 # record variable
                 self.turn_on_record(
                     variables, sampling_interval, to_file, indexes)
 
         else:  # list of variables, so just iterate though them
-            for variable in variables:
-                self.turn_on_record(
-                    variable, sampling_interval, to_file, indexes)
+            if "all" in variables:
+                self.__turn_on_all_record(sampling_interval, to_file, indexes)
+            else:
+                for variable in variables:
+                    self.turn_on_record(
+                        variable, sampling_interval, to_file, indexes)
+
+    def __turn_on_all_record(self, sampling_interval, to_file, indexes):
+        """
+
+        :param int sampling_interval: the interval to record them
+        :param to_file: If set, a file to write to (by handle or name)
+        :type to_file: neo.io.baseio.BaseIO or str or None
+        :param indexes: List of indexes to record or None for all
+        :type indexes: list(int) or None
+        :raises SimulatorRunningException: If sim.run is currently running
+        :raises SimulatorNotSetupException: If called before sim.setup
+        :raises SimulatorShutdownException: If called after sim.end
+        """
+        warn_once(
+            logger, 'record("all") is non-standard PyNN, and '
+                    'therefore may not be portable to other simulators.')
+
+        # iterate though all possible recordings for this vertex
+        for variable in self.__vertex.get_recordable_variables():
+            self.turn_on_record(
+                variable, sampling_interval, to_file, indexes)
 
     def turn_on_record(self, variable, sampling_interval=None, to_file=None,
                        indexes=None):
@@ -300,7 +314,8 @@ class Recorder(object):
             block.segments.append(segment)
             return
 
-        with NeoBufferDatabase(self.__data_cache[segment_number]) as db:
+        with NeoBufferDatabase(
+                self.__data_cache[segment_number], read_only=False) as db:
             db.add_segment(
                 block, self.__population.label, variables, view_indexes)
             if clear:
diff --git a/spynnaker/pyNN/utilities/neo_buffer_database.py b/spynnaker/pyNN/utilities/neo_buffer_database.py
index e6a178ff69..63262bd56e 100644
--- a/spynnaker/pyNN/utilities/neo_buffer_database.py
+++ b/spynnaker/pyNN/utilities/neo_buffer_database.py
@@ -54,7 +54,7 @@ class NeoBufferDatabase(BufferDatabase, NeoCsv):
     #: number of words per rewiring entry
     __REWIRING_N_WORDS = 2
 
-    def __init__(self, database_file=None):
+    def __init__(self, database_file=None, read_only=None):
         """
         Extra support for Neo on top of the Database for SQLite 3.
 
@@ -66,12 +66,18 @@ class NeoBufferDatabase(BufferDatabase, NeoCsv):
             database holding the data.
             If omitted the default location will be used.
         :type database_file: None or str
+        :param read_only:
+            By default the database is readonly if given a databas file.
+            This allows to overwire that (mainly for clear)
+        :type read_only: None or bool
         """
         if database_file is None:
             database_file = self.default_database_file()
-            read_only = False
+            if read_only is None:
+                read_only = False
         else:
-            read_only = True
+            if read_only is None:
+                read_only = True
 
         super(BufferDatabase, self).__init__(
             database_file, read_only=read_only)
diff --git a/spynnaker_integration_tests/test_various/test_clear.py b/spynnaker_integration_tests/test_various/test_clear.py
index 5e1d184e4c..6ee763d862 100644
--- a/spynnaker_integration_tests/test_various/test_clear.py
+++ b/spynnaker_integration_tests/test_various/test_clear.py
@@ -77,6 +77,39 @@ class TestClearData(BaseTestCase):
         self.assertEqual(10, v.size)
         sim.end()
 
+    def test_clear_previous_segment(self):
+        sim.setup(timestep=1.0)
+        sim.set_number_of_neurons_per_core(sim.IF_curr_exp, 100)
+
+        pop_1 = sim.Population(1, sim.IF_curr_exp(), label="pop_1")
+        input_pop = sim.Population(
+            1, sim.SpikeSourceArray(spike_times=[0, 10, 20]), label="input")
+        sim.Projection(input_pop, pop_1, sim.OneToOneConnector(),
+                       synapse_type=sim.StaticSynapse(weight=5, delay=1))
+        pop_1.record(["spikes", "v"])
+        sim.run(20)
+        sim.reset()
+        sim.run(20)
+        neo = pop_1.get_data(variables=["spikes", "v"], clear=True)
+        spikes = neo.segments[0].spiketrains
+        self.assertEqual(
+            '<SpikeTrain(array([ 7., 14.]) * ms, [0.0 ms, 20.0 ms])>',
+            repr(spikes[0]))
+        spikes = neo.segments[1].spiketrains
+        self.assertEqual(
+            '<SpikeTrain(array([ 7., 14.]) * ms, [0.0 ms, 20.0 ms])>',
+            repr(spikes[0]))
+        neo = pop_1.get_data(variables=["spikes", "v"], clear=True)
+        spikes = neo.segments[0].spiketrains
+        self.assertEqual(
+            '<SpikeTrain(array([], dtype=float64) * ms, [20.0 ms, 20.0 ms])>',
+            repr(spikes[0]))
+        spikes = neo.segments[1].spiketrains
+        self.assertEqual(
+            '<SpikeTrain(array([], dtype=float64) * ms, [20.0 ms, 20.0 ms])>',
+            repr(spikes[0]))
+        sim.end()
+
     def test_rewires(self):
         self.runsafe(self.make_rewires)