numbers-parser 4.10.4__py3-none-any.whl → 4.10.6__py3-none-any.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 (34) hide show
  1. numbers_parser/__init__.py +1 -1
  2. numbers_parser/_cat_numbers.py +4 -4
  3. numbers_parser/_unpack_numbers.py +5 -5
  4. numbers_parser/cell.py +150 -128
  5. numbers_parser/constants.py +5 -6
  6. numbers_parser/containers.py +11 -8
  7. numbers_parser/document.py +147 -108
  8. numbers_parser/exceptions.py +0 -7
  9. numbers_parser/formula.py +3 -4
  10. numbers_parser/generated/TNArchives_pb2.py +24 -26
  11. numbers_parser/generated/TSAArchives_pb2.py +26 -28
  12. numbers_parser/generated/TSCEArchives_pb2.py +8 -10
  13. numbers_parser/generated/TSCHArchives_GEN_pb2.py +28 -34
  14. numbers_parser/generated/TSCHArchives_pb2.py +61 -65
  15. numbers_parser/generated/TSDArchives_pb2.py +100 -110
  16. numbers_parser/generated/TSKArchives_pb2.py +168 -170
  17. numbers_parser/generated/TSPArchiveMessages_pb2.py +32 -34
  18. numbers_parser/generated/TSPMessages_pb2.py +40 -40
  19. numbers_parser/generated/TSSArchives_pb2.py +36 -36
  20. numbers_parser/generated/TSTArchives_pb2.py +321 -325
  21. numbers_parser/generated/TSTStylePropertyArchiving_pb2.py +8 -10
  22. numbers_parser/generated/TSWPArchives_pb2.py +250 -286
  23. numbers_parser/generated/TSWPCommandArchives_pb2.py +95 -95
  24. numbers_parser/iwafile.py +17 -17
  25. numbers_parser/iwork.py +33 -27
  26. numbers_parser/model.py +94 -52
  27. numbers_parser/numbers_uuid.py +6 -4
  28. {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/METADATA +9 -9
  29. numbers_parser-4.10.6.dist-info/RECORD +59 -0
  30. numbers_parser-4.10.4.dist-info/RECORD +0 -59
  31. numbers_parser/{mapping.py → generated/mapping.py} +24 -24
  32. {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/LICENSE.rst +0 -0
  33. {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/WHEEL +0 -0
  34. {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/entry_points.txt +0 -0
numbers_parser/model.py CHANGED
@@ -4,7 +4,7 @@ from collections import defaultdict
4
4
  from hashlib import sha1
5
5
  from pathlib import Path
6
6
  from struct import pack
7
- from typing import Dict, List, Tuple, Union
7
+ from typing import Dict, List, Optional, Tuple, Union
8
8
 
9
9
  from numbers_parser.bullets import (
10
10
  BULLET_CONVERSION,
@@ -86,7 +86,7 @@ FONT_FAMILY_TO_NAME = create_font_name_map(FONT_NAME_TO_FAMILY)
86
86
 
87
87
 
88
88
  class MergeCells:
89
- def __init__(self):
89
+ def __init__(self) -> None:
90
90
  self._references = defaultdict(lambda: False)
91
91
 
92
92
  def add_reference(self, row: int, col: int, rect: Tuple):
@@ -119,7 +119,7 @@ class MergeCells:
119
119
  class DataLists(Cacheable):
120
120
  """Model for TST.DataList with caching and key generation for new values."""
121
121
 
122
- def __init__(self, model: object, datalist_name: str, value_attr: str = None):
122
+ def __init__(self, model: object, datalist_name: str, value_attr: Optional[str] = None) -> None:
123
123
  self._model = model
124
124
  self._datalists = {}
125
125
  self._value_attr = value_attr
@@ -209,7 +209,7 @@ class _NumbersModel(Cacheable):
209
209
  Not to be used in application code.
210
210
  """
211
211
 
212
- def __init__(self, filepath: Path):
212
+ def __init__(self, filepath: Path) -> None:
213
213
  if filepath is None:
214
214
  filepath = Path(DEFAULT_DOCUMENT)
215
215
  self.objects = ObjectStore(filepath)
@@ -250,6 +250,7 @@ class _NumbersModel(Cacheable):
250
250
  return self.objects[sheet_id].name
251
251
  else:
252
252
  self.objects[sheet_id].name = value
253
+ return None
253
254
 
254
255
  def set_table_data(self, table_id: int, data: List):
255
256
  self._table_data[table_id] = data
@@ -331,10 +332,12 @@ class _NumbersModel(Cacheable):
331
332
  return self.objects[table_id].table_name
332
333
  else:
333
334
  self.objects[table_id].table_name = value
335
+ return None
334
336
 
335
- def table_name_enabled(self, table_id: int, enabled: bool = None):
337
+ def table_name_enabled(self, table_id: int, enabled: Optional[bool] = None):
336
338
  if enabled is not None:
337
339
  self.objects[table_id].table_name_enabled = enabled
340
+ return None
338
341
  else:
339
342
  return self.objects[table_id].table_name_enabled
340
343
 
@@ -359,7 +362,7 @@ class _NumbersModel(Cacheable):
359
362
 
360
363
  @cache(num_args=3)
361
364
  def format_archive(self, table_id: int, format_type: FormattingType, format: Formatting):
362
- """Create a table format from a Formatting spec and return the table format ID"""
365
+ """Create a table format from a Formatting spec and return the table format ID."""
363
366
  attrs = {x: getattr(format, x) for x in ALLOWED_FORMATTING_PARAMETERS[format_type]}
364
367
  attrs["format_type"] = FORMAT_TYPE_MAP[format_type]
365
368
 
@@ -377,7 +380,7 @@ class _NumbersModel(Cacheable):
377
380
  "value": item,
378
381
  "format": {"format_type": FormatType.TEXT},
379
382
  },
380
- }
383
+ },
381
384
  )
382
385
  else:
383
386
  tsce_items.append(
@@ -387,7 +390,7 @@ class _NumbersModel(Cacheable):
387
390
  "value": item,
388
391
  "format": {"format_type": FormatType.DECIMAL},
389
392
  },
390
- }
393
+ },
391
394
  )
392
395
  popup_menu_id, _ = self.objects.create_object_from_dict(
393
396
  f"Index/Tables/DataList-{parent_id}",
@@ -398,7 +401,7 @@ class _NumbersModel(Cacheable):
398
401
  return popup_menu_id
399
402
 
400
403
  def control_cell_archive(self, table_id: int, format_type: FormattingType, format: Formatting):
401
- """Create control cell archive from a Formatting spec and return the table format ID"""
404
+ """Create control cell archive from a Formatting spec and return the table format ID."""
402
405
  if format_type == FormattingType.TICKBOX:
403
406
  cell_spec = TSTArchives.CellSpecArchive(interaction_type=CellInteractionType.TOGGLE)
404
407
  elif format_type == FormattingType.RATING:
@@ -425,7 +428,7 @@ class _NumbersModel(Cacheable):
425
428
  return self._control_specs.lookup_key(table_id, cell_spec)
426
429
 
427
430
  def add_custom_decimal_format_archive(self, format: CustomFormatting) -> None:
428
- """Create a custom format from the format spec"""
431
+ """Create a custom format from the format spec."""
429
432
  integer_format = format.integer_format
430
433
  decimal_format = format.decimal_format
431
434
  num_integers = format.num_integers
@@ -513,7 +516,7 @@ class _NumbersModel(Cacheable):
513
516
  custom_format_list.uuids.append(format_uuid)
514
517
 
515
518
  def custom_format_id(self, table_id: int, format: CustomFormatting) -> int:
516
- """Look up the custom format and return the format ID for the table"""
519
+ """Look up the custom format and return the format ID for the table."""
517
520
  format_type = CUSTOM_FORMAT_TYPE_MAP[format.type]
518
521
  format_uuid = self._custom_format_uuids[format.name]
519
522
  custom_format = TSKArchives.FormatStructArchive(
@@ -605,12 +608,13 @@ class _NumbersModel(Cacheable):
605
608
  obj = self.objects[dependency_id]
606
609
  # if obj.owner_kind == OwnerKind.HAUNTED_OWNER:
607
610
  if obj.HasField("base_owner_uid") and obj.HasField(
608
- "formula_owner_uid"
611
+ "formula_owner_uid",
609
612
  ): # pragma: no branch
610
613
  base_owner_uid = NumbersUUID(obj.base_owner_uid).hex
611
614
  formula_owner_uid = NumbersUUID(obj.formula_owner_uid).hex
612
615
  if formula_owner_uid == haunted_owner:
613
616
  return base_owner_uid
617
+ return None
614
618
 
615
619
  @cache()
616
620
  def formula_cell_ranges(self, table_id: int) -> list:
@@ -672,7 +676,9 @@ class _NumbersModel(Cacheable):
672
676
  for row in range(row_start, row_end + 1):
673
677
  for col in range(col_start, col_end + 1):
674
678
  self._merge_cells[table_id].add_reference(
675
- row, col, (row_start, col_start, row_end, col_end)
679
+ row,
680
+ col,
681
+ (row_start, col_start, row_end, col_end),
676
682
  )
677
683
  self._merge_cells[table_id].add_anchor(row_start, col_start, size)
678
684
 
@@ -695,7 +701,9 @@ class _NumbersModel(Cacheable):
695
701
  for row in range(row_start, row_end + 1):
696
702
  for col in range(col_start, col_end + 1):
697
703
  self._merge_cells[table_id].add_reference(
698
- row, col, (row_start, col_start, row_end, col_end)
704
+ row,
705
+ col,
706
+ (row_start, col_start, row_end, col_end),
699
707
  )
700
708
  self._merge_cells[table_id].add_anchor(row_start, col_start, (num_rows, num_columns))
701
709
 
@@ -793,7 +801,8 @@ class _NumbersModel(Cacheable):
793
801
  buffers = []
794
802
  for tile in self.table_tiles(table_id):
795
803
  if not tile.last_saved_in_BNC:
796
- raise UnsupportedError("Pre-BNC storage is unsupported")
804
+ msg = "Pre-BNC storage is unsupported"
805
+ raise UnsupportedError(msg)
797
806
  for r in tile.rowInfos:
798
807
  buffer = get_storage_buffers_for_row(
799
808
  r.cell_storage_buffer,
@@ -851,7 +860,10 @@ class _NumbersModel(Cacheable):
851
860
  else:
852
861
  width = current_column_widths[col]
853
862
  header = TSTArchives.HeaderStorageBucket.Header(
854
- index=col, numberOfCells=num_rows, size=width, hidingState=0
863
+ index=col,
864
+ numberOfCells=num_rows,
865
+ size=width,
866
+ hidingState=0,
855
867
  )
856
868
  buckets.headers.append(header)
857
869
 
@@ -859,7 +871,9 @@ class _NumbersModel(Cacheable):
859
871
  merge_cells = self.merge_cells(table_id)
860
872
 
861
873
  merge_map_id, merge_map = self.objects.create_object_from_dict(
862
- "CalculationEngine", {}, TSTArchives.MergeRegionMapArchive
874
+ "CalculationEngine",
875
+ {},
876
+ TSTArchives.MergeRegionMapArchive,
863
877
  )
864
878
 
865
879
  merge_cells = self.merge_cells(table_id)
@@ -874,7 +888,11 @@ class _NumbersModel(Cacheable):
874
888
  base_data_store.merge_region_map.CopyFrom(TSPMessages.Reference(identifier=merge_map_id))
875
889
 
876
890
  def recalculate_row_info(
877
- 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,
878
896
  ) -> TSTArchives.TileRowInfo:
879
897
  row_info = TSTArchives.TileRowInfo()
880
898
  row_info.storage_version = 5
@@ -903,7 +921,7 @@ class _NumbersModel(Cacheable):
903
921
  return row_info
904
922
 
905
923
  @cache()
906
- def metadata_component(self, reference: Union[str, int] = None) -> int:
924
+ def metadata_component(self, reference: Optional[Union[str, int]] = None) -> int:
907
925
  """Return the ID of an object in the document metadata given it's name or ID."""
908
926
  component_map = {c.identifier: c for c in self.objects[PACKAGE_ID].components}
909
927
  if isinstance(reference, str):
@@ -933,8 +951,8 @@ class _NumbersModel(Cacheable):
933
951
  def add_component_reference(
934
952
  self,
935
953
  object_id: int,
936
- location: str = None,
937
- parent_id: int = None,
954
+ location: Optional[str] = None,
955
+ parent_id: Optional[int] = None,
938
956
  is_weak: bool = False,
939
957
  ):
940
958
  """Add an external reference to an object in a metadata component."""
@@ -946,7 +964,7 @@ class _NumbersModel(Cacheable):
946
964
  if is_weak:
947
965
  params["is_weak"] = True
948
966
  component.external_references.append(
949
- TSPArchiveMessages.ComponentExternalReference(**params)
967
+ TSPArchiveMessages.ComponentExternalReference(**params),
950
968
  )
951
969
 
952
970
  def recalculate_table_data(self, table_id: int, data: List):
@@ -990,7 +1008,9 @@ class _NumbersModel(Cacheable):
990
1008
  "should_use_wide_rows": True,
991
1009
  }
992
1010
  tile_id, tile = self.objects.create_object_from_dict(
993
- "Index/Tables/Tile-{}", tile_dict, TSTArchives.Tile
1011
+ "Index/Tables/Tile-{}",
1012
+ tile_dict,
1013
+ TSTArchives.Tile,
994
1014
  )
995
1015
  for row in range(row_start, row_end):
996
1016
  row_info = self.recalculate_row_info(table_id, data, row_start, row)
@@ -1033,7 +1053,7 @@ class _NumbersModel(Cacheable):
1033
1053
  height += table_model.default_row_height
1034
1054
  return round(height)
1035
1055
 
1036
- def row_height(self, table_id: int, row: int, height: int = None) -> int:
1056
+ def row_height(self, table_id: int, row: int, height: Optional[int] = None) -> int:
1037
1057
  if height is not None:
1038
1058
  if table_id not in self._row_heights:
1039
1059
  self._row_heights[table_id] = {}
@@ -1069,7 +1089,7 @@ class _NumbersModel(Cacheable):
1069
1089
  width += table_model.default_column_width
1070
1090
  return round(width)
1071
1091
 
1072
- def col_width(self, table_id: int, col: int, width: int = None) -> int:
1092
+ def col_width(self, table_id: int, col: int, width: Optional[int] = None) -> int:
1073
1093
  if width is not None:
1074
1094
  if table_id not in self._col_widths:
1075
1095
  self._col_widths[table_id] = {}
@@ -1089,14 +1109,14 @@ class _NumbersModel(Cacheable):
1089
1109
  else:
1090
1110
  return round(table_model.default_column_width)
1091
1111
 
1092
- def num_header_rows(self, table_id: int, num_headers: int = None) -> int:
1112
+ def num_header_rows(self, table_id: int, num_headers: Optional[int] = None) -> int:
1093
1113
  """Return/set the number of header rows."""
1094
1114
  table_model = self.objects[table_id]
1095
1115
  if num_headers is not None:
1096
1116
  table_model.number_of_header_rows = num_headers
1097
1117
  return table_model.number_of_header_rows
1098
1118
 
1099
- def num_header_cols(self, table_id: int, num_headers: int = None) -> int:
1119
+ def num_header_cols(self, table_id: int, num_headers: Optional[int] = None) -> int:
1100
1120
  """Return/set the number of header columns."""
1101
1121
  table_model = self.objects[table_id]
1102
1122
  if num_headers is not None:
@@ -1118,11 +1138,11 @@ class _NumbersModel(Cacheable):
1118
1138
  def last_table_offset(self, sheet_id):
1119
1139
  """Y offset of the last table in a sheet."""
1120
1140
  table_id = self.table_ids(sheet_id)[-1]
1121
- y_offset = [
1141
+ y_offset = next(
1122
1142
  self.objects[self.table_info_id(x)].super.geometry.position.y
1123
1143
  for x in self.table_ids(sheet_id)
1124
1144
  if x == table_id
1125
- ][0]
1145
+ ) # pragma: nocover (issue-1333)
1126
1146
 
1127
1147
  return self.table_height(table_id) + y_offset
1128
1148
 
@@ -1185,7 +1205,9 @@ class _NumbersModel(Cacheable):
1185
1205
  TSTArchives.HeaderStorageBucket,
1186
1206
  )
1187
1207
  self.add_component_metadata(
1188
- column_headers_id, "CalculationEngine", "Tables/HeaderStorageBucket-{}"
1208
+ column_headers_id,
1209
+ "CalculationEngine",
1210
+ "Tables/HeaderStorageBucket-{}",
1189
1211
  )
1190
1212
 
1191
1213
  style_table_id, _ = self.objects.create_object_from_dict(
@@ -1201,7 +1223,9 @@ class _NumbersModel(Cacheable):
1201
1223
  TSTArchives.TableDataList,
1202
1224
  )
1203
1225
  self.add_component_metadata(
1204
- formula_table_id, "CalculationEngine", "Tables/TableDataList-{}"
1226
+ formula_table_id,
1227
+ "CalculationEngine",
1228
+ "Tables/TableDataList-{}",
1205
1229
  )
1206
1230
 
1207
1231
  format_table_pre_bnc_id, _ = self.objects.create_object_from_dict(
@@ -1229,10 +1253,11 @@ class _NumbersModel(Cacheable):
1229
1253
  rowTileTree=TSTArchives.TableRBTree(),
1230
1254
  columnTileTree=TSTArchives.TableRBTree(),
1231
1255
  tiles=TSTArchives.TileStorage(
1232
- tile_size=DEFAULT_TILE_SIZE, should_use_wide_rows=True
1256
+ tile_size=DEFAULT_TILE_SIZE,
1257
+ should_use_wide_rows=True,
1233
1258
  ),
1234
1259
  **data_store_refs,
1235
- )
1260
+ ),
1236
1261
  )
1237
1262
 
1238
1263
  row_headers_id, _ = self.objects.create_object_from_dict(
@@ -1242,10 +1267,12 @@ class _NumbersModel(Cacheable):
1242
1267
  )
1243
1268
 
1244
1269
  self.add_component_metadata(
1245
- row_headers_id, "CalculationEngine", "Tables/HeaderStorageBucket-{}"
1270
+ row_headers_id,
1271
+ "CalculationEngine",
1272
+ "Tables/HeaderStorageBucket-{}",
1246
1273
  )
1247
1274
  table_model.base_data_store.rowHeaders.buckets.append(
1248
- TSPMessages.Reference(identifier=row_headers_id)
1275
+ TSPMessages.Reference(identifier=row_headers_id),
1249
1276
  )
1250
1277
 
1251
1278
  data = [
@@ -1272,7 +1299,7 @@ class _NumbersModel(Cacheable):
1272
1299
  )
1273
1300
 
1274
1301
  self.objects[sheet_id].drawable_infos.append(
1275
- TSPMessages.Reference(identifier=table_info_id)
1302
+ TSPMessages.Reference(identifier=table_info_id),
1276
1303
  )
1277
1304
  return table_model_id
1278
1305
 
@@ -1345,18 +1372,21 @@ class _NumbersModel(Cacheable):
1345
1372
  TSCEArchives.FormulaOwnerDependenciesArchive,
1346
1373
  )
