objutils 0.7.0__tar.gz → 0.7.2__tar.gz

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 (78) hide show
  1. {objutils-0.7.0 → objutils-0.7.2}/PKG-INFO +2 -1
  2. {objutils-0.7.0 → objutils-0.7.2}/objutils/__init__.py +1 -1
  3. {objutils-0.7.0 → objutils-0.7.2}/objutils/section.py +70 -44
  4. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_section.py +136 -0
  5. objutils-0.7.2/objutils/utils/arduino.py +51 -0
  6. {objutils-0.7.0 → objutils-0.7.2}/objutils/version.py +1 -1
  7. {objutils-0.7.0 → objutils-0.7.2}/pyproject.toml +4 -2
  8. {objutils-0.7.0 → objutils-0.7.2}/LICENSE +0 -0
  9. {objutils-0.7.0 → objutils-0.7.2}/build_ext.py +0 -0
  10. {objutils-0.7.0 → objutils-0.7.2}/docs/README.rst +0 -0
  11. {objutils-0.7.0 → objutils-0.7.2}/objutils/.coveragerc +0 -0
  12. {objutils-0.7.0 → objutils-0.7.2}/objutils/ash.py +0 -0
  13. {objutils-0.7.0 → objutils-0.7.2}/objutils/binfile.py +0 -0
  14. {objutils-0.7.0 → objutils-0.7.2}/objutils/checksums.py +0 -0
  15. {objutils-0.7.0 → objutils-0.7.2}/objutils/cosmac.py +0 -0
  16. {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/__init__.py +0 -0
  17. {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/constants.py +0 -0
  18. {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/encoding.py +0 -0
  19. {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/lineprog.py +0 -0
  20. {objutils-0.7.0 → objutils-0.7.2}/objutils/dwarf/sm.py +0 -0
  21. {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/__init__.py +0 -0
  22. {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/arm/__init__.py +0 -0
  23. {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/arm/attributes.py +0 -0
  24. {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/defs.py +0 -0
  25. {objutils-0.7.0 → objutils-0.7.2}/objutils/elf/model.py +0 -0
  26. {objutils-0.7.0 → objutils-0.7.2}/objutils/emon52.py +0 -0
  27. {objutils-0.7.0 → objutils-0.7.2}/objutils/etek.py +0 -0
  28. {objutils-0.7.0 → objutils-0.7.2}/objutils/exceptions.py +0 -0
  29. {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/__init__.py +0 -0
  30. {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/ctre.hpp +0 -0
  31. {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/difflib.h +0 -0
  32. {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/exceptions.cpp +0 -0
  33. {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/exceptions.hpp +0 -0
  34. {objutils-0.7.0 → objutils-0.7.2}/objutils/extensions/wrapper.cpp +0 -0
  35. {objutils-0.7.0 → objutils-0.7.2}/objutils/fpc.py +0 -0
  36. {objutils-0.7.0 → objutils-0.7.2}/objutils/hexdump.py +0 -0
  37. {objutils-0.7.0 → objutils-0.7.2}/objutils/hexfile.py +0 -0
  38. {objutils-0.7.0 → objutils-0.7.2}/objutils/ieee695.py +0 -0
  39. {objutils-0.7.0 → objutils-0.7.2}/objutils/ihex.py +0 -0
  40. {objutils-0.7.0 → objutils-0.7.2}/objutils/image.py +0 -0
  41. {objutils-0.7.0 → objutils-0.7.2}/objutils/logger.py +0 -0
  42. {objutils-0.7.0 → objutils-0.7.2}/objutils/mostec.py +0 -0
  43. {objutils-0.7.0 → objutils-0.7.2}/objutils/pickleif.py +0 -0
  44. {objutils-0.7.0 → objutils-0.7.2}/objutils/rca.py +0 -0
  45. {objutils-0.7.0 → objutils-0.7.2}/objutils/readers.py +0 -0
  46. {objutils-0.7.0 → objutils-0.7.2}/objutils/registry.py +0 -0
  47. {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_arm_attrs.py +0 -0
  48. {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_extract.py +0 -0
  49. {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_info.py +0 -0
  50. {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_elf_syms.py +0 -0
  51. {objutils-0.7.0 → objutils-0.7.2}/objutils/scripts/oj_hex_info.py +0 -0
  52. {objutils-0.7.0 → objutils-0.7.2}/objutils/shf.py +0 -0
  53. {objutils-0.7.0 → objutils-0.7.2}/objutils/sig.py +0 -0
  54. {objutils-0.7.0 → objutils-0.7.2}/objutils/srec.py +0 -0
  55. {objutils-0.7.0 → objutils-0.7.2}/objutils/tek.py +0 -0
  56. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/__init__.py +0 -0
  57. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_arm_attributes.py +0 -0
  58. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_ash.py +0 -0
  59. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_checksums.py +0 -0
  60. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_cygpath.py +0 -0
  61. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_diff_bin.py +0 -0
  62. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_emon52.py +0 -0
  63. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_fpc.py +0 -0
  64. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_hexdump.py +0 -0
  65. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_hexfile.py +0 -0
  66. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_ihex.py +0 -0
  67. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_image.py +0 -0
  68. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_mostec.py +0 -0
  69. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_readers.py +0 -0
  70. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_registry.py +0 -0
  71. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_repr.py +0 -0
  72. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_shf.py +0 -0
  73. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_srec.py +0 -0
  74. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_tek.py +0 -0
  75. {objutils-0.7.0 → objutils-0.7.2}/objutils/tests/test_titext.py +0 -0
  76. {objutils-0.7.0 → objutils-0.7.2}/objutils/titxt.py +0 -0
  77. {objutils-0.7.0 → objutils-0.7.2}/objutils/utils/__init__.py +0 -0
  78. {objutils-0.7.0 → objutils-0.7.2}/objutils/utils/diff.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: objutils
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Objectfile library for Python
5
5
  License: GPLv2
6
6
  Keywords: hex files,intel hex,s19,srec,srecords,object files,map files,embedded,microcontroller,ECU,shf,rfc4194
@@ -26,6 +26,7 @@ Requires-Dist: darglint (>=1.8.1,<2.0.0)
26
26
  Requires-Dist: flake8 (>=7.0.0,<8.0.0)
27
27
  Requires-Dist: isort (>=5.13.2,<6.0.0)
28
28
  Requires-Dist: mako (>=1.3.3,<2.0.0)
29
+ Requires-Dist: numpy (<=2.2.5)
29
30
  Requires-Dist: prettier (>=0.0.7,<0.0.8)
30
31
  Requires-Dist: rich (>=13.8.1,<14.0.0)
31
32
  Requires-Dist: sqlalchemy (>=2.0.29,<3.0.0)
@@ -13,7 +13,7 @@ Registers CODECS and implements an interface to them.
13
13
  The first parameter is always the codec name.
14
14
  """
15
15
 
16
- __version__ = "0.7.0"
16
+ __version__ = "0.7.2"
17
17
 
18
18
  __copyright__ = """
19
19
  objutils - Object file library for Python.
@@ -35,11 +35,14 @@ from array import array
35
35
  from collections import namedtuple
36
36
  from copy import copy
37
37
  from dataclasses import dataclass, field
38
- from operator import attrgetter
38
+ from functools import reduce
39
+ from operator import attrgetter, mul
39
40
  from typing import Any, List, Union
40
41
 
42
+ import numpy as np
43
+
41
44
  import objutils.hexdump as hexdump
42
- from objutils.exceptions import FeatureNotAvailableError, InvalidAddressError
45
+ from objutils.exceptions import InvalidAddressError
43
46
 
44
47
 
45
48
  try:
@@ -176,6 +179,43 @@ def _data_converter(data: Union[str, bytearray, array, Any]) -> bytearray:
176
179
  return data
177
180
 
178
181
 
182
+ def fortran_array_from_buffer(arr: bytearray, shape: tuple, dtype: str) -> np.ndarray:
183
+ if len(shape) <= 2:
184
+ return np.frombuffer(arr, dtype=dtype).reshape(shape[::-1]).T
185
+ # shape = list(reversed(shape))
186
+ lhs = shape[:-2]
187
+ num_slices = reduce(mul, lhs, 1)
188
+ rhs = shape[-2:]
189
+ slice_len = reduce(mul, rhs, 1)
190
+ buf = arr.copy()
191
+ offset = 0
192
+ for idx in range(num_slices):
193
+ ddx = buf[offset : offset + slice_len]
194
+ res = np.frombuffer(ddx, dtype=dtype).reshape(*reversed(rhs)).T
195
+ buf[offset : offset + slice_len] = res.tobytes()
196
+ offset += slice_len
197
+ return np.frombuffer(buf, dtype=dtype).reshape(shape)
198
+
199
+
200
+ def fortran_array_to_buffer(array: np.ndarray) -> bytearray:
201
+ shape = array.shape
202
+ if array.ndim <= 2:
203
+ return array.tobytes("F")
204
+ else:
205
+ lhs = shape[:-2]
206
+ num_slices = reduce(mul, lhs, 1)
207
+ rhs = shape[-2:]
208
+ slice_len = reduce(mul, rhs, 1)
209
+ rs_arr = array.reshape(num_slices, *rhs)
210
+ offset = 0
211
+ result = bytearray(array.nbytes)
212
+ for idx in range(num_slices):
213
+ slice = rs_arr[idx]
214
+ result[offset : offset + slice_len] = slice.T.tobytes()
215
+ offset += slice_len
216
+ return result
217
+
218
+
179
219
  @dataclass(repr=False, order=True)
180
220
  class Section:
181
221
  """Manage sections.
@@ -206,7 +246,7 @@ class Section:
206
246
  def tolist(self) -> List[int]:
207
247
  return array("B", self.data).tolist()
208
248
 
209
- def _verify_dtype(self, dtype):
249
+ def _verify_dtype(self, dtype: str) -> str:
210
250
  """ """
211
251
  dtype = dtype.lower().strip()
212
252
  if dtype == "byte":
@@ -219,7 +259,7 @@ class Section:
219
259
  raise TypeError(f"Invalid datatype {dtype!r}")
220
260
  return dtype.split("_")
221
261
 
222
- def _getformat(self, dtype, length=1):
262
+ def _getformat(self, dtype: str, length: int = 1) -> str:
223
263
  """ """
224
264
  fmt, bo = self._verify_dtype(dtype)
225
265
 
@@ -228,7 +268,7 @@ class Section:
228
268
  else:
229
269
  return f"{BYTEORDER.get(bo)}{FORMATS.get(fmt)}"
230
270
 
231
- def read(self, addr, length, **kws):
271
+ def read(self, addr: int, length: int, **kws) -> bytes:
232
272
  """
233
273
  Parameters
234
274
  ----------
@@ -244,7 +284,7 @@ class Section:
244
284
  data = self.data[offset : offset + length]
245
285
  return data
246
286
 
247
- def write(self, addr, data, **kws):
287
+ def write(self, addr: int, data: bytes, **kws) -> None:
248
288
  """
249
289
  Parameters
250
290
  ----------
@@ -262,7 +302,7 @@ class Section:
262
302
  raise InvalidAddressError(f"write(0x{addr:08x}) access out of bounds.")
263
303
  self.data[offset : offset + length] = data
264
304
 
265
- def read_numeric(self, addr, dtype, **kws):
305
+ def read_numeric(self, addr: int, dtype: str, **kws) -> Union[int, float]:
266
306
  offset = addr - self.start_address
267
307
  if offset < 0:
268
308
  raise InvalidAddressError(f"read_numeric(0x{addr:08x}) access out of bounds.")
@@ -276,7 +316,7 @@ class Section:
276
316
  data = self.apply_bitmask(data, dtype, bit_mask)
277
317
  return struct.unpack(fmt, data)[0]
278
318
 
279
- def apply_bitmask(self, data, dtype, bit_mask):
319
+ def apply_bitmask(self, data: bytes, dtype: str, bit_mask: int) -> bytes:
280
320
  """ """
281
321
  dtype, byteorder = dtype.lower().strip().split("_")
282
322
  byteorder = "little" if byteorder == "le" else "big"
@@ -286,7 +326,7 @@ class Section:
286
326
  tmp &= bit_mask
287
327
  return tmp.to_bytes(data_size, byteorder, signed=False)
288
328
 
289
- def write_numeric(self, addr, value, dtype, **kws):
329
+ def write_numeric(self, addr: int, value: Union[int, float], dtype: str, **kws) -> None:
290
330
  offset = addr - self.start_address
291
331
  if offset < 0:
292
332
  raise InvalidAddressError(f"write_numeric(0x{addr:08x}) access out of bounds.")
@@ -299,7 +339,7 @@ class Section:
299
339
 
300
340
  self.data[offset : offset + data_size] = struct.pack(fmt, value)
301
341
 
302
- def read_numeric_array(self, addr, length, dtype, **kws):
342
+ def read_numeric_array(self, addr: int, length: int, dtype: str, **kws) -> Union[List[int], List[float]]:
303
343
  offset = addr - self.start_address
304
344
  if offset < 0:
305
345
  raise InvalidAddressError(f"read_numeric_array(0x{addr:08x}) access out of bounds.")
@@ -310,7 +350,7 @@ class Section:
310
350
  data = self.data[offset : offset + data_size]
311
351
  return struct.unpack(fmt, data)
312
352
 
313
- def write_numeric_array(self, addr, data, dtype, **kws):
353
+ def write_numeric_array(self, addr: int, data: Union[List[int], List[float]], dtype: str, **kws) -> None:
314
354
  if not hasattr(data, "__iter__"):
315
355
  raise TypeError("data must be iterable")
316
356
  length = len(data)
@@ -323,7 +363,7 @@ class Section:
323
363
  raise InvalidAddressError(f"write_numeric_array(0x{addr:08x}) access out of bounds.")
324
364
  self.data[offset : offset + data_size] = struct.pack(fmt, *data)
325
365
 
326
- def read_string(self, addr, encoding="latin1", length=-1, **kws):
366
+ def read_string(self, addr: int, encoding: str = "latin1", length: int = -1, **kws) -> str:
327
367
  offset = addr - self.start_address
328
368
  if offset < 0:
329
369
  raise InvalidAddressError(f"read_string(0x{addr:08x}) access out of bounds.")
@@ -335,19 +375,15 @@ class Section:
335
375
  raise TypeError("Unterminated String!!!") # TODO: Testcase.
336
376
  return self.data[offset : offset + pos].decode(encoding=encoding)
337
377
 
338
- def write_string(self, addr, value, encoding="latin1", **kws):
378
+ def write_string(self, addr: int, value: str, encoding: str = "latin1", **kws):
339
379
  offset = addr - self.start_address
340
380
  if offset < 0:
341
381
  raise InvalidAddressError(f"write_string(0x{addr:08x}) access out of bounds.")
342
382
  self.data[offset : offset + len(value)] = bytes(value, encoding=encoding)
343
383
  self.data[offset + len(value)] = 0
344
384
 
345
- def write_ndarray(self, addr, array, order=None, **kws):
385
+ def write_ndarray(self, addr: int, array: np.ndarray, order: str = None, **kws) -> None:
346
386
  """ """
347
- try:
348
- import numpy as np
349
- except ImportError as e:
350
- raise FeatureNotAvailableError("write_ndarray() requires Numpy.") from e
351
387
  offset = addr - self.start_address
352
388
  if offset < 0:
353
389
  raise InvalidAddressError(f"write_ndarray(0x{addr:08x}) access out of bounds.")
@@ -356,36 +392,26 @@ class Section:
356
392
  data_size = array.nbytes
357
393
  if offset + data_size > self.length:
358
394
  raise InvalidAddressError(f"write_ndarray(0x{addr:08x}) access out of bounds.")
359
- self.data[offset : offset + data_size] = array.tobytes()
395
+ if order is not None and order == "F":
396
+ self.data[offset : offset + data_size] = fortran_array_to_buffer(array=array)
397
+ else:
398
+ self.data[offset : offset + data_size] = array.tobytes()
360
399
 
361
- def read_ndarray(self, addr, length, dtype, shape=None, order=None, **kws):
400
+ def read_ndarray(self, addr: int, length: int, dtype: str, shape: tuple = None, order: str = None, **kws) -> np.ndarray:
362
401
  """ """
363
- try:
364
- import numpy as np
365
- except ImportError as e:
366
- raise FeatureNotAvailableError("read_ndarray() requires Numpy.") from e
367
402
  offset = addr - self.start_address
368
403
  if offset < 0:
369
404
  raise InvalidAddressError(f"read_ndarray(0x{addr:08x}) access out of bounds.")
370
405
  if offset + length > self.length:
371
406
  raise InvalidAddressError(f"read_ndarray(0x{addr:08x}) access out of bounds.")
372
-
373
- """
374
- If the buffer has data that is not in machine byte-order, this should
375
- be specified as part of the data-type, e.g.::
376
-
377
- >>> dt = np.dtype(int)
378
- >>> dt = dt.newbyteorder('>')
379
- >>> np.frombuffer(buf, dtype=dt)
380
- """
381
407
  type_, byte_order = self._verify_dtype(dtype)
382
408
  dt = np.dtype(type_)
383
409
  dt = dt.newbyteorder(BYTEORDER.get(byte_order))
384
- arr = np.frombuffer(self.data[offset : offset + length], dtype=dt).reshape(shape)
385
- if order == "F":
386
- return arr.T # Fortran deposit, i.e. col-maj means transposition.
410
+ if order is not None and order == "F":
411
+ arr = fortran_array_from_buffer(arr=self.data[offset : offset + length], shape=shape, dtype=dt)
387
412
  else:
388
- return arr
413
+ arr = np.frombuffer(self.data[offset : offset + length], dtype=dt).reshape(shape)
414
+ return arr
389
415
 
390
416
  """
391
417
  def write_timestamp():
@@ -395,33 +421,33 @@ class Section:
395
421
  pass
396
422
  """
397
423
 
398
- def find(self, expr, addr=-1):
424
+ def find(self, expr: str, addr: int = -1) -> int:
399
425
  for item in re.finditer(bytes(expr), self.data):
400
426
  yield (self.start_address + item.start(), item.end() - item.start())
401
427
 
402
- def __repr__(self):
428
+ def __repr__(self) -> str:
403
429
  return "Section(address = 0X{:08X}, length = {:d}, data = {})".format(
404
430
  self.start_address,
405
431
  self.length,
406
432
  self.repr.repr(memoryview(self.data).tobytes()),
407
433
  )
408
434
 
409
- def __len__(self):
435
+ def __len__(self) -> int:
410
436
  return len(self.data)
411
437
 
412
438
  @property
413
- def length(self):
439
+ def length(self) -> int:
414
440
  return len(self)
415
441
 
416
- def __contains__(self, addr):
442
+ def __contains__(self, addr) -> bool:
417
443
  return self.start_address <= addr < (self.start_address + self.length)
418
444
 
419
445
  @property
420
- def address(self): # Alias
446
+ def address(self) -> int: # Alias
421
447
  return self.start_address
422
448
 
423
449
 
424
- def join_sections(sections):
450
+ def join_sections(sections: List[Section]) -> List[Section]:
425
451
  result_sections = []
426
452
  sections.sort(key=attrgetter("start_address"))
427
453
  prev_section = Section()
@@ -631,3 +631,139 @@ def test_read_ndarray_flat():
631
631
 
632
632
  result = sec.read_ndarray(0x1000, 24, "int32_le")
633
633
  assert np.array_equal(result, np.array([11, 22, 33, 44, 55, 66]))
634
+
635
+
636
+ @pytest.mark.skipif("NUMPY_SUPPORT == False")
637
+ def test_read_ndarray_fortan_01():
638
+ sec = Section(
639
+ start_address=0x1000,
640
+ data=bytearray(b"\x01\x00\x04\x00\x07\x00\n\x00\x02\x00\x05\x00\x08\x00\x0b\x00\x03\x00\x06\x00\t\x00\x0c\x00"),
641
+ )
642
+
643
+ result = sec.read_ndarray(0x1000, 24, shape=(3, 4), order="F", dtype="int16_le")
644
+ assert np.array_equal(
645
+ result,
646
+ np.array(
647
+ [
648
+ [1, 2, 3],
649
+ [
650
+ 4,
651
+ 5,
652
+ 6,
653
+ ],
654
+ [7, 8, 9],
655
+ [10, 11, 12],
656
+ ],
657
+ dtype=np.int16,
658
+ ),
659
+ )
660
+
661
+
662
+ @pytest.mark.skipif("NUMPY_SUPPORT == False")
663
+ def test_read_ndarray_fortan_02():
664
+ sec = Section(
665
+ start_address=0x1000,
666
+ data=[
667
+ 1,
668
+ 3,
669
+ 5,
670
+ 2,
671
+ 4,
672
+ 6,
673
+ 7,
674
+ 9,
675
+ 11,
676
+ 8,
677
+ 10,
678
+ 12,
679
+ 13,
680
+ 15,
681
+ 17,
682
+ 14,
683
+ 16,
684
+ 18,
685
+ 19,
686
+ 21,
687
+ 23,
688
+ 20,
689
+ 22,
690
+ 24,
691
+ 25,
692
+ 27,
693
+ 29,
694
+ 26,
695
+ 28,
696
+ 30,
697
+ 31,
698
+ 33,
699
+ 35,
700
+ 32,
701
+ 34,
702
+ 36,
703
+ 37,
704
+ 39,
705
+ 41,
706
+ 38,
707
+ 40,
708
+ 42,
709
+ 43,
710
+ 45,
711
+ 47,
712
+ 44,
713
+ 46,
714
+ 48,
715
+ ],
716
+ )
717
+
718
+ result = sec.read_ndarray(0x1000, 48, shape=(2, 4, 3, 2), order="F", dtype="int8_le")
719
+ assert np.array_equal(
720
+ result,
721
+ np.array(
722
+ [
723
+ [
724
+ [[1, 2], [3, 4], [5, 6]],
725
+ [[7, 8], [9, 10], [11, 12]],
726
+ [[13, 14], [15, 16], [17, 18]],
727
+ [[19, 20], [21, 22], [23, 24]],
728
+ ],
729
+ [
730
+ [[25, 26], [27, 28], [29, 30]],
731
+ [[31, 32], [33, 34], [35, 36]],
732
+ [[37, 38], [39, 40], [41, 42]],
733
+ [[43, 44], [45, 46], [47, 48]],
734
+ ],
735
+ ],
736
+ dtype=np.int8,
737
+ ),
738
+ )
739
+
740
+
741
+ @pytest.mark.skipif("NUMPY_SUPPORT == False")
742
+ def test_write_ndarray_fortan_01():
743
+ sec = Section(start_address=0x1000, data=bytearray(128))
744
+ arr = np.array(
745
+ [
746
+ [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]], [[13, 14], [15, 16], [17, 18]], [[19, 20], [21, 22], [23, 24]]],
747
+ [
748
+ [[25, 26], [27, 28], [29, 30]],
749
+ [[31, 32], [33, 34], [35, 36]],
750
+ [[37, 38], [39, 40], [41, 42]],
751
+ [[43, 44], [45, 46], [47, 48]],
752
+ ],
753
+ ],
754
+ dtype=np.int8,
755
+ )
756
+ sec.write_ndarray(0x1000, arr, order="F")
757
+ assert sec.read(0x1000, 48) == bytearray(
758
+ b"\x01\x03\x05\x02\x04\x06\x07\t\x0b\x08\n\x0c\r\x0f\x11\x0e\x10\x12\x13\x15\x17\x14\x16\x18\x19\x1b\x1d\x1a\x1c\x1e\x1f!# \"$%')&(*+-/,.0"
759
+ )
760
+
761
+
762
+ @pytest.mark.skipif("NUMPY_SUPPORT == False")
763
+ def test_write_ndarray_fortan_02():
764
+ sec = Section(start_address=0x1000, data=bytearray(128))
765
+ arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], dtype=np.int16)
766
+ sec.write_ndarray(0x1000, arr, order="F")
767
+ assert sec.read(0x1000, 24) == bytearray(
768
+ b"\x01\x00\x04\x00\x07\x00\n\x00\x02\x00\x05\x00\x08\x00\x0b\x00\x03\x00\x06\x00\t\x00\x0c\x00"
769
+ )
@@ -0,0 +1,51 @@
1
+ #!/bin/python
2
+
3
+ import hashlib
4
+ import tempfile
5
+ from pathlib import Path
6
+
7
+
8
+ ARDUINO_TEMP_BASE_A = Path(tempfile.gettempdir()) / "arduino" / "sketches"
9
+ ARDUINO_TEMP_BASE_B = Path(Path.home()) / "AppData" / "Local" / "arduino" / "sketches"
10
+
11
+ SUFFIXES = [".eep", ".elf", ".hex", ".map"]
12
+
13
+
14
+ def build_artifacts(sketch_name: str) -> Path:
15
+ """Get filenames of Arduino build artifact, e.g. elf-file."""
16
+ result = {}
17
+ path = Path(sketch_name)
18
+ if not path.exists():
19
+ raise ValueError(f"{sketch_name} not found.")
20
+ if path.is_file():
21
+ if path.suffix != ".ino":
22
+ raise ValueError("Expected file-extension '.ino'.")
23
+ path_to_dir = str(path.parent)
24
+ elif path.is_dir():
25
+ path_to_dir = str(path)
26
+ if ARDUINO_TEMP_BASE_A.exists():
27
+ base = ARDUINO_TEMP_BASE_A
28
+ elif ARDUINO_TEMP_BASE_B.exists():
29
+ base = ARDUINO_TEMP_BASE_B
30
+ else:
31
+ raise ValueError("Could not determine Arduino base directory")
32
+ sketch_dir = base / hashlib.md5(path_to_dir.encode("ascii")).hexdigest().upper()
33
+ if not sketch_dir.exists():
34
+ ValueError(f"directory {sketch_dir!r} does not exist.")
35
+ result["DIRECTORY"] = sketch_dir
36
+ NAMES = [f for f in sketch_dir.iterdir() if not f.is_dir() and f.suffix in SUFFIXES and "with_bootloader" not in f.name]
37
+ for name in NAMES:
38
+ result[name.suffix[1:].upper()] = name
39
+ return result
40
+
41
+
42
+ if __name__ == "__main__":
43
+ import sys
44
+
45
+ if len(sys.argv) != 2:
46
+ print("usage: arduino-build-artifacts <sketch-name>")
47
+ sys.exit(1)
48
+ artifacts = build_artifacts(sys.argv[1])
49
+ print()
50
+ for name, value in artifacts.items():
51
+ print(f"{name:9s}: {value}")
@@ -1,3 +1,3 @@
1
1
  """ objutils version module """
2
2
 
3
- __version__ = "0.7.0"
3
+ __version__ = "0.7.2"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "objutils"
3
- version = "0.7.0"
3
+ version = "0.7.2"
4
4
  description = "Objectfile library for Python"
5
5
  authors = ["Christoph Schueler <cpu12.gems@googlemail.com>"]
6
6
  license = "GPLv2"
@@ -49,6 +49,7 @@ oj-elf-syms = "objutils.scripts.oj_elf_syms:main"
49
49
  oj-hex-info = "objutils.scripts.oj_hex_info:main"
50
50
  oj-elf-arm-attrs = "objutils.scripts.oj_elf_arm_attrs:main"
51
51
  oj-elf-extract = "objutils.scripts.oj_elf_extract:main"
52
+ arduino-build-artifacts = "objutils.utils.arduino:main"
52
53
 
53
54
 
54
55
  [tool.poetry.dependencies]
@@ -63,13 +64,14 @@ prettier = "^0.0.7"
63
64
  black = "^24.4.1"
64
65
  rich = "^13.8.1"
65
66
  bandit = "^1.8.2"
67
+ numpy = "<=2.2.5"
66
68
 
67
69
 
68
70
  [tool.poetry.group.dev.dependencies]
69
71
  pre-commit = "^3.7.0"
70
72
  pytest = "^8.1.1"
71
73
  flake8-bugbear = "^24.4.21"
72
- mccabe = "^0.7.0"
74
+ mccabe = "^0.7.2"
73
75
  pycodestyle = "^2.11.1"
74
76
  pyflakes = "^3.2.0"
75
77
  ruff = "^0.4.1"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes