numbers-parser 4.11.5__tar.gz → 4.12.0__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 (59) hide show
  1. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/PKG-INFO +2 -1
  2. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/pyproject.toml +2 -2
  3. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/cell.py +2 -2
  4. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/model.py +157 -20
  5. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/LICENSE.rst +0 -0
  6. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/README.md +0 -0
  7. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/__init__.py +0 -0
  8. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/_cat_numbers.py +0 -0
  9. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/_unpack_numbers.py +0 -0
  10. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/bullets.py +0 -0
  11. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/constants.py +0 -0
  12. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/containers.py +0 -0
  13. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/currencies.py +0 -0
  14. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/data/empty.numbers +0 -0
  15. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/document.py +0 -0
  16. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/exceptions.py +0 -0
  17. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/experimental.py +0 -0
  18. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/formula.py +0 -0
  19. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TNArchives_pb2.py +0 -0
  20. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TNArchives_sos_pb2.py +0 -0
  21. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TNCommandArchives_pb2.py +0 -0
  22. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TNCommandArchives_sos_pb2.py +0 -0
  23. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSAArchives_pb2.py +0 -0
  24. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSAArchives_sos_pb2.py +0 -0
  25. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSACommandArchives_sos_pb2.py +0 -0
  26. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCEArchives_pb2.py +0 -0
  27. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCH3DArchives_pb2.py +0 -0
  28. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCHArchives_Common_pb2.py +0 -0
  29. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCHArchives_GEN_pb2.py +0 -0
  30. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCHArchives_pb2.py +0 -0
  31. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCHArchives_sos_pb2.py +0 -0
  32. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCHCommandArchives_pb2.py +0 -0
  33. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCHPreUFFArchives_pb2.py +0 -0
  34. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCKArchives_pb2.py +0 -0
  35. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSCKArchives_sos_pb2.py +0 -0
  36. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSDArchives_pb2.py +0 -0
  37. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSDArchives_sos_pb2.py +0 -0
  38. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSDCommandArchives_pb2.py +0 -0
  39. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSKArchives_pb2.py +0 -0
  40. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSPArchiveMessages_pb2.py +0 -0
  41. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSPDatabaseMessages_pb2.py +0 -0
  42. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSPMessages_pb2.py +0 -0
  43. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSSArchives_pb2.py +0 -0
  44. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSSArchives_sos_pb2.py +0 -0
  45. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSTArchives_pb2.py +0 -0
  46. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSTArchives_sos_pb2.py +0 -0
  47. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSTCommandArchives_pb2.py +0 -0
  48. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSTStylePropertyArchiving_pb2.py +0 -0
  49. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSWPArchives_pb2.py +0 -0
  50. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSWPArchives_sos_pb2.py +0 -0
  51. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/TSWPCommandArchives_pb2.py +0 -0
  52. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/__init__.py +0 -0
  53. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/fontmap.py +0 -0
  54. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/functionmap.py +0 -0
  55. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/generated/mapping.py +0 -0
  56. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/iwafile.py +0 -0
  57. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/iwork.py +0 -0
  58. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/src/numbers_parser/numbers_cache.py +0 -0
  59. {numbers_parser-4.11.5 → numbers_parser-4.12.0}/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.11.5
3
+ Version: 4.12.0
4
4
  Summary: Read and write Apple Numbers spreadsheets
5
5
  Home-page: https://github.com/masaccio/numbers-parser
6
6
  License: MIT
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
18
+ Requires-Dist: colorama (>=0.4.6,<0.5.0)
18
19
  Requires-Dist: compact-json (>=1.1.3,<2.0.0)
19
20
  Requires-Dist: enum-tools (>=0.11)
20
21
  Requires-Dist: importlib-resources (>=6.1)
@@ -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.11.5"
15
+ version = "4.12.0"
16
16
 
17
17
  [tool.poetry.scripts]
18
18
  cat-numbers = "numbers_parser._cat_numbers:main"
@@ -30,6 +30,7 @@ sigfig = "^1.3.2"
30
30
  setuptools = ">=69.0.3"
31
31
  importlib-resources = ">=6.1"
32
32
  enum-tools = ">=0.11"
33
+ colorama = "^0.4.6"
33
34
 
34
35
  [tool.poetry.group.dev.dependencies]
35
36
  black = "*"
@@ -44,7 +45,6 @@ pytest-cov = ">=4.0,>=5.0"
44
45
  pytest-profiling = "^1.7.0"
45
46
  pytest-xdist = "^3.3.1"