1347
1374
  calc_engine.dependency_tracker.formula_owner_dependencies.append(
1348
- TSPMessages.Reference(identifier=formula_deps_id)
1375
+ TSPMessages.Reference(identifier=formula_deps_id),
1349
1376
  )
1350
1377
  owner_id_map.append(
1351
1378
  TSCEArchives.OwnerIDMapArchive.OwnerIDMapArchiveEntry(
1352
- internal_owner_id=next_owner_id, owner_id=formula_owner_uuid.protobuf4
1353
- )
1379
+ internal_owner_id=next_owner_id,
1380
+ owner_id=formula_owner_uuid.protobuf4,
1381
+ ),
1354
1382
  )
1355
1383
 
1356
1384
  def add_sheet(self, sheet_name: str) -> int:
1357
1385
  """Add a new sheet with a copy of a table from another sheet."""
1358
1386
  sheet_id, _ = self.objects.create_object_from_dict(
1359
- "Document", {"name": sheet_name}, TNArchives.SheetArchive
1387
+ "Document",
1388
+ {"name": sheet_name},
1389
+ TNArchives.SheetArchive,
1360
1390
  )
1361
1391
 
1362
1392
  self.add_component_reference(sheet_id, "CalculationEngine", DOCUMENT_ID, is_weak=True)
