sciform 0.32.3__py3-none-any.whl → 0.34.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 +16 -8
- sciform/format_utils.py +26 -94
- sciform/formatter.py +154 -56
- sciform/formatting.py +99 -30
- sciform/fsml.py +7 -7
- sciform/global_configuration.py +39 -36
- sciform/modes.py +3 -10
- sciform/options/__init__.py +1 -0
- sciform/options/conversion.py +120 -0
- sciform/{rendered_options.py → options/finalized_options.py} +8 -13
- sciform/{global_options.py → options/global_options.py} +10 -11
- sciform/options/input_options.py +104 -0
- sciform/options/populated_options.py +136 -0
- sciform/options/validation.py +101 -0
- sciform/output_conversion.py +168 -0
- sciform/scinum.py +13 -12
- {sciform-0.32.3.dist-info → sciform-0.34.0.dist-info}/METADATA +20 -12
- sciform-0.34.0.dist-info/RECORD +23 -0
- sciform/user_options.py +0 -189
- sciform-0.32.3.dist-info/RECORD +0 -18
- {sciform-0.32.3.dist-info → sciform-0.34.0.dist-info}/LICENSE +0 -0
- {sciform-0.32.3.dist-info → sciform-0.34.0.dist-info}/WHEEL +0 -0
- {sciform-0.32.3.dist-info → sciform-0.34.0.dist-info}/top_level.txt +0 -0
sciform/formatting.py
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
"""Main formatting functions."""
|
2
|
+
from __future__ import annotations
|
2
3
|
|
3
4
|
from dataclasses import replace
|
4
5
|
from decimal import Decimal
|
5
|
-
from typing import cast
|
6
|
+
from typing import TYPE_CHECKING, cast
|
6
7
|
from warnings import warn
|
7
8
|
|
9
|
+
from typing_extensions import Self
|
10
|
+
|
8
11
|
from sciform.format_utils import (
|
12
|
+
Number,
|
9
13
|
construct_val_unc_exp_str,
|
10
14
|
construct_val_unc_str,
|
11
15
|
format_num_by_top_bottom_dig,
|
@@ -13,9 +17,8 @@ from sciform.format_utils import (
|
|
13
17
|
get_mantissa_exp_base,
|
14
18
|
get_round_digit,
|
15
19
|
get_val_unc_exp,
|
16
|
-
|
20
|
+
get_val_unc_mantissa_strs,
|
17
21
|
get_val_unc_top_digit,
|
18
|
-
latex_translate,
|
19
22
|
round_val_unc,
|
20
23
|
)
|
21
24
|
from sciform.grouping import add_separators
|
@@ -26,10 +29,35 @@ from sciform.modes import (
|
|
26
29
|
RoundModeEnum,
|
27
30
|
SignModeEnum,
|
28
31
|
)
|
29
|
-
from sciform.
|
32
|
+
from sciform.options.conversion import finalize_populated_options, populate_options
|
33
|
+
from sciform.output_conversion import convert_sciform_format
|
34
|
+
|
35
|
+
if TYPE_CHECKING: # pragma: no cover
|
36
|
+
from sciform.options.finalized_options import FinalizedOptions
|
37
|
+
from sciform.options.input_options import InputOptions
|
38
|
+
from sciform.options.populated_options import PopulatedOptions
|
39
|
+
|
40
|
+
|
41
|
+
def format_from_options(
|
42
|
+
value: Number,
|
43
|
+
uncertainty: Number | None = None,
|
44
|
+
/,
|
45
|
+
input_options: InputOptions | None = None,
|
46
|
+
) -> FormattedNumber:
|
47
|
+
"""Finalize options and select value of value/uncertainty formatter."""
|
48
|
+
populated_options = populate_options(input_options)
|
49
|
+
finalized_options = finalize_populated_options(populated_options)
|
50
|
+
value = Decimal(str(value))
|
51
|
+
|
52
|
+
if uncertainty is not None:
|
53
|
+
uncertainty = Decimal(str(uncertainty))
|
54
|
+
formatted_str = format_val_unc(value, uncertainty, finalized_options)
|
55
|
+
else:
|
56
|
+
formatted_str = format_num(value, finalized_options)
|
57
|
+
return FormattedNumber(formatted_str, populated_options)
|
30
58
|
|
31
59
|
|
32
|
-
def format_non_finite(num: Decimal, options:
|
60
|
+
def format_non_finite(num: Decimal, options: FinalizedOptions) -> str:
|
33
61
|
"""Format non-finite numbers."""
|
34
62
|
if num.is_nan():
|
35
63
|
num_str = "nan"
|
@@ -53,8 +81,6 @@ def format_non_finite(num: Decimal, options: RenderedOptions) -> str:
|
|
53
81
|
exp_mode=exp_mode,
|
54
82
|
exp_format=options.exp_format,
|
55
83
|
capitalize=options.capitalize,
|
56
|
-
latex=options.latex,
|
57
|
-
latex_trim_whitespace=True,
|
58
84
|
superscript=options.superscript,
|
59
85
|
extra_si_prefixes=options.extra_si_prefixes,
|
60
86
|
extra_iec_prefixes=options.extra_iec_prefixes,
|
@@ -73,13 +99,10 @@ def format_non_finite(num: Decimal, options: RenderedOptions) -> str:
|
|
73
99
|
else:
|
74
100
|
result = result.lower()
|
75
101
|
|
76
|
-
if options.latex:
|
77
|
-
result = latex_translate(result)
|
78
|
-
|
79
102
|
return result
|
80
103
|
|
81
104
|
|
82
|
-
def format_num(num: Decimal, options:
|
105
|
+
def format_num(num: Decimal, options: FinalizedOptions) -> str:
|
83
106
|
"""Format a single number according to input options."""
|
84
107
|
if not num.is_finite():
|
85
108
|
return format_non_finite(num, options)
|
@@ -115,13 +138,13 @@ def format_num(num: Decimal, options: RenderedOptions) -> str:
|
|
115
138
|
"""
|
116
139
|
exp_val = 0
|
117
140
|
|
118
|
-
|
141
|
+
left_pad_char = options.left_pad_char.value
|
119
142
|
mantissa_str = format_num_by_top_bottom_dig(
|
120
143
|
mantissa_rounded.normalize(),
|
121
144
|
options.left_pad_dec_place,
|
122
145
|
round_digit,
|
123
146
|
options.sign_mode,
|
124
|
-
|
147
|
+
left_pad_char,
|
125
148
|
)
|
126
149
|
|
127
150
|
upper_separator = options.upper_separator.value
|
@@ -140,8 +163,6 @@ def format_num(num: Decimal, options: RenderedOptions) -> str:
|
|
140
163
|
exp_mode=exp_mode,
|
141
164
|
exp_format=options.exp_format,
|
142
165
|
capitalize=options.capitalize,
|
143
|
-
latex=options.latex,
|
144
|
-
latex_trim_whitespace=False,
|
145
166
|
superscript=options.superscript,
|
146
167
|
extra_si_prefixes=options.extra_si_prefixes,
|
147
168
|
extra_iec_prefixes=options.extra_iec_prefixes,
|
@@ -150,13 +171,10 @@ def format_num(num: Decimal, options: RenderedOptions) -> str:
|
|
150
171
|
|
151
172
|
result = f"{mantissa_str}{exp_str}"
|
152
173
|
|
153
|
-
if options.latex:
|
154
|
-
result = latex_translate(result)
|
155
|
-
|
156
174
|
return result
|
157
175
|
|
158
176
|
|
159
|
-
def format_val_unc(val: Decimal, unc: Decimal, options:
|
177
|
+
def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str:
|
160
178
|
"""Format value/uncertainty pair according to input options."""
|
161
179
|
exp_mode = options.exp_mode
|
162
180
|
|
@@ -205,7 +223,7 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
205
223
|
use_pdg_sig_figs=options.pdg_sig_figs,
|
206
224
|
)
|
207
225
|
|
208
|
-
exp_val
|
226
|
+
exp_val = get_val_unc_exp(
|
209
227
|
val_rounded,
|
210
228
|
unc_rounded,
|
211
229
|
options.exp_mode,
|
@@ -240,7 +258,7 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
240
258
|
* With the calculated shared exponent
|
241
259
|
* Without percent mode (percent mode for val/unc pairs is
|
242
260
|
handled below in the scope of this function)
|
243
|
-
* Without superscript, prefix, parts-per
|
261
|
+
* Without superscript, prefix, or parts-per translations.
|
244
262
|
The remaining steps rely on parsing an exponent string like
|
245
263
|
'e+03' or similar. Such translations are handled within the
|
246
264
|
scope of this function.
|
@@ -253,7 +271,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
253
271
|
exp_mode=exp_mode,
|
254
272
|
exp_val=exp_val,
|
255
273
|
superscript=False,
|
256
|
-
latex=False,
|
257
274
|
exp_format=ExpFormatEnum.STANDARD,
|
258
275
|
)
|
259
276
|
|
@@ -265,10 +282,9 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
265
282
|
val_mantissa_exp_str = format_num(val_rounded, val_format_options)
|
266
283
|
unc_mantissa_exp_str = format_num(unc_rounded, unc_format_options)
|
267
284
|
|
268
|
-
|
285
|
+
val_mantissa_str, unc_mantissa_str = get_val_unc_mantissa_strs(
|
269
286
|
val_mantissa_exp_str,
|
270
287
|
unc_mantissa_exp_str,
|
271
|
-
exp_driver_type,
|
272
288
|
)
|
273
289
|
|
274
290
|
val_unc_str = construct_val_unc_str(
|
@@ -278,12 +294,11 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
278
294
|
unc_mantissa,
|
279
295
|
decimal_separator=options.decimal_separator,
|
280
296
|
paren_uncertainty=options.paren_uncertainty,
|
281
|
-
latex=options.latex,
|
282
297
|
pm_whitespace=options.pm_whitespace,
|
283
298
|
paren_uncertainty_separators=options.paren_uncertainty_separators,
|
284
299
|
)
|
285
300
|
|
286
|
-
if
|
301
|
+
if val.is_finite() or unc.is_finite() or options.nan_inf_exp:
|
287
302
|
val_unc_exp_str = construct_val_unc_exp_str(
|
288
303
|
val_unc_str=val_unc_str,
|
289
304
|
exp_val=exp_val,
|
@@ -293,7 +308,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
293
308
|
extra_iec_prefixes=options.extra_iec_prefixes,
|
294
309
|
extra_parts_per_forms=options.extra_parts_per_forms,
|
295
310
|
capitalize=options.capitalize,
|
296
|
-
latex=options.latex,
|
297
311
|
superscript=options.superscript,
|
298
312
|
paren_uncertainty=options.paren_uncertainty,
|
299
313
|
)
|
@@ -303,7 +317,62 @@ def format_val_unc(val: Decimal, unc: Decimal, options: RenderedOptions) -> str:
|
|
303
317
|
if options.exp_mode is ExpModeEnum.PERCENT:
|
304
318
|
val_unc_exp_str = f"({val_unc_exp_str})%"
|
305
319
|
|
306
|
-
if options.latex:
|
307
|
-
val_unc_exp_str = latex_translate(val_unc_exp_str)
|
308
|
-
|
309
320
|
return val_unc_exp_str
|
321
|
+
|
322
|
+
|
323
|
+
class FormattedNumber(str):
|
324
|
+
"""
|
325
|
+
Representation of a formatted value of value/uncertainty pair.
|
326
|
+
|
327
|
+
The :class:`FormattedNumber` class is returned by ``sciform``
|
328
|
+
formatting methods. In most cases it behaves like a regular python
|
329
|
+
string, but it provides functionality for post-converting the string
|
330
|
+
to various other formats such as latex or html. This allows the
|
331
|
+
formatted number to be displayed in a range of contexts other than
|
332
|
+
e.g. text terminals.
|
333
|
+
|
334
|
+
The :class:`FormattedNumber` class should never be instantiated
|
335
|
+
directly.
|
336
|
+
"""
|
337
|
+
|
338
|
+
__slots__ = {
|
339
|
+
"populated_options": "Record of the :class:`PopulatedOptions` used to "
|
340
|
+
"generate the :class:`FormattedNumber`.",
|
341
|
+
}
|
342
|
+
|
343
|
+
def __new__(
|
344
|
+
cls: type[Self],
|
345
|
+
formatted_str: str,
|
346
|
+
populated_options: PopulatedOptions,
|
347
|
+
) -> Self:
|
348
|
+
"""Get a new string."""
|
349
|
+
obj = super().__new__(cls, formatted_str)
|
350
|
+
obj.populated_options = populated_options
|
351
|
+
return obj
|
352
|
+
|
353
|
+
def as_str(self: FormattedNumber) -> str:
|
354
|
+
"""Return the string representation of the formatted number."""
|
355
|
+
return self.__str__()
|
356
|
+
|
357
|
+
def as_ascii(self: FormattedNumber) -> str:
|
358
|
+
"""Return the ascii representation of the formatted number."""
|
359
|
+
return convert_sciform_format(self, "ascii")
|
360
|
+
|
361
|
+
def as_html(self: FormattedNumber) -> str:
|
362
|
+
"""Return the html representation of the formatted number."""
|
363
|
+
return convert_sciform_format(self, "html")
|
364
|
+
|
365
|
+
def as_latex(self: FormattedNumber, *, strip_math_mode: bool = False) -> str:
|
366
|
+
"""Return the latex representation of the formatted number."""
|
367
|
+
latex_repr = convert_sciform_format(self, "latex")
|
368
|
+
if strip_math_mode:
|
369
|
+
latex_repr = latex_repr.strip("$")
|
370
|
+
return latex_repr
|
371
|
+
|
372
|
+
def _repr_html_(self: FormattedNumber) -> str:
|
373
|
+
"""Hook for HTML display.""" # noqa: D401
|
374
|
+
return self.as_html()
|
375
|
+
|
376
|
+
def _repr_latex_(self: FormattedNumber) -> str:
|
377
|
+
"""Hook for LaTeX display.""" # noqa: D401
|
378
|
+
return self.as_latex()
|
sciform/fsml.py
CHANGED
@@ -4,11 +4,11 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
import re
|
6
6
|
|
7
|
-
from sciform.
|
7
|
+
from sciform.options.input_options import InputOptions
|
8
8
|
|
9
9
|
pattern = re.compile(
|
10
10
|
r"""^
|
11
|
-
(?:(?P<
|
11
|
+
(?:(?P<left_pad_char>[ 0])=)?
|
12
12
|
(?P<sign_mode>[-+ ])?
|
13
13
|
(?P<alternate_mode>\#)?
|
14
14
|
(?P<left_pad_dec_place>\d+)?
|
@@ -51,14 +51,14 @@ def parse_exp_mode(
|
|
51
51
|
return exp_mode, capitalize
|
52
52
|
|
53
53
|
|
54
|
-
def format_options_from_fmt_spec(fmt_spec: str) ->
|
55
|
-
"""Resolve
|
54
|
+
def format_options_from_fmt_spec(fmt_spec: str) -> InputOptions:
|
55
|
+
"""Resolve InputOptions from format specification string."""
|
56
56
|
match = pattern.match(fmt_spec)
|
57
57
|
if match is None:
|
58
58
|
msg = f"Invalid format specifier: '{fmt_spec}'"
|
59
59
|
raise ValueError(msg)
|
60
60
|
|
61
|
-
|
61
|
+
left_pad_char = match.group("left_pad_char")
|
62
62
|
sign_mode = match.group("sign_mode")
|
63
63
|
|
64
64
|
alternate_mode = match.group("alternate_mode")
|
@@ -101,8 +101,8 @@ def format_options_from_fmt_spec(fmt_spec: str) -> UserOptions:
|
|
101
101
|
else:
|
102
102
|
paren_uncertainty = None
|
103
103
|
|
104
|
-
return
|
105
|
-
|
104
|
+
return InputOptions(
|
105
|
+
left_pad_char=left_pad_char,
|
106
106
|
sign_mode=sign_mode,
|
107
107
|
left_pad_dec_place=left_pad_dec_place,
|
108
108
|
round_mode=round_mode,
|
sciform/global_configuration.py
CHANGED
@@ -4,21 +4,28 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
from typing import TYPE_CHECKING
|
6
6
|
|
7
|
-
from sciform import global_options
|
8
|
-
from sciform.
|
7
|
+
from sciform.options import global_options
|
8
|
+
from sciform.options.conversion import populate_options
|
9
|
+
from sciform.options.input_options import InputOptions
|
9
10
|
|
10
11
|
if TYPE_CHECKING: # pragma: no cover
|
11
12
|
from types import TracebackType
|
12
13
|
|
13
|
-
from sciform
|
14
|
+
from sciform import modes
|
15
|
+
from sciform.options.populated_options import PopulatedOptions
|
14
16
|
|
15
17
|
|
16
|
-
def
|
17
|
-
"""
|
18
|
-
|
18
|
+
def get_default_global_options() -> PopulatedOptions:
|
19
|
+
"""Return the package default global options."""
|
20
|
+
return global_options.PKG_DEFAULT_OPTIONS
|
19
21
|
|
20
22
|
|
21
|
-
def
|
23
|
+
def get_global_options() -> PopulatedOptions:
|
24
|
+
"""Return the current global options."""
|
25
|
+
return global_options.GLOBAL_DEFAULT_OPTIONS
|
26
|
+
|
27
|
+
|
28
|
+
def set_global_options( # noqa: PLR0913
|
22
29
|
*,
|
23
30
|
exp_mode: modes.ExpMode | None = None,
|
24
31
|
exp_val: int | type(modes.AutoExpVal) | None = None,
|
@@ -28,7 +35,7 @@ def set_global_defaults( # noqa: PLR0913
|
|
28
35
|
decimal_separator: modes.DecimalSeparators | None = None,
|
29
36
|
lower_separator: modes.LowerSeparators | None = None,
|
30
37
|
sign_mode: modes.SignMode | None = None,
|
31
|
-
|
38
|
+
left_pad_char: modes.LeftPadChar | None = None,
|
32
39
|
left_pad_dec_place: int | None = None,
|
33
40
|
exp_format: modes.ExpFormat | None = None,
|
34
41
|
extra_si_prefixes: dict[int, str] | None = None,
|
@@ -36,7 +43,6 @@ def set_global_defaults( # noqa: PLR0913
|
|
36
43
|
extra_parts_per_forms: dict[int, str] | None = None,
|
37
44
|
capitalize: bool | None = None,
|
38
45
|
superscript: bool | None = None,
|
39
|
-
latex: bool | None = None,
|
40
46
|
nan_inf_exp: bool | None = None,
|
41
47
|
paren_uncertainty: bool | None = None,
|
42
48
|
pdg_sig_figs: bool | None = None,
|
@@ -48,11 +54,11 @@ def set_global_defaults( # noqa: PLR0913
|
|
48
54
|
add_ppth_form: bool = False,
|
49
55
|
) -> None:
|
50
56
|
"""
|
51
|
-
Configure global
|
57
|
+
Configure the global options.
|
52
58
|
|
53
59
|
Accepts the same keyword arguments as :class:`Formatter`.
|
54
60
|
"""
|
55
|
-
|
61
|
+
input_options = InputOptions(
|
56
62
|
exp_mode=exp_mode,
|
57
63
|
exp_val=exp_val,
|
58
64
|
round_mode=round_mode,
|
@@ -61,7 +67,7 @@ def set_global_defaults( # noqa: PLR0913
|
|
61
67
|
decimal_separator=decimal_separator,
|
62
68
|
lower_separator=lower_separator,
|
63
69
|
sign_mode=sign_mode,
|
64
|
-
|
70
|
+
left_pad_char=left_pad_char,
|
65
71
|
left_pad_dec_place=left_pad_dec_place,
|
66
72
|
exp_format=exp_format,
|
67
73
|
extra_si_prefixes=extra_si_prefixes,
|
@@ -69,7 +75,6 @@ def set_global_defaults( # noqa: PLR0913
|
|
69
75
|
extra_parts_per_forms=extra_parts_per_forms,
|
70
76
|
capitalize=capitalize,
|
71
77
|
superscript=superscript,
|
72
|
-
latex=latex,
|
73
78
|
nan_inf_exp=nan_inf_exp,
|
74
79
|
paren_uncertainty=paren_uncertainty,
|
75
80
|
pdg_sig_figs=pdg_sig_figs,
|
@@ -80,30 +85,30 @@ def set_global_defaults( # noqa: PLR0913
|
|
80
85
|
add_small_si_prefixes=add_small_si_prefixes,
|
81
86
|
add_ppth_form=add_ppth_form,
|
82
87
|
)
|
83
|
-
|
88
|
+
set_global_options_populated(populate_options(input_options))
|
84
89
|
|
85
90
|
|
86
|
-
def
|
87
|
-
"""Directly set global
|
88
|
-
global_options.GLOBAL_DEFAULT_OPTIONS =
|
91
|
+
def set_global_options_populated(populated_options: PopulatedOptions) -> None:
|
92
|
+
"""Directly set global options to input :class:`PopulatedOptions`."""
|
93
|
+
global_options.GLOBAL_DEFAULT_OPTIONS = populated_options
|
89
94
|
|
90
95
|
|
91
|
-
def
|
92
|
-
"""Reset global
|
96
|
+
def reset_global_options() -> None:
|
97
|
+
"""Reset global options to :mod:`sciform` package defaults."""
|
93
98
|
global_options.GLOBAL_DEFAULT_OPTIONS = global_options.PKG_DEFAULT_OPTIONS
|
94
99
|
|
95
100
|
|
96
|
-
class
|
101
|
+
class GlobalOptionsContext:
|
97
102
|
"""
|
98
|
-
Temporarily update global
|
103
|
+
Temporarily update global options.
|
99
104
|
|
100
|
-
New
|
101
|
-
global settings are re-applied when the context is exited.
|
102
|
-
the same keyword arguments as :class:`Formatter`.
|
105
|
+
New global options are applied when the context is entered and the
|
106
|
+
original global settings are re-applied when the context is exited.
|
107
|
+
Accepts the same keyword arguments as :class:`Formatter`.
|
103
108
|
"""
|
104
109
|
|
105
110
|
def __init__( # noqa: PLR0913
|
106
|
-
self:
|
111
|
+
self: GlobalOptionsContext,
|
107
112
|
*,
|
108
113
|
exp_mode: modes.ExpMode | None = None,
|
109
114
|
exp_val: int | type(modes.AutoExpVal) | None = None,
|
@@ -113,7 +118,7 @@ class GlobalDefaultsContext:
|
|
113
118
|
decimal_separator: modes.DecimalSeparators | None = None,
|
114
119
|
lower_separator: modes.LowerSeparators | None = None,
|
115
120
|
sign_mode: modes.SignMode | None = None,
|
116
|
-
|
121
|
+
left_pad_char: modes.LeftPadChar | None = None,
|
117
122
|
left_pad_dec_place: int | None = None,
|
118
123
|
exp_format: modes.ExpFormat | None = None,
|
119
124
|
extra_si_prefixes: dict[int, str] | None = None,
|
@@ -121,7 +126,6 @@ class GlobalDefaultsContext:
|
|
121
126
|
extra_parts_per_forms: dict[int, str] | None = None,
|
122
127
|
capitalize: bool | None = None,
|
123
128
|
superscript: bool | None = None,
|
124
|
-
latex: bool | None = None,
|
125
129
|
nan_inf_exp: bool | None = None,
|
126
130
|
paren_uncertainty: bool | None = None,
|
127
131
|
pdg_sig_figs: bool | None = None,
|
@@ -132,7 +136,7 @@ class GlobalDefaultsContext:
|
|
132
136
|
add_small_si_prefixes: bool = False,
|
133
137
|
add_ppth_form: bool = False,
|
134
138
|
) -> None:
|
135
|
-
|
139
|
+
input_options = InputOptions(
|
136
140
|
exp_mode=exp_mode,
|
137
141
|
exp_val=exp_val,
|
138
142
|
round_mode=round_mode,
|
@@ -141,7 +145,7 @@ class GlobalDefaultsContext:
|
|
141
145
|
decimal_separator=decimal_separator,
|
142
146
|
lower_separator=lower_separator,
|
143
147
|
sign_mode=sign_mode,
|
144
|
-
|
148
|
+
left_pad_char=left_pad_char,
|
145
149
|
left_pad_dec_place=left_pad_dec_place,
|
146
150
|
exp_format=exp_format,
|
147
151
|
extra_si_prefixes=extra_si_prefixes,
|
@@ -149,7 +153,6 @@ class GlobalDefaultsContext:
|
|
149
153
|
extra_parts_per_forms=extra_parts_per_forms,
|
150
154
|
capitalize=capitalize,
|
151
155
|
superscript=superscript,
|
152
|
-
latex=latex,
|
153
156
|
nan_inf_exp=nan_inf_exp,
|
154
157
|
paren_uncertainty=paren_uncertainty,
|
155
158
|
pdg_sig_figs=pdg_sig_figs,
|
@@ -160,19 +163,19 @@ class GlobalDefaultsContext:
|
|
160
163
|
add_small_si_prefixes=add_small_si_prefixes,
|
161
164
|
add_ppth_form=add_ppth_form,
|
162
165
|
)
|
163
|
-
self.
|
166
|
+
self.populated_options = populate_options(input_options)
|
164
167
|
self.initial_global_defaults = None
|
165
168
|
|
166
|
-
def __enter__(self:
|
169
|
+
def __enter__(self: GlobalOptionsContext) -> None:
|
167
170
|
"""Enter the context."""
|
168
|
-
self.initial_global_defaults =
|
169
|
-
|
171
|
+
self.initial_global_defaults = get_global_options()
|
172
|
+
set_global_options_populated(self.populated_options)
|
170
173
|
|
171
174
|
def __exit__(
|
172
|
-
self:
|
175
|
+
self: GlobalOptionsContext,
|
173
176
|
exc_type: type[BaseException] | None,
|
174
177
|
exc_val: BaseException | None,
|
175
178
|
exc_tb: TracebackType | None,
|
176
179
|
) -> None:
|
177
180
|
"""Exit the context."""
|
178
|
-
|
181
|
+
set_global_options_populated(self.initial_global_defaults)
|
sciform/modes.py
CHANGED
@@ -50,11 +50,11 @@ class AutoDigits(metaclass=SentinelMeta):
|
|
50
50
|
"""
|
51
51
|
|
52
52
|
|
53
|
-
|
53
|
+
LeftPadChar = Literal[" ", "0"]
|
54
54
|
|
55
55
|
|
56
|
-
class
|
57
|
-
"""
|
56
|
+
class LeftPadCharEnum(str, Enum):
|
57
|
+
"""Left pad character mode Enum."""
|
58
58
|
|
59
59
|
SPACE = " "
|
60
60
|
ZERO = "0"
|
@@ -145,13 +145,6 @@ class ExpFormatEnum(str, Enum):
|
|
145
145
|
PARTS_PER = "parts_per"
|
146
146
|
|
147
147
|
|
148
|
-
class ExpDriver(Enum):
|
149
|
-
"""Exponent drive Enum. Used for value/uncertainty formatting."""
|
150
|
-
|
151
|
-
VAL = "val"
|
152
|
-
UNC = "unc"
|
153
|
-
|
154
|
-
|
155
148
|
T = TypeVar("T", bound=Enum)
|
156
149
|
|
157
150
|
|
@@ -0,0 +1 @@
|
|
1
|
+
"""Code pertaining to sciform options handling."""
|
@@ -0,0 +1,120 @@
|
|
1
|
+
"""Code for converting between various types of sciform options."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from dataclasses import asdict
|
6
|
+
from typing import TYPE_CHECKING
|
7
|
+
|
8
|
+
from sciform import modes
|
9
|
+
from sciform.options import global_options
|
10
|
+
from sciform.options.finalized_options import FinalizedOptions
|
11
|
+
from sciform.options.populated_options import PopulatedOptions
|
12
|
+
from sciform.options.validation import validate_options
|
13
|
+
|
14
|
+
if TYPE_CHECKING: # pragma: no cover
|
15
|
+
from sciform.options.input_options import InputOptions
|
16
|
+
|
17
|
+
|
18
|
+
def populate_extra_si_prefixes(
|
19
|
+
extra_si_prefixes: dict[int, str] | None,
|
20
|
+
*,
|
21
|
+
add_c_prefix: bool,
|
22
|
+
add_small_si_prefixes: bool,
|
23
|
+
) -> dict[int, str]:
|
24
|
+
"""Populate extra_si_prefixes dict."""
|
25
|
+
if add_c_prefix:
|
26
|
+
if extra_si_prefixes is None:
|
27
|
+
extra_si_prefixes = {}
|
28
|
+
if -2 not in extra_si_prefixes:
|
29
|
+
extra_si_prefixes[-2] = "c"
|
30
|
+
if add_small_si_prefixes:
|
31
|
+
if extra_si_prefixes is None:
|
32
|
+
extra_si_prefixes = {}
|
33
|
+
if -2 not in extra_si_prefixes:
|
34
|
+
extra_si_prefixes[-2] = "c"
|
35
|
+
if -1 not in extra_si_prefixes:
|
36
|
+
extra_si_prefixes[-1] = "d"
|
37
|
+
if +1 not in extra_si_prefixes:
|
38
|
+
extra_si_prefixes[+1] = "da"
|
39
|
+
if +2 not in extra_si_prefixes:
|
40
|
+
extra_si_prefixes[+2] = "h"
|
41
|
+
return extra_si_prefixes
|
42
|
+
|
43
|
+
|
44
|
+
def populate_extra_parts_per_forms(
|
45
|
+
extra_parts_per_forms: dict[int, str] | None,
|
46
|
+
*,
|
47
|
+
add_ppth_form: bool,
|
48
|
+
) -> dict[int, str]:
|
49
|
+
"""Populate extra_si_prefixes dict."""
|
50
|
+
if add_ppth_form:
|
51
|
+
if extra_parts_per_forms is None:
|
52
|
+
extra_parts_per_forms = {}
|
53
|
+
if -3 not in extra_parts_per_forms:
|
54
|
+
extra_parts_per_forms[-3] = "ppth"
|
55
|
+
return extra_parts_per_forms
|
56
|
+
|
57
|
+
|
58
|
+
def populate_options(input_options: InputOptions) -> PopulatedOptions:
|
59
|
+
"""Populate InputOptions into PopulatedOptions."""
|
60
|
+
global_options_dict = asdict(global_options.GLOBAL_DEFAULT_OPTIONS)
|
61
|
+
input_options_dict = asdict(input_options)
|
62
|
+
kwargs = {}
|
63
|
+
for key in list(input_options_dict.keys()):
|
64
|
+
if key in ["add_c_prefix", "add_small_si_prefixes", "add_ppth_form"]:
|
65
|
+
continue
|
66
|
+
|
67
|
+
value = input_options_dict[key]
|
68
|
+
if key == "left_pad_char" and value == 0:
|
69
|
+
value = "0"
|
70
|
+
|
71
|
+
if key == "extra_si_prefixes":
|
72
|
+
value = populate_extra_si_prefixes(
|
73
|
+
value,
|
74
|
+
add_c_prefix=input_options.add_c_prefix,
|
75
|
+
add_small_si_prefixes=input_options.add_small_si_prefixes,
|
76
|
+
)
|
77
|
+
if key == "extra_parts_per_forms" and input_options.add_ppth_form:
|
78
|
+
value = populate_extra_parts_per_forms(
|
79
|
+
value,
|
80
|
+
add_ppth_form=input_options.add_ppth_form,
|
81
|
+
)
|
82
|
+
|
83
|
+
if value is None:
|
84
|
+
populated_value = global_options_dict[key]
|
85
|
+
else:
|
86
|
+
populated_value = value
|
87
|
+
|
88
|
+
kwargs[key] = populated_value
|
89
|
+
populated_options = PopulatedOptions(**kwargs)
|
90
|
+
validate_options(populated_options)
|
91
|
+
return populated_options
|
92
|
+
|
93
|
+
|
94
|
+
key_to_enum_dict = {
|
95
|
+
"exp_mode": modes.ExpModeEnum,
|
96
|
+
"round_mode": modes.RoundModeEnum,
|
97
|
+
"upper_separator": modes.SeparatorEnum,
|
98
|
+
"decimal_separator": modes.SeparatorEnum,
|
99
|
+
"lower_separator": modes.SeparatorEnum,
|
100
|
+
"sign_mode": modes.SignModeEnum,
|
101
|
+
"left_pad_char": modes.LeftPadCharEnum,
|
102
|
+
"exp_format": modes.ExpFormatEnum,
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
def finalize_populated_options(populated_options: PopulatedOptions) -> FinalizedOptions:
|
107
|
+
"""Convert PopulatedOptions into FinalizedOptions with enum values."""
|
108
|
+
kwargs = populated_options.as_dict()
|
109
|
+
for key, value in kwargs.items():
|
110
|
+
if key in key_to_enum_dict:
|
111
|
+
enum = key_to_enum_dict[key]
|
112
|
+
kwargs[key] = modes.mode_str_to_enum(value, enum)
|
113
|
+
return FinalizedOptions(**kwargs)
|
114
|
+
|
115
|
+
|
116
|
+
def finalize_input_options(input_options: InputOptions) -> FinalizedOptions:
|
117
|
+
"""Convert InputOptions into FinalizedOptions."""
|
118
|
+
populated_options = populate_options(input_options)
|
119
|
+
finalized_options = finalize_populated_options(populated_options)
|
120
|
+
return finalized_options
|