numbers-parser 4.8.0__py3-none-any.whl → 4.9.0__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/cell.py +110 -13
- numbers_parser/cell_storage.py +48 -12
- numbers_parser/constants.py +109 -6
- numbers_parser/containers.py +2 -2
- numbers_parser/document.py +303 -136
- numbers_parser/file.py +9 -4
- numbers_parser/model.py +104 -7
- {numbers_parser-4.8.0.dist-info → numbers_parser-4.9.0.dist-info}/METADATA +96 -74
- {numbers_parser-4.8.0.dist-info → numbers_parser-4.9.0.dist-info}/RECORD +12 -12
- {numbers_parser-4.8.0.dist-info → numbers_parser-4.9.0.dist-info}/LICENSE.rst +0 -0
- {numbers_parser-4.8.0.dist-info → numbers_parser-4.9.0.dist-info}/WHEEL +0 -0
- {numbers_parser-4.8.0.dist-info → numbers_parser-4.9.0.dist-info}/entry_points.txt +0 -0
numbers_parser/cell.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from collections import namedtuple
|
|
3
|
-
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
4
|
from datetime import datetime as builtin_datetime
|
|
5
5
|
from datetime import timedelta as builtin_timedelta
|
|
6
6
|
from enum import IntEnum
|
|
7
|
+
from os.path import basename
|
|
7
8
|
from typing import Any, List, Tuple, Union
|
|
8
9
|
from warnings import warn
|
|
9
10
|
|
|
@@ -27,6 +28,7 @@ from numbers_parser.constants import (
|
|
|
27
28
|
EMPTY_STORAGE_BUFFER,
|
|
28
29
|
MAX_BASE,
|
|
29
30
|
MAX_SIGNIFICANT_DIGITS,
|
|
31
|
+
ControlFormattingType,
|
|
30
32
|
CustomFormattingType,
|
|
31
33
|
FormattingType,
|
|
32
34
|
FormatType,
|
|
@@ -75,18 +77,43 @@ __all__ = [
|
|
|
75
77
|
|
|
76
78
|
|
|
77
79
|
class BackgroundImage:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
"""
|
|
81
|
+
A named document style that can be applied to cells.
|
|
82
|
+
|
|
83
|
+
.. code-block:: python
|
|
84
|
+
|
|
85
|
+
fh = open("cats.png", mode="rb")
|
|
86
|
+
image_data = fh.read()
|
|
87
|
+
cats_bg = doc.add_style(
|
|
88
|
+
name="Cats",
|
|
89
|
+
bg_image=BackgroundImage(image_data, "cats.png")
|
|
90
|
+
)
|
|
91
|
+
table.write(0, 0, "❤️ cats", style=cats_bg)
|
|
92
|
+
|
|
93
|
+
Currently only standard image files and not 'advanced' image fills are
|
|
94
|
+
supported. Tiling and scaling is not reported back and cannot be changed
|
|
95
|
+
when saving new cells.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
data: bytes
|
|
100
|
+
Raw image data for a cell background image.
|
|
101
|
+
filename: str
|
|
102
|
+
Path to the image file.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
def __init__(self, data: bytes = None, filename: str = None):
|
|
106
|
+
self._data = data
|
|
107
|
+
self._filename = basename(filename)
|
|
81
108
|
|
|
82
109
|
@property
|
|
83
110
|
def data(self) -> bytes:
|
|
84
|
-
"""The background image as
|
|
111
|
+
"""bytes: The background image as bytes for a cell, or None if no image."""
|
|
85
112
|
return self._data
|
|
86
113
|
|
|
87
114
|
@property
|
|
88
115
|
def filename(self) -> str:
|
|
89
|
-
"""The image filename for a cell, or None if no image."""
|
|
116
|
+
"""str: The image filename for a cell, or None if no image."""
|
|
90
117
|
return self._filename
|
|
91
118
|
|
|
92
119
|
|
|
@@ -184,6 +211,8 @@ class Style:
|
|
|
184
211
|
------
|
|
185
212
|
TypeError:
|
|
186
213
|
If arguments do not match the specified type or for objects have invalid arguments
|
|
214
|
+
IndexError:
|
|
215
|
+
If an image filename already exists in document
|
|
187
216
|
"""
|
|
188
217
|
|
|
189
218
|
alignment: Alignment = DEFAULT_ALIGNMENT_CLASS # : horizontal and vertical alignment
|
|
@@ -230,6 +259,7 @@ class Style:
|
|
|
230
259
|
return [
|
|
231
260
|
"alignment",
|
|
232
261
|
"bg_color",
|
|
262
|
+
"bg_image",
|
|
233
263
|
"first_indent",
|
|
234
264
|
"left_indent",
|
|
235
265
|
"right_indent",
|
|
@@ -273,9 +303,9 @@ class Style:
|
|
|
273
303
|
if not isinstance(self.font_name, str):
|
|
274
304
|
raise TypeError("font name must be a string")
|
|
275
305
|
|
|
276
|
-
for
|
|
277
|
-
if not isinstance(getattr(self,
|
|
278
|
-
raise TypeError(f"{
|
|
306
|
+
for attr in ["bold", "italic", "underline", "strikethrough"]:
|
|
307
|
+
if not isinstance(getattr(self, attr), bool):
|
|
308
|
+
raise TypeError(f"{attr} argument must be boolean")
|
|
279
309
|
|
|
280
310
|
def __setattr__(self, name: str, value: Any) -> None:
|
|
281
311
|
"""Detect changes to cell styles and flag the style for
|
|
@@ -333,6 +363,36 @@ class BorderType(IntEnum):
|
|
|
333
363
|
|
|
334
364
|
|
|
335
365
|
class Border:
|
|
366
|
+
"""
|
|
367
|
+
Create a cell border to use with the :py:class:`~numbers_parser.Table` method
|
|
368
|
+
:py:meth:`~numbers_parser.Table.set_cell_border`.
|
|
369
|
+
|
|
370
|
+
.. code-block:: python
|
|
371
|
+
|
|
372
|
+
border_style = Border(8.0, RGB(29, 177, 0)
|
|
373
|
+
table.set_cell_border("B6", "left", border_style, "solid"), 3)
|
|
374
|
+
table.set_cell_border(6, 1, "right", border_style, "dashes"))
|
|
375
|
+
|
|
376
|
+
Parameters
|
|
377
|
+
----------
|
|
378
|
+
width: float, optional, default: 0.35
|
|
379
|
+
Number of rows in the first table of a new document.
|
|
380
|
+
color: RGB, optional, default: RGB(0, 0, 0)
|
|
381
|
+
The line color for the border if present
|
|
382
|
+
style: BorderType, optional, default: ``None``
|
|
383
|
+
The type of border to create or ``None`` if there is no border defined. Valid
|
|
384
|
+
border types are:
|
|
385
|
+
|
|
386
|
+
* ``"solid"``: a solid line
|
|
387
|
+
* ``"dashes"``: a dashed line
|
|
388
|
+
* ``"dots"``: a dotted line
|
|
389
|
+
|
|
390
|
+
Raises
|
|
391
|
+
------
|
|
392
|
+
TypeError:
|
|
393
|
+
If the width is not a float, or the border type is invalid.
|
|
394
|
+
"""
|
|
395
|
+
|
|
336
396
|
def __init__(
|
|
337
397
|
self,
|
|
338
398
|
width: float = DEFAULT_BORDER_WIDTH,
|
|
@@ -545,8 +605,14 @@ class Cell(Cacheable):
|
|
|
545
605
|
else:
|
|
546
606
|
raise ValueError("Can't determine cell type from type " + type(value).__name__)
|
|
547
607
|
|
|
548
|
-
def _set_formatting(
|
|
549
|
-
self
|
|
608
|
+
def _set_formatting(
|
|
609
|
+
self,
|
|
610
|
+
format_id: int,
|
|
611
|
+
format_type: FormattingType,
|
|
612
|
+
control_id: int = None,
|
|
613
|
+
is_currency: bool = False,
|
|
614
|
+
) -> None:
|
|
615
|
+
self._storage.set_formatting(format_id, format_type, control_id, is_currency)
|
|
550
616
|
|
|
551
617
|
def __init__(self, row: int, col: int, value):
|
|
552
618
|
self._value = value
|
|
@@ -675,7 +741,32 @@ class Cell(Cacheable):
|
|
|
675
741
|
|
|
676
742
|
@property
|
|
677
743
|
def formatted_value(self) -> str:
|
|
678
|
-
"""
|
|
744
|
+
"""
|
|
745
|
+
str: The formatted value of the cell as it appears in Numbers.
|
|
746
|
+
|
|
747
|
+
Interactive elements are converted into a suitable text format where
|
|
748
|
+
supported, or as their number values where there is no suitable
|
|
749
|
+
visual representation. Currently supported mappings are:
|
|
750
|
+
|
|
751
|
+
* Checkboxes are U+2610 (Ballow Box) or U+2611 (Ballot Box with Check)
|
|
752
|
+
* Ratings are their star value represented using (U+2605) (Black Star)
|
|
753
|
+
|
|
754
|
+
.. code-block:: python
|
|
755
|
+
|
|
756
|
+
>>> table = doc.sheets[0].tables[0]
|
|
757
|
+
>>> table.cell(0,0).value
|
|
758
|
+
False
|
|
759
|
+
>>> table.cell(0,0).formatted_value
|
|
760
|
+
'☐'
|
|
761
|
+
>>> table.cell(0,1).value
|
|
762
|
+
True
|
|
763
|
+
>>> table.cell(0,1).formatted_value
|
|
764
|
+
'☑'
|
|
765
|
+
>>> table.cell(1,1).value
|
|
766
|
+
3.0
|
|
767
|
+
>>> table.cell(1,1).formatted_value
|
|
768
|
+
'★★★'
|
|
769
|
+
"""
|
|
679
770
|
if self._storage is None:
|
|
680
771
|
return ""
|
|
681
772
|
else:
|
|
@@ -1049,16 +1140,22 @@ def xl_col_to_name(col, col_abs=False):
|
|
|
1049
1140
|
|
|
1050
1141
|
@dataclass()
|
|
1051
1142
|
class Formatting:
|
|
1052
|
-
|
|
1143
|
+
allow_none: bool = False
|
|
1053
1144
|
base_places: int = 0
|
|
1054
1145
|
base_use_minus_sign: bool = True
|
|
1055
1146
|
base: int = 10
|
|
1147
|
+
control_format: ControlFormattingType = ControlFormattingType.NUMBER
|
|
1056
1148
|
currency_code: str = "GBP"
|
|
1057
1149
|
date_time_format: str = DEFAULT_DATETIME_FORMAT
|
|
1058
1150
|
decimal_places: int = None
|
|
1059
1151
|
fraction_accuracy: FractionAccuracy = FractionAccuracy.THREE
|
|
1152
|
+
increment: float = 1.0
|
|
1153
|
+
maximum: float = 100.0
|
|
1154
|
+
minimum: float = 1.0
|
|
1155
|
+
popup_values: List[str] = field(default_factory=lambda: ["Item 1"])
|
|
1060
1156
|
negative_style: NegativeNumberStyle = NegativeNumberStyle.MINUS
|
|
1061
1157
|
show_thousands_separator: bool = False
|
|
1158
|
+
type: FormattingType = FormattingType.NUMBER
|
|
1062
1159
|
use_accounting_style: bool = False
|
|
1063
1160
|
_format_id = None
|
|
1064
1161
|
|
numbers_parser/cell_storage.py
CHANGED
|
@@ -11,6 +11,8 @@ from pendulum import datetime, duration
|
|
|
11
11
|
|
|
12
12
|
from numbers_parser import __name__ as numbers_parser_name
|
|
13
13
|
from numbers_parser.constants import (
|
|
14
|
+
CHECKBOX_FALSE_VALUE,
|
|
15
|
+
CHECKBOX_TRUE_VALUE,
|
|
14
16
|
CURRENCY_CELL_TYPE,
|
|
15
17
|
CUSTOM_TEXT_PLACEHOLDER,
|
|
16
18
|
DATETIME_FIELD_MAP,
|
|
@@ -21,6 +23,7 @@ from numbers_parser.constants import (
|
|
|
21
23
|
SECONDS_IN_DAY,
|
|
22
24
|
SECONDS_IN_HOUR,
|
|
23
25
|
SECONDS_IN_WEEK,
|
|
26
|
+
STAR_RATING_VALUE,
|
|
24
27
|
CellPadding,
|
|
25
28
|
CellType,
|
|
26
29
|
CustomFormattingType,
|
|
@@ -60,7 +63,7 @@ class CellStorage(Cacheable):
|
|
|
60
63
|
# "cond_style_id",
|
|
61
64
|
# "cond_rule_style_id",
|
|
62
65
|
"formula_id",
|
|
63
|
-
|
|
66
|
+
"control_id",
|
|
64
67
|
"formula_error_id",
|
|
65
68
|
"suggest_id",
|
|
66
69
|
"num_format_id",
|
|
@@ -95,7 +98,7 @@ class CellStorage(Cacheable):
|
|
|
95
98
|
# self.cond_style_id = None
|
|
96
99
|
# self.cond_rule_style_id = None
|
|
97
100
|
self.formula_id = None
|
|
98
|
-
|
|
101
|
+
self.control_id = None
|
|
99
102
|
self.formula_error_id = None
|
|
100
103
|
self.suggest_id = None
|
|
101
104
|
self.num_format_id = None
|
|
@@ -148,9 +151,9 @@ class CellStorage(Cacheable):
|
|
|
148
151
|
if flags & 0x200:
|
|
149
152
|
self.formula_id = unpack("<i", buffer[offset : offset + 4])[0]
|
|
150
153
|
offset += 4
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
if flags & 0x400:
|
|
155
|
+
self.control_id = unpack("<i", buffer[offset : offset + 4])[0]
|
|
156
|
+
offset += 4
|
|
154
157
|
# if flags & 0x800:
|
|
155
158
|
# self.formula_error_id = unpack("<i", buffer[offset : offset + 4])[0]
|
|
156
159
|
# offset += 4
|
|
@@ -158,7 +161,7 @@ class CellStorage(Cacheable):
|
|
|
158
161
|
self.suggest_id = unpack("<i", buffer[offset : offset + 4])[0]
|
|
159
162
|
offset += 4
|
|
160
163
|
# Skip unused flags
|
|
161
|
-
offset += 4 * bin(flags &
|
|
164
|
+
offset += 4 * bin(flags & 0x900).count("1")
|
|
162
165
|
#
|
|
163
166
|
if flags & 0x2000:
|
|
164
167
|
self.num_format_id = unpack("<i", buffer[offset : offset + 4])[0]
|
|
@@ -300,13 +303,15 @@ class CellStorage(Cacheable):
|
|
|
300
303
|
format = self.model.table_format(self.table_id, self.text_format_id)
|
|
301
304
|
elif self.currency_format_id is not None:
|
|
302
305
|
format = self.model.table_format(self.table_id, self.currency_format_id)
|
|
306
|
+
elif self.bool_format_id is not None and self.type == CellType.BOOL:
|
|
307
|
+
format = self.model.table_format(self.table_id, self.bool_format_id)
|
|
303
308
|
elif self.num_format_id is not None:
|
|
304
309
|
format = self.model.table_format(self.table_id, self.num_format_id)
|
|
305
|
-
elif self.bool_format_id is not None:
|
|
306
|
-
format = self.model.table_format(self.table_id, self.bool_format_id)
|
|
307
310
|
else:
|
|
308
311
|
return str(self.value)
|
|
309
312
|
|
|
313
|
+
debug("custom_format: @[%d,%d]: format_type=%s, ", self.row, self.col, format.format_type)
|
|
314
|
+
|
|
310
315
|
if format.HasField("custom_uid"):
|
|
311
316
|
format_uuid = NumbersUUID(format.custom_uid).hex
|
|
312
317
|
format_map = self.model.custom_format_map()
|
|
@@ -336,6 +341,10 @@ class CellStorage(Cacheable):
|
|
|
336
341
|
return format_fraction(self.d128, format)
|
|
337
342
|
elif format.format_type == FormatType.SCIENTIFIC:
|
|
338
343
|
return format_scientific(self.d128, format)
|
|
344
|
+
elif format.format_type == FormatType.CHECKBOX:
|
|
345
|
+
return CHECKBOX_TRUE_VALUE if self.value else CHECKBOX_FALSE_VALUE
|
|
346
|
+
elif format.format_type == FormatType.RATING:
|
|
347
|
+
return STAR_RATING_VALUE * int(self.d128)
|
|
339
348
|
else:
|
|
340
349
|
formatted_value = str(self.value)
|
|
341
350
|
return formatted_value
|
|
@@ -362,6 +371,14 @@ class CellStorage(Cacheable):
|
|
|
362
371
|
|
|
363
372
|
def duration_format(self) -> str:
|
|
364
373
|
format = self.model.table_format(self.table_id, self.duration_format_id)
|
|
374
|
+
debug(
|
|
375
|
+
"duration_format: @[%d,%d]: table_id=%d, duration_format_id=%d, duration_style=%s",
|
|
376
|
+
self.row,
|
|
377
|
+
self.col,
|
|
378
|
+
self.table_id,
|
|
379
|
+
self.duration_format_id,
|
|
380
|
+
format.duration_style,
|
|
381
|
+
)
|
|
365
382
|
|
|
366
383
|
duration_style = format.duration_style
|
|
367
384
|
unit_largest = format.duration_unit_largest
|
|
@@ -431,15 +448,34 @@ class CellStorage(Cacheable):
|
|
|
431
448
|
|
|
432
449
|
return duration_str
|
|
433
450
|
|
|
434
|
-
def
|
|
435
|
-
self,
|
|
451
|
+
def set_formatting(
|
|
452
|
+
self,
|
|
453
|
+
format_id: int,
|
|
454
|
+
format_type: Union[FormattingType, CustomFormattingType],
|
|
455
|
+
control_id: int = None,
|
|
456
|
+
is_currency: bool = False,
|
|
436
457
|
) -> None:
|
|
458
|
+
self.is_currency = is_currency
|
|
437
459
|
if format_type == FormattingType.CURRENCY:
|
|
438
460
|
self.currency_format_id = format_id
|
|
439
|
-
|
|
461
|
+
elif format_type == FormattingType.TICKBOX:
|
|
462
|
+
self.bool_format_id = format_id
|
|
463
|
+
self.control_id = control_id
|
|
464
|
+
elif format_type == FormattingType.RATING:
|
|
465
|
+
self.num_format_id = format_id
|
|
466
|
+
self.control_id = control_id
|
|
467
|
+
elif format_type in [FormattingType.SLIDER, FormattingType.STEPPER]:
|
|
468
|
+
if is_currency:
|
|
469
|
+
self.currency_format_id = format_id
|
|
470
|
+
else:
|
|
471
|
+
self.num_format_id = format_id
|
|
472
|
+
self.control_id = control_id
|
|
473
|
+
elif format_type == FormattingType.POPUP:
|
|
474
|
+
self.text_format_id = format_id
|
|
475
|
+
self.control_id = control_id
|
|
440
476
|
elif format_type in [FormattingType.DATETIME, CustomFormattingType.DATETIME]:
|
|
441
477
|
self.date_format_id = format_id
|
|
442
|
-
elif format_type
|
|
478
|
+
elif format_type in [FormattingType.TEXT, CustomFormattingType.TEXT]:
|
|
443
479
|
self.text_format_id = format_id
|
|
444
480
|
else:
|
|
445
481
|
self.num_format_id = format_id
|
numbers_parser/constants.py
CHANGED
|
@@ -20,6 +20,7 @@ __all__ = [
|
|
|
20
20
|
"FormattingType",
|
|
21
21
|
"NegativeNumberStyle",
|
|
22
22
|
"FractionAccuracy",
|
|
23
|
+
"ControlFormattingType",
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
DEFAULT_DOCUMENT = files("numbers_parser") / "data" / "empty.numbers"
|
|
@@ -44,8 +45,11 @@ DEFAULT_TEXT_INSET = 4.0
|
|
|
44
45
|
DEFAULT_TEXT_WRAP = True
|
|
45
46
|
EMPTY_STORAGE_BUFFER = b"\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
46
47
|
|
|
47
|
-
# Formatting defaults
|
|
48
|
+
# Formatting values and defaults
|
|
48
49
|
DEFAULT_DATETIME_FORMAT = "dd MMM YYY HH:MM"
|
|
50
|
+
CHECKBOX_FALSE_VALUE = "☐"
|
|
51
|
+
CHECKBOX_TRUE_VALUE = "☑"
|
|
52
|
+
STAR_RATING_VALUE = "★"
|
|
49
53
|
|
|
50
54
|
# Numbers limits
|
|
51
55
|
MAX_TILE_SIZE = 256
|
|
@@ -179,6 +183,39 @@ class FormattingType(IntEnum):
|
|
|
179
183
|
NUMBER = 5
|
|
180
184
|
PERCENTAGE = 6
|
|
181
185
|
SCIENTIFIC = 7
|
|
186
|
+
TICKBOX = 8
|
|
187
|
+
RATING = 9
|
|
188
|
+
SLIDER = 10
|
|
189
|
+
STEPPER = 11
|
|
190
|
+
POPUP = 12
|
|
191
|
+
TEXT = 13
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class ControlFormattingType(IntEnum):
|
|
195
|
+
BASE = 1
|
|
196
|
+
CURRENCY = 2
|
|
197
|
+
FRACTION = 4
|
|
198
|
+
NUMBER = 5
|
|
199
|
+
PERCENTAGE = 6
|
|
200
|
+
SCIENTIFIC = 7
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
FORMATTING_ALLOWED_CELLS = {
|
|
204
|
+
"base": ["NumberCell"],
|
|
205
|
+
"currency": ["NumberCell"],
|
|
206
|
+
"datetime": ["DateCell"],
|
|
207
|
+
"fraction": ["NumberCell"],
|
|
208
|
+
"number": ["NumberCell"],
|
|
209
|
+
"percentage": ["NumberCell"],
|
|
210
|
+
"popup": ["NumberCell", "TextCell"],
|
|
211
|
+
"rating": ["NumberCell"],
|
|
212
|
+
"scientific": ["NumberCell"],
|
|
213
|
+
"slider": ["NumberCell"],
|
|
214
|
+
"stepper": ["NumberCell"],
|
|
215
|
+
"tickbox": ["BoolCell"],
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
FORMATTING_ACTION_CELLS = ["tickbox", "rating", "popup", "slider", "stepper"]
|
|
182
219
|
|
|
183
220
|
|
|
184
221
|
class CustomFormattingType(IntEnum):
|
|
@@ -187,6 +224,13 @@ class CustomFormattingType(IntEnum):
|
|
|
187
224
|
TEXT = 103
|
|
188
225
|
|
|
189
226
|
|
|
227
|
+
CUSTOM_FORMATTING_ALLOWED_CELLS = {
|
|
228
|
+
"number": ["NumberCell"],
|
|
229
|
+
"datetime": ["DateCell"],
|
|
230
|
+
"text": ["TextCell"],
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
190
234
|
@enum_tools.documentation.document_enum
|
|
191
235
|
class NegativeNumberStyle(IntEnum):
|
|
192
236
|
"""
|
|
@@ -236,19 +280,47 @@ class FractionAccuracy(IntEnum):
|
|
|
236
280
|
|
|
237
281
|
|
|
238
282
|
ALLOWED_FORMATTING_PARAMETERS = {
|
|
239
|
-
FormattingType.BASE: [
|
|
283
|
+
FormattingType.BASE: [
|
|
284
|
+
"base",
|
|
285
|
+
"base_places",
|
|
286
|
+
"base_use_minus_sign",
|
|
287
|
+
],
|
|
240
288
|
FormattingType.CURRENCY: [
|
|
289
|
+
"currency_code",
|
|
241
290
|
"decimal_places",
|
|
242
|
-
"show_thousands_separator",
|
|
243
291
|
"negative_style",
|
|
292
|
+
"show_thousands_separator",
|
|
244
293
|
"use_accounting_style",
|
|
245
|
-
"currency_code",
|
|
246
294
|
],
|
|
247
295
|
FormattingType.DATETIME: ["date_time_format"],
|
|
248
296
|
FormattingType.FRACTION: ["fraction_accuracy"],
|
|
249
|
-
FormattingType.NUMBER: [
|
|
250
|
-
|
|
297
|
+
FormattingType.NUMBER: [
|
|
298
|
+
"decimal_places",
|
|
299
|
+
"show_thousands_separator",
|
|
300
|
+
"negative_style",
|
|
301
|
+
],
|
|
302
|
+
FormattingType.PERCENTAGE: [
|
|
303
|
+
"decimal_places",
|
|
304
|
+
"show_thousands_separator",
|
|
305
|
+
"negative_style",
|
|
306
|
+
],
|
|
251
307
|
FormattingType.SCIENTIFIC: ["decimal_places"],
|
|
308
|
+
FormattingType.POPUP: ["popup_values", "allow_none"],
|
|
309
|
+
FormattingType.RATING: [],
|
|
310
|
+
FormattingType.SLIDER: [
|
|
311
|
+
"control_format",
|
|
312
|
+
"increment",
|
|
313
|
+
"maximum",
|
|
314
|
+
"minimum",
|
|
315
|
+
],
|
|
316
|
+
FormattingType.STEPPER: [
|
|
317
|
+
"control_format",
|
|
318
|
+
"increment",
|
|
319
|
+
"maximum",
|
|
320
|
+
"minimum",
|
|
321
|
+
],
|
|
322
|
+
FormattingType.TICKBOX: [],
|
|
323
|
+
FormattingType.TEXT: [],
|
|
252
324
|
}
|
|
253
325
|
|
|
254
326
|
FORMAT_TYPE_MAP = {
|
|
@@ -258,7 +330,13 @@ FORMAT_TYPE_MAP = {
|
|
|
258
330
|
FormattingType.FRACTION: FormatType.FRACTION,
|
|
259
331
|
FormattingType.NUMBER: FormatType.DECIMAL,
|
|
260
332
|
FormattingType.PERCENTAGE: FormatType.PERCENT,
|
|
333
|
+
FormattingType.POPUP: FormatType.TEXT,
|
|
334
|
+
FormattingType.RATING: FormatType.RATING,
|
|
261
335
|
FormattingType.SCIENTIFIC: FormatType.SCIENTIFIC,
|
|
336
|
+
FormattingType.SLIDER: FormatType.DECIMAL,
|
|
337
|
+
FormattingType.STEPPER: FormatType.DECIMAL,
|
|
338
|
+
FormattingType.TICKBOX: FormatType.CHECKBOX,
|
|
339
|
+
FormattingType.TEXT: FormatType.TEXT,
|
|
262
340
|
}
|
|
263
341
|
|
|
264
342
|
CUSTOM_FORMAT_TYPE_MAP = {
|
|
@@ -268,7 +346,32 @@ CUSTOM_FORMAT_TYPE_MAP = {
|
|
|
268
346
|
}
|
|
269
347
|
|
|
270
348
|
|
|
349
|
+
class CellInteractionType(IntEnum):
|
|
350
|
+
VALUE_EDITING = 0
|
|
351
|
+
FORMULA_EDITING = 1
|
|
352
|
+
STOCK = 2
|
|
353
|
+
CATEGORY_SUMMARY = 3
|
|
354
|
+
STEPPER = 4
|
|
355
|
+
SLIDER = 5
|
|
356
|
+
RATING = 6
|
|
357
|
+
POPUP = 7
|
|
358
|
+
TOGGLE = 8
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
CONTROL_CELL_TYPE_MAP = {
|
|
362
|
+
FormattingType.POPUP: CellInteractionType.POPUP,
|
|
363
|
+
FormattingType.SLIDER: CellInteractionType.SLIDER,
|
|
364
|
+
FormattingType.STEPPER: CellInteractionType.STEPPER,
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
@enum_tools.documentation.document_enum
|
|
271
369
|
class PaddingType(IntEnum):
|
|
370
|
+
"""How integers and decimals are padded in custom number formats"""
|
|
371
|
+
|
|
272
372
|
NONE = 0
|
|
373
|
+
"""No number padding."""
|
|
273
374
|
ZEROS = 1
|
|
375
|
+
"""Pad integers with leading spaces and decimals with trailing spaces."""
|
|
274
376
|
SPACES = 2
|
|
377
|
+
"""Pad integers with leading zeroes and decimals with trailing zeroes."""
|
numbers_parser/containers.py
CHANGED
|
@@ -59,7 +59,7 @@ class ObjectStore:
|
|
|
59
59
|
self._objects[PACKAGE_ID].last_object_identifier = self._max_id
|
|
60
60
|
return self._max_id
|
|
61
61
|
|
|
62
|
-
def create_object_from_dict(self, iwa_file: str, object_dict: dict, cls: object):
|
|
62
|
+
def create_object_from_dict(self, iwa_file: str, object_dict: dict, cls: object, append=False):
|
|
63
63
|
"""Create a new object and store the associated IWA segment. Return the
|
|
64
64
|
message ID for the object and the newly created object. If the IWA
|
|
65
65
|
file cannot be found, it will be created.
|
|
@@ -70,7 +70,7 @@ class ObjectStore:
|
|
|
70
70
|
new_id = self.new_message_id()
|
|
71
71
|
iwa_segment = create_iwa_segment(new_id, cls, object_dict)
|
|
72
72
|
|
|
73
|
-
if iwa_pathname is None:
|
|
73
|
+
if iwa_pathname is None and not append:
|
|
74
74
|
iwa_pathname = iwa_file.format(new_id) + ".iwa"
|
|
75
75
|
chunks = {"chunks": [{"archives": [iwa_segment.to_dict()]}]}
|
|
76
76
|
self._file_store[iwa_pathname] = IWAFile.from_dict(chunks)
|