pyxcp 0.25.1__cp314-cp314-macosx_11_0_arm64.whl → 0.25.9__cp314-cp314-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. pyxcp/__init__.py +2 -2
  2. pyxcp/cmdline.py +14 -29
  3. pyxcp/config/__init__.py +1257 -1257
  4. pyxcp/cpp_ext/aligned_buffer.hpp +1 -1
  5. pyxcp/cpp_ext/cpp_ext.cpython-310-darwin.so +0 -0
  6. pyxcp/cpp_ext/cpp_ext.cpython-311-darwin.so +0 -0
  7. pyxcp/cpp_ext/cpp_ext.cpython-312-darwin.so +0 -0
  8. pyxcp/cpp_ext/cpp_ext.cpython-313-darwin.so +0 -0
  9. pyxcp/cpp_ext/cpp_ext.cpython-314-darwin.so +0 -0
  10. pyxcp/cpp_ext/extension_wrapper.cpp +79 -2
  11. pyxcp/cpp_ext/framing.hpp +1 -1
  12. pyxcp/cpp_ext/helper.hpp +280 -280
  13. pyxcp/cpp_ext/sxi_framing.hpp +1 -1
  14. pyxcp/daq_stim/__init__.py +95 -32
  15. pyxcp/daq_stim/optimize/binpacking.py +2 -2
  16. pyxcp/daq_stim/scheduler.cpp +8 -8
  17. pyxcp/errormatrix.py +2 -2
  18. pyxcp/examples/xcp_read_benchmark.py +2 -2
  19. pyxcp/examples/xcp_skel.py +1 -2
  20. pyxcp/examples/xcp_unlock.py +10 -12
  21. pyxcp/examples/xcp_user_supplied_driver.py +1 -2
  22. pyxcp/examples/xcphello.py +2 -15
  23. pyxcp/examples/xcphello_recorder.py +2 -2
  24. pyxcp/master/__init__.py +1 -0
  25. pyxcp/master/master.py +14 -20
  26. pyxcp/recorder/.idea/misc.xml +1 -1
  27. pyxcp/recorder/.idea/modules.xml +1 -1
  28. pyxcp/recorder/.idea/recorder.iml +1 -1
  29. pyxcp/recorder/.idea/vcs.xml +1 -1
  30. pyxcp/recorder/converter/__init__.py +4 -10
  31. pyxcp/recorder/reader.hpp +138 -138
  32. pyxcp/recorder/reco.py +1 -0
  33. pyxcp/recorder/rekorder.hpp +274 -274
  34. pyxcp/recorder/wrap.cpp +184 -184
  35. pyxcp/recorder/writer.hpp +302 -302
  36. pyxcp/scripts/xcp_daq_recorder.py +54 -0
  37. pyxcp/scripts/xcp_fetch_a2l.py +2 -2
  38. pyxcp/scripts/xcp_id_scanner.py +1 -2
  39. pyxcp/scripts/xcp_info.py +66 -51
  40. pyxcp/scripts/xcp_profile.py +1 -2
  41. pyxcp/tests/test_binpacking.py +1 -0
  42. pyxcp/tests/test_daq.py +1 -1
  43. pyxcp/tests/test_framing.py +1 -1
  44. pyxcp/tests/test_master.py +104 -83
  45. pyxcp/tests/test_transport.py +0 -1
  46. pyxcp/timing.py +1 -1
  47. pyxcp/transport/base.py +1 -1
  48. pyxcp/transport/can.py +1 -1
  49. pyxcp/transport/eth.py +1 -1
  50. pyxcp/transport/hdf5_policy.py +167 -0
  51. pyxcp/transport/sxi.py +1 -1
  52. pyxcp/transport/transport_ext.cpython-310-darwin.so +0 -0
  53. pyxcp/transport/transport_ext.cpython-311-darwin.so +0 -0
  54. pyxcp/transport/transport_ext.cpython-312-darwin.so +0 -0
  55. pyxcp/transport/transport_ext.cpython-313-darwin.so +0 -0
  56. pyxcp/transport/transport_ext.cpython-314-darwin.so +0 -0
  57. pyxcp/transport/usb_transport.py +1 -1
  58. pyxcp/{utils.py → utils/__init__.py} +1 -2
  59. pyxcp/utils/cli.py +78 -0
  60. {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/METADATA +1 -1
  61. {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/RECORD +64 -56
  62. {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/WHEEL +1 -1
  63. {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/entry_points.txt +0 -0
  64. {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env python
2
2
 
3
+ from contextlib import suppress
4
+ import json
3
5
  from time import time_ns
4
- from typing import Dict, List, Optional, TextIO, Union
6
+ from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
7
+
8
+ from pyxcp.cpp_ext.cpp_ext import DaqList, PredefinedDaqList
5
9
 
6
10
  from pyxcp import types
7
11
  from pyxcp.config import get_application
8
- from pyxcp.cpp_ext.cpp_ext import DaqList, PredefinedDaqList
9
12
  from pyxcp.daq_stim.optimize import make_continuous_blocks
10
13
  from pyxcp.daq_stim.optimize.binpacking import first_fit_decreasing
11
14
  from pyxcp.recorder import DaqOnlinePolicy as _DaqOnlinePolicy
@@ -27,6 +30,83 @@ DAQ_TIMESTAMP_SIZE = {
27
30
  }
28
31
 
29
32
 
33
+ def load_daq_lists_from_json(file_path: str) -> List[DaqList]:
34
+ """Load and validate DAQ-list from JSON file."""
35
+ with open(file_path, "r", encoding="utf-8") as f:
36
+ config = json.load(f)
37
+
38
+ if not isinstance(config, list):
39
+ raise ValueError("DAQ configuration must be a JSON array (list)")
40
+
41
+ daq_lists: List[DaqList] = []
42
+ for idx, entry in enumerate(config):
43
+ if not isinstance(entry, dict):
44
+ raise TypeError(f"Entry {idx} must be an object/dict")
45
+
46
+ required = {"name", "event_num", "stim", "enable_timestamps", "measurements", "priority", "prescaler"}
47
+ missing = required - set(entry.keys())
48
+ if missing:
49
+ raise ValueError(f"Entry {idx} missing required keys: {missing}")
50
+
51
+ # Basic type conversions / checks
52
+ name = entry["name"]
53
+ if not isinstance(name, str):
54
+ raise TypeError(f"Entry {idx} 'name' must be a string")
55
+
56
+ try:
57
+ event_num = int(entry["event_num"])
58
+ except Exception as e:
59
+ raise TypeError(f"Entry {idx} 'event_num' must be an integer") from e
60
+
61
+ stim = bool(entry["stim"])
62
+ enable_timestamps = bool(entry["enable_timestamps"])
63
+
64
+ try:
65
+ priority = int(entry["priority"])
66
+ prescaler = int(entry["prescaler"])
67
+ except Exception as e:
68
+ raise TypeError(f"Entry {idx} 'priority' and 'prescaler' must be integers") from e
69
+
70
+ measurements_raw = entry["measurements"]
71
+ if not isinstance(measurements_raw, list):
72
+ raise TypeError(f"Entry {idx} 'measurements' must be a list")
73
+
74
+ measurements: List[Tuple[str, int, int, str]] = []
75
+ for m_idx, m in enumerate(measurements_raw):
76
+ if not (isinstance(m, (list, tuple)) and len(m) == 4):
77
+ raise ValueError(f"Entry {idx} measurement {m_idx} must be a 4-element list/tuple")
78
+ m_name, m_addr, m_offset, m_type = m
79
+
80
+ if not isinstance(m_name, str):
81
+ raise TypeError(f"Entry {idx} measurement {m_idx} name must be a string")
82
+ try:
83
+ m_addr = int(m_addr)
84
+ except Exception as e:
85
+ raise TypeError(f"Entry {idx} measurement {m_idx} address must be an integer") from e
86
+ try:
87
+ m_offset = int(m_offset)
88
+ except Exception as e:
89
+ raise TypeError(f"Entry {idx} measurement {m_idx} offset must be an integer") from e
90
+ if not isinstance(m_type, str):
91
+ raise TypeError(f"Entry {idx} measurement {m_idx} type must be a string")
92
+
93
+ measurements.append((m_name, m_addr, m_offset, m_type))
94
+
95
+ daq_kwargs: Dict[str, Any] = {
96
+ "name": name,
97
+ "event_num": event_num,
98
+ "stim": stim,
99
+ "enable_timestamps": enable_timestamps,
100
+ "measurements": measurements,
101
+ "priority": priority,
102
+ "prescaler": prescaler,
103
+ }
104
+
105
+ daq_lists.append(DaqList(**daq_kwargs))
106
+
107
+ return daq_lists
108
+
109
+
30
110
  class DaqProcessor:
31
111
  def __init__(self, daq_lists: List[Union[DaqList, PredefinedDaqList]]):
32
112
  self.daq_lists = daq_lists
@@ -74,14 +154,13 @@ class DaqProcessor:
74
154
  self.selectable_timestamps = False
75
155
  max_payload_size_first = max_payload_size
76
156
  if not self.supports_timestampes:
77
- # print("NO TIMESTAMP SUPPORT")
78
- pass
157
+ self.log.info("No timestamp support")
79
158
  else:
80
159
  if self.ts_fixed:
81
- # print("Fixed timestamp")
160
+ self.log.debug("Fixed timestamps")
82
161
  max_payload_size_first = max_payload_size - self.ts_size
83
162
  else:
84
- # print("timestamp variable.")
163
+ self.log.debug("Variable timestamps.")
85
164
  self.selectable_timestamps = True
86
165
  except Exception as e:
87
166
  raise TypeError(f"DAQ_INFO corrupted: {e}") from e
@@ -159,8 +238,6 @@ class DaqProcessor:
159
238
  )
160
239
  res = self.xcp_master.startStopDaqList(0x02, i)
161
240
  self._first_pids.append(res.firstPid)
162
- if start_datetime:
163
- pass
164
241
  self.measurement_params = MeasurementParameters(
165
242
  byte_order,
166
243
  header_len,
@@ -184,26 +261,21 @@ class DaqProcessor:
184
261
  # If a fatal OS error occurred during acquisition, skip sending stop to the slave to avoid
185
262
  # cascading timeouts/unrecoverable errors and shut down transport gracefully instead.
186
263
  if getattr(self, "_fatal_os_error", False):
187
- try:
264
+ with suppress(Exception):
188
265
  self.log.error(
189
266
  "DAQ stop skipped due to previous fatal OS error (e.g., disk full or out-of-memory). Closing transport."
190
267
  )
191
- except Exception:
192
- pass # nosec
193
268
  try:
194
269
  # Best-effort: stop listener and close transport so threads finish cleanly.
195
270
  if hasattr(self.xcp_master, "transport") and self.xcp_master.transport is not None:
196
271
  # Signal listeners to stop
197
- try:
272
+ with suppress(Exception):
198
273
  if hasattr(self.xcp_master.transport, "closeEvent"):
199
274
  self.xcp_master.transport.closeEvent.set()
200
- except Exception:
201
- pass # nosec
275
+
202
276
  # Close transport connection
203
- try:
277
+ with suppress(Exception):
204
278
  self.xcp_master.transport.close()
205
- except Exception:
206
- pass # nosec
207
279
  finally:
208
280
  return
209
281
  self.xcp_master.startStopSynch(0x00)
@@ -268,30 +340,21 @@ class DaqToCsv(DaqOnlinePolicy):
268
340
  except (OSError, MemoryError) as ex:
269
341
  # Mark fatal condition to alter shutdown path and avoid further writes/commands.
270
342
  self._fatal_os_error = True
271
- try:
343
+ with suppress(Exception):
272
344
  self.log.critical(f"DAQ file write failed: {ex.__class__.__name__}: {ex}. Initiating graceful shutdown.")
273
- except Exception:
274
- pass # nosec
345
+
275
346
  # Stop listener to prevent more DAQ traffic and avoid thread crashes.
276
- try:
347
+ with suppress(Exception):
277
348
  if hasattr(self.xcp_master, "transport") and self.xcp_master.transport is not None:
278
349
  if hasattr(self.xcp_master.transport, "closeEvent"):
279
350
  self.xcp_master.transport.closeEvent.set()
280
- except Exception:
281
- pass # nosec
282
351
  # Best-effort: close any opened files to flush buffers and release resources.
283
- try:
352
+ with suppress(Exception):
284
353
  for f in getattr(self, "files", {}).values():
285
- try:
354
+ with suppress(Exception):
286
355
  f.flush()
287
- except Exception:
288
- pass # nosec
289
- try:
356
+ with suppress(Exception):
290
357
  f.close()
291
- except Exception:
292
- pass # nosec
293
- except Exception:
294
- pass # nosec
295
358
  # Do not re-raise; allow the system to continue to a controlled shutdown.
296
359
  return
297
360
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Bin-packing algorithms.
3
- """
2
+ """Bin-packing algorithms."""
3
+
4
4
  from typing import List, Optional
5
5
 
6
6
  from pyxcp.cpp_ext.cpp_ext import Bin
@@ -10,10 +10,10 @@ VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) {
10
10
  std::printf("TimerRoutine lpParam is NULL\n");
11
11
  return;
12
12
  }
13
-
13
+
14
14
  const auto* param = static_cast<const int*>(lpParam);
15
15
  std::printf("Timer routine called. Parameter is %d.\n", *param);
16
-
16
+
17
17
  if (TimerOrWaitFired) {
18
18
  std::printf("The wait timed out.\n");
19
19
  } else {
@@ -30,10 +30,10 @@ namespace {
30
30
 
31
31
  #if defined(_M_X64) || defined(_M_IX86) || defined(__SSE__)
32
32
  #include <xmmintrin.h>
33
-
33
+
34
34
  void mul4_vectorized(float* ptr) {
35
35
  if (ptr == nullptr) return;
36
-
36
+
37
37
  __m128 f = _mm_loadu_ps(ptr);
38
38
  f = _mm_mul_ps(f, f);
39
39
  _mm_storeu_ps(ptr, f);
@@ -41,10 +41,10 @@ namespace {
41
41
 
42
42
  #elif defined(_M_ARM64) || defined(__ARM_NEON)
43
43
  #include <arm_neon.h>
44
-
44
+
45
45
  void mul4_vectorized(float* ptr) {
46
46
  if (ptr == nullptr) return;
47
-
47
+
48
48
  float32x4_t f = vld1q_f32(ptr);
49
49
  f = vmulq_f32(f, f);
50
50
  vst1q_f32(ptr, f);
@@ -54,9 +54,9 @@ namespace {
54
54
  // Scalar fallback
55
55
  void mul4_vectorized(float* ptr) {
56
56
  if (ptr == nullptr) return;
57
-
57
+
58
58
  for (size_t i = 0; i < VECTOR_SIZE; ++i) {
59
59
  ptr[i] *= ptr[i];
60
60
  }
61
61
  }
62
- #endif
62
+ #endif
pyxcp/errormatrix.py CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Types and structures to support error-handling as specified by XCP.
3
- """
2
+ """Types and structures to support error-handling as specified by XCP."""
3
+
4
4
  import enum
5
5
  from collections import namedtuple
6
6
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Very basic hello-world example.
3
- """
2
+ """Very basic hello-world example."""
3
+
4
4
  import time
5
5
 
6
6
  import matplotlib.pyplot as plt
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python
2
- """Use this as a copy-and-paste template for your own scripts.
3
- """
2
+ """Use this as a copy-and-paste template for your own scripts."""
4
3
 
5
4
  from pyxcp.cmdline import ArgumentParser
6
5
 
@@ -1,20 +1,13 @@
1
1
  #!/usr/bin/env python
2
- """Very basic hello-world example.
3
- """
4
- from pyxcp.cmdline import ArgumentParser
5
-
6
-
7
- """
8
- """
2
+ """Very basic hello-world example."""
9
3
 
4
+ import argparse
10
5
 
11
- def callout(master, args):
12
- if args.sk_dll:
13
- master.seedNKeyDLL = args.sk_dll
6
+ from pyxcp.cmdline import ArgumentParser
14
7
 
15
8
 
16
- ap = ArgumentParser(callout)
17
- ap.parser.add_argument(
9
+ parser = argparse.ArgumentParser(description="XCP unlock example")
10
+ parser.add_argument(
18
11
  "-s",
19
12
  "--sk-dll",
20
13
  dest="sk_dll",
@@ -23,7 +16,12 @@ ap.parser.add_argument(
23
16
  default=None,
24
17
  )
25
18
 
19
+ ap = ArgumentParser(parser)
20
+
26
21
  with ap.run() as x:
22
+ if ap.args.sk_dll:
23
+ x.seedNKeyDLL = ap.args.sk_dll
24
+
27
25
  x.connect()
28
26
 
29
27
  print("")
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
 
3
- from typing import Dict, List, Optional
3
+ from typing import Optional
4
4
 
5
5
  import can
6
6
 
@@ -9,7 +9,6 @@ from pyxcp.transport.can import CanInterfaceBase
9
9
 
10
10
 
11
11
  class CustomCANInterface(CanInterfaceBase):
12
-
13
12
  def init(self):
14
13
  """Initialize the CAN interface here."""
15
14
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  """Very basic hello-world example."""
3
+
3
4
  from pprint import pprint
4
5
 
5
6
  from pyxcp.cmdline import ArgumentParser
@@ -9,21 +10,7 @@ from pyxcp.utils import decode_bytes
9
10
  daq_info = False
10
11
 
11
12
 
12
- def callout(master, args):
13
- global daq_info
14
- if args.daq_info:
15
- daq_info = True
16
-
17
-
18
- ap = ArgumentParser(description="pyXCP hello world.", callout=callout)
19
- ap.parser.add_argument(
20
- "-d",
21
- "--daq-info",
22
- dest="daq_info",
23
- help="Display DAQ-info",
24
- default=False,
25
- action="store_true",
26
- )
13
+ ap = ArgumentParser(description="pyXCP hello world.")
27
14
 
28
15
  with ap.run() as x:
29
16
  x.connect()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Very basic hello-world example.
3
- """
2
+ """Very basic hello-world example."""
3
+
4
4
  from pprint import pprint
5
5
 
6
6
  from pyxcp.cmdline import ArgumentParser
pyxcp/master/__init__.py CHANGED
@@ -6,4 +6,5 @@
6
6
 
7
7
  .. [1] XCP Specification, Part 2 - Protocol Layer Specification
8
8
  """
9
+
9
10
  from .master import Master # noqa: F401
pyxcp/master/master.py CHANGED
@@ -6,14 +6,16 @@
6
6
 
7
7
  .. [1] XCP Specification, Part 2 - Protocol Layer Specification
8
8
  """
9
- from __future__ import annotations
10
9
 
11
10
  import functools
12
11
  import logging
13
12
  import struct
14
13
  import traceback
15
14
  import warnings
16
- from typing import Any, Callable, Collection, Dict, Optional, Tuple, TypeVar
15
+ from contextlib import suppress
16
+ from typing import Any, Callable, Collection, TypeVar
17
+
18
+ from pyxcp.daq_stim.stim import DaqEventInfo, Stim
17
19
 
18
20
  from pyxcp import checksum, types
19
21
  from pyxcp.constants import (
@@ -26,7 +28,6 @@ from pyxcp.constants import (
26
28
  makeWordPacker,
27
29
  makeWordUnpacker,
28
30
  )
29
- from pyxcp.daq_stim.stim import DaqEventInfo, Stim
30
31
  from pyxcp.master.errorhandler import (
31
32
  SystemExit,
32
33
  disable_error_handling,
@@ -37,7 +38,6 @@ from pyxcp.master.errorhandler import (
37
38
  from pyxcp.transport.base import create_transport
38
39
  from pyxcp.utils import decode_bytes, delay, short_sleep
39
40
 
40
-
41
41
  # Type variables for better type hinting
42
42
  T = TypeVar("T")
43
43
  R = TypeVar("R")
@@ -211,7 +211,7 @@ class Master:
211
211
  self.slaveProperties.pgmProcessor = SlaveProperties()
212
212
  self.slaveProperties.transport_layer = self.transport_name.upper()
213
213
 
214
- def __enter__(self) -> Master:
214
+ def __enter__(self):
215
215
  """Context manager entry part.
216
216
 
217
217
  This method is called when entering a context manager block.
@@ -225,9 +225,7 @@ class Master:
225
225
  self.transport.connect()
226
226
  return self
227
227
 
228
- def __exit__(
229
- self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: traceback.TracebackType | None
230
- ) -> None:
228
+ def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb) -> None:
231
229
  """Context manager exit part.
232
230
 
233
231
  This method is called when exiting a context manager block.
@@ -541,11 +539,7 @@ class Master:
541
539
  """
542
540
  # Send GET_ID command to the slave
543
541
  response = self.transport.request(types.Command.GET_ID, mode)
544
-
545
- # Parse the response with the correct byte order
546
542
  result = types.GetIDResponse.parse(response, byteOrder=self.slaveProperties.byteOrder)
547
-
548
- # Extract the length from the response
549
543
  result.length = self.DWORD_unpack(response[3:7])[0]
550
544
 
551
545
  return result
@@ -751,15 +745,14 @@ class Master:
751
745
  # Larger sizes will send in multiple CAN messages
752
746
  # Each valid message will start with 0xFF followed by the upload bytes
753
747
  # The last message might be padded to the required DLC
754
- remaining_bytes = byte_count - len(response)
755
- while remaining_bytes:
748
+ remaining_bytes = byte_count - len(response) # NOTE: Due to padding the result may negative!
749
+ while remaining_bytes > 0:
756
750
  if len(self.transport.resQueue):
757
751
  data = self.transport.resQueue.popleft()
758
752
  response += data[1 : remaining_bytes + 1]
759
753
  remaining_bytes = byte_count - len(response)
760
754
  else:
761
755
  short_sleep()
762
-
763
756
  return response
764
757
 
765
758
  @wrapped
@@ -2326,7 +2319,7 @@ class Master:
2326
2319
  if self.currentProtectionStatus is None:
2327
2320
  try:
2328
2321
  status = self.getStatus()
2329
- except Exception as e: # may temporary ERR_OUT_OF_RANGE
2322
+ except Exception: # may temporary ERR_OUT_OF_RANGE
2330
2323
  return {"dbg": None, "pgm": None, "stim": None, "daq": None, "calpag": None}
2331
2324
  self._setProtectionStatus(status.resourceProtectionStatus)
2332
2325
  return self.currentProtectionStatus
@@ -2499,7 +2492,10 @@ class Master:
2499
2492
  name = STD_IDS[id_value]
2500
2493
  else:
2501
2494
  name = f"USER_{idx}"
2502
- yield id_value, name,
2495
+ yield (
2496
+ id_value,
2497
+ name,
2498
+ )
2503
2499
 
2504
2500
  return generate()
2505
2501
 
@@ -2590,10 +2586,8 @@ class Master:
2590
2586
  return (types.TryCommandResult.OK, res)
2591
2587
  finally:
2592
2588
  # Ensure suppression flag is restored even on success/other exceptions
2593
- try:
2589
+ with suppress(Exception):
2594
2590
  set_suppress_xcp_error_log(_prev_suppress)
2595
- except Exception:
2596
- pass # nosec B110
2597
2591
 
2598
2592
 
2599
2593
  def ticks_to_seconds(ticks, resolution):
@@ -1,4 +1,4 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <project version="4">
3
3
  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
4
- </project>
4
+ </project>
@@ -5,4 +5,4 @@
5
5
  <module fileurl="file://$PROJECT_DIR$/.idea/recorder.iml" filepath="$PROJECT_DIR$/.idea/recorder.iml" />
6
6
  </modules>
7
7
  </component>
8
- </project>
8
+ </project>
@@ -3,4 +3,4 @@
3
3
  <component name="SonarLintModuleSettings">
4
4
  <option name="uniqueId" value="ce2142a1-5ccc-4675-8d23-c6ee960ba851" />
5
5
  </component>
6
- </module>
6
+ </module>
@@ -7,4 +7,4 @@
7
7
  <mapping directory="$PROJECT_DIR$/simde" vcs="Git" />
8
8
  <mapping directory="$PROJECT_DIR$/simdjson" vcs="Git" />
9
9
  </component>
10
- </project>
10
+ </project>
@@ -1,5 +1,6 @@
1
1
  """Convert pyXCPs .xmraw files to common data formats."""
2
2
 
3
+ from contextlib import suppress
3
4
  import csv
4
5
  import logging
5
6
  import os
@@ -119,10 +120,8 @@ class XcpLogFileDecoder(_XcpLogFileDecoder):
119
120
  self.out_file_suffix = out_file_suffix
120
121
  self.target_type_map = target_type_map or {}
121
122
  if remove_file:
122
- try:
123
+ with suppress(FileNotFoundError):
123
124
  os.unlink(self.out_file_name)
124
- except FileNotFoundError:
125
- pass
126
125
 
127
126
  def initialize(self) -> None:
128
127
  self.on_initialize()
@@ -154,7 +153,6 @@ class XcpLogFileDecoder(_XcpLogFileDecoder):
154
153
 
155
154
 
156
155
  class CollectRows:
157
-
158
156
  def on_daq_list(self, daq_list_num: int, timestamp0: int, timestamp1: int, measurements: list) -> None:
159
157
  storage_container = self.tables[daq_list_num]
160
158
  storage_container.timestamp0.append(timestamp0)
@@ -214,7 +212,6 @@ class ArrowConverter(CollectRows, XcpLogFileDecoder):
214
212
 
215
213
 
216
214
  class CsvConverter(XcpLogFileDecoder):
217
-
218
215
  def __init__(self, recording_file_name: str, target_file_name: str = ""):
219
216
  super().__init__(
220
217
  recording_file_name=recording_file_name, out_file_suffix=".csv", remove_file=False, target_file_name=target_file_name
@@ -242,7 +239,6 @@ class CsvConverter(XcpLogFileDecoder):
242
239
 
243
240
 
244
241
  class ExcelConverter(XcpLogFileDecoder):
245
-
246
242
  def __init__(self, recording_file_name: str, target_file_name: str = ""):
247
243
  super().__init__(recording_file_name=recording_file_name, out_file_suffix=".xlsx", target_file_name=target_file_name)
248
244
 
@@ -273,7 +269,6 @@ class ExcelConverter(XcpLogFileDecoder):
273
269
 
274
270
 
275
271
  class HdfConverter(CollectRows, XcpLogFileDecoder):
276
-
277
272
  def __init__(self, recording_file_name: str, target_file_name: str = ""):
278
273
  super().__init__(recording_file_name=recording_file_name, out_file_suffix=".h5", target_file_name=target_file_name)
279
274
 
@@ -296,7 +291,6 @@ class HdfConverter(CollectRows, XcpLogFileDecoder):
296
291
 
297
292
 
298
293
  class MdfConverter(CollectRows, XcpLogFileDecoder):
299
-
300
294
  def __init__(self, recording_file_name: str, target_file_name: str = ""):
301
295
  super().__init__(
302
296
  recording_file_name=recording_file_name,
@@ -367,8 +361,8 @@ class SqliteConverter(XcpLogFileDecoder):
367
361
  self.create_table(sc)
368
362
  self.logger.info(f"Creating table {sc.name!r}.")
369
363
  self.insert_stmt[sc.name] = (
370
- f"""INSERT INTO {sc.name}({', '.join(['timestamp0', 'timestamp1'] + [r.name for r in sc.arr])})"""
371
- f""" VALUES({', '.join(["?" for _ in range(len(sc.arr) + 2)])})"""
364
+ f"""INSERT INTO {sc.name}({", ".join(["timestamp0", "timestamp1"] + [r.name for r in sc.arr])})"""
365
+ f""" VALUES({", ".join(["?" for _ in range(len(sc.arr) + 2)])})"""
372
366
  )
373
367
 
374
368
  def on_finalize(self) -> None: