numbers-parser 4.10.5__tar.gz → 4.10.6__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 (58) hide show
  1. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/PKG-INFO +3 -3
  2. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/README.md +2 -2
  3. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/pyproject.toml +3 -2
  4. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/cell.py +49 -27
  5. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/document.py +30 -13
  6. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/iwafile.py +2 -2
  7. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/iwork.py +2 -2
  8. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/model.py +48 -18
  9. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/LICENSE.rst +0 -0
  10. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/__init__.py +0 -0
  11. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/_cat_numbers.py +0 -0
  12. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/_unpack_numbers.py +0 -0
  13. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/bullets.py +0 -0
  14. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/constants.py +0 -0
  15. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/containers.py +0 -0
  16. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/currencies.py +0 -0
  17. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/data/empty.numbers +0 -0
  18. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/exceptions.py +0 -0
  19. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/experimental.py +0 -0
  20. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/formula.py +0 -0
  21. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TNArchives_pb2.py +0 -0
  22. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TNArchives_sos_pb2.py +0 -0
  23. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TNCommandArchives_pb2.py +0 -0
  24. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TNCommandArchives_sos_pb2.py +0 -0
  25. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSAArchives_pb2.py +0 -0
  26. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSAArchives_sos_pb2.py +0 -0
  27. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSACommandArchives_sos_pb2.py +0 -0
  28. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCEArchives_pb2.py +0 -0
  29. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCH3DArchives_pb2.py +0 -0
  30. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCHArchives_Common_pb2.py +0 -0
  31. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCHArchives_GEN_pb2.py +0 -0
  32. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCHArchives_pb2.py +0 -0
  33. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCHArchives_sos_pb2.py +0 -0
  34. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCHCommandArchives_pb2.py +0 -0
  35. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSCHPreUFFArchives_pb2.py +0 -0
  36. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSDArchives_pb2.py +0 -0
  37. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSDArchives_sos_pb2.py +0 -0
  38. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSDCommandArchives_pb2.py +0 -0
  39. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSKArchives_pb2.py +0 -0
  40. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSKArchives_sos_pb2.py +0 -0
  41. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSPArchiveMessages_pb2.py +0 -0
  42. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSPDatabaseMessages_pb2.py +0 -0
  43. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSPMessages_pb2.py +0 -0
  44. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSSArchives_pb2.py +0 -0
  45. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSSArchives_sos_pb2.py +0 -0
  46. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSTArchives_pb2.py +0 -0
  47. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSTArchives_sos_pb2.py +0 -0
  48. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSTCommandArchives_pb2.py +0 -0
  49. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSTStylePropertyArchiving_pb2.py +0 -0
  50. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSWPArchives_pb2.py +0 -0
  51. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSWPArchives_sos_pb2.py +0 -0
  52. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/TSWPCommandArchives_pb2.py +0 -0
  53. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/__init__.py +0 -0
  54. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/fontmap.py +0 -0
  55. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/generated/functionmap.py +0 -0
  56. {numbers_parser-4.10.5/src/numbers_parser → numbers_parser-4.10.6/src/numbers_parser/generated}/mapping.py +24 -24
  57. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/numbers_cache.py +0 -0
  58. {numbers_parser-4.10.5 → numbers_parser-4.10.6}/src/numbers_parser/numbers_uuid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbers-parser
3
- Version: 4.10.5
3
+ Version: 4.10.6
4
4
  Summary: Read and write Apple Numbers spreadsheets
5
5
  Home-page: https://github.com/masaccio/numbers-parser
6
6
  License: MIT