@@ -1467,7 +1497,7 @@ class _NumbersModel(Cacheable):
1467
1497
  TSSArchives.StylesheetArchive.IdentifiedStyleEntry(
1468
1498
  identifier=style_id_name,
1469
1499
  style=TSPMessages.Reference(identifier=para_style_id),
1470
- )
1500
+ ),
1471
1501
  )
1472
1502
 
1473
1503
  theme_id = self.objects[DOCUMENT_ID].theme.identifier
@@ -1563,7 +1593,7 @@ class _NumbersModel(Cacheable):
1563
1593
  preferred_file_name=style.bg_image.filename,
1564
1594
  file_name=style.bg_image.filename,
1565
1595
  materialized_length=len(style.bg_image.data),
1566
- )
1596
+ ),
1567
1597
  )
1568
1598
  self._images[digest] = image_id
1569
1599
  color_attrs = {
@@ -1572,8 +1602,8 @@ class _NumbersModel(Cacheable):
1572
1602
  "technique": "ScaleToFill",
1573
1603
  "imagedata": {"identifier": image_id},
1574
1604
  "interpretsUntaggedImageDataAsGeneric": False,
1575
- }
1576
- }
1605
+ },
1606
+ },
1577
1607
  }
1578
1608
  elif style.bg_color is not None:
