sciform 0.36.0__py3-none-any.whl → 0.38.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.
- sciform/__init__.py +0 -3
- sciform/api/formatter.py +12 -22
- sciform/api/global_configuration.py +5 -9
- sciform/format_utils/exponents.py +2 -3
- sciform/format_utils/make_strings.py +32 -22
- sciform/format_utils/numbers.py +13 -14
- sciform/format_utils/rounding.py +17 -21
- sciform/formatting/fsml.py +23 -8
- sciform/formatting/number_formatting.py +68 -39
- sciform/options/conversion.py +2 -1
- sciform/options/finalized_options.py +2 -8
- sciform/options/global_options.py +3 -5
- sciform/options/input_options.py +2 -3
- sciform/options/option_types.py +12 -46
- sciform/options/populated_options.py +4 -6
- sciform/options/validation.py +69 -59
- {sciform-0.36.0.dist-info → sciform-0.38.0.dist-info}/METADATA +68 -55
- sciform-0.38.0.dist-info/RECORD +31 -0
- {sciform-0.36.0.dist-info → sciform-0.38.0.dist-info}/WHEEL +1 -1
- sciform-0.36.0.dist-info/RECORD +0 -31
- {sciform-0.36.0.dist-info → sciform-0.38.0.dist-info}/LICENSE +0 -0
- {sciform-0.36.0.dist-info → sciform-0.38.0.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
5
5
|
from dataclasses import replace
|
6
6
|
from decimal import Decimal
|
7
7
|
from typing import TYPE_CHECKING, cast
|
8
|
-
from warnings import warn
|
9
8
|
|
10
9
|
from sciform.api.formatted_number import FormattedNumber
|
11
10
|
from sciform.format_utils.exponents import get_exp_str, get_val_unc_exp
|
@@ -25,9 +24,9 @@ from sciform.format_utils.rounding import get_round_dec_place, round_val_unc
|
|
25
24
|
from sciform.formatting.parser import parse_val_unc_from_input
|
26
25
|
from sciform.options.conversion import finalize_populated_options, populate_options
|
27
26
|
from sciform.options.option_types import (
|
28
|
-
AutoExpVal,
|
29
27
|
ExpFormatEnum,
|
30
28
|
ExpModeEnum,
|
29
|
+
ExpValEnum,
|
31
30
|
RoundModeEnum,
|
32
31
|
SignModeEnum,
|
33
32
|
)
|
@@ -79,7 +78,7 @@ def format_non_finite(num: Decimal, options: FinalizedOptions) -> str:
|
|
79
78
|
exp_mode = options.exp_mode
|
80
79
|
|
81
80
|
exp_val = options.exp_val
|
82
|
-
if options.exp_val is
|
81
|
+
if options.exp_val is ExpValEnum.AUTO:
|
83
82
|
exp_val = 0
|
84
83
|
|
85
84
|
exp_str = get_exp_str(
|
@@ -180,7 +179,7 @@ def format_num(num: Decimal, options: FinalizedOptions) -> str:
|
|
180
179
|
return result
|
181
180
|
|
182
181
|
|
183
|
-
def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str:
|
182
|
+
def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str: # noqa: PLR0915
|
184
183
|
"""Format value/uncertainty pair according to input options."""
|
185
184
|
exp_mode = options.exp_mode
|
186
185
|
|
@@ -190,13 +189,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
|
|
190
189
|
)
|
191
190
|
raise NotImplementedError(msg)
|
192
191
|
|
193
|
-
if options.round_mode is RoundModeEnum.DEC_PLACE:
|
194
|
-
msg = (
|
195
|
-
"Precision round mode not available for value/uncertainty formatting. "
|
196
|
-
"Rounding is always applied as significant figures for the uncertainty."
|
197
|
-
)
|
198
|
-
warn(msg, stacklevel=2)
|
199
|
-
|
200
192
|
unc = abs(unc)
|
201
193
|
if exp_mode is ExpModeEnum.PERCENT:
|
202
194
|
val *= 100
|
@@ -210,31 +202,72 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
|
|
210
202
|
"""
|
211
203
|
exp_mode = ExpModeEnum.FIXEDPOINT
|
212
204
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
205
|
+
if options.round_mode is RoundModeEnum.DEC_PLACE:
|
206
|
+
"""
|
207
|
+
We calculate the exponent twice in case rounding the mantissa changes the
|
208
|
+
required exponent. For example, 0.0999 ± 0.0999 displayed in scientific notation
|
209
|
+
would be (9.99 ± 9.99)e-02 but rounded to zero digits-past-the-decimal gives
|
210
|
+
(10 ± 10)e-02, so we need to recalculate the exponent to get (1 ± 1)e-01.
|
211
|
+
"""
|
212
|
+
exp_val = get_val_unc_exp(
|
213
|
+
val,
|
214
|
+
unc,
|
215
|
+
options.exp_mode,
|
216
|
+
options.exp_val,
|
217
|
+
)
|
218
|
+
val_mantissa = val * Decimal(10) ** (-Decimal(exp_val))
|
219
|
+
unc_mantissa = unc * Decimal(10) ** (-Decimal(exp_val))
|
220
|
+
val_mantissa_rounded, unc_mantissa_rounded, _ = round_val_unc(
|
221
|
+
val_mantissa,
|
222
|
+
unc_mantissa,
|
223
|
+
options.round_mode,
|
224
|
+
options.ndigits,
|
225
|
+
)
|
226
|
+
val_rounded = val_mantissa_rounded * Decimal(10) ** Decimal(exp_val)
|
227
|
+
unc_rounded = unc_mantissa_rounded * Decimal(10) ** Decimal(exp_val)
|
228
|
+
exp_val = get_val_unc_exp(
|
229
|
+
val_rounded,
|
230
|
+
unc_rounded,
|
231
|
+
options.exp_mode,
|
232
|
+
options.exp_val,
|
233
|
+
)
|
234
|
+
"""
|
235
|
+
ndigits that will be used for separate digits-past-the-decimal rounding for the
|
236
|
+
value and uncertainty.
|
237
|
+
"""
|
238
|
+
ndigits = options.ndigits
|
239
|
+
else:
|
240
|
+
"""
|
241
|
+
We round twice in case the first rounding changes the digits place to which we
|
242
|
+
need to round. E.g. rounding 0.0999 ± 0.0999 to one significant figure would
|
243
|
+
naively result in rounding to the -2 place, leaving us with 0.10 ± 0.10. But the
|
244
|
+
-2 place actually corresponds to two significant figures, so we re-round to the
|
245
|
+
-1 place to get 0.1 ± 0.1.
|
246
|
+
"""
|
247
|
+
val_rounded, unc_rounded, _ = round_val_unc(
|
248
|
+
val,
|
249
|
+
unc,
|
250
|
+
options.round_mode,
|
251
|
+
options.ndigits,
|
252
|
+
)
|
253
|
+
val_rounded, unc_rounded, round_digit = round_val_unc(
|
254
|
+
val_rounded,
|
255
|
+
unc_rounded,
|
256
|
+
options.round_mode,
|
257
|
+
options.ndigits,
|
258
|
+
)
|
231
259
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
260
|
+
exp_val = get_val_unc_exp(
|
261
|
+
val_rounded,
|
262
|
+
unc_rounded,
|
263
|
+
options.exp_mode,
|
264
|
+
options.exp_val,
|
265
|
+
)
|
266
|
+
"""
|
267
|
+
ndigits that will be used for separate digits-past-the-decimal rounding for the
|
268
|
+
value and uncertainty.
|
269
|
+
"""
|
270
|
+
ndigits = -round_digit + exp_val
|
238
271
|
|
239
272
|
val_mantissa, _, _ = get_mantissa_exp_base(
|
240
273
|
val_rounded,
|
@@ -254,8 +287,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
|
|
254
287
|
left_pad_matching=options.left_pad_matching,
|
255
288
|
)
|
256
289
|
|
257
|
-
ndigits = -round_digit + exp_val
|
258
|
-
|
259
290
|
"""
|
260
291
|
We will format the val and unc mantissas
|
261
292
|
* using decimal place rounding mode with the ndigits calculated
|
@@ -294,8 +325,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
|
|
294
325
|
val_unc_str = construct_val_unc_str(
|
295
326
|
val_mantissa_str=val_mantissa_str,
|
296
327
|
unc_mantissa_str=unc_mantissa_str,
|
297
|
-
val_mantissa=val_mantissa,
|
298
|
-
unc_mantissa=unc_mantissa,
|
299
328
|
decimal_separator=options.decimal_separator,
|
300
329
|
paren_uncertainty=options.paren_uncertainty,
|
301
330
|
pm_whitespace=options.pm_whitespace,
|
sciform/options/conversion.py
CHANGED
@@ -90,6 +90,7 @@ def populate_options(input_options: InputOptions) -> PopulatedOptions:
|
|
90
90
|
|
91
91
|
key_to_enum_dict = {
|
92
92
|
"exp_mode": option_types.ExpModeEnum,
|
93
|
+
"exp_val": option_types.ExpValEnum,
|
93
94
|
"round_mode": option_types.RoundModeEnum,
|
94
95
|
"upper_separator": option_types.SeparatorEnum,
|
95
96
|
"decimal_separator": option_types.SeparatorEnum,
|
@@ -104,7 +105,7 @@ def finalize_populated_options(populated_options: PopulatedOptions) -> Finalized
|
|
104
105
|
"""Convert PopulatedOptions into FinalizedOptions with enum values."""
|
105
106
|
kwargs = populated_options.as_dict()
|
106
107
|
for key, value in kwargs.items():
|
107
|
-
if key in key_to_enum_dict:
|
108
|
+
if key in key_to_enum_dict and isinstance(value, str):
|
108
109
|
enum = key_to_enum_dict[key]
|
109
110
|
kwargs[key] = option_types.mode_str_to_enum(value, enum)
|
110
111
|
return FinalizedOptions(**kwargs)
|
@@ -10,8 +10,6 @@ from __future__ import annotations
|
|
10
10
|
from dataclasses import dataclass
|
11
11
|
from typing import TYPE_CHECKING
|
12
12
|
|
13
|
-
from sciform.options.validation import validate_options
|
14
|
-
|
15
13
|
if TYPE_CHECKING: # pragma: no cover
|
16
14
|
from sciform.options import option_types
|
17
15
|
|
@@ -21,9 +19,9 @@ class FinalizedOptions:
|
|
21
19
|
"""Rendered options: All options populated and using Enum instead of Literal."""
|
22
20
|
|
23
21
|
exp_mode: option_types.ExpModeEnum
|
24
|
-
exp_val: int |
|
22
|
+
exp_val: int | option_types.ExpValEnum
|
25
23
|
round_mode: option_types.RoundModeEnum
|
26
|
-
ndigits: int
|
24
|
+
ndigits: int
|
27
25
|
upper_separator: option_types.UpperSeparatorEnums
|
28
26
|
decimal_separator: option_types.DecimalSeparatorEnums
|
29
27
|
lower_separator: option_types.LowerSeparatorEnums
|
@@ -38,10 +36,6 @@ class FinalizedOptions:
|
|
38
36
|
superscript: bool
|
39
37
|
nan_inf_exp: bool
|
40
38
|
paren_uncertainty: bool
|
41
|
-
pdg_sig_figs: bool
|
42
39
|
left_pad_matching: bool
|
43
40
|
paren_uncertainty_trim: bool
|
44
41
|
pm_whitespace: bool
|
45
|
-
|
46
|
-
def __post_init__(self: FinalizedOptions) -> None:
|
47
|
-
validate_options(self, none_allowed=False)
|
@@ -1,13 +1,12 @@
|
|
1
1
|
"""Global Options."""
|
2
2
|
|
3
|
-
from sciform.options import option_types
|
4
3
|
from sciform.options.populated_options import PopulatedOptions
|
5
4
|
|
6
5
|
PKG_DEFAULT_OPTIONS = PopulatedOptions(
|
7
6
|
exp_mode="fixed_point",
|
8
|
-
exp_val=
|
9
|
-
round_mode="
|
10
|
-
ndigits=
|
7
|
+
exp_val="auto",
|
8
|
+
round_mode="all",
|
9
|
+
ndigits=2,
|
11
10
|
upper_separator="",
|
12
11
|
decimal_separator=".",
|
13
12
|
lower_separator="",
|
@@ -22,7 +21,6 @@ PKG_DEFAULT_OPTIONS = PopulatedOptions(
|
|
22
21
|
superscript=False,
|
23
22
|
nan_inf_exp=False,
|
24
23
|
paren_uncertainty=False,
|
25
|
-
pdg_sig_figs=False,
|
26
24
|
left_pad_matching=False,
|
27
25
|
paren_uncertainty_trim=True,
|
28
26
|
pm_whitespace=True,
|
sciform/options/input_options.py
CHANGED
@@ -51,9 +51,9 @@ class InputOptions:
|
|
51
51
|
""" # noqa: E501
|
52
52
|
|
53
53
|
exp_mode: option_types.ExpMode | None = None
|
54
|
-
exp_val: int |
|
54
|
+
exp_val: int | option_types.ExpVal | None = None
|
55
55
|
round_mode: option_types.RoundMode | None = None
|
56
|
-
ndigits: int |
|
56
|
+
ndigits: int | None = None
|
57
57
|
upper_separator: option_types.UpperSeparators | None = None
|
58
58
|
decimal_separator: option_types.DecimalSeparators | None = None
|
59
59
|
lower_separator: option_types.LowerSeparators | None = None
|
@@ -68,7 +68,6 @@ class InputOptions:
|
|
68
68
|
superscript: bool | None = None
|
69
69
|
nan_inf_exp: bool | None = None
|
70
70
|
paren_uncertainty: bool | None = None
|
71
|
-
pdg_sig_figs: bool | None = None
|
72
71
|
left_pad_matching: bool | None = None
|
73
72
|
paren_uncertainty_trim: bool | None = None
|
74
73
|
pm_whitespace: bool | None = None
|
sciform/options/option_types.py
CHANGED
@@ -5,51 +5,6 @@ from __future__ import annotations
|
|
5
5
|
from enum import Enum
|
6
6
|
from typing import Literal, TypeVar
|
7
7
|
|
8
|
-
|
9
|
-
class SentinelMeta(type):
|
10
|
-
"""Sentinel metaclass, __repr__ returns class name."""
|
11
|
-
|
12
|
-
def __repr__(cls: SentinelMeta) -> str:
|
13
|
-
return cls.__name__
|
14
|
-
|
15
|
-
|
16
|
-
class AutoExpVal(metaclass=SentinelMeta):
|
17
|
-
"""
|
18
|
-
Flag for auto-exponent calculation mode.
|
19
|
-
|
20
|
-
* For scientific exponent mode the base-10 exponent is selected so
|
21
|
-
that the mantissa ``m`` satisfies ``1 <= m < 10``.
|
22
|
-
* For engineering exponent mode the base-10 exponent is chosen so
|
23
|
-
that it is an integer multiple of 3 and the mantissa ``m``
|
24
|
-
satisfies ``1 <= m < 1000``.
|
25
|
-
* For shifted engineering exponent mode the base-10 exponent is
|
26
|
-
chosen so that it is an integer multiple of 3 and the mantissa
|
27
|
-
``m`` satisfies ``0.1 <= m < 100``.
|
28
|
-
* For binary exponent mode the base-2 exponent is chosen so that
|
29
|
-
the mantissa ``m`` satisfies ``1 <= m < 2``.
|
30
|
-
* For binary IEC exponent mode the base-2 exponent is chosen so
|
31
|
-
that the mantissa ``m`` satisfies ``1 <= m < 1024 = 2**10``.
|
32
|
-
"""
|
33
|
-
|
34
|
-
|
35
|
-
class AutoDigits(metaclass=SentinelMeta):
|
36
|
-
"""
|
37
|
-
Flag for auto ndigits calculation mode.
|
38
|
-
|
39
|
-
In both sig fig and ndigits round modes this auto ndigits
|
40
|
-
option chooses the ndigits so that the least significant digit of
|
41
|
-
the input number will be displayed.
|
42
|
-
For example the number 123.456789 would be displayed with either 9
|
43
|
-
significant figures or 6 digits past the decimal point so that in
|
44
|
-
either case all digits are shown.
|
45
|
-
|
46
|
-
When used with sig fig rounding and in combination with the
|
47
|
-
``pdg_sig_figs`` option, the number of significant figures will be
|
48
|
-
chosen to be one or two in accordance with the Particle Data Group
|
49
|
-
algorithm.
|
50
|
-
"""
|
51
|
-
|
52
|
-
|
53
8
|
LeftPadChar = Literal[" ", "0"]
|
54
9
|
|
55
10
|
|
@@ -101,7 +56,7 @@ LowerSeparatorEnums = Literal[
|
|
101
56
|
]
|
102
57
|
|
103
58
|
|
104
|
-
RoundMode = Literal["sig_fig", "dec_place"]
|
59
|
+
RoundMode = Literal["sig_fig", "dec_place", "all", "pdg"]
|
105
60
|
|
106
61
|
|
107
62
|
class RoundModeEnum(str, Enum):
|
@@ -109,6 +64,8 @@ class RoundModeEnum(str, Enum):
|
|
109
64
|
|
110
65
|
SIG_FIG = "sig_fig"
|
111
66
|
DEC_PLACE = "dec_place"
|
67
|
+
ALL = "all"
|
68
|
+
PDG = "pdg"
|
112
69
|
|
113
70
|
|
114
71
|
ExpMode = Literal[
|
@@ -145,6 +102,15 @@ class ExpFormatEnum(str, Enum):
|
|
145
102
|
PARTS_PER = "parts_per"
|
146
103
|
|
147
104
|
|
105
|
+
ExpVal = Literal["auto"]
|
106
|
+
|
107
|
+
|
108
|
+
class ExpValEnum(str, Enum):
|
109
|
+
"""Exponent value Enum."""
|
110
|
+
|
111
|
+
AUTO = "auto"
|
112
|
+
|
113
|
+
|
148
114
|
T = TypeVar("T", bound=Enum)
|
149
115
|
|
150
116
|
|
@@ -44,7 +44,7 @@ class PopulatedOptions:
|
|
44
44
|
>>> print(formatter.populated_options)
|
45
45
|
PopulatedOptions(
|
46
46
|
'exp_mode': 'engineering',
|
47
|
-
'exp_val':
|
47
|
+
'exp_val': 'auto',
|
48
48
|
'round_mode': 'sig_fig',
|
49
49
|
'ndigits': 2,
|
50
50
|
'upper_separator': '',
|
@@ -61,13 +61,12 @@ class PopulatedOptions:
|
|
61
61
|
'superscript': True,
|
62
62
|
'nan_inf_exp': False,
|
63
63
|
'paren_uncertainty': False,
|
64
|
-
'pdg_sig_figs': False,
|
65
64
|
'left_pad_matching': False,
|
66
65
|
'paren_uncertainty_trim': True,
|
67
66
|
'pm_whitespace': True,
|
68
67
|
)
|
69
68
|
>>> print(formatter.populated_options.as_dict())
|
70
|
-
{'exp_mode': 'engineering', 'exp_val':
|
69
|
+
{'exp_mode': 'engineering', 'exp_val': 'auto', 'round_mode': 'sig_fig', 'ndigits': 2, 'upper_separator': '', 'decimal_separator': '.', 'lower_separator': '', 'sign_mode': '-', 'left_pad_char': ' ', 'left_pad_dec_place': 0, 'exp_format': 'standard', 'extra_si_prefixes': {}, 'extra_iec_prefixes': {}, 'extra_parts_per_forms': {}, 'capitalize': False, 'superscript': True, 'nan_inf_exp': False, 'paren_uncertainty': False, 'left_pad_matching': False, 'paren_uncertainty_trim': True, 'pm_whitespace': True}
|
71
70
|
|
72
71
|
Note that :class:`PopulatedOptions` lacks the ``add_c_prefix``,
|
73
72
|
``add_small_si_prefixes`` and ``add_ppth_form`` options present
|
@@ -93,9 +92,9 @@ class PopulatedOptions:
|
|
93
92
|
""" # noqa: E501
|
94
93
|
|
95
94
|
exp_mode: option_types.ExpMode
|
96
|
-
exp_val: int |
|
95
|
+
exp_val: int | option_types.ExpVal
|
97
96
|
round_mode: option_types.RoundMode
|
98
|
-
ndigits: int
|
97
|
+
ndigits: int
|
99
98
|
upper_separator: option_types.UpperSeparators
|
100
99
|
decimal_separator: option_types.DecimalSeparators
|
101
100
|
lower_separator: option_types.LowerSeparators
|
@@ -110,7 +109,6 @@ class PopulatedOptions:
|
|
110
109
|
superscript: bool
|
111
110
|
nan_inf_exp: bool
|
112
111
|
paren_uncertainty: bool
|
113
|
-
pdg_sig_figs: bool
|
114
112
|
left_pad_matching: bool
|
115
113
|
paren_uncertainty_trim: bool
|
116
114
|
pm_whitespace: bool
|
sciform/options/validation.py
CHANGED
@@ -14,7 +14,7 @@ if TYPE_CHECKING: # pragma: no cover
|
|
14
14
|
|
15
15
|
|
16
16
|
def validate_options(
|
17
|
-
options: InputOptions | PopulatedOptions
|
17
|
+
options: InputOptions | PopulatedOptions,
|
18
18
|
*,
|
19
19
|
none_allowed: bool,
|
20
20
|
) -> None:
|
@@ -31,59 +31,49 @@ allowed_round_modes = get_args(option_types.RoundMode)
|
|
31
31
|
|
32
32
|
|
33
33
|
def validate_rounding(
|
34
|
-
options: InputOptions | PopulatedOptions
|
34
|
+
options: InputOptions | PopulatedOptions,
|
35
35
|
*,
|
36
36
|
none_allowed: bool,
|
37
37
|
) -> None:
|
38
38
|
r"""Validate ndigits if round_mode == "sig_fig"."""
|
39
|
-
if
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
msg = f"round_mode must be in {allowed_round_modes}, not {options.round_mode}."
|
44
|
-
raise ValueError(msg)
|
45
|
-
|
46
|
-
if not (none_allowed and options.ndigits is None) and not isinstance(
|
47
|
-
options.ndigits,
|
48
|
-
(int, type(option_types.AutoDigits)),
|
49
|
-
):
|
50
|
-
msg = f'ndigits must be an "int" or "AutoDigits", not {options.ndigits}.'
|
39
|
+
if none_allowed and options.ndigits is None:
|
40
|
+
pass
|
41
|
+
elif not isinstance(options.ndigits, int):
|
42
|
+
msg = f"ndigits must be an int, not {options.ndigits}."
|
51
43
|
raise TypeError(msg)
|
52
44
|
|
53
|
-
if
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
45
|
+
if none_allowed and options.round_mode is None:
|
46
|
+
pass
|
47
|
+
else:
|
48
|
+
if options.round_mode not in allowed_round_modes:
|
49
|
+
msg = (
|
50
|
+
f"round_mode must be in {allowed_round_modes}, not "
|
51
|
+
f"{options.round_mode}."
|
52
|
+
)
|
53
|
+
raise ValueError(msg)
|
54
|
+
if options.round_mode == "sig_fig" and options.ndigits < 1:
|
55
|
+
msg = f"ndigits must be >= 1 for sig fig rounding, not {options.ndigits}."
|
56
|
+
raise ValueError(msg)
|
61
57
|
|
62
58
|
|
63
59
|
allowed_exp_modes = get_args(option_types.ExpMode)
|
64
|
-
allowed_exp_val_types = (int, type(option_types.AutoExpVal), type(None))
|
65
60
|
allowed_exp_formats = get_args(option_types.ExpFormat)
|
66
61
|
|
67
62
|
|
68
|
-
def
|
63
|
+
def validate_exp_val(
|
69
64
|
options: InputOptions | PopulatedOptions | FinalizedOptions,
|
70
65
|
*,
|
71
66
|
none_allowed: bool,
|
72
67
|
) -> None:
|
73
|
-
"""Validate exponent
|
74
|
-
if
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
raise ValueError(msg)
|
80
|
-
|
81
|
-
if not (none_allowed and options.exp_val is None):
|
82
|
-
if not isinstance(options.exp_val, allowed_exp_val_types):
|
83
|
-
msg = f"exp_val must be an int, AutoExpVal, or None, not {options.exp_val}."
|
68
|
+
"""Validate exponent value."""
|
69
|
+
if none_allowed and options.exp_val is None:
|
70
|
+
pass
|
71
|
+
else:
|
72
|
+
if not isinstance(options.exp_val, int) and options.exp_val != "auto":
|
73
|
+
msg = f"exp_val must be an int, 'auto', or None, not {options.exp_val}."
|
84
74
|
raise TypeError(msg)
|
85
75
|
|
86
|
-
if options.exp_val
|
76
|
+
if options.exp_val != "auto":
|
87
77
|
if options.exp_mode in ["fixed_point", "percent"] and options.exp_val != 0:
|
88
78
|
msg = (
|
89
79
|
f"Exponent must must be 0, not exp_val={options.exp_val}, for "
|
@@ -106,10 +96,24 @@ def validate_exp_options(
|
|
106
96
|
)
|
107
97
|
raise ValueError(msg)
|
108
98
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
99
|
+
|
100
|
+
def validate_exp_options(
|
101
|
+
options: InputOptions | PopulatedOptions | FinalizedOptions,
|
102
|
+
*,
|
103
|
+
none_allowed: bool,
|
104
|
+
) -> None:
|
105
|
+
"""Validate exponent options."""
|
106
|
+
if none_allowed and options.exp_mode is None:
|
107
|
+
pass
|
108
|
+
elif options.exp_mode not in allowed_exp_modes:
|
109
|
+
msg = f"exp_mode must be in {allowed_exp_modes}, not {options.exp_mode}."
|
110
|
+
raise ValueError(msg)
|
111
|
+
|
112
|
+
validate_exp_val(options, none_allowed=none_allowed)
|
113
|
+
|
114
|
+
if none_allowed and options.exp_format is None:
|
115
|
+
pass
|
116
|
+
elif options.exp_format not in allowed_exp_formats:
|
113
117
|
msg = (
|
114
118
|
f"{options.exp_format} must be in {allowed_exp_formats}, not "
|
115
119
|
f"{options.exp_format}."
|
@@ -126,10 +130,9 @@ def validate_sign_mode(
|
|
126
130
|
none_allowed: bool,
|
127
131
|
) -> None:
|
128
132
|
r"""Validate ndigits if round_mode == "sig_fig"."""
|
129
|
-
if
|
130
|
-
|
131
|
-
|
132
|
-
):
|
133
|
+
if none_allowed and options.sign_mode is None:
|
134
|
+
pass
|
135
|
+
elif options.sign_mode not in allowed_sign_modes:
|
133
136
|
msg = f"sign_mode must be in {allowed_sign_modes}, not {options.sign_mode}."
|
134
137
|
raise ValueError(msg)
|
135
138
|
|
@@ -140,7 +143,9 @@ def validate_separator_options(
|
|
140
143
|
none_allowed: bool,
|
141
144
|
) -> None:
|
142
145
|
"""Validate separator user input."""
|
143
|
-
if
|
146
|
+
if none_allowed and options.upper_separator is None:
|
147
|
+
pass
|
148
|
+
else:
|
144
149
|
if options.upper_separator not in get_args(option_types.UpperSeparators):
|
145
150
|
msg = (
|
146
151
|
f"upper_separator must be in "
|
@@ -155,9 +160,9 @@ def validate_separator_options(
|
|
155
160
|
)
|
156
161
|
raise ValueError(msg)
|
157
162
|
|
158
|
-
if
|
159
|
-
|
160
|
-
):
|
163
|
+
if none_allowed and options.decimal_separator is None:
|
164
|
+
pass
|
165
|
+
elif options.decimal_separator not in get_args(option_types.DecimalSeparators):
|
161
166
|
msg = (
|
162
167
|
f"decimal_separator must be in "
|
163
168
|
f"{get_args(option_types.DecimalSeparators)}, not "
|
@@ -165,9 +170,9 @@ def validate_separator_options(
|
|
165
170
|
)
|
166
171
|
raise ValueError(msg)
|
167
172
|
|
168
|
-
if
|
169
|
-
|
170
|
-
):
|
173
|
+
if none_allowed and options.lower_separator is None:
|
174
|
+
pass
|
175
|
+
elif options.lower_separator not in get_args(option_types.LowerSeparators):
|
171
176
|
msg = (
|
172
177
|
f"lower_separator must be in {get_args(option_types.LowerSeparators)}, "
|
173
178
|
f"not {options.lower_separator}."
|
@@ -188,7 +193,9 @@ def validate_extra_translations(
|
|
188
193
|
]
|
189
194
|
|
190
195
|
for translation_dict in translations_dicts:
|
191
|
-
if
|
196
|
+
if none_allowed and translation_dict is None:
|
197
|
+
pass
|
198
|
+
else:
|
192
199
|
for key, value in translation_dict.items():
|
193
200
|
if not isinstance(key, int):
|
194
201
|
msg = f'Translation dictionary keys must be integers, not "{key}".'
|
@@ -208,16 +215,19 @@ def validate_left_pad_options(
|
|
208
215
|
none_allowed: bool,
|
209
216
|
) -> None:
|
210
217
|
"""Validate left padding options."""
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
218
|
+
if none_allowed and options.left_pad_dec_place is None:
|
219
|
+
pass
|
220
|
+
else:
|
221
|
+
dec_place_msg = (
|
222
|
+
f"left_pad_dec_place must an an int >= 0, not {options.left_pad_dec_place}."
|
223
|
+
)
|
215
224
|
if not isinstance(options.left_pad_dec_place, int):
|
216
225
|
raise TypeError(dec_place_msg)
|
217
226
|
if options.left_pad_dec_place < 0:
|
218
227
|
raise ValueError(dec_place_msg)
|
219
|
-
|
220
|
-
|
221
|
-
|
228
|
+
|
229
|
+
if none_allowed and options.left_pad_char is None:
|
230
|
+
pass
|
231
|
+
elif options.left_pad_char not in [0, "0", " "]:
|
222
232
|
msg = f'left_pad_char must be in [" ", "0", 0], not {options.left_pad_char}.'
|
223
233
|
raise ValueError(msg)
|