@@ -34,8 +34,8 @@ Description-Content-Type: text/markdown
34
34
  [![Test Status](https://github.com/masaccio/numbers-parser/actions/workflows/run-all-tests.yml/badge.svg)](https://github.com/masaccio/numbers-parser/actions/workflows/run-all-tests.yml)[![Security Checks](https://github.com/masaccio/numbers-parser/actions/workflows/codeql.yml/badge.svg)](https://github.com/masaccio/numbers-parser/actions/workflows/codeql.yml)[![Code Coverage](https://codecov.io/gh/masaccio/numbers-parser/branch/main/graph/badge.svg?token=EKIUFGT05E)](https://codecov.io/gh/masaccio/numbers-parser)[![PyPI Version](https://badge.fury.io/py/numbers-parser.svg)](https://badge.fury.io/py/numbers-parser)
35
35
 
36
36
  `numbers-parser` is a Python module for parsing [Apple Numbers](https://www.apple.com/numbers/)`.numbers` files. It supports Numbers files
37
- generated by Numbers version 10.3, and up with the latest tested version being 13.2
38
- (current as of September 2023).
37
+ generated by Numbers version 10.3, and up with the latest tested version being 14.0
38
+ (current as of April 2024).
39
39
 
40
40
  It supports and is tested against Python versions from 3.9 onwards. It is not compatible
41
41
  with earlier versions of Python.
@@ -3,8 +3,8 @@
3
3
  [![Test Status](https://github.com/masaccio/numbers-parser/actions/workflows/run-all-tests.yml/badge.svg)](https://github.com/masaccio/numbers-parser/actions/workflows/run-all-tests.yml)[![Security Checks](https://github.com/masaccio/numbers-parser/actions/workflows/codeql.yml/badge.svg)](https://github.com/masaccio/numbers-parser/actions/workflows/codeql.yml)[![Code Coverage](https://codecov.io/gh/masaccio/numbers-parser/branch/main/graph/badge.svg?token=EKIUFGT05E)](https://codecov.io/gh/masaccio/numbers-parser)[![PyPI Version](https://badge.fury.io/py/numbers-parser.svg)](https://badge.fury.io/py/numbers-parser)
4
4
 
5
5
  `numbers-parser` is a Python module for parsing [Apple Numbers](https://www.apple.com/numbers/)`.numbers` files. It supports Numbers files
6
- generated by Numbers version 10.3, and up with the latest tested version being 13.2
7
- (current as of September 2023).
6
+ generated by Numbers version 10.3, and up with the latest tested version being 14.0
7
+ (current as of April 2024).
8
8
 
9
9
  It supports and is tested against Python versions from 3.9 onwards. It is not compatible
10
10
  with earlier versions of Python.
@@ -12,7 +12,7 @@ name = "numbers-parser"
12
12
  packages = [{include = "numbers_parser", from = "src"}]
13
13
  readme = "README.md"
14
14
  repository = "https://github.com/masaccio/numbers-parser"
15
- version = "4.10.5"
15
+ version = "4.10.6"
16
16
 
17
17
  [tool.poetry.scripts]
18
18
  cat-numbers = "numbers_parser._cat_numbers:main"
@@ -108,10 +108,11 @@ profile = "black"
108
108
  exclude = [
109
109
  # Machine-generated files
110
110
  ".bootstrap/*",
111
+ ".tox/*",
112
+ ".vscode/*",
111
113
  "src/numbers_parser/generated/*",
112
114
  # Third-party files not to lint
113
115
  "src/debug/lldbutil.py", # Tox
114
- ".tox/*",
115
116
  ]
116
117
  fix = true
117
118
  ignore = [
@@ -587,8 +587,9 @@ class CellStorageFlags:
587
587
 
588
588
  class Cell(CellStorageFlags, Cacheable):
589
589
  """.. NOTE::
590
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
591
- """
590
+
591
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
592
+ """ # fmt: skip
592
593
 
593
594
  def __init__(self, row: int, col: int, value) -> None:
594
595
  self._value = value
@@ -679,7 +680,7 @@ class Cell(CellStorageFlags, Cacheable):
679
680
  bullet or numbering character. Newlines are not included in the
680
681
  bullet list.
681
682
 
682
- Example:
683
+ Example
683
684
  -------
684
685
  .. code-block:: python
685
686
 
@@ -741,7 +742,7 @@ class Cell(CellStorageFlags, Cacheable):
741
742
  def style(self) -> Union[Style, None]:
742
743
  """Style | None: The :class:`Style` associated with the cell or ``None``.
743
744
 
744
- Warns:
745
+ Warns
745
746
  -----
746
747
  UnsupportedWarning: On assignment; use
747
748
  :py:meth:`numbers_parser.Table.set_cell_style` instead.
@@ -762,7 +763,7 @@ class Cell(CellStorageFlags, Cacheable):
762
763
  def border(self) -> Union[CellBorder, None]:
763
764
  """CellBorder| None: The :class:`CellBorder` associated with the cell or ``None``.
764
765
 
765
- Warns:
766
+ Warns
766
767
  -----
767
768
  UnsupportedWarning: On assignment; use
768
769
  :py:meth:`numbers_parser.Table.set_cell_border` instead.
@@ -820,7 +821,12 @@ class Cell(CellStorageFlags, Cacheable):
820
821
 
821
822
  @classmethod
822
823
  def _from_storage( # noqa: PLR0913, PLR0912
823
- cls, table_id: int, row: int, col: int, buffer: bytearray, model: object,
824
+ cls,
825
+ table_id: int,
826
+ row: int,
827
+ col: int,
828
+ buffer: bytearray,
829
+ model: object,
824
830
  ) -> None:
825
831
  d128 = None
826
832
  double = None
@@ -1029,7 +1035,7 @@ class Cell(CellStorageFlags, Cacheable):
1029
1035
  flags = 2
1030
1036
  length += 8
1031
1037
  cell_type = TSTArchives.durationCellType
1032
- value = value = pack("<d", float(self.value.total_seconds()))
1038
+ value = pack("<d", float(self.value.total_seconds()))
1033
1039
  elif isinstance(self, EmptyCell):
1034
1040
  flags = 0
1035
1041
  cell_type = TSTArchives.emptyCellValueType
@@ -1139,8 +1145,12 @@ class Cell(CellStorageFlags, Cacheable):
1139
1145
 
1140
1146
  image_id = style.cell_properties.cell_fill.image.imagedata.identifier
1141
1147
  datas = self._model.objects[PACKAGE_ID].datas
1142
- stored_filename = next(x.file_name for x in datas if x.identifier == image_id)
1143
- preferred_filename = next(x.preferred_file_name for x in datas if x.identifier == image_id)
1148
+ stored_filename = next(
1149
+ x.file_name for x in datas if x.identifier == image_id
1150
+ ) # pragma: nocover (issue-1333)
1151
+ preferred_filename = next(
1152
+ x.preferred_file_name for x in datas if x.identifier == image_id
1153
+ ) # pragma: nocover (issue-1333)
1144
1154
  all_paths = self._model.objects.file_store.keys()
1145
1155
  image_pathnames = [x for x in all_paths if x == f"Data/{stored_filename}"]
1146
1156
 
@@ -1186,7 +1196,9 @@ class Cell(CellStorageFlags, Cacheable):
1186
1196
  )
1187
1197
  else:
1188
1198
  formatted_value = _decode_number_format(
1189
- custom_format, self._d128, format_map[format_uuid].name,
1199
+ custom_format,
1200
+ self._d128,
1201
+ format_map[format_uuid].name,
1190
1202
  )
1191
1203
  elif format.format_type == FormatType.DECIMAL:
1192
1204
  return _format_decimal(self._d128, format)
@@ -1344,8 +1356,9 @@ class Cell(CellStorageFlags, Cacheable):
1344
1356
 
1345
1357
  class NumberCell(Cell):
1346
1358
  """.. NOTE::
1347
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1348
- """
1359
+
1360
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1361
+ """ # fmt: skip
1349
1362
 
1350
1363
  def __init__(self, row: int, col: int, value: float, cell_type=CellType.NUMBER) -> None:
1351
1364
  self._type = cell_type
@@ -1368,8 +1381,9 @@ class TextCell(Cell):
1368
1381
 
1369
1382
  class RichTextCell(Cell):
1370
1383
  """.. NOTE::
1371
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1372
- """
1384
+
1385
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1386
+ """ # fmt: skip
1373
1387
 
1374
1388
  def __init__(self, row: int, col: int, value) -> None:
1375
1389
  super().__init__(row, col, value["text"])
@@ -1411,7 +1425,7 @@ class RichTextCell(Cell):
1411
1425
  of cells where :py:attr:`numbers_parser.Cell.is_bulleted` is ``True`` is a
1412
1426
  list of text and URL tuples.
1413
1427
 
1414
- Example:
1428
+ Example
1415
1429
  -------
1416
1430
  .. code-block:: python
1417
1431
 
@@ -1428,8 +1442,9 @@ class BulletedTextCell(RichTextCell):
1428
1442
 
1429
1443
  class EmptyCell(Cell):
1430
1444
  """.. NOTE::
1431
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1432
- """
1445
+
1446
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1447
+ """ # fmt: skip
1433
1448
 
1434
1449
  def __init__(self, row: int, col: int) -> None:
1435
1450
  super().__init__(row, col, None)
@@ -1446,8 +1461,9 @@ class EmptyCell(Cell):
1446
1461
 
1447
1462
  class BoolCell(Cell):
1448
1463
  """.. NOTE::
1449
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1450
- """
1464
+
1465
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1466
+ """ # fmt: skip
1451
1467
 
1452
1468
  def __init__(self, row: int, col: int, value: bool) -> None:
1453
1469
  super().__init__(row, col, value)
@@ -1461,8 +1477,9 @@ class BoolCell(Cell):
1461
1477
 
1462
1478
  class DateCell(Cell):
1463
1479
  """.. NOTE::
1464
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1465
- """
1480
+
1481
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1482
+ """ # fmt: skip
1466
1483
 
1467
1484
  def __init__(self, row: int, col: int, value: DateTime) -> None:
1468
1485
  super().__init__(row, col, value)
@@ -1485,8 +1502,9 @@ class DurationCell(Cell):
1485
1502
 
1486
1503
  class ErrorCell(Cell):
1487
1504
  """.. NOTE::
1488
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1489
- """
1505
+
1506
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1507
+ """ # fmt: skip
1490
1508
 
1491
1509
  def __init__(self, row: int, col: int) -> None:
1492
1510
  super().__init__(row, col, None)
@@ -1499,8 +1517,9 @@ class ErrorCell(Cell):
1499
1517
 
1500
1518
  class MergedCell(Cell):
1501
1519
  """.. NOTE::
1502
- Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1503
- """
1520
+
1521
+ Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
1522
+ """ # fmt: skip
1504
1523
 
1505
1524
  def __init__(self, row: int, col: int) -> None:
1506
1525
  super().__init__(row, col, None)
@@ -1643,7 +1662,8 @@ def _decode_number_format(format, value, name): # noqa: PLR0912
1643
1662
  if format.currency_code != "":
1644
1663
  # Replace currency code with symbol and no-break space
1645
1664
  custom_format_string = custom_format_string.replace(
1646
- "\u00a4", format.currency_code + "\u00a0",
1665
+ "\u00a4",
1666
+ format.currency_code + "\u00a0",
1647
1667
  )
1648
1668
 
1649
1669
  if (match := re.search(r"([#0.,]+(E[+]\d+)?)", custom_format_string)) is None:
@@ -1794,7 +1814,9 @@ def _format_decimal(value: float, format, percent: bool = False) -> str:
1794
1814
  else:
1795
1815
  formatted_value = sigfig.round(value, MAX_SIGNIFICANT_DIGITS, type=str, warn=False)
1796
1816
  formatted_value = sigfig.round(
1797
- formatted_value, decimals=format.decimal_places, type=str,
1817
+ formatted_value,
1818
+ decimals=format.decimal_places,
1819
+ type=str,
1798
1820
  )
1799
1821
  if format.show_thousands_separator:
1800
1822
  formatted_value = sigfig.round(formatted_value, spacer=",", spacing=3, type=str)
@@ -199,7 +199,13 @@ class Document:
199
199
  Table(
200
200
  self._model,
201
201
  self._model.add_table(
202
- new_sheet_id, table_name, prev_table_id, 0, 0, num_rows, num_cols,
202
+ new_sheet_id,
203
+ table_name,
204
+ prev_table_id,
205
+ 0,
206
+ 0,
207
+ num_rows,
208
+ num_cols,
203
209
  ),
204
210
  ),
205
211
  )
@@ -402,7 +408,13 @@ class Sheet:
402
408
  return self._add_table(table_name, from_table_id, x, y, num_rows, num_cols)
403
409
 
404
410
  def _add_table( # noqa: PLR0913
405
- self, table_name, from_table_id, x, y, num_rows, num_cols,
411
+ self,
412
+ table_name,
413
+ from_table_id,
414
+ x,
415
+ y,
416
+ num_rows,
417
+ num_cols,
406
418
  ) -> object:
407
419
  if table_name is not None:
408
420
  if table_name in self._tables:
@@ -415,7 +427,13 @@ class Sheet:
415
427
  table_name = f"Table {table_num}"
416
428
 
417
429
  new_table_id = self._model.add_table(
418
- self._sheet_id, table_name, from_table_id, x, y, num_rows, num_cols,
430
+ self._sheet_id,
431
+ table_name,
432
+ from_table_id,
433
+ x,
434
+ y,
435
+ num_rows,
436
+ num_cols,
419
437
  )
420
438
  self._tables.append(Table(self._model, new_table_id))
421
439
  return self._tables[-1]
@@ -469,14 +487,14 @@ class Table(Cacheable):
469
487
  def num_header_rows(self) -> int:
470
488
  """int: The number of header rows.
471
489
 
472
- Example:
490
+ Example
473
491
  -------
474
492
  .. code-block:: python
475
493
 
476
494
  # Add an extra header row
477
495
  table.num_header_rows += 1
478
496
 
479
- Raises:
497
+ Raises
480
498
  ------
481
499
  ValueError:
482
500
  If the number of headers is negative, exceeds the number of rows in the
@@ -501,14 +519,14 @@ class Table(Cacheable):
501
519
  def num_header_cols(self) -> int:
502
520
  """int: The number of header columns.
503
521
 
504
- Example:
522
+ Example
505
523
  -------
506
524
  .. code-block:: python
507
525
 
508
526
  # Add an extra header column
509
527
  table.num_header_cols += 1
510
528
 
511
- Raises:
529
+ Raises
512
530
  ------
513
531
  ValueError:
514
532
  If the number of headers is negative, exceeds the number of rows in the
@@ -605,7 +623,7 @@ class Table(Cacheable):
605
623
  def merge_ranges(self) -> List[str]:
606
624
  """List[str]: The merge ranges of cells in A1 notation.
607
625
 
608
- Example:
626
+ Example
609
627
  -------
610
628
  .. code-block:: python
611
629
 
@@ -1160,13 +1178,13 @@ class Table(Cacheable):
1160
1178
  * **param3** (:py:class:`Border`): The border to add.
1161
1179
  * **param4** (*int*, *optional*, default: 1): The length of the stroke to add.
1162
1180
 
1163
- Raises:
1181
+ Raises
1164
1182
  ------
1165
1183
  TypeError:
1166
1184
  If an invalid number of arguments is passed or if the types of the arguments
1167
1185
  are invalid.
1168
1186
 
1169
- Warns:
1187
+ Warns
1170
1188
  -----
1171
1189
  RuntimeWarning:
1172
1190
  If any of the sides to which the border is applied have been merged.
@@ -1438,6 +1456,7 @@ class Table(Cacheable):
1438
1456
  def _set_cell_data_format(self, row: int, col: int, format_type_name: str, **kwargs) -> None:
1439
1457
  try:
1440
1458
  format_type = FormattingType[format_type_name.upper()]
1459
+ _ = FORMATTING_ALLOWED_CELLS[format_type_name]
1441
1460
  except (KeyError, AttributeError):
1442
1461
  msg = f"unsuported cell format type '{format_type_name}'"
1443
1462
  raise TypeError(msg) from None
@@ -1462,9 +1481,7 @@ class Table(Cacheable):
1462
1481
  try:
1463
1482
  control_format = kwargs["control_format"].name
1464
1483
  number_format_type = FormattingType[control_format]
1465
- is_currency = (
1466
- kwargs["control_format"] == ControlFormattingType.CURRENCY
1467
- )
1484
+ is_currency = kwargs["control_format"] == ControlFormattingType.CURRENCY
1468
1485
  except (KeyError, AttributeError):
1469
1486
  control_format = kwargs["control_format"]
1470
1487
  msg = f"unsupported number format '{control_format}' for {format_type_name}"
@@ -13,8 +13,8 @@ from google.protobuf.json_format import MessageToDict, ParseDict
13
13
  from google.protobuf.message import EncodeError
14
14
 
15
15
  from numbers_parser.exceptions import NotImplementedError
16
+ from numbers_parser.generated.mapping import ID_NAME_MAP, NAME_CLASS_MAP, NAME_ID_MAP
16
17
  from numbers_parser.generated.TSPArchiveMessages_pb2 import ArchiveInfo
17
- from numbers_parser.mapping import ID_NAME_MAP, NAME_CLASS_MAP, NAME_ID_MAP
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
  debug = logger.debug
@@ -219,7 +219,7 @@ class IWAArchiveSegment:
219
219
  if object_length != provided_length:
220
220
  message_info.length = object_length
221
221
  except EncodeError as e: # pragma: no cover
222
- msg = "Failed to encode object: {}\nObject: '{}'\nMessage info: {}".format(e, repr(obj), message_info)
222
+ msg = f"Failed to encode object: {e}\nObject: '{repr(obj)}'\nMessage info: {message_info}"
223
223
  raise ValueError(
224
224
  msg,
225
225
  ) from None
@@ -90,12 +90,12 @@ class IWork:
90
90
  def open(self, filepath: Path) -> None:
91
91
  """Open an iWork file and read in the files and archives contained in it.
92
92
 
93
- Raises:
93
+ Raises
94
94
  ------
95
95
  FileFormatError
96
96
  If any errors occur extracting data from the archive
97
97
 
98
- Warns:
98
+ Warns
99
99
  -----
100
100
  RuntimeWarning
101
101
  If the version of the document is one that the IWork blob handler
@@ -676,7 +676,9 @@ class _NumbersModel(Cacheable):
676
676
  for row in range(row_start, row_end + 1):
677
677
  for col in range(col_start, col_end + 1):
678
678
  self._merge_cells[table_id].add_reference(
679
- row, col, (row_start, col_start, row_end, col_end),
679
+ row,
680
+ col,
681
+ (row_start, col_start, row_end, col_end),
680
682
  )
681
683
  self._merge_cells[table_id].add_anchor(row_start, col_start, size)
682
684
 
@@ -699,7 +701,9 @@ class _NumbersModel(Cacheable):
699
701
  for row in range(row_start, row_end + 1):
700
702
  for col in range(col_start, col_end + 1):
701
703
  self._merge_cells[table_id].add_reference(
702
- row, col, (row_start, col_start, row_end, col_end),
704
+ row,
705
+ col,
706
+ (row_start, col_start, row_end, col_end),
703
707
  )
704
708
  self._merge_cells[table_id].add_anchor(row_start, col_start, (num_rows, num_columns))
705
709
 
@@ -711,7 +715,6 @@ class _NumbersModel(Cacheable):
711
715
  for sheet_id in self.sheet_ids(): # pragma: no branch
712
716
  if table_id in self.table_ids(sheet_id):
713
717
  return sheet_id
714
- return None
715
718
 
716
719
  @cache()
717
720
  def table_uuids_to_id(self, table_uuid) -> int:
@@ -719,7 +722,6 @@ class _NumbersModel(Cacheable):
719
722
  for table_id in self.table_ids(sheet_id):
720
723
  if table_uuid == self.table_base_id(table_id):
721
724
  return table_id
722
- return None
723
725
 
724
726
  def node_to_ref(self, this_table_id: int, row: int, col: int, node):
725
727
  if node.HasField("AST_cross_table_reference_extra_info"):
@@ -858,7 +860,10 @@ class _NumbersModel(Cacheable):
858
860
  else:
859
861
  width = current_column_widths[col]
860
862
  header = TSTArchives.HeaderStorageBucket.Header(
861
- index=col, numberOfCells=num_rows, size=width, hidingState=0,
863
+ index=col,
864
+ numberOfCells=num_rows,
865
+ size=width,
866
+ hidingState=0,
862
867
  )
863
868
  buckets.headers.append(header)
864
869
 
@@ -866,7 +871,9 @@ class _NumbersModel(Cacheable):
866
871
  merge_cells = self.merge_cells(table_id)
867
872
 
868
873
  merge_map_id, merge_map = self.objects.create_object_from_dict(
869
- "CalculationEngine", {}, TSTArchives.MergeRegionMapArchive,
874
+ "CalculationEngine",
875
+ {},
876
+ TSTArchives.MergeRegionMapArchive,
870
877
  )
871
878
 
872
879
  merge_cells = self.merge_cells(table_id)
@@ -881,7 +888,11 @@ class _NumbersModel(Cacheable):
881
888
  base_data_store.merge_region_map.CopyFrom(TSPMessages.Reference(identifier=merge_map_id))
882
889
 
883
890
  def recalculate_row_info(
884
- self, table_id: int, data: List, tile_row_offset: int, row: int,
891
+ self,
892
+ table_id: int,
893
+ data: List,
894
+ tile_row_offset: int,
895
+ row: int,
885
896
  ) -> TSTArchives.TileRowInfo:
886
897
  row_info = TSTArchives.TileRowInfo()
887
898
  row_info.storage_version = 5
@@ -997,7 +1008,9 @@ class _NumbersModel(Cacheable):
997
1008
  "should_use_wide_rows": True,
998
1009
  }
999
1010
  tile_id, tile = self.objects.create_object_from_dict(
1000
- "Index/Tables/Tile-{}", tile_dict, TSTArchives.Tile,
1011
+ "Index/Tables/Tile-{}",
1012
+ tile_dict,
1013
+ TSTArchives.Tile,
1001
1014
  )
1002
1015
  for row in range(row_start, row_end):
1003
1016
  row_info = self.recalculate_row_info(table_id, data, row_start, row)
@@ -1129,7 +1142,7 @@ class _NumbersModel(Cacheable):
1129
1142
  self.objects[self.table_info_id(x)].super.geometry.position.y
1130
1143
  for x in self.table_ids(sheet_id)
1131
1144
  if x == table_id
1132
- )
1145
+ ) # pragma: nocover (issue-1333)
1133
1146
 
1134
1147
  return self.table_height(table_id) + y_offset
1135
1148
 
@@ -1192,7 +1205,9 @@ class _NumbersModel(Cacheable):
1192
1205
  TSTArchives.HeaderStorageBucket,
1193
1206
  )
1194
1207
  self.add_component_metadata(
1195
- column_headers_id, "CalculationEngine", "Tables/HeaderStorageBucket-{}",
1208
+ column_headers_id,
1209
+ "CalculationEngine",
1210
+ "Tables/HeaderStorageBucket-{}",
1196
1211
  )
1197
1212
 
1198
1213
  style_table_id, _ = self.objects.create_object_from_dict(
@@ -1208,7 +1223,9 @@ class _NumbersModel(Cacheable):
1208
1223
  TSTArchives.TableDataList,
1209
1224
  )
1210
1225
  self.add_component_metadata(
1211
- formula_table_id, "CalculationEngine", "Tables/TableDataList-{}",
1226
+ formula_table_id,
1227
+ "CalculationEngine",
1228
+ "Tables/TableDataList-{}",
1212
1229
  )
1213
1230
 
1214
1231
  format_table_pre_bnc_id, _ = self.objects.create_object_from_dict(
@@ -1236,7 +1253,8 @@ class _NumbersModel(Cacheable):
1236
1253
  rowTileTree=TSTArchives.TableRBTree(),
1237
1254
  columnTileTree=TSTArchives.TableRBTree(),
1238
1255
  tiles=TSTArchives.TileStorage(
1239
- tile_size=DEFAULT_TILE_SIZE, should_use_wide_rows=True,
1256
+ tile_size=DEFAULT_TILE_SIZE,
1257
+ should_use_wide_rows=True,
1240
1258
  ),
1241
1259
  **data_store_refs,
1242
1260
  ),
@@ -1249,7 +1267,9 @@ class _NumbersModel(Cacheable):
1249
1267
  )
1250
1268
 
1251
1269
  self.add_component_metadata(
1252
- row_headers_id, "CalculationEngine", "Tables/HeaderStorageBucket-{}",
1270
+ row_headers_id,
1271
+ "CalculationEngine",
1272
+ "Tables/HeaderStorageBucket-{}",
1253
1273
  )
1254
1274
  table_model.base_data_store.rowHeaders.buckets.append(
1255
1275
  TSPMessages.Reference(identifier=row_headers_id),
@@ -1356,14 +1376,17 @@ class _NumbersModel(Cacheable):
1356
1376
  )
1357
1377
  owner_id_map.append(
1358
1378
  TSCEArchives.OwnerIDMapArchive.OwnerIDMapArchiveEntry(
1359
- internal_owner_id=next_owner_id, owner_id=formula_owner_uuid.protobuf4,
1379
+ internal_owner_id=next_owner_id,
1380
+ owner_id=formula_owner_uuid.protobuf4,
1360
1381
  ),
1361
1382
  )
1362
1383
 
1363
1384
  def add_sheet(self, sheet_name: str) -> int:
1364
1385
  """Add a new sheet with a copy of a table from another sheet."""
1365
1386
  sheet_id, _ = self.objects.create_object_from_dict(
1366
- "Document", {"name": sheet_name}, TNArchives.SheetArchive,
1387
+ "Document",
1388
+ {"name": sheet_name},
1389
+ TNArchives.SheetArchive,
1367
1390
  )
1368
1391
 
1369
1392
  self.add_component_reference(sheet_id, "CalculationEngine", DOCUMENT_ID, is_weak=True)
@@ -1793,7 +1816,6 @@ class _NumbersModel(Cacheable):
1793
1816
  "bullet_chars": bullet_chars,
1794
1817
  "hyperlinks": hyperlinks,
1795
1818
  }