46
47
  ruff = "*"
47
- termcolor = ">=2.2"
48
48
  tox = "^4.11.4"
49
49
  python-magic = ">=0.4"
50
50
  tqdm = ">=4.66"
@@ -993,7 +993,7 @@ class Cell(CellStorageFlags, Cacheable):
993
993
  )
994
994
  self._model.add_component_reference(
995
995
  self._style._text_style_obj_id,
996
- parent_id=self._model._table_styles.id(self._table_id),
996
+ component_id=self._model._table_styles.id(self._table_id),
997
997
  )
998
998
 
999
999
  if self._style._cell_style_obj_id is not None:
@@ -1003,7 +1003,7 @@ class Cell(CellStorageFlags, Cacheable):
1003
1003
  )
1004
1004
  self._model.add_component_reference(
1005
1005
  self._style._cell_style_obj_id,
1006
- parent_id=self._model._table_styles.id(self._table_id),
1006
+ component_id=self._model._table_styles.id(self._table_id),
1007
1007
  )
1008
1008
 
1009
1009
  length = 12
@@ -331,10 +331,140 @@ class _NumbersModel(Cacheable):
331
331
  else:
332
332
  return not table_info.super.caption_hidden
333
333
 
334
+ def captions_style_id(self):
335
+ stylesheet = self.objects[self.find_refs("StylesheetArchive")[0]]
336
+ caption_styles = [
337
+ x for x in stylesheet.identifier_to_style_map if "Caption" in x.identifier
338
+ ]
339
+ return caption_styles[0].style.identifier
340
+
341
+ def caption_paragraph_style_id(self):
342
+ style_map = {
343
+ id: self.objects[id]
344
+ for id in self.find_refs("ParagraphStyleArchive")
345
+ if "Caption" in self.objects[id].super.name
346
+ }
347
+ return list(style_map.keys())[0]
348
+
349
+ @cache(num_args=0)
350
+ def stylesheet_id(self):
351
+ return self.find_refs("StylesheetArchive")[0]
352
+
353
+ def set_reference(self, obj: object, id: int):
354
+ obj.MergeFrom(TSPMessages.Reference(identifier=id))
355
+
356
+ def create_path_source_archive(self, table_id):
357
+ return TSDArchives.PathSourceArchive(
358
+ horizontalFlip=False,
359
+ verticalFlip=False,
360
+ bezier_path_source=TSDArchives.BezierPathSourceArchive(
361
+ naturalSize=TSPMessages.Size(width=self.table_width(table_id), height=0.0),
362
+ path=TSPMessages.Path(
363
+ elements=[
364
+ TSPMessages.Path.Element(
365
+ type=TSPMessages.Path.ElementType.moveTo,
366
+ points=[TSPMessages.Point(x=0.0, y=0.0)],
367
+ ),
368
+ TSPMessages.Path.Element(
369
+ type=TSPMessages.Path.ElementType.lineTo,
370
+ points=[TSPMessages.Point(x=100.0, y=0.0)],
371
+ ),
372
+ TSPMessages.Path.Element(
373
+ type=TSPMessages.Path.ElementType.lineTo,
374
+ points=[TSPMessages.Point(x=100.0, y=100.0)],
375
+ ),
376
+ TSPMessages.Path.Element(
377
+ type=TSPMessages.Path.ElementType.lineTo,
378
+ points=[TSPMessages.Point(x=0.0, y=100.0)],
379
+ ),
380
+ TSPMessages.Path.Element(
381
+ type=TSPMessages.Path.ElementType.closeSubpath,
382
+ ),
383
+ TSPMessages.Path.Element(
384
+ type=TSPMessages.Path.ElementType.moveTo,
385
+ points=[TSPMessages.Point(x=0.0, y=0.0)],
386
+ ),
387
+ ]
388
+ ),
389
+ ),
390
+ )
391
+
392
+ def create_caption_archive(self, table_id):
393
+ table_info_id = self.table_info_id(table_id)
394
+ table_info = self.objects[table_info_id]
395
+ caption_placement_id, _ = self.objects.create_object_from_dict(
396
+ "CalculationEngine",
397
+ {
398
+ "caption_anchor_location": 1,
399
+ "drawable_anchor_location": 7,
400
+ },
401
+ TSAArchives.CaptionPlacementArchive,
402
+ )
403
+ caption_info_id, caption_info = self.objects.create_object_from_dict(
404
+ "CalculationEngine",
405
+ {"childInfoKind": "Caption", "placement": {"identifier": caption_placement_id}},
406
+ TSAArchives.CaptionInfoArchive,
407
+ )
408
+ storage_id, storage = self.objects.create_object_from_dict(
409
+ "CalculationEngine",
410
+ {
411
+ "text": ["Caption"],
412
+ "in_document": True,
413
+ "style_sheet": {"identifier": self.stylesheet_id()},
414
+ "table_para_style": {
415
+ "entries": [
416
+ {
417
+ "character_index": 0,
418
+ "object": {"identifier": self.caption_paragraph_style_id()},
419
+ }
420
+ ]
421
+ },
422
+ "table_para_starts": {"entries": [{"character_index": 0, "first": 0, "second": 0}]},
423
+ "table_para_bidi": {"entries": [{"character_index": 0, "first": 0, "second": 0}]},
424
+ "table_drop_cap_style": {"entries": [{"character_index": 0}]},
425
+ },
426
+ TSWPArchives.StorageArchive,
427
+ )
428
+ for object_id in [storage_id, self.captions_style_id(), self.caption_paragraph_style_id()]:
429
+ self.add_component_reference(
430
+ object_id, location="CalculationEngine", component_id=self.stylesheet_id()
431
+ )
432
+ caption_info.super.MergeFrom(
433
+ TSWPArchives.ShapeInfoArchive(
434
+ is_text_box=True,
435
+ owned_storage=TSPMessages.Reference(identifier=storage_id),
436
+ deprecated_storage=TSPMessages.Reference(identifier=storage_id),
437
+ super=TSDArchives.ShapeArchive(
438
+ super=self.create_drawable(table_info_id, 0, 0, flags=1),
439
+ style={"identifier": self.captions_style_id()},
440
+ strokePatternOffsetDistance=0.0,
441
+ pathsource=self.create_path_source_archive(table_id),
442
+ ),
443
+ )
444
+ )
445
+
446
+ self.set_reference(table_info.super.caption, caption_info_id)
447
+ component = self.metadata_component(self.calc_engine_id())
448
+ component.object_uuid_map_entries.append(
449
+ TSPArchiveMessages.ObjectUUIDMapEntry(
450
+ identifier=caption_info_id, uuid=NumbersUUID().protobuf2
451
+ )
452
+ )
453
+
334
454
  def caption_text(self, table_id: int, caption: str = None) -> str:
