diff --git a/src/rosbags/rosbag1/reader.py b/src/rosbags/rosbag1/reader.py index 0ee6c784..6f190db4 100644 --- a/src/rosbags/rosbag1/reader.py +++ b/src/rosbags/rosbag1/reader.py @@ -436,17 +436,17 @@ class Reader: @property def duration(self) -> int: """Duration in nanoseconds between earliest and latest messages.""" - return self.end_time - self.start_time + return self.end_time - self.start_time if self.chunk_infos else 0 @property def start_time(self) -> int: """Timestamp in nanoseconds of the earliest message.""" - return min(x.start_time for x in self.chunk_infos) + return min(x.start_time for x in self.chunk_infos) if self.chunk_infos else 2**63 - 1 @property def end_time(self) -> int: """Timestamp in nanoseconds after the latest message.""" - return max(x.end_time for x in self.chunk_infos) + return max(x.end_time for x in self.chunk_infos) if self.chunk_infos else 0 @property def message_count(self) -> int: diff --git a/src/rosbags/rosbag2/reader.py b/src/rosbags/rosbag2/reader.py index dfc19a9b..a830724a 100644 --- a/src/rosbags/rosbag2/reader.py +++ b/src/rosbags/rosbag2/reader.py @@ -191,17 +191,18 @@ class Reader: def duration(self) -> int: """Duration in nanoseconds between earliest and latest messages.""" nsecs: int = self.metadata['duration']['nanoseconds'] - return nsecs + 1 + return nsecs + 1 if self.message_count else 0 @property def start_time(self) -> int: """Timestamp in nanoseconds of the earliest message.""" - return self.metadata['starting_time']['nanoseconds_since_epoch'] + nsecs: int = self.metadata['starting_time']['nanoseconds_since_epoch'] + return nsecs if self.message_count else 2**63 - 1 @property def end_time(self) -> int: """Timestamp in nanoseconds after the latest message.""" - return self.start_time + self.duration + return self.start_time + self.duration if self.message_count else 0 @property def message_count(self) -> int: diff --git a/tests/test_reader.py b/tests/test_reader.py index 84ecddfd..a574e39b 100644 --- a/tests/test_reader.py +++ b/tests/test_reader.py @@ -55,6 +55,22 @@ rosbag2_bagfile_information: compression_mode: {compression_mode} """ +METADATA_EMPTY = """ +rosbag2_bagfile_information: + version: 4 + storage_identifier: sqlite3 + relative_file_paths: + - db.db3 + duration: + nanoseconds: 0 + starting_time: + nanoseconds_since_epoch: 0 + message_count: 0 + topics_with_message_count: [] + compression_format: "" + compression_mode: "" +""" + @pytest.fixture(params=['none', 'file', 'message']) def bag(request: SubRequest, tmp_path: Path) -> Path: @@ -117,6 +133,21 @@ def bag(request: SubRequest, tmp_path: Path) -> Path: return tmp_path +def test_empty_bag(tmp_path: Path) -> None: + """Test bags with broken fs layout.""" + (tmp_path / 'metadata.yaml').write_text(METADATA_EMPTY) + dbpath = tmp_path / 'db.db3' + dbh = sqlite3.connect(dbpath) + dbh.executescript(Writer.SQLITE_SCHEMA) + + with Reader(tmp_path) as reader: + assert reader.message_count == 0 + assert reader.start_time == 2**63 - 1 + assert reader.end_time == 0 + assert reader.duration == 0 + assert not list(reader.messages()) + + def test_reader(bag: Path) -> None: """Test reader and deserializer on simple bag.""" with Reader(bag) as reader: diff --git a/tests/test_reader1.py b/tests/test_reader1.py index 2a9cbe1d..47f9cfdd 100644 --- a/tests/test_reader1.py +++ b/tests/test_reader1.py @@ -202,6 +202,10 @@ def test_reader(tmp_path: Path) -> None: # pylint: disable=too-many-statements write_bag(bag, create_default_header()) with Reader(bag) as reader: assert reader.message_count == 0 + assert reader.start_time == 2**63 - 1 + assert reader.end_time == 0 + assert reader.duration == 0 + assert not list(reader.messages()) # empty bag, explicit encryptor bag = tmp_path / 'test.bag'