1796
- return None
1797
1819
 
1798
1820
  def cell_text_style(self, cell: Cell) -> object:
1799
1821
  """Return the text style object for the cell or, if none
@@ -1967,7 +1989,12 @@ class _NumbersModel(Cacheable):
1967
1989
  return None
1968
1990
 
1969
1991
  def set_cell_border( # noqa: PLR0913
1970
- self, table_id: int, row: int, col: int, side: str, border_value: Border,
1992
+ self,
1993
+ table_id: int,
1994
+ row: int,
1995
+ col: int,
1996
+ side: str,
1997
+ border_value: Border,
1971
1998
  ):
1972
1999
  """Set the 2 borders adjacent to a stroke if within the table range."""
1973
2000
  if side == "top":
@@ -2230,7 +2257,10 @@ def node_to_row_col_ref(node: object, table_name: str, row: int, col: int) -> st
2230
2257
 
2231
2258
 
2232
2259
  def get_storage_buffers_for_row(
2233
- storage_buffer: bytes, offsets: list, num_cols: int, has_wide_offsets: bool,
2260
+ storage_buffer: bytes,
2261
+ offsets: list,
2262
+ num_cols: int,
2263
+ has_wide_offsets: bool,
2234
2264
  ) -> List[bytes]:
2235
2265
  """Extract storage buffers for each cell in a table row.