335
455
  table_info = self.objects[self.table_info_id(table_id)]
336
456
  caption_info_id = table_info.super.caption.identifier
337
- caption_storage_id = self.objects[caption_info_id].super.owned_storage.identifier
457
+ caption_archive = self.objects[caption_info_id]
458
+
459
+ if caption_archive.DESCRIPTOR.name == "StandinCaptionArchive":
460
+ if caption is None:
461
+ return "Caption"
462
+ else:
463
+ self.create_caption_archive(table_id)
464
+ caption_info_id = table_info.super.caption.identifier
465
+ caption_archive = self.objects[caption_info_id]
466
+
467
+ caption_storage_id = caption_archive.super.owned_storage.identifier
338
468
  caption_text = self.objects[caption_storage_id].text
339
469
  if caption is not None:
340
470
  caption_text[0] = caption
@@ -882,7 +1012,7 @@ class _NumbersModel(Cacheable):
882
1012
  merge_map.cell_range.append(cell_range)
883
1013
 
884
1014
  base_data_store = self.objects[table_id].base_data_store
885
- base_data_store.merge_region_map.CopyFrom(TSPMessages.Reference(identifier=merge_map_id))
1015
+ self.set_reference(base_data_store.merge_region_map, merge_map_id)
886
1016
 
887
1017
  def recalculate_row_info(
888
1018
  self,
@@ -943,19 +1073,19 @@ class _NumbersModel(Cacheable):
943
1073
  save_token=1,
944
1074
  )
945
1075
  self.objects[PACKAGE_ID].components.append(component_info)
946
- self.add_component_reference(object_id, parent)
1076
+ self.add_component_reference(object_id, location=parent)
947
1077
 
948
1078
  def add_component_reference(
949
1079
  self,
950
1080
  object_id: int,
951
1081
  location: Optional[str] = None,
952
- parent_id: Optional[int] = None,
1082
+ component_id: Optional[int] = None,
953
1083
  is_weak: bool = False,
954
1084
  ):
955
1085
  """Add an external reference to an object in a metadata component."""
