sciform 0.33.0__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.
@@ -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
@@ -1,23 +1,23 @@
1
1
  """
2
2
  Rendered format options used in sciform backend formatting algorithm.
3
3
 
4
- :class:`UserOptions` are converted into :class:`RenderedOptions`
4
+ :class:`InputOptions` are converted into :class:`FinalizedOptions`
5
5
  internally at format time.
6
6
  """
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from dataclasses import asdict, dataclass
11
- from enum import Enum
12
- from pprint import pformat
10
+ from dataclasses import dataclass
13
11
  from typing import TYPE_CHECKING
14
12
 
13
+ from sciform.options.validation import validate_options
14
+
15
15
  if TYPE_CHECKING: # pragma: no cover
16
16
  from sciform import modes
17
17
 
18
18
 
19
19
  @dataclass(frozen=True)
20
- class RenderedOptions:
20
+ class FinalizedOptions:
21
21
  """Rendered options: All options populated and using Enum instead of Literal."""
22
22
 
23
23
  exp_mode: modes.ExpModeEnum
@@ -43,9 +43,5 @@ class RenderedOptions:
43
43
  paren_uncertainty_separators: bool
44
44
  pm_whitespace: bool
45
45
 
46
- def __str__(self: RenderedOptions) -> str:
47
- options_dict = asdict(self)
48
- for key, value in options_dict.items():
49
- if isinstance(value, Enum):
50
- options_dict[key] = value.value
51
- return pformat(options_dict, sort_dicts=False)
46
+ def __post_init__(self: FinalizedOptions) -> None:
47
+ validate_options(self)
@@ -1,20 +1,20 @@
1
1
  """Global Options."""
2
2
 
3
3
  from sciform import modes
4
- from sciform.rendered_options import RenderedOptions
4
+ from sciform.options.populated_options import PopulatedOptions
5
5
 