2236
2266
 
@@ -1,35 +1,35 @@
1
1
  from numbers_parser.generated import TNArchives_pb2 as TNArchives
2
- from numbers_parser.generated import TNArchives_sos_pb2 as TNArchives_sos
3
- from numbers_parser.generated import TNCommandArchives_pb2 as TNCommandArchives
4
- from numbers_parser.generated import TNCommandArchives_sos_pb2 as TNCommandArchives_sos
5
- from numbers_parser.generated import TSAArchives_pb2 as TSAArchives
6
- from numbers_parser.generated import TSAArchives_sos_pb2 as TSAArchives_sos
7
- from numbers_parser.generated import TSACommandArchives_sos_pb2 as TSACommandArchives_sos
8
- from numbers_parser.generated import TSCEArchives_pb2 as TSCEArchives
2
+ from numbers_parser.generated import TSTArchives_pb2 as TSTArchives
9
3
  from numbers_parser.generated import TSCH3DArchives_pb2 as TSCH3DArchives
10
- from numbers_parser.generated import TSCHArchives_Common_pb2 as TSCHArchives_Common
4
+ from numbers_parser.generated import TSSArchives_pb2 as TSSArchives
5
+ from numbers_parser.generated import TSAArchives_sos_pb2 as TSAArchives_sos
11
6
  from numbers_parser.generated import TSCHArchives_GEN_pb2 as TSCHArchives_GEN