956
- component = self.metadata_component(location or parent_id)
957
- if parent_id is not None:
958
- params = {"object_identifier": object_id, "component_identifier": parent_id}
1086
+ component = self.metadata_component(location or component_id)
1087
+ if component_id is not None:
1088
+ params = {"object_identifier": object_id, "component_identifier": component_id}
959
1089
  else:
960
1090
  params = {"component_identifier": object_id}
961
1091
  if is_weak:
@@ -1175,7 +1305,15 @@ class _NumbersModel(Cacheable):
1175
1305
 
1176
1306
  return self.table_height(table_id) + y_offset
1177
1307
 
1178
- def create_drawable(self, sheet_id: int, x: float, y: float) -> object:
1308
+ def create_drawable(
1309
+ self,
1310
+ sheet_id: int,
1311
+ x: float,
1312
+ y: float,
1313
+ flags: int = 3,
1314
+ height: float = 231.0,
1315
+ width: float = 494.0,
1316
+ ) -> object:
1179
1317
  """Create a DrawableArchive for a new table in a sheet."""
1180
1318
  table_x = x if x is not None else 0.0
1181
1319
  table_y = y if y is not None else self.last_table_offset(sheet_id) + DEFAULT_TABLE_OFFSET
@@ -1183,9 +1321,9 @@ class _NumbersModel(Cacheable):
1183
1321
  parent=TSPMessages.Reference(identifier=sheet_id),
1184
1322
  geometry=TSDArchives.GeometryArchive(
1185
1323
  angle=0.0,
1186
- flags=3,
1324
+ flags=flags,
1187
1325
  position=TSPMessages.Point(x=table_x, y=table_y),
1188
- size=TSPMessages.Size(height=231.0, width=494.0),
1326
+ size=TSPMessages.Size(height=height, width=width),
1189
1327
  ),
1190
1328
  )
1191
1329
 
@@ -1255,19 +1393,14 @@ class _NumbersModel(Cacheable):
1255
1393
  caption_info.super.CopyFrom(from_caption_info.super)
1256
1394
  caption_info.super.super.CopyFrom(from_caption_info.super.super)
1257
1395
  caption_info.super.super.super.CopyFrom(from_caption_info.super.super.super)
1258
- caption_info.super.deprecated_storage.MergeFrom(
1259
- TSPMessages.Reference(identifier=caption_storage_id)
1260
- )
1261
- caption_info.super.owned_storage.MergeFrom(
1262
- TSPMessages.Reference(identifier=caption_storage_id)
1263
- )
1264
-
1396
+ self.set_reference(caption_info.super.deprecated_storage, caption_storage_id)
1397
+ self.set_reference(caption_info.super.owned_storage, caption_storage_id)
1265
1398
  sidecar_id, _ = self.objects.create_object_from_dict(
1266
1399
  "CalculationEngine",
1267
1400
  {"max_order": 1, "column_count": 0, "row_count": 0},
1268
1401
  TSTArchives.StrokeSidecarArchive,
1269
1402
  )
1270
- table_model.stroke_sidecar.MergeFrom(TSPMessages.Reference(identifier=sidecar_id))
1403
+ self.set_reference(table_model.stroke_sidecar, sidecar_id)
1271
1404
 
1272
1405
  style_table_id, _ = self.objects.create_object_from_dict(
1273
1406
  "Index/Tables/DataList-{}",
@@ -1351,7 +1484,9 @@ class _NumbersModel(Cacheable):
1351
1484
  TSPMessages.Reference(identifier=table_info_id)
1352
1485
  )
1353
1486
  table_info.super.caption.MergeFrom(TSPMessages.Reference(identifier=caption_info_id))
1354
- self.add_component_reference(table_info_id, "Document", self.calc_engine_id())
1487
+ self.add_component_reference(
1488
+ table_info_id, location="Document", component_id=self.calc_engine_id()
1489
+ )
1355
1490
 
1356
1491
  self.add_formula_owner(
1357
1492
  table_info_id,
@@ -1452,7 +1587,9 @@ class _NumbersModel(Cacheable):
1452
1587
  TNArchives.SheetArchive,
1453
1588
  )
1454
1589
 
1455
- self.add_component_reference(sheet_id, "CalculationEngine", DOCUMENT_ID, is_weak=True)
1590
+ self.add_component_reference(
1591
+ sheet_id, location="CalculationEngine", component_id=DOCUMENT_ID, is_weak=True
1592
+ )
1456
1593
 
1457
1594
  self.objects[DOCUMENT_ID].sheets.append(TSPMessages.Reference(identifier=sheet_id))
1458
1595