6
- PKG_DEFAULT_OPTIONS = RenderedOptions(
7
- exp_mode=modes.ExpModeEnum.FIXEDPOINT,
6
+ PKG_DEFAULT_OPTIONS = PopulatedOptions(
7
+ exp_mode="fixed_point",
8
8
  exp_val=modes.AutoExpVal,
9
- round_mode=modes.RoundModeEnum.SIG_FIG,
9
+ round_mode="sig_fig",
10
10
  ndigits=modes.AutoDigits,
11
- upper_separator=modes.SeparatorEnum.NONE,
12
- decimal_separator=modes.SeparatorEnum.POINT,
13
- lower_separator=modes.SeparatorEnum.NONE,
14
- sign_mode=modes.SignModeEnum.NEGATIVE,
15
- left_pad_char=modes.LeftPadCharEnum.SPACE,
11
+ upper_separator="",
12
+ decimal_separator=".",
13
+ lower_separator="",
14
+ sign_mode="-",
15
+ left_pad_char=" ",
16
16
  left_pad_dec_place=0,
17
- exp_format=modes.ExpFormatEnum.STANDARD,
17
+ exp_format="standard",
18
18
  extra_si_prefixes={},
19
19
  extra_iec_prefixes={},
20
20
  extra_parts_per_forms={},
@@ -0,0 +1,104 @@
1
+ """InputOptions Dataclass which stores user input."""
2
+
3
+
4
+ from __future__ import annotations
5
+
6
+ from dataclasses import asdict, dataclass
7
+ from pprint import pformat
8
+ from typing import TYPE_CHECKING, Any, Literal
9
+
10
+ from sciform.options.validation import validate_options
11
+
12
+ if TYPE_CHECKING: # pragma: no cover
13
+ from sciform import modes
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class InputOptions:
18
+ """
19
+ Dataclass storing user input.
20
+
21
+ Stores the user input to :class:`Formatter`, so any keyword
22
+ arguments that can be passed into :class:`Formatter` are stored in
23
+ :class:`InputOptions`. Any unpopulated options retain the ``None``
24
+ value. At format time the :class:`InputOptions` are populated and
25
+ replaced by a :class:`PopulatedOptions` instance which necessarily
26
+ has all attributes populated with meaningful values.
27
+
28
+ :class:`InputOptions` instances should only be accessed via the
29
+ :class:`Formatter.input_options()` property. They should not be
30
+ instantiated directly.
31
+
32
+ >>> from sciform import Formatter
33
+ >>> formatter = Formatter(
34
+ ... exp_mode="engineering",
35
+ ... round_mode="sig_fig",
36
+ ... ndigits=2,
37
+ ... superscript=True,
38
+ ... )
39
+ >>> print(formatter.input_options.round_mode)
40
+ sig_fig
41
+ >>> print(formatter.input_options.exp_format)
42
+ None
43
+ >>> print(formatter.input_options)
44
+ InputOptions(
45
+ 'exp_mode': 'engineering',
46
+ 'round_mode': 'sig_fig',
47
+ 'ndigits': 2,
48
+ 'superscript': True,
49
+ )
50
+ >>> print(formatter.input_options.as_dict())
51
+ {'exp_mode': 'engineering', 'round_mode': 'sig_fig', 'ndigits': 2, 'superscript': True}
52
+ """ # noqa: E501
53
+
54
+ exp_mode: modes.ExpMode | None = None
55
+ exp_val: int | type(modes.AutoExpVal) | None = None
56
+ round_mode: modes.RoundMode | None = None
57
+ ndigits: int | type(modes.AutoDigits) | None = None
58
+ upper_separator: modes.UpperSeparators | None = None
59
+ decimal_separator: modes.DecimalSeparators | None = None
60
+ lower_separator: modes.LowerSeparators | None = None
61
+ sign_mode: modes.SignMode | None = None
62
+ left_pad_char: modes.LeftPadChar | Literal[0] | None = None
63
+ left_pad_dec_place: int | None = None
64
+ exp_format: modes.ExpFormat | None = None
65
+ extra_si_prefixes: dict[int, str] | None = None
66
+ extra_iec_prefixes: dict[int, str] | None = None
67
+ extra_parts_per_forms: dict[int, str] | None = None
68
+ capitalize: bool | None = None
69
+ superscript: bool | None = None
70
+ nan_inf_exp: bool | None = None
71
+ paren_uncertainty: bool | None = None
72
+ pdg_sig_figs: bool | None = None
73
+ left_pad_matching: bool | None = None
74
+ paren_uncertainty_separators: bool | None = None
75
+ pm_whitespace: bool | None = None
76
+
77
+ add_c_prefix: bool = None
78
+ add_small_si_prefixes: bool = None
79
+ add_ppth_form: bool = None
80
+
81
+ def __post_init__(self: InputOptions) -> None:
82
+ validate_options(self)
83
+
84
+ def as_dict(self: InputOptions) -> dict[str, Any]:
85
+ """
86
+ Return a dict representation of the InputOptions.
87
+
88
+ This dict can be passed into :class:`Formatter` as ``**kwargs``,
89
+ possibly after modification. This allows for the possibility of
90
+ constructing new :class:`Formatter` instances based on old ones.
91
+ Only explicitly populated attributes are included in the
92
+ returned dictionary.
93
+ """
94
+ options_dict = asdict(self)
95
+ for key in list(options_dict.keys()):
96
+ if options_dict[key] is None:
97
+ del options_dict[key]
98
+ return options_dict
99
+
100
+ def __str__(self: InputOptions) -> str:
101
+ options_str = pformat(self.as_dict(), width=-1, sort_dicts=False)
102
+ options_str = options_str.lstrip("{").rstrip("}")
103
+ options_str = f"InputOptions(\n {options_str},\n)"
104
+ return options_str
@@ -0,0 +1,136 @@
1
+ """InputOptions Dataclass which stores user input."""
2
+
3
+
4
+ from __future__ import annotations
5
+
6
+ from dataclasses import asdict, dataclass
7
+ from pprint import pformat
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ from sciform.options.validation import validate_options
11
+
12
+ if TYPE_CHECKING: # pragma: no cover
13
+ from sciform import modes
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class PopulatedOptions:
18
+ """
19
+ Dataclass storing fully populated formatting options.
20
+
21
+ User input options during :class:`Formatter` initialization are
22
+ stored in :class:`InputOptions` instances. But
23
+ :class:`InputOptions` instances don't necessarily have all options
24
+ populated as required for the formatting algorithm. At formatting
25
+ time the unpopulated options are populated from the global options.
26
+ The new resulting options object with all options populated is a
27
+ :class:`PopulatedOptions` instances. Note that the global options
28
+ are stored as a :class:`PopulatedOptions` instance.
29
+
30
+ :class:`PopulatedOptions` instances should only be accessed via the
31
+ :class:`Formatter.populated_options()` property. They should not be
32
+ instantiated directly.
33
+
34
+ >>> from sciform import Formatter
35
+ >>> formatter = Formatter(
36
+ ... exp_mode="engineering",
37
+ ... round_mode="sig_fig",
38
+ ... ndigits=2,
39
+ ... superscript=True,
40
+ ... )
41
+ >>> print(formatter.populated_options.round_mode)
42
+ sig_fig
43
+ >>> print(formatter.populated_options.exp_format)
44
+ standard
45
+ >>> print(formatter.populated_options)
46
+ PopulatedOptions(
47
+ 'exp_mode': 'engineering',
48
+ 'exp_val': AutoExpVal,
49
+ 'round_mode': 'sig_fig',
50
+ 'ndigits': 2,
51
+ 'upper_separator': '',
52
+ 'decimal_separator': '.',
53
+ 'lower_separator': '',
54
+ 'sign_mode': '-',
55
+ 'left_pad_char': ' ',
56
+ 'left_pad_dec_place': 0,
57
+ 'exp_format': 'standard',
58
+ 'extra_si_prefixes': {},
59
+ 'extra_iec_prefixes': {},
60
+ 'extra_parts_per_forms': {},
61
+ 'capitalize': False,
62
+ 'superscript': True,
63
+ 'nan_inf_exp': False,
64
+ 'paren_uncertainty': False,
65
+ 'pdg_sig_figs': False,
66
+ 'left_pad_matching': False,
67
+ 'paren_uncertainty_separators': True,
68
+ 'pm_whitespace': True,
69
+ )
70
+ >>> print(formatter.populated_options.as_dict())
71
+ {'exp_mode': 'engineering', 'exp_val': AutoExpVal, '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, 'pdg_sig_figs': False, 'left_pad_matching': False, 'paren_uncertainty_separators': True, 'pm_whitespace': True}
72
+
73
+ Note that :class:`PopulatedOptions` lacks the ``add_c_prefix``,
74
+ ``add_small_si_prefixes`` and ``add_ppth_form`` options present
75
+ in :class:`InputOptions`. These options are helper functions which
76
+ modify the corresponding exponent replacement dictionaries.
77
+
78
+ >>> formatter = Formatter(
79
+ ... exp_mode="engineering",
80
+ ... exp_format="prefix",
81
+ ... add_c_prefix=True,
82
+ ... )
83
+ >>> print(formatter.input_options)
84
+ InputOptions(
85
+ 'exp_mode': 'engineering',
86
+ 'exp_format': 'prefix',
87
+ 'add_c_prefix': True,
88
+ )
89
+ >>> print(formatter.input_options.extra_si_prefixes)
90
+ None
91
+ >>> print(formatter.populated_options.extra_si_prefixes)
92
+ {-2: 'c'}
93
+
94
+ """ # noqa: E501
95
+
96
+ exp_mode: modes.ExpMode
97
+ exp_val: int | type(modes.AutoExpVal)
98
+ round_mode: modes.RoundMode
99
+ ndigits: int | type(modes.AutoDigits)
100
+ upper_separator: modes.UpperSeparators
101
+ decimal_separator: modes.DecimalSeparators
102
+ lower_separator: modes.LowerSeparators
103
+ sign_mode: modes.SignMode
104
+ left_pad_char: modes.LeftPadChar
105
+ left_pad_dec_place: int
106
+ exp_format: modes.ExpFormat
107
+ extra_si_prefixes: dict[int, str]
108
+ extra_iec_prefixes: dict[int, str]
109
+ extra_parts_per_forms: dict[int, str]
110
+ capitalize: bool
111
+ superscript: bool
112
+ nan_inf_exp: bool
113
+ paren_uncertainty: bool
114
+ pdg_sig_figs: bool
115
+ left_pad_matching: bool
116
+ paren_uncertainty_separators: bool
117
+ pm_whitespace: bool
118
+
119
+ def __post_init__(self: PopulatedOptions) -> None:
120
+ validate_options(self)
121
+
122
+ def as_dict(self: PopulatedOptions) -> dict[str, Any]:
123
+ """
124
+ Return a dict representation of the PopulatedOptions.
125
+
126
+ This dict can be passed into :class:`Formatter` as ``**kwargs``,
127
+ possibly after modification. This allows for the possibility of
128
+ constructing new :class:`Formatter` instances based on old ones.
129
+ """
130
+ return asdict(self)
131
+
132
+ def __str__(self: PopulatedOptions) -> str:
133
+ options_str = pformat(self.as_dict(), width=-1, sort_dicts=False)
134
+ options_str = options_str.lstrip("{").rstrip("}")
135
+ options_str = f"PopulatedOptions(\n {options_str},\n)"
136
+ return options_str
@@ -0,0 +1,101 @@
1
+ """Options validation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, get_args
6
+
7
+ from sciform import modes
8
+
9
+ if TYPE_CHECKING: # pragma: no cover
10
+ from sciform.options.finalized_options import FinalizedOptions
11
+ from sciform.options.input_options import InputOptions
12
+ from sciform.options.populated_options import PopulatedOptions
13
+
14
+
15
+ def validate_options(
16
+ options: InputOptions | PopulatedOptions | FinalizedOptions,
17
+ ) -> None:
18
+ """Validate user inputs."""
19
+ validate_sig_fig_round_mode(options)
20
+ validate_exp_val(options)
21
+ validate_separator_options(options)
22
+
23
+
24
+ def validate_sig_fig_round_mode(
25
+ options: InputOptions | PopulatedOptions | FinalizedOptions,
26
+ ) -> None:
27
+ r"""Validate ndigits if round_mode == "sig_fig"."""
28
+ if (
29
+ options.round_mode == "sig_fig"
30
+ and isinstance(options.ndigits, int)
31
+ and options.ndigits < 1
32
+ ):
33
+ msg = f"ndigits must be >= 1 for sig fig rounding, not {options.ndigits}."
34
+ raise ValueError(msg)
35
+
36
+
37
+ def validate_exp_val(
38
+ options: InputOptions | PopulatedOptions | FinalizedOptions,
39
+ ) -> None:
40
+ """Validate exp_val."""
41
+ if options.exp_val is not modes.AutoExpVal and options.exp_val is not None:
42
+ if options.exp_mode in ["fixed_point", "percent"] and options.exp_val != 0:
43
+ msg = (
44
+ f"Exponent must must be 0, not exp_val={options.exp_val}, for "
45
+ f"fixed point and percent exponent modes."
46
+ )
47
+ raise ValueError(msg)
48
+ if (
49
+ options.exp_mode in ["engineering", "engineering_shifted"]
50
+ and options.exp_val % 3 != 0
51
+ ):
52
+ msg = (
53
+ f"Exponent must be a multiple of 3, not exp_val={options.exp_val}, "
54
+ f"for engineering exponent modes."
55
+ )
56
+ raise ValueError(msg)
57
+ if options.exp_mode == "binary_iec" and options.exp_val % 10 != 0:
58
+ msg = (
59
+ f"Exponent must be a multiple of 10, not "
60
+ f"exp_val={options.exp_val}, for binary IEC exponent mode."
61
+ )
62
+ raise ValueError(msg)
63
+
64
+
65
+ def validate_separator_options(
66
+ options: InputOptions | PopulatedOptions | FinalizedOptions,
67
+ ) -> None:
68
+ """Validate separator user input."""
69
+ if options.upper_separator is not None:
70
+ if options.upper_separator not in get_args(modes.UpperSeparators):
71
+ msg = (
72
+ f"upper_separator must be in "
73
+ f"{get_args(modes.UpperSeparators)}, not "
74
+ f"{options.upper_separator}."
75
+ )
76
+ raise ValueError(msg)
77
+ if options.upper_separator == options.decimal_separator:
78
+ msg = (
79
+ f"upper_separator and decimal_separator "
80
+ f"({options.upper_separator}) cannot be equal."
81
+ )
82
+ raise ValueError(msg)
83
+
84
+ if options.decimal_separator is not None and (
85
+ options.decimal_separator not in get_args(modes.DecimalSeparators)
86
+ ):
87
+ msg = (
88
+ f"decimal_separator must be in "
89
+ f"{get_args(modes.DecimalSeparators)}, not "
90
+ f"{options.decimal_separator}."
91
+ )
92
+ raise ValueError(msg)
93
+
94
+ if options.lower_separator is not None and (
95
+ options.lower_separator not in get_args(modes.LowerSeparators)
96
+ ):
97
+ msg = (
98
+ f"lower_separator must be in {get_args(modes.LowerSeparators)}, "
99
+ f"not {options.lower_separator}."
100
+ )
101
+ raise ValueError(msg)
@@ -84,9 +84,9 @@ def convert_sciform_format(
84
84
 
85
85
  >>> from sciform.output_conversion import convert_sciform_format
86
86
  >>> print(convert_sciform_format("(7.8900 ± 0.0001)×10²", "latex"))
87
- (7.8900\:\pm\:0.0001)\times10^{2}
87
+ $(7.8900\:\pm\:0.0001)\times10^{2}$
88
88
  >>> print(convert_sciform_format("16.18033E+03", "latex"))
89
- 16.18033\times10^{3}
89
+ $16.18033\times10^{3}$
90
90
 
91
91
  HTML
92
92
  ====
sciform/scinum.py CHANGED
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  from decimal import Decimal
6
6
  from typing import TYPE_CHECKING
7
7
 
8
- from sciform.formatting import format_num, format_val_unc
8
+ from sciform.formatting import FormattedNumber, format_from_options
9
9
  from sciform.fsml import format_options_from_fmt_spec
10
10
 
11
11
  if TYPE_CHECKING: # pragma: no cover
@@ -23,13 +23,13 @@ class SciNum:
23
23
  be populated with global default settings at format time.
24
24
 
25
25
  >>> from sciform import SciNum
26
- >>> snum = SciNum(12345.54321)
27
- >>> print(f"{snum:!3f}")
26
+ >>> num = SciNum(12345.54321)
27
+ >>> print(f"{num:!3f}")
28
28
  12300
29
- >>> print(f"{snum:+2.3R}")
29
+ >>> print(f"{num:+2.3R}")
30
30
  + 12.346E+03
31
- >>> snum = SciNum(123456.654321, 0.0234)
32
- >>> print(f"{snum:#!2r()}")
31
+ >>> num = SciNum(123456.654321, 0.0234)
32
+ >>> print(f"{num:#!2r()}")
33
33
  (0.123456654(23))e+06
34
34
  """
35
35
 
@@ -45,12 +45,13 @@ class SciNum:
45
45
  else:
46
46
  self.uncertainty = Decimal(str(uncertainty))
47
47
 
48
- def __format__(self: SciNum, fmt: str) -> str:
49
- user_options = format_options_from_fmt_spec(fmt)
50
- rendered_options = user_options.render()
51
- if self.uncertainty is not None:
52
- return format_val_unc(self.value, self.uncertainty, rendered_options)
53
- return format_num(self.value, rendered_options)
48
+ def __format__(self: SciNum, fmt: str) -> FormattedNumber:
49
+ input_options = format_options_from_fmt_spec(fmt)
50
+ return format_from_options(
51
+ self.value,
52
+ self.uncertainty,
53
+ input_options=input_options,
54
+ )
54
55
 
55
56
  def __repr__(self: SciNum) -> str:
56
57
  if self.uncertainty is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sciform
3
- Version: 0.33.0
3
+ Version: 0.34.0
4
4
  Summary: A package for formatting numbers into scientific formatted strings.
5
5
  Author-email: Justin Gerber <justin.gerber48@gmail.com>
6
6
  Project-URL: homepage, https://github.com/jagerber48/sciform
@@ -132,18 +132,22 @@ You can view the on-going review
132
132
  Usage
133
133
  =====
134
134
 
135
+ Here we provide a few key usage examples.
136
+ For many more details see
137
+ `Usage <https://sciform.readthedocs.io/en/stable/usage.html>`_.
138
+
135
139
  ``sciform`` provides a wide variety of formatting options which can be
136
140
  controlled when constructing ``Formatter`` objects which are then used
137
141
  to format numbers into strings according to the selected options.
138
142
 
139
143
  >>> from sciform import Formatter
140
- >>> sform = Formatter(
144
+ >>> formatter = Formatter(
141
145
  ... round_mode="dec_place", ndigits=6, upper_separator=" ", lower_separator=" "
142
146
  ... )
143
- >>> print(sform(51413.14159265359))
147
+ >>> print(formatter(51413.14159265359))
144
148
  51 413.141 593
145
- >>> sform = Formatter(round_mode="sig_fig", ndigits=4, exp_mode="engineering")
146
- >>> print(sform(123456.78))
149
+ >>> formatter = Formatter(round_mode="sig_fig", ndigits=4, exp_mode="engineering")
150
+ >>> print(formatter(123456.78))
147
151
  123.5e+03
148
152
 
149
153
  Users can also format numbers by constructing ``SciNum`` objects and
@@ -162,11 +166,11 @@ to format pairs of numbers as value/uncertainty pairs.
162
166
  This can be done by passing two numbers into a ``Formatter`` call or by
163
167
  using the ``SciNum`` object.
164
168
 
165
- >>> sform = Formatter(ndigits=2, upper_separator=" ", lower_separator=" ")
166
- >>> print(sform(123456.654321, 0.00345))
169
+ >>> formatter = Formatter(ndigits=2, upper_separator=" ", lower_separator=" ")
170
+ >>> print(formatter(123456.654321, 0.00345))
167
171
  123 456.654 3 ± 0.003 4
168
- >>> sform = Formatter(ndigits=4, exp_mode="engineering")
169
- >>> print(sform(123456.654321, 0.00345))
172
+ >>> formatter = Formatter(ndigits=4, exp_mode="engineering")
173
+ >>> print(formatter(123456.654321, 0.00345))
170
174
  (123.456654321 ± 0.000003450)e+03
171
175
 
172
176
  >>> num = SciNum(123456.654321, 0.00345)
@@ -0,0 +1,23 @@
1
+ sciform/__init__.py,sha256=S6-oZ4wA-h2iFlpUhrRLDSycdn5b8kRd5s5xGI64-a8,844
2
+ sciform/format_utils.py,sha256=JNFlSxxM9K3M1KI5oLyTsPPzAsvgKDQAGgxPN3wqG_I,16545
3
+ sciform/formatter.py,sha256=paVP2I6IO9y7lvkFB7_tMGFikfp7MS9PSlSG5zPWrzQ,15057
4
+ sciform/formatting.py,sha256=Z2jLIeuqMm6JWd_FurJ_-rU0Yr96jT-tb8CYEzjPgZA,12228
5
+ sciform/fsml.py,sha256=r22RiBPrkDaiPgE2VQrtGms9aBmWqolymsmmnp-z57s,3378
6
+ sciform/global_configuration.py,sha256=L3nORbdGOO6ZZk8Xv81lr8S95Od35CgxlpOsdJDxs44,6964
7
+ sciform/grouping.py,sha256=1hZjjVKRUy477LGGFniZwwEHHBDaSb6E0K3SAeCACVY,1641
8
+ sciform/modes.py,sha256=8slohyIPHeAdgq3aszoNq9RJl6ibageFqDMxeC9NhrQ,3893
9
+ sciform/output_conversion.py,sha256=IwylcmSXdfIZlVaa7fplL0E0F6JdtJyoHC_T9ZwGYo8,5489
10
+ sciform/prefix.py,sha256=1rJeKMs8m97V3ZvMzHikqXLDDINp9aEK0AI3YaCcRMw,596
11
+ sciform/scinum.py,sha256=oqbXiENMwELQmhVF7sR6fcnBECqDV8GNyOLNIrNIB9I,1857
12
+ sciform/options/__init__.py,sha256=tw_CZHaNrdixZoQyG6ZD5UMKkQxXok0qBQCxt28Gh20,51
13
+ sciform/options/conversion.py,sha256=ReqASoGNQIfa-r5-HEGZxokENti_NRkAjRP-zrxY0EU,4124
14
+ sciform/options/finalized_options.py,sha256=PNcoAiB_WccbqxRJ5o_WPLnqb_n3J_MDpFTKqJxdSBM,1388
15
+ sciform/options/global_options.py,sha256=8493K2Yu47D8-Dr6rgVWVKAVo-aAVaPzFNEpG7X0IAk,782
16
+ sciform/options/input_options.py,sha256=gGUhuZr_t89IVhHwpEbtzLV9hvjMXVdMCgwe9OghO4k,3788
17
+ sciform/options/populated_options.py,sha256=rVExq0YXzpk9kk-KUVm2oGXQEH56jBDGtZZ2vTqLqqo,4999
18
+ sciform/options/validation.py,sha256=O1UTe5yHA0eN7sTtDsMNBh-1t3C-lbPayGoW9kn7FSU,3527
19
+ sciform-0.34.0.dist-info/LICENSE,sha256=-oyCEZu-6HLrRSfRg44uuNDE0c59GVEdqYIgidqSP70,1056
20
+ sciform-0.34.0.dist-info/METADATA,sha256=wZhvWEVrSkst3jLEYmpX5imgbzg0IatMk861S37M0f4,8002
21
+ sciform-0.34.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
22
+ sciform-0.34.0.dist-info/top_level.txt,sha256=mC01YOQ-1u5pDk9BJia-pQKLUMvkreMsldDpFcp7NV8,8
23
+ sciform-0.34.0.dist-info/RECORD,,