12
- from numbers_parser.generated import TSCHArchives_pb2 as TSCHArchives
13
- from numbers_parser.generated import TSCHArchives_sos_pb2 as TSCHArchives_sos
14
- from numbers_parser.generated import TSCHCommandArchives_pb2 as TSCHCommandArchives
15
- from numbers_parser.generated import TSCHPreUFFArchives_pb2 as TSCHPreUFFArchives
16
- from numbers_parser.generated import TSDArchives_pb2 as TSDArchives
17
- from numbers_parser.generated import TSDArchives_sos_pb2 as TSDArchives_sos
7
+ from numbers_parser.generated import TSTStylePropertyArchiving_pb2 as TSTStylePropertyArchiving
8
+ from numbers_parser.generated import TSPMessages_pb2 as TSPMessages
18
9
  from numbers_parser.generated import TSDCommandArchives_pb2 as TSDCommandArchives
19
- from numbers_parser.generated import TSKArchives_pb2 as TSKArchives
20
- from numbers_parser.generated import TSKArchives_sos_pb2 as TSKArchives_sos
21
- from numbers_parser.generated import TSPArchiveMessages_pb2 as TSPArchiveMessages
10
+ from numbers_parser.generated import TSCHPreUFFArchives_pb2 as TSCHPreUFFArchives
11
+ from numbers_parser.generated import TSWPCommandArchives_pb2 as TSWPCommandArchives
22
12
  from numbers_parser.generated import TSPDatabaseMessages_pb2 as TSPDatabaseMessages