1579
1609
  color_attrs = {
@@ -1585,8 +1615,8 @@ class _NumbersModel(Cacheable):
1585
1615
  "b": style.bg_color.b / 255,
1586
1616
  "a": 1.0,
1587
1617
  "rgbspace": "srgb",
1588
- }
1589
- }
1618
+ },
1619
+ },
1590
1620
  }
1591
1621
  else:
1592
1622
  color_attrs = {}
@@ -1622,7 +1652,7 @@ class _NumbersModel(Cacheable):
1622
1652
  TSSArchives.StylesheetArchive.IdentifiedStyleEntry(
1623
1653
  identifier=style_id_name,
1624
1654
  style=TSPMessages.Reference(identifier=cell_style_id),
1625
- )
1655
+ ),
1626
1656
  )
1627
1657
 
1628
1658
  return cell_style_id
@@ -1665,7 +1695,7 @@ class _NumbersModel(Cacheable):
1665
1695
  custom_format_list_id = self.objects[DOCUMENT_ID].super.custom_format_list.identifier
1666
1696
  custom_formats = self.objects[custom_format_list_id].custom_formats
1667
1697
  custom_format_names = [x.name for x in custom_formats]
1668
- custom_format_uuids = [x for x in self.objects[custom_format_list_id].uuids]
1698
+ custom_format_uuids = list(self.objects[custom_format_list_id].uuids)
1669
1699
  self._custom_formats = {}
