numbers-parser 4.13.3__tar.gz → 4.14.1__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.
- numbers_parser-4.13.3/README.md → numbers_parser-4.14.1/PKG-INFO +31 -15
- numbers_parser-4.13.3/PKG-INFO → numbers_parser-4.14.1/README.md +1 -48
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/pyproject.toml +7 -9
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/__init__.py +2 -1
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/_cat_numbers.py +14 -5
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/_unpack_numbers.py +2 -3
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/bullets.py +7 -8
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/cell.py +23 -26
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/constants.py +16 -5
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/document.py +3 -4
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/formula.py +2 -3
- numbers_parser-4.14.1/src/numbers_parser/roman.py +18 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/LICENSE.rst +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/_csv2numbers.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/containers.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/currencies.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/data/empty.numbers +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/exceptions.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/experimental.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TNArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TNArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TNCommandArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TNCommandArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSAArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSAArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSACommandArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCEArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCH3DArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_Common_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_GEN_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHCommandArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHPreUFFArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCKArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCKArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSDArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSDArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSDCommandArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSKArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSPArchiveMessages_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSPDatabaseMessages_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSPMessages_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSSArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSSArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSTArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSTArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSTCommandArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSTStylePropertyArchiving_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSWPArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSWPArchives_sos_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSWPCommandArchives_pb2.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/__init__.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/fontmap.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/functionmap.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/mapping.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/iwafile.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/iwork.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/model.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/numbers_cache.py +0 -0
- {numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/numbers_uuid.py +0 -0
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: numbers-parser
|
|
3
|
+
Version: 4.14.1
|
|
4
|
+
Summary: Read and write Apple Numbers spreadsheets
|
|
5
|
+
Home-page: https://github.com/masaccio/numbers-parser
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: Jon Connell
|
|
8
|
+
Author-email: python@figsandfudge.com
|
|
9
|
+
Requires-Python: >=3.9,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
|
|
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)
|
|
21
|
+
Requires-Dist: protobuf
|
|
22
|
+
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
23
|
+
Requires-Dist: python-snappy (>=0.7,<0.8)
|
|
24
|
+
Requires-Dist: setuptools (>=70.0.0)
|
|
25
|
+
Requires-Dist: sigfig (>=1.3.3,<2.0.0)
|
|
26
|
+
Project-URL: Documentation, https://github.com/masaccio/numbers-parser/blob/main/README.md
|
|
27
|
+
Project-URL: Repository, https://github.com/masaccio/numbers-parser
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
1
30
|
# numbers-parser
|
|
2
31
|
|
|
3
32
|
[](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)
|
|
@@ -97,21 +126,7 @@ the column values.
|
|
|
97
126
|
|
|
98
127
|
Cells are objects with a common base class of `Cell`. All cell types
|
|
99
128
|
have a property `value` which returns the contents of the cell as a
|
|
100
|
-
python datatype.
|
|
101
|
-
[pendulum](https://pendulum.eustace.io) instead of python’s builtin
|
|
102
|
-
types. Available cell types are:
|
|
103
|
-
|
|
104
|
-
| Cell type | value type | Additional properties |
|
|
105
|
-
|--------------|---------------------|--------------------------------------------------------------------------------------------------------|
|
|
106
|
-
| NumberCell | `float` | |
|
|
107
|
-
| TextCell | `str` | |
|
|
108
|
-
| RichTextCell | `str` | See [Rich text](https://masaccio.github.io/numbers-parser/api/cells.html#numbers_parser.RichTextCell) |
|
|
109
|
-
| EmptyCell | `None` | |
|
|
110
|
-
| BoolCell | `bool` | |
|
|
111
|
-
| DateCell | `pendulum.datetime` | |
|
|
112
|
-
| DurationCell | `pendulum.duration` | |
|
|
113
|
-
| ErrorCell | `None` | |
|
|
114
|
-
| MergedCell | `None` | See [Merged cells](https://masaccio.github.io/numbers-parser/api/cells.html#numbers_parser.MergedCell) |
|
|
129
|
+
python datatype. Available cell types are:
|
|
115
130
|
|
|
116
131
|
Cell references can be either zero-offset row/column integers or an
|
|
117
132
|
Excel/Numbers A1 notation. Where cell values are not `None` the
|
|
@@ -478,3 +493,4 @@ The following limitations are expected to always remain:
|
|
|
478
493
|
## License
|
|
479
494
|
|
|
480
495
|
All code in this repository is licensed under the [MIT License](https://github.com/masaccio/numbers-parser/blob/master/LICENSE.rst).
|
|
496
|
+
|
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: numbers-parser
|
|
3
|
-
Version: 4.13.3
|
|
4
|
-
Summary: Read and write Apple Numbers spreadsheets
|
|
5
|
-
Home-page: https://github.com/masaccio/numbers-parser
|
|
6
|
-
License: MIT
|
|
7
|
-
Author: Jon Connell
|
|
8
|
-
Author-email: python@figsandfudge.com
|
|
9
|
-
Requires-Python: >=3.9,<4.0
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
|
|
18
|
-
Requires-Dist: colorama (>=0.4.6,<0.5.0)
|
|
19
|
-
Requires-Dist: compact-json (>=1.1.3,<2.0.0)
|
|
20
|
-
Requires-Dist: enum-tools (>=0.11)
|
|
21
|
-
Requires-Dist: importlib-resources (>=6.1)
|
|
22
|
-
Requires-Dist: pendulum (>=3.0,<4.0)
|
|
23
|
-
Requires-Dist: protobuf
|
|
24
|
-
Requires-Dist: python-snappy (>=0.7,<0.8)
|
|
25
|
-
Requires-Dist: regex (>2024.0)
|
|
26
|
-
Requires-Dist: roman (>=4.0)
|
|
27
|
-
Requires-Dist: setuptools (>=69.0.3)
|
|
28
|
-
Requires-Dist: sigfig (>=1.3.2,<2.0.0)
|
|
29
|
-
Project-URL: Documentation, https://github.com/masaccio/numbers-parser/blob/main/README.md
|
|
30
|
-
Project-URL: Repository, https://github.com/masaccio/numbers-parser
|
|
31
|
-
Description-Content-Type: text/markdown
|
|
32
|
-
|
|
33
1
|
# numbers-parser
|
|
34
2
|
|
|
35
3
|
[](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)
|
|
@@ -129,21 +97,7 @@ the column values.
|
|
|
129
97
|
|
|
130
98
|
Cells are objects with a common base class of `Cell`. All cell types
|
|
131
99
|
have a property `value` which returns the contents of the cell as a
|
|
132
|
-
python datatype.
|
|
133
|
-
[pendulum](https://pendulum.eustace.io) instead of python’s builtin
|
|
134
|
-
types. Available cell types are:
|
|
135
|
-
|
|
136
|
-
| Cell type | value type | Additional properties |
|
|
137
|
-
|--------------|---------------------|--------------------------------------------------------------------------------------------------------|
|
|
138
|
-
| NumberCell | `float` | |
|
|
139
|
-
| TextCell | `str` | |
|
|
140
|
-
| RichTextCell | `str` | See [Rich text](https://masaccio.github.io/numbers-parser/api/cells.html#numbers_parser.RichTextCell) |
|
|
141
|
-
| EmptyCell | `None` | |
|
|
142
|
-
| BoolCell | `bool` | |
|
|
143
|
-
| DateCell | `pendulum.datetime` | |
|
|
144
|
-
| DurationCell | `pendulum.duration` | |
|
|
145
|
-
| ErrorCell | `None` | |
|
|
146
|
-
| MergedCell | `None` | See [Merged cells](https://masaccio.github.io/numbers-parser/api/cells.html#numbers_parser.MergedCell) |
|
|
100
|
+
python datatype. Available cell types are:
|
|
147
101
|
|
|
148
102
|
Cell references can be either zero-offset row/column integers or an
|
|
149
103
|
Excel/Numbers A1 notation. Where cell values are not `None` the
|
|
@@ -510,4 +464,3 @@ The following limitations are expected to always remain:
|
|
|
510
464
|
## License
|
|
511
465
|
|
|
512
466
|
All code in this repository is licensed under the [MIT License](https://github.com/masaccio/numbers-parser/blob/master/LICENSE.rst).
|
|
513
|
-
|
|
@@ -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.
|
|
15
|
+
version = "4.14.1"
|
|
16
16
|
|
|
17
17
|
[tool.poetry.scripts]
|
|
18
18
|
cat-numbers = "numbers_parser._cat_numbers:main"
|
|
@@ -21,17 +21,14 @@ csv2numbers = "numbers_parser._csv2numbers:main"
|
|
|
21
21
|
|
|
22
22
|
[tool.poetry.dependencies]
|
|
23
23
|
compact-json = "^1.1.3"
|
|
24
|
-
pendulum = "^3.0"
|
|
25
24
|
protobuf = "*"
|
|
26
25
|
python = ">=3.9,<4.0"
|
|
27
26
|
python-snappy = "^0.7"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
sigfig = "^1.3.2"
|
|
31
|
-
setuptools = ">=69.0.3"
|
|
27
|
+
sigfig = "^1.3.3"
|
|
28
|
+
setuptools = ">=70.0.0"
|
|
32
29
|
importlib-resources = ">=6.1"
|
|
33
30
|
enum-tools = ">=0.11"
|
|
34
|
-
|
|
31
|
+
python-dateutil = "^2.9.0.post0"
|
|
35
32
|
|
|
36
33
|
[tool.poetry.group.dev.dependencies]
|
|
37
34
|
black = "*"
|
|
@@ -43,12 +40,13 @@ pytest = ">=7.2.0"
|
|
|
43
40
|
pytest-check = ">=1.0"
|
|
44
41
|
pytest-console-scripts = "^1.3.1"
|
|
45
42
|
pytest-cov = ">=4.0,>=5.0"
|
|
46
|
-
pytest-profiling = "^1.7.0"
|
|
47
43
|
pytest-xdist = "^3.3.1"
|
|
48
44
|
ruff = "*"
|
|
49
45
|
tox = "^4.11.4"
|
|
50
46
|
python-magic = ">=0.4"
|
|
51
47
|
tqdm = ">=4.66"
|
|
48
|
+
colorama = "^0.4.6"
|
|
49
|
+
roman = "^4.2"
|
|
52
50
|
|
|
53
51
|
[tool.poetry.group.docs]
|
|
54
52
|
optional = true
|
|
@@ -88,7 +86,7 @@ addopts = "--cov=src/numbers_parser --cov-report=html --cov-report=term-missing:
|
|
|
88
86
|
legacy_tox_ini = """
|
|
89
87
|
[tox]
|
|
90
88
|
isolated_build = true
|
|
91
|
-
envlist = py39, py310, py311, py312
|
|
89
|
+
envlist = py39, py310, py311, py312, py313
|
|
92
90
|
[testenv]
|
|
93
91
|
deps =
|
|
94
92
|
pytest
|
|
@@ -37,7 +37,8 @@ def _check_installed_numbers_version():
|
|
|
37
37
|
installed_version = re.sub(r"(\d+)\.(\d+)\.\d+", r"\1.\2", installed_version)
|
|
38
38
|
if installed_version not in SUPPORTED_NUMBERS_VERSIONS:
|
|
39
39
|
warnings.warn(
|
|
40
|
-
f"Numbers version {installed_version} not tested with this version",
|
|
40
|
+
f"Numbers version {installed_version} not tested with this version",
|
|
41
|
+
stacklevel=2,
|
|
41
42
|
)
|
|
42
43
|
fp.close()
|
|
43
44
|
return installed_version
|
|
@@ -3,7 +3,7 @@ import csv
|
|
|
3
3
|
import logging
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
-
import sigfig
|
|
6
|
+
from sigfig import round as sigfig
|
|
7
7
|
|
|
8
8
|
from numbers_parser import Document, ErrorCell, FileError, FileFormatError, NumberCell, _get_version
|
|
9
9
|
from numbers_parser import __name__ as numbers_parser_name
|
|
@@ -49,15 +49,24 @@ def command_line_parser():
|
|
|
49
49
|
help="Dump formatted cells (durations) as they appear in Numbers",
|
|
50
50
|
)
|
|
51
51
|
parser.add_argument(
|
|
52
|
-
"-s",
|
|
52
|
+
"-s",
|
|
53
|
+
"--sheet",
|
|
54
|
+
action="append",
|
|
55
|
+
help="Names of sheet(s) to include in export",
|
|
53
56
|
)
|
|
54
57
|
parser.add_argument(
|
|
55
|
-
"-t",
|
|
58
|
+
"-t",
|
|
59
|
+
"--table",
|
|
60
|
+
action="append",
|
|
61
|
+
help="Names of table(s) to include in export",
|
|
56
62
|
)
|
|
57
63
|
parser.add_argument("document", nargs="*", help="Document(s) to export")
|
|
58
64
|
parser.add_argument("--debug", default=False, action="store_true", help="Enable debug logging")
|
|
59
65
|
parser.add_argument(
|
|
60
|
-
"--experimental",
|
|
66
|
+
"--experimental",
|
|
67
|
+
default=False,
|
|
68
|
+
action="store_true",
|
|
69
|
+
help=argparse.SUPPRESS,
|
|
61
70
|
)
|
|
62
71
|
return parser
|
|
63
72
|
|
|
@@ -81,7 +90,7 @@ def cell_as_string(args, cell):
|
|
|
81
90
|
elif args.formatting and cell.formatted_value is not None:
|
|
82
91
|
return cell.formatted_value
|
|
83
92
|
elif isinstance(cell, NumberCell):
|
|
84
|
-
return sigfig
|
|
93
|
+
return sigfig(cell.value, sigfigs=MAX_SIGNIFICANT_DIGITS, warn=False)
|
|
85
94
|
elif cell.value is None:
|
|
86
95
|
return ""
|
|
87
96
|
else:
|
|
@@ -11,7 +11,6 @@ from binascii import hexlify
|
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
|
|
14
|
-
import regex
|
|
15
14
|
from compact_json import Formatter
|
|
16
15
|
|
|
17
16
|
from numbers_parser import __name__ as numbers_parser_name
|
|
@@ -35,7 +34,7 @@ class NumbersUnpacker(IWorkHandler):
|
|
|
35
34
|
|
|
36
35
|
def store_file(self, filename: str, blob: bytes) -> None:
|
|
37
36
|
"""Store a profobuf archive."""
|
|
38
|
-
filename =
|
|
37
|
+
filename = re.sub(r".*\.numbers/", "", str(filename))
|
|
39
38
|
self.ensure_directory_exists(filename)
|
|
40
39
|
target_path = os.path.join(self.output_dir, filename)
|
|
41
40
|
if isinstance(blob, IWAFile):
|
|
@@ -102,7 +101,7 @@ class NumbersUnpacker(IWorkHandler):
|
|
|
102
101
|
elif k in ["cell_offsets", k == "cell_offsets_pre_bnc"]:
|
|
103
102
|
offsets = array("h", b64decode(obj[k])).tolist()
|
|
104
103
|
obj[k] = ",".join([str(x) for x in offsets])
|
|
105
|
-
obj[k] =
|
|
104
|
+
obj[k] = re.sub(r"(?:,-1)+$", ",[...]", obj[k])
|
|
106
105
|
else: # list
|
|
107
106
|
for v in obj:
|
|
108
107
|
if isinstance(v, (dict, list)):
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
from roman import toRoman
|
|
2
|
-
|
|
3
1
|
from numbers_parser.generated.TSWPArchives_pb2 import ListStyleArchive
|
|
2
|
+
from numbers_parser.roman import to_roman
|
|
4
3
|
|
|
5
4
|
BULLET_PREFIXES = {
|
|
6
5
|
ListStyleArchive.kNumericDecimal: "",
|
|
@@ -24,12 +23,12 @@ BULLET_CONVERSION = {
|
|
|
24
23
|
ListStyleArchive.kNumericDecimal: lambda x: str(x + 1),
|
|
25
24
|
ListStyleArchive.kNumericDoubleParen: lambda x: str(x + 1),
|
|
26
25
|
ListStyleArchive.kNumericRightParen: lambda x: str(x + 1),
|
|
27
|
-
ListStyleArchive.kRomanUpperDecimal: lambda x:
|
|
28
|
-
ListStyleArchive.kRomanUpperDoubleParen: lambda x:
|
|
29
|
-
ListStyleArchive.kRomanUpperRightParen: lambda x:
|
|
30
|
-
ListStyleArchive.kRomanLowerDecimal: lambda x:
|
|
31
|
-
ListStyleArchive.kRomanLowerDoubleParen: lambda x:
|
|
32
|
-
ListStyleArchive.kRomanLowerRightParen: lambda x:
|
|
26
|
+
ListStyleArchive.kRomanUpperDecimal: lambda x: to_roman(x + 1),
|
|
27
|
+
ListStyleArchive.kRomanUpperDoubleParen: lambda x: to_roman(x + 1),
|
|
28
|
+
ListStyleArchive.kRomanUpperRightParen: lambda x: to_roman(x + 1),
|
|
29
|
+
ListStyleArchive.kRomanLowerDecimal: lambda x: to_roman(x + 1).lower(),
|
|
30
|
+
ListStyleArchive.kRomanLowerDoubleParen: lambda x: to_roman(x + 1).lower(),
|
|
31
|
+
ListStyleArchive.kRomanLowerRightParen: lambda x: to_roman(x + 1).lower(),
|
|
33
32
|
ListStyleArchive.kAlphaUpperDecimal: lambda x: chr(x + 65),
|
|
34
33
|
ListStyleArchive.kAlphaUpperDoubleParen: lambda x: chr(x + 65),
|
|
35
34
|
ListStyleArchive.kAlphaUpperRightParen: lambda x: chr(x + 65),
|
|
@@ -3,8 +3,7 @@ import math
|
|
|
3
3
|
import re
|
|
4
4
|
from collections import namedtuple
|
|
5
5
|
from dataclasses import asdict, dataclass, field, fields
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from datetime import timedelta as builtin_timedelta
|
|
6
|
+
from datetime import datetime, timedelta
|
|
8
7
|
from enum import IntEnum
|
|
9
8
|
from fractions import Fraction
|
|
10
9
|
from hashlib import sha1
|
|
@@ -13,13 +12,9 @@ from struct import pack, unpack
|
|
|
13
12
|
from typing import Any, List, Optional, Tuple, Union
|
|
14
13
|
from warnings import warn
|
|
15
14
|
|
|
16
|
-
import sigfig
|
|
17
|
-
from pendulum import DateTime, Duration, datetime, duration
|
|
18
|
-
from pendulum import instance as pendulum_instance
|
|
15
|
+
from sigfig import round as sigfig
|
|
19
16
|
|
|
20
17
|
from numbers_parser import __name__ as numbers_parser_name
|
|
21
|
-
|
|
22
|
-
# from numbers_parser.cell_storage import CellStorage, CellType
|
|
23
18
|
from numbers_parser.constants import (
|
|
24
19
|
CHECKBOX_FALSE_VALUE,
|
|
25
20
|
CHECKBOX_TRUE_VALUE,
|
|
@@ -802,7 +797,7 @@ class Cell(CellStorageFlags, Cacheable):
|
|
|
802
797
|
elif isinstance(value, int):
|
|
803
798
|
cell = NumberCell(row, col, value)
|
|
804
799
|
elif isinstance(value, float):
|
|
805
|
-
rounded_value = sigfig
|
|
800
|
+
rounded_value = sigfig(value, sigfigs=MAX_SIGNIFICANT_DIGITS, warn=False)
|
|
806
801
|
if rounded_value != value:
|
|
807
802
|
warn(
|
|
808
803
|
f"'{value}' rounded to {MAX_SIGNIFICANT_DIGITS} significant digits",
|
|
@@ -810,9 +805,9 @@ class Cell(CellStorageFlags, Cacheable):
|
|
|
810
805
|
stacklevel=2,
|
|
811
806
|
)
|
|
812
807
|
cell = NumberCell(row, col, rounded_value)
|
|
813
|
-
elif isinstance(value,
|
|
814
|
-
cell = DateCell(row, col,
|
|
815
|
-
elif isinstance(value,
|
|
808
|
+
elif isinstance(value, datetime):
|
|
809
|
+
cell = DateCell(row, col, value)
|
|
810
|
+
elif isinstance(value, timedelta):
|
|
816
811
|
cell = DurationCell(row, col, value)
|
|
817
812
|
else:
|
|
818
813
|
raise ValueError("Can't determine cell type from type " + type(value).__name__)
|
|
@@ -882,7 +877,6 @@ class Cell(CellStorageFlags, Cacheable):
|
|
|
882
877
|
offset += 4
|
|
883
878
|
# Skip unused flags
|
|
884
879
|
offset += 4 * bin(flags & 0x900).count("1")
|
|
885
|
-
#
|
|
886
880
|
if flags & 0x2000:
|
|
887
881
|
storage_flags._num_format_id = unpack("<i", buffer[offset : offset + 4])[0]
|
|
888
882
|
offset += 4
|
|
@@ -916,12 +910,12 @@ class Cell(CellStorageFlags, Cacheable):
|
|
|
916
910
|
elif cell_type == TSTArchives.textCellType:
|
|
917
911
|
cell = TextCell(row, col, model.table_string(table_id, storage_flags._string_id))
|
|
918
912
|
elif cell_type == TSTArchives.dateCellType:
|
|
919
|
-
cell = DateCell(row, col, EPOCH +
|
|
913
|
+
cell = DateCell(row, col, EPOCH + timedelta(seconds=seconds))
|
|
920
914
|
cell._datetime = cell._value
|
|
921
915
|
elif cell_type == TSTArchives.boolCellType:
|
|
922
916
|
cell = BoolCell(row, col, double > 0.0)
|
|
923
917
|
elif cell_type == TSTArchives.durationCellType:
|
|
924
|
-
cell = DurationCell(row, col,
|
|
918
|
+
cell = DurationCell(row, col, timedelta(seconds=double))
|
|
925
919
|
elif cell_type == TSTArchives.formulaErrorCellType:
|
|
926
920
|
cell = ErrorCell(row, col)
|
|
927
921
|
elif cell_type == TSTArchives.automaticCellType:
|
|
@@ -1024,7 +1018,11 @@ class Cell(CellStorageFlags, Cacheable):
|
|
|
1024
1018
|
flags = 4
|
|
1025
1019
|
length += 8
|
|
1026
1020
|
cell_type = TSTArchives.dateCellType
|
|
1027
|
-
date_delta = self._value.astimezone() - EPOCH
|
|
1021
|
+
# date_delta = self._value.astimezone() - EPOCH
|
|
1022
|
+
if self._value.tzinfo is None:
|
|
1023
|
+
date_delta = self._value - EPOCH
|
|
1024
|
+
else:
|
|
1025
|
+
date_delta = self._value - EPOCH.astimezone(self._value.tzinfo)
|
|
1028
1026
|
value = pack("<d", float(date_delta.total_seconds()))
|
|
1029
1027
|
elif isinstance(self, BoolCell):
|
|
1030
1028
|
flags = 2
|
|
@@ -1483,7 +1481,7 @@ class DateCell(Cell):
|
|
|
1483
1481
|
Do not instantiate directly. Cells are created by :py:class:`~numbers_parser.Document`.
|
|
1484
1482
|
""" # fmt: skip
|
|
1485
1483
|
|
|
1486
|
-
def __init__(self, row: int, col: int, value:
|
|
1484
|
+
def __init__(self, row: int, col: int, value: datetime) -> None:
|
|
1487
1485
|
super().__init__(row, col, value)
|
|
1488
1486
|
self._type = CellType.DATE
|
|
1489
1487
|
|
|
@@ -1493,12 +1491,12 @@ class DateCell(Cell):
|
|
|
1493
1491
|
|
|
1494
1492
|
|
|
1495
1493
|
class DurationCell(Cell):
|
|
1496
|
-
def __init__(self, row: int, col: int, value:
|
|
1494
|
+
def __init__(self, row: int, col: int, value: timedelta) -> None:
|
|
1497
1495
|
super().__init__(row, col, value)
|
|
1498
1496
|
self._type = CellType.DURATION
|
|
1499
1497
|
|
|
1500
1498
|
@property
|
|
1501
|
-
def value(self) ->
|
|
1499
|
+
def value(self) -> timedelta:
|
|
1502
1500
|
return self._value
|
|
1503
1501
|
|
|
1504
1502
|
|
|
@@ -1734,7 +1732,7 @@ def _decode_number_format(format, value, name): # noqa: PLR0912
|
|
|
1734
1732
|
int_width = num_integers
|
|
1735
1733
|
|
|
1736
1734
|
# value_1 = str(value).split(".")[0]
|
|
1737
|
-
# value_2 = sigfig
|
|
1735
|
+
# value_2 = sigfig(str(value).split(".")[1], sigfig=MAX_SIGNIFICANT_DIGITS, warn=False)
|
|
1738
1736
|
# int_pad_space_as_zero = (
|
|
1739
1737
|
# num_integers > 0
|
|
1740
1738
|
# and num_decimals > 0
|
|
@@ -1812,16 +1810,16 @@ def _format_decimal(value: float, format, percent: bool = False) -> str:
|
|
|
1812
1810
|
formatted_value = f"{int(value):{thousands}}"
|
|
1813
1811
|
else:
|
|
1814
1812
|
if format.decimal_places >= DECIMAL_PLACES_AUTO:
|
|
1815
|
-
formatted_value = str(sigfig
|
|
1813
|
+
formatted_value = str(sigfig(value, MAX_SIGNIFICANT_DIGITS, warn=False))
|
|
1816
1814
|
else:
|
|
1817
|
-
formatted_value = sigfig
|
|
1818
|
-
formatted_value = sigfig
|
|
1815
|
+
formatted_value = sigfig(value, MAX_SIGNIFICANT_DIGITS, type=str, warn=False)
|
|
1816
|
+
formatted_value = sigfig(
|
|
1819
1817
|
formatted_value,
|
|
1820
1818
|
decimals=format.decimal_places,
|
|
1821
1819
|
type=str,
|
|
1822
1820
|
)
|
|
1823
1821
|
if format.show_thousands_separator:
|
|
1824
|
-
formatted_value = sigfig
|
|
1822
|
+
formatted_value = sigfig(formatted_value, spacer=",", spacing=3, type=str)
|
|
1825
1823
|
try:
|
|
1826
1824
|
(integer, decimal) = formatted_value.split(".")
|
|
1827
1825
|
formatted_value = integer + "." + decimal.replace(",", "")
|
|
@@ -1945,7 +1943,7 @@ def _format_fraction(value: float, format) -> str:
|
|
|
1945
1943
|
|
|
1946
1944
|
|
|
1947
1945
|
def _format_scientific(value: float, format) -> str:
|
|
1948
|
-
formatted_value = sigfig
|
|
1946
|
+
formatted_value = sigfig(value, sigfigs=MAX_SIGNIFICANT_DIGITS, warn=False)
|
|
1949
1947
|
return f"{formatted_value:.{format.decimal_places}E}"
|
|
1950
1948
|
|
|
1951
1949
|
|
|
@@ -1992,8 +1990,7 @@ def _auto_units(cell_value, format):
|
|
|
1992
1990
|
unit_smallest = DurationUnits.HOUR
|
|
1993
1991
|
elif cell_value % SECONDS_IN_WEEK:
|
|
1994
1992
|
unit_smallest = DurationUnits.DAY
|
|
1995
|
-
|
|
1996
|
-
unit_smallest = unit_largest
|
|
1993
|
+
unit_smallest = max(unit_smallest, unit_largest)
|
|
1997
1994
|
|
|
1998
1995
|
return unit_smallest, unit_largest
|
|
1999
1996
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from collections import OrderedDict
|
|
2
|
+
from datetime import datetime
|
|
2
3
|
from enum import IntEnum
|
|
4
|
+
from math import ceil
|
|
3
5
|
|
|
4
6
|
import enum_tools.documentation
|
|
5
|
-
from pendulum import datetime
|
|
6
7
|
|
|
7
8
|
try:
|
|
8
9
|
from importlib.resources import files
|
|
@@ -99,6 +100,16 @@ def _days_occurred_in_month(value: datetime) -> str:
|
|
|
99
100
|
return str(n_days)
|
|
100
101
|
|
|
101
102
|
|
|
103
|
+
def _day_of_year(value: datetime) -> int:
|
|
104
|
+
"""Return the day number in a year for a datetime."""
|
|
105
|
+
return value.timetuple().tm_yday
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _week_of_month(value: datetime) -> int:
|
|
109
|
+
"""Return the week number in a month for a datetime."""
|
|
110
|
+
return int(ceil((value.day + value.replace(day=1).weekday()) / 7.0))
|
|
111
|
+
|
|
112
|
+
|
|
102
113
|
DATETIME_FIELD_MAP = OrderedDict(
|
|
103
114
|
[
|
|
104
115
|
("a", lambda x: x.strftime("%p").lower()),
|
|
@@ -113,9 +124,9 @@ DATETIME_FIELD_MAP = OrderedDict(
|
|
|
113
124
|
("M", "%-m"),
|
|
114
125
|
("d", "%-d"),
|
|
115
126
|
("dd", "%d"),
|
|
116
|
-
("DDD", lambda x: str(x
|
|
117
|
-
("DD", lambda x: str(x
|
|
118
|
-
("D", lambda x: str(x
|
|
127
|
+
("DDD", lambda x: str(_day_of_year(x)).zfill(3)),
|
|
128
|
+
("DD", lambda x: str(_day_of_year(x)).zfill(2)),
|
|
129
|
+
("D", lambda x: str(_day_of_year(x)).zfill(1)),
|
|
119
130
|
("HH", "%H"),
|
|
120
131
|
("H", "%-H"),
|
|
121
132
|
("hh", "%I"),
|
|
@@ -128,7 +139,7 @@ DATETIME_FIELD_MAP = OrderedDict(
|
|
|
128
139
|
("m", lambda x: str(x.minute)),
|
|
129
140
|
("ss", "%S"),
|
|
130
141
|
("s", lambda x: str(x.second)),
|
|
131
|
-
("W", lambda x: str(x
|
|
142
|
+
("W", lambda x: str(_week_of_month(x) - 1)),
|
|
132
143
|
("ww", "%W"),
|
|
133
144
|
("G", "AD"), # TODO: support BC
|
|
134
145
|
("F", lambda x: _days_occurred_in_month(x)),
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
from typing import Dict, Iterator, List, Optional, Tuple, Union
|
|
3
4
|
from warnings import warn
|
|
4
5
|
|
|
5
|
-
from pendulum import DateTime, Duration
|
|
6
|
-
|
|
7
6
|
from numbers_parser.cell import (
|
|
8
7
|
BackgroundImage,
|
|
9
8
|
Border,
|
|
@@ -951,7 +950,7 @@ class Table(Cacheable):
|
|
|
951
950
|
self,
|
|
952
951
|
num_rows: Optional[int] = 1,
|
|
953
952
|
start_row: Optional[Union[int, None]] = None,
|
|
954
|
-
default: Optional[Union[str, int, float, bool,
|
|
953
|
+
default: Optional[Union[str, int, float, bool, datetime, timedelta]] = None,
|
|
955
954
|
) -> None:
|
|
956
955
|
"""Add or insert rows to the table.
|
|
957
956
|
|
|
@@ -1013,7 +1012,7 @@ class Table(Cacheable):
|
|
|
1013
1012
|
self,
|
|
1014
1013
|
num_cols: Optional[int] = 1,
|
|
1015
1014
|
start_col: Optional[Union[int, None]] = None,
|
|
1016
|
-
default: Optional[Union[str, int, float, bool,
|
|
1015
|
+
default: Optional[Union[str, int, float, bool, datetime, timedelta]] = None,
|
|
1017
1016
|
) -> None:
|
|
1018
1017
|
"""Add or insert columns to the table.
|
|
1019
1018
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import warnings
|
|
3
|
-
|
|
4
|
-
from pendulum import datetime, duration
|
|
3
|
+
from datetime import datetime, timedelta
|
|
5
4
|
|
|
6
5
|
from numbers_parser.exceptions import UnsupportedWarning
|
|
7
6
|
from numbers_parser.generated import TSCEArchives_pb2 as TSCEArchives
|
|
@@ -68,7 +67,7 @@ class Formula(list):
|
|
|
68
67
|
def date(self, *args):
|
|
69
68
|
# Date literals exported as DATE()
|
|
70
69
|
node = args[2]
|
|
71
|
-
dt = datetime(2001, 1, 1) +
|
|
70
|
+
dt = datetime(2001, 1, 1) + timedelta(seconds=node.AST_date_node_dateNum)
|
|
72
71
|
self.push(f"DATE({dt.year},{dt.month},{dt.day})")
|
|
73
72
|
|
|
74
73
|
def div(self, *args):
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
def to_roman(value: int) -> str:
|
|
2
|
+
"""Convert an integer to a Roman number in the available range of values."""
|
|
3
|
+
if value == 0:
|
|
4
|
+
return "N"
|
|
5
|
+
|
|
6
|
+
if value < 1 or value > 3999:
|
|
7
|
+
raise ValueError("Number out of range for Roman numerals")
|
|
8
|
+
|
|
9
|
+
int_values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
|
|
10
|
+
roman_symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
|
|
11
|
+
|
|
12
|
+
roman_num = ""
|
|
13
|
+
for i in range(len(int_values)):
|
|
14
|
+
while value >= int_values[i]:
|
|
15
|
+
roman_num += roman_symbols[i]
|
|
16
|
+
value -= int_values[i]
|
|
17
|
+
|
|
18
|
+
return roman_num
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TNArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TNArchives_sos_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSAArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSAArchives_sos_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCEArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCH3DArchives_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_GEN_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCHArchives_sos_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCKArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSCKArchives_sos_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSDArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSDArchives_sos_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSKArchives_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSPMessages_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSSArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSSArchives_sos_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSTArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSTArchives_sos_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSWPArchives_pb2.py
RENAMED
|
File without changes
|
{numbers_parser-4.13.3 → numbers_parser-4.14.1}/src/numbers_parser/generated/TSWPArchives_sos_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|