23
- from numbers_parser.generated import TSPMessages_pb2 as TSPMessages
24
- from numbers_parser.generated import TSSArchives_pb2 as TSSArchives
25
13
  from numbers_parser.generated import TSSArchives_sos_pb2 as TSSArchives_sos
26
- from numbers_parser.generated import TSTArchives_pb2 as TSTArchives
27
- from numbers_parser.generated import TSTArchives_sos_pb2 as TSTArchives_sos
28
- from numbers_parser.generated import TSTCommandArchives_pb2 as TSTCommandArchives
29
- from numbers_parser.generated import TSTStylePropertyArchiving_pb2 as TSTStylePropertyArchiving
14
+ from numbers_parser.generated import TSDArchives_sos_pb2 as TSDArchives_sos
15
+ from numbers_parser.generated import TNCommandArchives_pb2 as TNCommandArchives
16
+ from numbers_parser.generated import TSPArchiveMessages_pb2 as TSPArchiveMessages
17
+ from numbers_parser.generated import TSCHCommandArchives_pb2 as TSCHCommandArchives
30
18
  from numbers_parser.generated import TSWPArchives_pb2 as TSWPArchives
31
19
  from numbers_parser.generated import TSWPArchives_sos_pb2 as TSWPArchives_sos
32
- from numbers_parser.generated import TSWPCommandArchives_pb2 as TSWPCommandArchives
20
+ from numbers_parser.generated import TNCommandArchives_sos_pb2 as TNCommandArchives_sos
21
+ from numbers_parser.generated import TSKArchives_sos_pb2 as TSKArchives_sos
22
+ from numbers_parser.generated import TSCHArchives_sos_pb2 as TSCHArchives_sos
23
+ from numbers_parser.generated import TSDArchives_pb2 as TSDArchives
24
+ from numbers_parser.generated import TNArchives_sos_pb2 as TNArchives_sos
25
+ from numbers_parser.generated import TSKArchives_pb2 as TSKArchives
26
+ from numbers_parser.generated import TSTCommandArchives_pb2 as TSTCommandArchives
27
+ from numbers_parser.generated import TSCHArchives_pb2 as TSCHArchives
28
+ from numbers_parser.generated import TSACommandArchives_sos_pb2 as TSACommandArchives_sos
29
+ from numbers_parser.generated import TSTArchives_sos_pb2 as TSTArchives_sos
30
+ from numbers_parser.generated import TSAArchives_pb2 as TSAArchives
31
+ from numbers_parser.generated import TSCEArchives_pb2 as TSCEArchives
32
+ from numbers_parser.generated import TSCHArchives_Common_pb2 as TSCHArchives_Common
33
33
 
34
34
  PROTO_FILES = [
35
35
  TNArchives,