1670
1700
  self._custom_format_archives = {}
1671
1701
  self._custom_format_uuids = {}
@@ -1828,6 +1858,7 @@ class _NumbersModel(Cacheable):
1828
1858
  return rgb(cell_properties.color)
1829
1859
  elif cell_properties.HasField("gradient"):
1830
1860
  return [(rgb(s.color)) for s in cell_properties.gradient.stops]
1861
+ return None
1831
1862
 
1832
1863
  def char_property(self, style: object, field: str):
1833
1864
  """Return a char_property field from a style if present
@@ -1958,7 +1989,12 @@ class _NumbersModel(Cacheable):
1958
1989
  return None
1959
1990
 
1960
1991
  def set_cell_border( # noqa: PLR0913
1961
- 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,
1962
1998
  ):
1963
1999
  """Set the 2 borders adjacent to a stroke if within the table range."""
1964
2000
  if side == "top":
@@ -2127,7 +2163,7 @@ class _NumbersModel(Cacheable):
2127
2163
  # New stroke in middle of existing stroke
2128
2164
  stroke_run.length = origin - stroke_start
2129
2165
  stroke_layer.stroke_runs.append(
2130
- TSTArchives.StrokeLayerArchive.StrokeRunArchive()
2166
+ TSTArchives.StrokeLayerArchive.StrokeRunArchive(),
2131
2167
  )
2132
2168
  stroke_layer.stroke_runs[-1].CopyFrom(stroke_run)
2133
2169
  stroke_layer.stroke_runs[-1].origin = origin + length
@@ -2150,7 +2186,8 @@ class _NumbersModel(Cacheable):
2150
2186
  """Store image data in the file store."""
2151
2187
  stored_filename = f"Data/{filename}"
2152
2188
  if stored_filename in self.objects.file_store:
2153
- raise IndexError(f"{filename}: image already exists in document")
2189
+ msg = f"{filename}: image already exists in document"
2190
+ raise IndexError(msg)
2154
2191
  self.objects.file_store[stored_filename] = data
2155
2192
 
2156
2193
  def next_image_identifier(self):
@@ -2220,17 +2257,22 @@ def node_to_row_col_ref(node: object, table_name: str, row: int, col: int) -> st
2220
2257
 
2221
2258
 
2222
2259
  def get_storage_buffers_for_row(
2223
- 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,
2224
2264
  ) -> List[bytes]:
2225
2265
  """Extract storage buffers for each cell in a table row.
