From 08eadbb51a80c1a596e0560164bc8bdc33462c3d Mon Sep 17 00:00:00 2001 From: Yi-111-a <153097222+Yi-111-a@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:00:16 +0800 Subject: [PATCH] fix(neuralynx): handle unclosed files with unparseable TimeClosed (#1901) --- neo/rawio/neuralynxrawio/nlxheader.py | 5 +++- neo/test/rawiotest/test_neuralynxrawio.py | 35 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/neo/rawio/neuralynxrawio/nlxheader.py b/neo/rawio/neuralynxrawio/nlxheader.py index 54bd57c99..af7b8d916 100644 --- a/neo/rawio/neuralynxrawio/nlxheader.py +++ b/neo/rawio/neuralynxrawio/nlxheader.py @@ -350,7 +350,10 @@ def _setTimeDate(self, txt_header): sr = NlxHeader._closeDatetime2_pat.search(txt_header) if sr: dt2 = sr.groupdict() - self["recording_closed"] = dateutil.parser.parse(f"{dt2['date']} {dt2['time']}") + try: + self["recording_closed"] = dateutil.parser.parse(f"{dt2['date']} {dt2['time']}") + except (ValueError, dateutil.parser.ParserError): + pass def _normalize_types(self): """ diff --git a/neo/test/rawiotest/test_neuralynxrawio.py b/neo/test/rawiotest/test_neuralynxrawio.py index 0a1c90980..41411af8b 100644 --- a/neo/test/rawiotest/test_neuralynxrawio.py +++ b/neo/test/rawiotest/test_neuralynxrawio.py @@ -2,6 +2,7 @@ import unittest import os +import tempfile import numpy as np import re @@ -562,6 +563,40 @@ def test_filename_prop(self): hdr = NlxHeader(filename) self.assertEqual(r"C:\CheetahData\2000-01-01_00-00-00\CSC5.ncs", hdr["OriginalFileName"]) +class TestNlxHeaderUnclosedFile(unittest.TestCase): + def test_unclosed_file_datetime(self): + # Neuralynx files where recording was not properly closed (#1901) + header_txt = ( + "######## Neuralynx Data File Header\r\n" + "-FileType NCS\r\n" + "-FileVersion 3.4\r\n" + "-RecordSize 1044\r\n" + "-AcqEntName CSC1\r\n" + "-HardwareSubSystemName AcqSystem1\r\n" + "-HardwareSubSystemType AcqSys\r\n" + "-SamplingFrequency 32000\r\n" + "-ADMaxValue 32767\r\n" + "-ADBitVolts 0.000000030517578125\r\n" + "-NumADChannels 1\r\n" + "-ADChannel 0\r\n" + "-InputRange 1000\r\n" + "-InputInverted False\r\n" + "-ApplicationName Cheetah \"5.7.4\"\r\n" + "-TimeCreated 2017/02/16 17:56:04\r\n" + "-TimeClosed File was not properly closed\r\n" + ) + with tempfile.NamedTemporaryFile("w", delete=False, suffix=".ncs") as f: + f.write(header_txt.ljust(NlxHeader.HEADER_SIZE, " ")) + temp_file = f.name + try: + hdr = NlxHeader(temp_file) + self.assertEqual(datetime.datetime(2017, 2, 16, 17, 56, 4), hdr["recording_opened"]) + self.assertIsNone(hdr.get("recording_closed")) + self.assertEqual("File was not properly closed", hdr["TimeClosed"]) + finally: + if os.path.exists(temp_file): + os.remove(temp_file) + if __name__ == "__main__": unittest.main()