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.
- numbers_parser/__init__.py +1 -1
- numbers_parser/_cat_numbers.py +4 -4
- numbers_parser/_unpack_numbers.py +5 -5
- numbers_parser/cell.py +150 -128
- numbers_parser/constants.py +5 -6
- numbers_parser/containers.py +11 -8
- numbers_parser/document.py +147 -108
- numbers_parser/exceptions.py +0 -7
- numbers_parser/formula.py +3 -4
- numbers_parser/generated/TNArchives_pb2.py +24 -26
- numbers_parser/generated/TSAArchives_pb2.py +26 -28
- numbers_parser/generated/TSCEArchives_pb2.py +8 -10
- numbers_parser/generated/TSCHArchives_GEN_pb2.py +28 -34
- numbers_parser/generated/TSCHArchives_pb2.py +61 -65
- numbers_parser/generated/TSDArchives_pb2.py +100 -110
- numbers_parser/generated/TSKArchives_pb2.py +168 -170
- numbers_parser/generated/TSPArchiveMessages_pb2.py +32 -34
- numbers_parser/generated/TSPMessages_pb2.py +40 -40
- numbers_parser/generated/TSSArchives_pb2.py +36 -36
- numbers_parser/generated/TSTArchives_pb2.py +321 -325
- numbers_parser/generated/TSTStylePropertyArchiving_pb2.py +8 -10
- numbers_parser/generated/TSWPArchives_pb2.py +250 -286
- numbers_parser/generated/TSWPCommandArchives_pb2.py +95 -95
- numbers_parser/iwafile.py +17 -17
- numbers_parser/iwork.py +33 -27
- numbers_parser/model.py +94 -52
- numbers_parser/numbers_uuid.py +6 -4
- {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/METADATA +9 -9
- numbers_parser-4.10.6.dist-info/RECORD +59 -0
- numbers_parser-4.10.4.dist-info/RECORD +0 -59
- numbers_parser/{mapping.py → generated/mapping.py} +24 -24
- {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/LICENSE.rst +0 -0
- {numbers_parser-4.10.4.dist-info → numbers_parser-4.10.6.dist-info}/WHEEL +0 -0
- {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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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",
|
|
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,
|
|
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-{}",
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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",
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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()
|
numbers_parser/numbers_uuid.py
CHANGED
|
@@ -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
|
-
|
|
36
|
+
msg = "Unsupported UUID dict structure"
|
|
37
|
+
raise UnsupportedError(msg)
|
|
37
38
|
else:
|
|
38
|
-
|
|
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.
|
|
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
|
|
20
|
-
Requires-Dist: importlib-resources (>=6.1
|
|
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.
|
|
24
|
-
Requires-Dist: regex (
|
|
25
|
-
Requires-Dist: roman (>=
|
|
26
|
-
Requires-Dist: setuptools (>=69.0.3
|
|
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
|
[](https://github.com/masaccio/numbers-parser/actions/workflows/run-all-tests.yml)[](https://github.com/masaccio/numbers-parser/actions/workflows/codeql.yml)[](https://codecov.io/gh/masaccio/numbers-parser)[](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
|
|
38
|
-
(current as of
|
|
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,,
|