2226
2266
 
2227
2267
  Args:
2268
+ ----
2228
2269
  storage_buffer: cell_storage_buffer or cell_storage_buffer for a table row
2229
2270
  offsets: 16-bit cell offsets for a table row
2230
2271
  num_cols: number of columns in a table row
2231
2272
  has_wide_offsets: use 4-byte offsets rather than 1-byte offset
2232
2273
 
2233
2274
  Returns:
2275
+ -------
2234
2276
  data: list of bytes for each cell in a row, or None if empty
2235
2277
  """
2236
2278
  offsets = array("h", offsets).tolist()
@@ -5,7 +5,7 @@ from numbers_parser.generated import TSPMessages_pb2 as TSPMessages
5
5
 
6
6
 
7
7
  class NumbersUUID(UUID):
8
- def __init__(self, uuid=None):
8
+ def __init__(self, uuid=None) -> None:
9
9
  if uuid is None:
10
10
  super().__init__(int=uuid1().int)
11
11
  elif isinstance(uuid, int):
@@ -33,9 +33,11 @@ class NumbersUUID(UUID):
33
33
  uuid_int = int(uuid["upper"]) << 64 | int(uuid["lower"])
34
34
  super().__init__(int=uuid_int)
35
35
  else:
36
- raise UnsupportedError("Unsupported UUID dict structure")
36
+ msg = "Unsupported UUID dict structure"
37
+ raise UnsupportedError(msg)
37
38
  else:
38
- raise UnsupportedError(f"Unsupported UUID init type {type(uuid).__name__}")
39
+ msg = f"Unsupported UUID init type {type(uuid).__name__}"
40
+ raise UnsupportedError(msg)
39
41
 
40
42
  @property
41
43
  def dict2(self) -> dict:
@@ -69,5 +71,5 @@ class NumbersUUID(UUID):
69
71
  uuid_w1 = (self.int >> 32) & 0xFFFFFFFF
70
72
  uuid_w0 = self.int & 0xFFFFFFFF
71
73
  return TSPMessages.CFUUIDArchive(
72
- uuid_w3=uuid_w3, uuid_w2=uuid_w2, uuid_w1=uuid_w1, uuid_w0=uuid_w0
74
+ uuid_w3=uuid_w3, uuid_w2=uuid_w2, uuid_w1=uuid_w1, uuid_w0=uuid_w0,
73
75
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbers-parser
3
- Version: 4.10.4
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
@@ -16,14 +16,14 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
18
18
  Requires-Dist: compact-json (>=1.1.3,<2.0.0)
19
- Requires-Dist: enum-tools (>=0.11.0,<0.12.0)
20
- Requires-Dist: importlib-resources (>=6.1.1,<7.0.0)
19
+ Requires-Dist: enum-tools (>=0.11)
20
+ Requires-Dist: importlib-resources (>=6.1)
21
21
  Requires-Dist: pendulum (>=3.0,<4.0)
22
22
  Requires-Dist: protobuf
23
- Requires-Dist: python-snappy (>=0.6.1,<0.7.0)
24
- Requires-Dist: regex (>=2022.9.13,<2023.0.0)
25
- Requires-Dist: roman (>=3.3,<4.0)
26
- Requires-Dist: setuptools (>=69.0.3,<70.0.0)
23
+ Requires-Dist: python-snappy (>=0.7,<0.8)
24
+ Requires-Dist: regex (>2024.0)
25
+ Requires-Dist: roman (>=4.0)
26
+ Requires-Dist: setuptools (>=69.0.3)
27
27
  Requires-Dist: sigfig (>=1.3.2,<2.0.0)
28
28
  Project-URL: Documentation, https://github.com/masaccio/numbers-parser/blob/main/README.md
29
29
  Project-URL: Repository, https://github.com/masaccio/numbers-parser
@@ -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.
@@ -0,0 +1,59 @@
1
+ numbers_parser/__init__.py,sha256=1guReSiMinXSKkip4UoC-a1X9OAgdiYTTDiZ03FDmqE,1411
2
+ numbers_parser/_cat_numbers.py,sha256=3tLvBQEagGcNL26XxfqguNim0JDtTNgEbiGKpLjBxLI,4623
3
+ numbers_parser/_unpack_numbers.py,sha256=PNEENAir573lxIbocK5WdY2KIhIak323ixvNyp7S0js,7004
4
+ numbers_parser/bullets.py,sha256=OnVVMPjhTDrC-ncw52Gb00UEXNmn2Rvd3xi7lfqW3hk,2616
5
+ numbers_parser/cell.py,sha256=z-D_xoH6N6JcXzcgKxXsbFHqM9FtMEsLBazt2TLdLVQ,76351
6
+ numbers_parser/constants.py,sha256=CyZvHPKHtET2TgpD-eiCS2vkoz8U5Of43rxPnAD0RgM,9912
7
+ numbers_parser/containers.py,sha256=j0FhaXPUG5YSRK5_3WIxXQOeckHVu24KMlYetWIZ_Xg,4882
8
+ numbers_parser/currencies.py,sha256=8k4a3WKmDoHeurkDICymHX13N7ManHSTaka_JNXCZYA,3767
9
+ numbers_parser/data/empty.numbers,sha256=8JOp035V-p2ff9_Wao7mLcYvb6_if6O2cus_esjVA9k,90316
10
+ numbers_parser/document.py,sha256=mi9AxaxrtVFDu-aGQU_TnlVyRMHi_F4UZMPy50g7Z4c,57837
11
+ numbers_parser/exceptions.py,sha256=0Jnmw06YlGvYcvzqc2wiR2Y4eAgvFJLpf0tFrsmlyPU,607
12
+ numbers_parser/experimental.py,sha256=WARjTa-2ePb8Ga8Q6oDP6EJCs12ofLRF2YpwzUu66ZI,374
13
+ numbers_parser/formula.py,sha256=4KQIhS6NMOdvz9rLsaVqXGnUDA4QCDpH8Lrz516PoU0,10574
14
+ numbers_parser/generated/TNArchives_pb2.py,sha256=cps3nLPpNWdSxhxmpWTDXiWeTE7HzxHcuaOReuY01v0,15834
15
+ numbers_parser/generated/TNArchives_sos_pb2.py,sha256=AYI1X5t5Gb4l941jXlHEY0v97ToIze0bSYBR7KQmS0A,1215
16
+ numbers_parser/generated/TNCommandArchives_pb2.py,sha256=AtDBJ_r-slDRVzHxJdXXZPAhpf-jpHj27ujIa2-aPtg,18271
17
+ numbers_parser/generated/TNCommandArchives_sos_pb2.py,sha256=MhIENEtVylmebThyhglAwO6dhu23UuF2DvdxtUoEvf0,1857
18
+ numbers_parser/generated/TSAArchives_pb2.py,sha256=P6IPcixKO2NdgJISbipbsCTI25SPjGMBqwsaRd5DxwE,19809
19
+ numbers_parser/generated/TSAArchives_sos_pb2.py,sha256=UlEScYhun_N-Cbr2v5RcgvJuwkloUuPJbrWxnQTOAfo,2033
20
+ numbers_parser/generated/TSACommandArchives_sos_pb2.py,sha256=dyjRN08Ly1qp5m3jcOE5yClARAzg5KyOYNMWyplRq8w,3907
21
+ numbers_parser/generated/TSCEArchives_pb2.py,sha256=BgV0Bw70bSLqs9v_q75HxT5_VTu4pb75AFVuOJUxOpo,64758
22
+ numbers_parser/generated/TSCH3DArchives_pb2.py,sha256=eV4GahEGv_3nGNgnN6xc3kfJ07UT3oALlLeJdh0GcQ4,11162
23
+ numbers_parser/generated/TSCHArchives_Common_pb2.py,sha256=dqgymAVSSQmjp3XuuXFRfXoSXhbQqaQXWbd-JUJs7Nc,8655
24
+ numbers_parser/generated/TSCHArchives_GEN_pb2.py,sha256=_v3oN76ohi0uDlzoIg6AZnGWyirjLzhBSRLunsFkSco,45616
25
+ numbers_parser/generated/TSCHArchives_pb2.py,sha256=r4iqZeywfS8kHaZoeMWUfXAXXycrSyhwyp0JpIVsPME,23803
26
+ numbers_parser/generated/TSCHArchives_sos_pb2.py,sha256=xyzFKVpIc_SriTn-z_Y7-HkDSRwVfjwE_bl5WwHd0p0,63730
27
+ numbers_parser/generated/TSCHCommandArchives_pb2.py,sha256=DkJUuBn-LXiY3a5rXipzFxb2mvOthHOKXdjaxYgt0as,27446
28
+ numbers_parser/generated/TSCHPreUFFArchives_pb2.py,sha256=EWhd5HcquCEYeFac1hwlHJuWu1glbTicfa2MaKK-XPY,30051
29
+ numbers_parser/generated/TSDArchives_pb2.py,sha256=G5vUxZbx66eTdNgxbagUQmo6N7pvfoXwU07jBgv90cU,39093
30
+ numbers_parser/generated/TSDArchives_sos_pb2.py,sha256=Q2MYAXjAW-PGE3FY8kFH89rry9PPUQv7DS956wymFwo,6022
31
+ numbers_parser/generated/TSDCommandArchives_pb2.py,sha256=DFxngZeWeqjBc-Y_EZxP1emHK5I_qQj5ewkc_xq_gfo,29192
32
+ numbers_parser/generated/TSKArchives_pb2.py,sha256=naNFAUk-D-rtD2vq-X2K6N7IOtDapBxF-ms4vVpdn-I,53324
33
+ numbers_parser/generated/TSKArchives_sos_pb2.py,sha256=Pi6hjw0g3JSrZ-y0gbqkojRB6_abYavqwoygiqmxgYE,1941
34
+ numbers_parser/generated/TSPArchiveMessages_pb2.py,sha256=5Th08Q19AOsMEMggvM9fda1StJjV8LTDDI5x7pY6aM8,17950
35
+ numbers_parser/generated/TSPDatabaseMessages_pb2.py,sha256=_jvq890xBQpSDcYOKgII30XlxukPBRZBu0kkRpbJ-z0,2024
36
+ numbers_parser/generated/TSPMessages_pb2.py,sha256=LBHRhNnQdDu226sh3gK_AOjbO3LDkGCWpVi1wzf7emA,13032
37
+ numbers_parser/generated/TSSArchives_pb2.py,sha256=grvUGHXl2hHcXKzsuoxyquskuo0cV1y841hHERFiYz0,9893
38
+ numbers_parser/generated/TSSArchives_sos_pb2.py,sha256=FAhtvQ9TBg18AcIk4HwGCreNWlEu3k_kK_9jRVsh7FM,2842
39
+ numbers_parser/generated/TSTArchives_pb2.py,sha256=smmTu4cTaCsX4Jp0TpVuuzaS_KYznpUB-h-4vZg82Yg,88138
40
+ numbers_parser/generated/TSTArchives_sos_pb2.py,sha256=JxiMXSdTH5VJo-c5zDdD_tzGQCTrUDE2K0YP_x-zh84,12597
41
+ numbers_parser/generated/TSTCommandArchives_pb2.py,sha256=LEyGJBOLdhxVarepxGfHprNs8vIAmSCO-iNnl3Afdkk,59523
42
+ numbers_parser/generated/TSTStylePropertyArchiving_pb2.py,sha256=0ADsIwTk4GcTeQJRhYxEEjsD_SuLEOSUaGYdHnsO9CA,12415
43
+ numbers_parser/generated/TSWPArchives_pb2.py,sha256=1jndSYYOlamxOkUlcWeDgdScduqX9OhJy2HSuZEKFhU,55326
44
+ numbers_parser/generated/TSWPArchives_sos_pb2.py,sha256=poJ49WA4JjZsHpmROyv4jFl2xGpJy6pTRCaJQZ5ZGr0,29114
45
+ numbers_parser/generated/TSWPCommandArchives_pb2.py,sha256=LCAklKgtN5EZt8cvO6jELYHyZhRqYunvbanV79a4Gu4,25482
46
+ numbers_parser/generated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ numbers_parser/generated/fontmap.py,sha256=pqc1HwwTr3UbFMmhUaHJg1dX5-3pXbyhfS2bkdZHKnI,22748
48
+ numbers_parser/generated/functionmap.py,sha256=VdZo0ERMYONcrnJFwABcSCHb8pjA4wY2ogt8Janz57M,6082
49
+ numbers_parser/generated/mapping.py,sha256=5yU_B_K6RECcTu8VnjC882rrnEvVI28LQvs4d9264Xg,32215
50
+ numbers_parser/iwafile.py,sha256=4_MMtHdWMAfIzwODyaM7DsWKh-8yJ2blTfbues8sbdI,11915
51
+ numbers_parser/iwork.py,sha256=CXXM797MqcIokovrIBAx--LNG7tIVpKqeBwR4V2OrzQ,9141
52
+ numbers_parser/model.py,sha256=Xqp_pc4hDKLUpP06_eQTruaq_4ey295yLpNyoapxXpg,98360
53
+ numbers_parser/numbers_cache.py,sha256=1ghEBghQAYFpPiEeOtb74i016mXc039v1pOubbqvaLs,1141
54
+ numbers_parser/numbers_uuid.py,sha256=q0IbHFKuBXC7MnZN3g55dgCVKOLD-4SO4MdXeN6dt0g,2699
55
+ numbers_parser-4.10.6.dist-info/LICENSE.rst,sha256=8vTa1-5KSdHrTpU9rlheO5005EWReEPMpjV7BjSaMc4,1050
56
+ numbers_parser-4.10.6.dist-info/METADATA,sha256=aWN8OAVae4iYCg5W-JTD_hmh_CrCeZPd_jalwo6fbkQ,16213
57
+ numbers_parser-4.10.6.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
58
+ numbers_parser-4.10.6.dist-info/entry_points.txt,sha256=V91uB9vBPxf3eCY1h-0syv21imYCT0MJfMxf87DmwIk,115
59
+ numbers_parser-4.10.6.dist-info/RECORD,,