From 44bf3de167d449a71af9d3e3f9e67d22a00051d6 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:12:05 +0100 Subject: [PATCH 01/12] Add format lookup map --- can/io/trc.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/can/io/trc.py b/can/io/trc.py index 2dbe3763c..cf1760fba 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -278,10 +278,12 @@ class TRCWriter(TextIOMessageWriter): file: TextIO first_timestamp: Optional[float] - FORMAT_MESSAGE = ( - "{msgnr:>7} {time:13.3f} DT {channel:>2} {id:>8} {dir:>2} - {dlc:<4} {data}" - ) - FORMAT_MESSAGE_V1_0 = "{msgnr:>6}) {time:7.0f} {id:>8} {dlc:<1} {data}" + MESSAGE_FORMAT_MAP: Mapping[TRCFileVersion, str] = { + TRCFileVersion.V1_0: "{msgnr:>6}) {time:7.0f} {id:>8} {dlc:<1} {data}", + TRCFileVersion.V2_1: ( + "{msgnr:>7} {time:13.3f} DT {channel:>2} {id:>8} {dir:>2} - {dlc:<4} {data}" + ), + } def __init__( self, @@ -309,7 +311,7 @@ def __init__( self.msgnr = 0 self.first_timestamp = None self.file_version = TRCFileVersion.V2_1 - self._msg_fmt_string = self.FORMAT_MESSAGE_V1_0 + self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] self._format_message = self._format_message_init def _write_header_v1_0(self, start_time: datetime) -> None: @@ -381,13 +383,12 @@ def _format_message_by_format(self, msg, channel): def _format_message_init(self, msg, channel): if self.file_version == TRCFileVersion.V1_0: self._format_message = self._format_message_by_format - self._msg_fmt_string = self.FORMAT_MESSAGE_V1_0 elif self.file_version == TRCFileVersion.V2_1: self._format_message = self._format_message_by_format - self._msg_fmt_string = self.FORMAT_MESSAGE else: raise NotImplementedError("File format is not supported") + self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] return self._format_message_by_format(msg, channel) def write_header(self, timestamp: float) -> None: From e99bc00f4635cc324915ae88fe3029f696111d64 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:23:09 +0100 Subject: [PATCH 02/12] Remove format message init stuff --- can/io/trc.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/can/io/trc.py b/can/io/trc.py index cf1760fba..f1ac74052 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -312,7 +312,6 @@ def __init__( self.first_timestamp = None self.file_version = TRCFileVersion.V2_1 self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] - self._format_message = self._format_message_init def _write_header_v1_0(self, start_time: datetime) -> None: lines = [ @@ -361,7 +360,7 @@ def _write_header_v2_1(self, start_time: datetime) -> None: ] self.file.writelines(line + "\n" for line in lines) - def _format_message_by_format(self, msg, channel): + def _format_message(self, msg, channel): if msg.is_extended_id: arb_id = f"{msg.arbitration_id:07X}" else: @@ -380,17 +379,6 @@ def _format_message_by_format(self, msg, channel): ) return serialized - def _format_message_init(self, msg, channel): - if self.file_version == TRCFileVersion.V1_0: - self._format_message = self._format_message_by_format - elif self.file_version == TRCFileVersion.V2_1: - self._format_message = self._format_message_by_format - else: - raise NotImplementedError("File format is not supported") - - self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] - return self._format_message_by_format(msg, channel) - def write_header(self, timestamp: float) -> None: # write start of file header start_time = datetime.fromtimestamp(timestamp, timezone.utc) From 132a93d4468578344f46d45f9cce1219e6a6f17d Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:28:05 +0100 Subject: [PATCH 03/12] Add function for setup of file version --- can/io/trc.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/can/io/trc.py b/can/io/trc.py index f1ac74052..01126bfd1 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -310,8 +310,15 @@ def __init__( self.header_written = False self.msgnr = 0 self.first_timestamp = None - self.file_version = TRCFileVersion.V2_1 - self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] + self._setup_file_version(TRCFileVersion.V2_1) + + def _setup_file_version(self, file_version: Union[int, TRCFileVersion]): + try: + self.file_version = TRCFileVersion(file_version) + self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] + except (KeyError, ValueError) as exc: + err_msg = f"File version is not supported: {file_version}" + raise NotImplementedError(err_msg) from exc def _write_header_v1_0(self, start_time: datetime) -> None: lines = [ From 406b278aedad48df7dcbc08ac0c8f600fd6d0c59 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:29:28 +0100 Subject: [PATCH 04/12] Add file version as init parameter --- can/io/trc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/can/io/trc.py b/can/io/trc.py index 01126bfd1..7f9ff9db8 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -289,6 +289,7 @@ def __init__( self, file: Union[StringPathLike, TextIO], channel: int = 1, + file_version: Union[int, TRCFileVersion] = TRCFileVersion.V2_1, **kwargs: Any, ) -> None: """ @@ -310,7 +311,7 @@ def __init__( self.header_written = False self.msgnr = 0 self.first_timestamp = None - self._setup_file_version(TRCFileVersion.V2_1) + self._setup_file_version(file_version) def _setup_file_version(self, file_version: Union[int, TRCFileVersion]): try: From e736744285864578bbdd03a6763d21979fe95ed8 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:30:29 +0100 Subject: [PATCH 05/12] Add missing import --- can/io/trc.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/can/io/trc.py b/can/io/trc.py index 7f9ff9db8..c2a647521 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -11,7 +11,17 @@ import os from datetime import datetime, timedelta, timezone from enum import Enum -from typing import Any, Callable, Dict, Generator, Optional, TextIO, Tuple, Union +from typing import ( + Any, + Callable, + Dict, + Generator, + Mapping, + Optional, + TextIO, + Tuple, + Union, +) from ..message import Message from ..typechecking import StringPathLike From 39f3c8f534b7b7387e8928ee55f6d2c648ebf829 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:35:07 +0100 Subject: [PATCH 06/12] Add type hints for format message --- can/io/trc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/io/trc.py b/can/io/trc.py index c2a647521..e11767cbc 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -378,7 +378,7 @@ def _write_header_v2_1(self, start_time: datetime) -> None: ] self.file.writelines(line + "\n" for line in lines) - def _format_message(self, msg, channel): + def _format_message(self, msg: Message, channel: int) -> str: if msg.is_extended_id: arb_id = f"{msg.arbitration_id:07X}" else: From 61923083439856d482b76c3490fd50e1b47274e8 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 12:38:00 +0100 Subject: [PATCH 07/12] Add docstring for new parameter --- can/io/trc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/can/io/trc.py b/can/io/trc.py index e11767cbc..970292c11 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -308,6 +308,7 @@ def __init__( write mode, not binary write mode. :param channel: a default channel to use when the message does not have a channel set + :param file_version: the trc file format version. Version 2.1 by default """ super().__init__(file, mode="w") self.channel = channel From 39e8a01c6c146acaa1265297c0d6765f7c8b4881 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 13:06:45 +0100 Subject: [PATCH 08/12] Fix test case for expicit file version --- test/logformats_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/logformats_test.py b/test/logformats_test.py index a2fd0fe09..e48cb6f83 100644 --- a/test/logformats_test.py +++ b/test/logformats_test.py @@ -1058,8 +1058,7 @@ class TestTrcFileFormatV1_0(TestTrcFileFormatBase): @staticmethod def Writer(filename): - writer = can.TRCWriter(filename) - writer.file_version = can.TRCFileVersion.V1_0 + writer = can.TRCWriter(filename, file_version=can.TRCFileVersion.V1_0) return writer def _setup_instance(self): From d69601849ac0852e522e62e041d141b592ca36b9 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 13:11:44 +0100 Subject: [PATCH 09/12] Add None handling for first_timestamp --- can/io/trc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/io/trc.py b/can/io/trc.py index 970292c11..0e5235598 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -389,7 +389,7 @@ def _format_message(self, msg: Message, channel: int) -> str: serialized = self._msg_fmt_string.format( msgnr=self.msgnr, - time=(msg.timestamp - self.first_timestamp) * 1000, + time=(msg.timestamp - (self.first_timestamp or 0.0)) * 1000, channel=channel, id=arb_id, dir="Rx" if msg.is_rx else "Tx", From e4efeb2ebd008e58a152b4a83d45704666f2eee0 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 13:12:19 +0100 Subject: [PATCH 10/12] Add return type hint --- can/io/trc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/io/trc.py b/can/io/trc.py index 0e5235598..9671fa1f6 100644 --- a/can/io/trc.py +++ b/can/io/trc.py @@ -324,7 +324,7 @@ def __init__( self.first_timestamp = None self._setup_file_version(file_version) - def _setup_file_version(self, file_version: Union[int, TRCFileVersion]): + def _setup_file_version(self, file_version: Union[int, TRCFileVersion]) -> None: try: self.file_version = TRCFileVersion(file_version) self._msg_fmt_string = self.MESSAGE_FORMAT_MAP[self.file_version] From 5a142c2f313dd159a625502df8dff0cbf1639bb9 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 18:25:16 +0100 Subject: [PATCH 11/12] Add documentation for TRCFileVersion --- doc/file_io.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/file_io.rst b/doc/file_io.rst index ff9431695..7911a5785 100644 --- a/doc/file_io.rst +++ b/doc/file_io.rst @@ -184,6 +184,14 @@ The following class can be used to read messages from TRC file: :members: +The following enum can be used during creation of a TRC file with :ref:`TRCWriter` to select a specific file version: + +.. autoclass:: can.TRCFileVersion + :show-inheritance: + :members: + :undoc-members: + + Rotating Loggers ---------------- From 2c9019eb74076991736a1d76e54348a870e46fee Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 18:27:35 +0100 Subject: [PATCH 12/12] Fix ref --- doc/file_io.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/file_io.rst b/doc/file_io.rst index 7911a5785..5189c6598 100644 --- a/doc/file_io.rst +++ b/doc/file_io.rst @@ -184,7 +184,7 @@ The following class can be used to read messages from TRC file: :members: -The following enum can be used during creation of a TRC file with :ref:`TRCWriter` to select a specific file version: +The following enum can be used during creation of a TRC file with `TRCWriter` to select a specific file version: .. autoclass:: can.TRCFileVersion :show-inheritance: