Repository: BlueBrain/libsonata (language: python)

Issue:
Query start and end time of spike reports
Hello,

Currently, the only way to know the start and end time of a spike report is by loading the whole report and search for the highest timestamp.

It would be useful to have a similar method as `ReportReader`'s `getTimes()` to directly return this value from the SpikeReader members.


Discussion / hints:
I think that @jorblancoa or @alkino should suggest and implement how best to handle this.

Fix patch:
diff --git a/include/bbp/sonata/report_reader.h b/include/bbp/sonata/report_reader.h
index cf7ac457..8e33966e 100644
--- a/include/bbp/sonata/report_reader.h
+++ b/include/bbp/sonata/report_reader.h
@@ -51,6 +51,11 @@ class SONATA_API SpikeReader
             by_time = 2,
         };
 
+        /**
+         * Return (tstart, tstop) of the population
+         */
+        std::tuple<double, double> getTimes() const;
+
         /**
          * Return reports for this population.
          */
diff --git a/python/bindings.cpp b/python/bindings.cpp
index eb6156f0..c30e603d 100644
--- a/python/bindings.cpp
+++ b/python/bindings.cpp
@@ -614,7 +614,10 @@ PYBIND11_MODULE(_libsonata, m) {
                     return "by_time";
                 return "none";
             },
-            DOC_SPIKEREADER_POP(getSorting));
+            DOC_SPIKEREADER_POP(getSorting))
+        .def_property_readonly("times",
+                               &SpikeReader::Population::getTimes,
+                               DOC_SPIKEREADER_POP(getTimes));
     py::class_<SpikeReader>(m, "SpikeReader", "Used to read spike files")
         .def(py::init([](py::object h5_filepath) { return SpikeReader(py::str(h5_filepath)); }),
              "h5_filepath"_a)
diff --git a/python/generated/docstrings.h b/python/generated/docstrings.h
index ac49a0b2..a721d850 100644
--- a/python/generated/docstrings.h
+++ b/python/generated/docstrings.h
@@ -518,6 +518,8 @@ static const char *__doc_bbp_sonata_SpikeReader_Population_get = R"doc(Return re
 
 static const char *__doc_bbp_sonata_SpikeReader_Population_getSorting = R"doc(Return the way data are sorted ('none', 'by_id', 'by_time'))doc";
 
+static const char *__doc_bbp_sonata_SpikeReader_Population_getTimes = R"doc(Return (tstart, tstop) of the population)doc";
+
 static const char *__doc_bbp_sonata_SpikeReader_Population_sorting = R"doc()doc";
 
 static const char *__doc_bbp_sonata_SpikeReader_Population_spikes = R"doc()doc";
diff --git a/src/report_reader.cpp b/src/report_reader.cpp
index 25e94bf7..6df810b8 100644
--- a/src/report_reader.cpp
+++ b/src/report_reader.cpp
@@ -112,6 +112,10 @@ auto SpikeReader::openPopulation(const std::string& populationName) const -> con
     return populations_.at(populationName);
 }
 
+std::tuple<double, double> SpikeReader::Population::getTimes() const {
+    return std::tie(tstart_, tstop_);
+}
+
 Spikes SpikeReader::Population::get(const nonstd::optional<Selection>& node_ids,
                                     const nonstd::optional<double>& tstart,
                                     const nonstd::optional<double>& tstop) const {


Test patch:
diff --git a/python/tests/test.py b/python/tests/test.py
index 53cbf152..10a40a47 100644
--- a/python/tests/test.py
+++ b/python/tests/test.py
@@ -291,6 +291,9 @@ def test_get_spikes_from_population(self):
 
         self.assertEqual(len(self.test_obj['All'].get(node_ids=[])), 0)
 
+    def test_getTimes_from_population(self):
+        self.assertEqual(self.test_obj['All'].times, (0.1, 1.3))
+
 class TestSomaReportPopulation(unittest.TestCase):
     def setUp(self):
         path = os.path.join(PATH, "somas.h5")
diff --git a/tests/test_report_reader.cpp b/tests/test_report_reader.cpp
index e21bd9fe..ce881a41 100644
--- a/tests/test_report_reader.cpp
+++ b/tests/test_report_reader.cpp
@@ -33,6 +33,8 @@ TEST_CASE("SpikeReader", "[base]") {
     REQUIRE(reader.openPopulation("All").get(Selection({{5, 6}}), 0.1, 0.1) ==
             std::vector<std::pair<uint64_t, double>>{{5, 0.1}});
     REQUIRE(reader.openPopulation("empty").get() == std::vector<std::pair<uint64_t, double>>{});
+
+    REQUIRE(reader.openPopulation("All").getTimes() == std::make_tuple(0.1, 1.3));
 }
 
 TEST_CASE("SomaReportReader limits", "[base]") {