Skip to content

Commit 541e9c4

Browse files
authored
refactor: improve pint-convert (#2136)
- guard execution in __main__ - move code to functions
1 parent 645158a commit 541e9c4

File tree

1 file changed

+155
-149
lines changed

1 file changed

+155
-149
lines changed

pint/pint_convert.py

+155-149
Original file line numberDiff line numberDiff line change
@@ -1,190 +1,215 @@
11
#!/usr/bin/env python3
2-
2+
# type: ignore
33
"""
4-
pint-convert
5-
~~~~~~~~~~~~
4+
pint-convert
5+
~~~~~~~~~~~~
66
7-
:copyright: 2020 by Pint Authors, see AUTHORS for more details.
8-
:license: BSD, see LICENSE for more details.
7+
:copyright: 2020 by Pint Authors, see AUTHORS for more details.
8+
:license: BSD, see LICENSE for more details.
99
"""
1010

1111
from __future__ import annotations
1212

1313
import argparse
1414
import contextlib
1515
import re
16+
from typing import Any
1617

1718
from pint import UnitRegistry
19+
from pint.compat import HAS_UNCERTAINTIES, ufloat
20+
1821

19-
parser = argparse.ArgumentParser(description="Unit converter.", usage=argparse.SUPPRESS)
20-
parser.add_argument(
21-
"-s",
22-
"--system",
23-
metavar="sys",
24-
default="SI",
25-
help="unit system to convert to (default: SI)",
26-
)
27-
parser.add_argument(
28-
"-p",
29-
"--prec",
30-
metavar="n",
31-
type=int,
32-
default=12,
33-
help="number of maximum significant figures (default: 12)",
34-
)
35-
parser.add_argument(
36-
"-u",
37-
"--prec-unc",
38-
metavar="n",
39-
type=int,
40-
default=2,
41-
help="number of maximum uncertainty digits (default: 2)",
42-
)
43-
parser.add_argument(
44-
"-U",
45-
"--with-unc",
46-
dest="unc",
47-
action="store_true",
48-
help="consider uncertainties in constants",
49-
)
50-
parser.add_argument(
51-
"-C",
52-
"--no-corr",
53-
dest="corr",
54-
action="store_false",
55-
help="ignore correlations between constants",
56-
)
57-
parser.add_argument(
58-
"fr", metavar="from", type=str, help="unit or quantity to convert from"
59-
)
60-
parser.add_argument("to", type=str, nargs="?", help="unit to convert to")
61-
try:
62-
args = parser.parse_args()
63-
except SystemExit:
64-
parser.print_help()
65-
raise
66-
67-
ureg = UnitRegistry()
68-
ureg.auto_reduce_dimensions = True
69-
ureg.autoconvert_offset_to_baseunit = True
70-
ureg.enable_contexts("Gau", "ESU", "sp", "energy", "boltzmann")
71-
ureg.default_system = args.system
72-
73-
74-
def _set(key: str, value):
22+
def _set(ureg: UnitRegistry, key: str, value: Any):
7523
obj = ureg._units[key].converter
7624
object.__setattr__(obj, "scale", value)
7725

7826

79-
if args.unc:
80-
try:
81-
import uncertainties
82-
except ImportError:
83-
raise Exception(
84-
"Failed to import uncertainties library!\n Please install uncertainties package"
85-
)
86-
27+
def _define_constants(ureg: UnitRegistry):
8728
# Measured constants subject to correlation
8829
# R_i: Rydberg constant
8930
# g_e: Electron g factor
9031
# m_u: Atomic mass constant
9132
# m_e: Electron mass
9233
# m_p: Proton mass
9334
# m_n: Neutron mass
94-
# x_Cu: Copper x unit
95-
# x_Mo: Molybdenum x unit
96-
# A_s: Angstrom star
97-
R_i = (ureg._units["R_inf"].converter.scale, 0.0000000000012e7)
98-
g_e = (ureg._units["g_e"].converter.scale, 0.00000000000036)
99-
m_u = (ureg._units["m_u"].converter.scale, 0.00000000052e-27)
100-
m_e = (ureg._units["m_e"].converter.scale, 0.0000000028e-31)
101-
m_p = (ureg._units["m_p"].converter.scale, 0.00000000052e-27)
102-
m_n = (ureg._units["m_n"].converter.scale, 0.00000000085e-27)
103-
x_Cu = (ureg._units["x_unit_Cu"].converter.scale, 0.00000028e-13)
104-
x_Mo = (ureg._units["x_unit_Mo"].converter.scale, 0.00000053e-13)
105-
A_s = (ureg._units["angstrom_star"].converter.scale, 0.00000090e-10)
35+
R_i = (ureg._units["R_inf"].converter.scale, 0.0000000000021e7)
36+
g_e = (ureg._units["g_e"].converter.scale, 0.00000000000035)
37+
m_u = (ureg._units["m_u"].converter.scale, 0.00000000050e-27)
38+
m_e = (ureg._units["m_e"].converter.scale, 0.00000000028e-30)
39+
m_p = (ureg._units["m_p"].converter.scale, 0.00000000051e-27)
40+
m_n = (ureg._units["m_n"].converter.scale, 0.00000000095e-27)
10641
if args.corr:
107-
# fmt: off
10842
# Correlation matrix between measured constants (to be completed below)
109-
# R_i g_e m_u m_e m_p m_n x_Cu x_Mo A_s
43+
# R_i g_e m_u m_e m_p m_n
11044
corr = [
111-
[ 1.00000, -0.00122, 0.00438, 0.00225, 0.00455, 0.00277, 0.00000, 0.00000, 0.00000], # R_i
112-
[-0.00122, 1.00000, 0.97398, 0.97555, 0.97404, 0.59702, 0.00000, 0.00000, 0.00000], # g_e
113-
[ 0.00438, 0.97398, 1.00000, 0.99839, 0.99965, 0.61279, 0.00000, 0.00000, 0.00000], # m_u
114-
[ 0.00225, 0.97555, 0.99839, 1.00000, 0.99845, 0.61199, 0.00000, 0.00000, 0.00000], # m_e
115-
[ 0.00455, 0.97404, 0.99965, 0.99845, 1.00000, 0.61281, 0.00000, 0.00000, 0.00000], # m_p
116-
[ 0.00277, 0.59702, 0.61279, 0.61199, 0.61281, 1.00000,-0.00098,-0.00108,-0.00063], # m_n
117-
[ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,-0.00098, 1.00000, 0.00067, 0.00039], # x_Cu
118-
[ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,-0.00108, 0.00067, 1.00000, 0.00100], # x_Mo
119-
[ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,-0.00063, 0.00039, 0.00100, 1.00000], # A_s
120-
]
121-
# fmt: on
45+
[1.0, -0.00206, 0.00369, 0.00436, 0.00194, 0.00233], # R_i
46+
[-0.00206, 1.0, 0.99029, 0.99490, 0.97560, 0.52445], # g_e
47+
[0.00369, 0.99029, 1.0, 0.99536, 0.98516, 0.52959], # m_u
48+
[0.00436, 0.99490, 0.99536, 1.0, 0.98058, 0.52714], # m_e
49+
[0.00194, 0.97560, 0.98516, 0.98058, 1.0, 0.51521], # m_p
50+
[0.00233, 0.52445, 0.52959, 0.52714, 0.51521, 1.0],
51+
] # m_n
12252
try:
123-
(
124-
R_i,
125-
g_e,
126-
m_u,
127-
m_e,
128-
m_p,
129-
m_n,
130-
x_Cu,
131-
x_Mo,
132-
A_s,
133-
) = uncertainties.correlated_values_norm(
134-
[R_i, g_e, m_u, m_e, m_p, m_n, x_Cu, x_Mo, A_s], corr
53+
import uncertainties
54+
55+
(R_i, g_e, m_u, m_e, m_p, m_n) = uncertainties.correlated_values_norm(
56+
[R_i, g_e, m_u, m_e, m_p, m_n], corr
13557
)
13658
except AttributeError:
13759
raise Exception(
13860
"Correlation cannot be calculated!\n Please install numpy package"
13961
)
14062
else:
141-
R_i = uncertainties.ufloat(*R_i)
142-
g_e = uncertainties.ufloat(*g_e)
143-
m_u = uncertainties.ufloat(*m_u)
144-
m_e = uncertainties.ufloat(*m_e)
145-
m_p = uncertainties.ufloat(*m_p)
146-
m_n = uncertainties.ufloat(*m_n)
147-
x_Cu = uncertainties.ufloat(*x_Cu)
148-
x_Mo = uncertainties.ufloat(*x_Mo)
149-
A_s = uncertainties.ufloat(*A_s)
150-
151-
_set("R_inf", R_i)
152-
_set("g_e", g_e)
153-
_set("m_u", m_u)
154-
_set("m_e", m_e)
155-
_set("m_p", m_p)
156-
_set("m_n", m_n)
157-
_set("x_unit_Cu", x_Cu)
158-
_set("x_unit_Mo", x_Mo)
159-
_set("angstrom_star", A_s)
63+
R_i = ufloat(*R_i)
64+
g_e = ufloat(*g_e)
65+
m_u = ufloat(*m_u)
66+
m_e = ufloat(*m_e)
67+
m_p = ufloat(*m_p)
68+
m_n = ufloat(*m_n)
69+
70+
_set(ureg, "R_inf", R_i)
71+
_set(ureg, "g_e", g_e)
72+
_set(ureg, "m_u", m_u)
73+
_set(ureg, "m_e", m_e)
74+
_set(ureg, "m_p", m_p)
75+
_set(ureg, "m_n", m_n)
16076

16177
# Measured constants with zero correlation
16278
_set(
79+
ureg,
16380
"gravitational_constant",
164-
uncertainties.ufloat(
165-
ureg._units["gravitational_constant"].converter.scale, 0.00015e-11
166-
),
81+
ufloat(ureg._units["gravitational_constant"].converter.scale, 0.00015e-11),
82+
)
83+
84+
_set(
85+
ureg,
86+
"d_220",
87+
ufloat(ureg._units["d_220"].converter.scale, 0.000000032e-10),
88+
)
89+
90+
_set(
91+
ureg,
92+
"K_alpha_Cu_d_220",
93+
ufloat(ureg._units["K_alpha_Cu_d_220"].converter.scale, 0.00000022),
94+
)
95+
96+
_set(
97+
ureg,
98+
"K_alpha_Mo_d_220",
99+
ufloat(ureg._units["K_alpha_Mo_d_220"].converter.scale, 0.00000019),
100+
)
101+
102+
_set(
103+
ureg,
104+
"K_alpha_W_d_220",
105+
ufloat(ureg._units["K_alpha_W_d_220"].converter.scale, 0.000000098),
167106
)
168107

169108
ureg._root_units_cache = {}
170109
ureg._build_cache()
171110

172111

173-
def convert(u_from, u_to=None, unc=None, factor=None):
112+
if __name__ == "__main__":
113+
parser = argparse.ArgumentParser(
114+
description="Unit converter.", usage=argparse.SUPPRESS
115+
)
116+
parser.add_argument(
117+
"-s",
118+
"--system",
119+
metavar="sys",
120+
default="SI",
121+
help="unit system to convert to (default: SI)",
122+
)
123+
parser.add_argument(
124+
"-p",
125+
"--prec",
126+
metavar="n",
127+
type=int,
128+
default=12,
129+
help="number of maximum significant figures (default: 12)",
130+
)
131+
parser.add_argument(
132+
"-u",
133+
"--prec-unc",
134+
metavar="n",
135+
type=int,
136+
default=2,
137+
help="number of maximum uncertainty digits (default: 2)",
138+
)
139+
parser.add_argument(
140+
"-U",
141+
"--with-unc",
142+
dest="unc",
143+
action="store_true",
144+
help="consider uncertainties in constants",
145+
)
146+
parser.add_argument(
147+
"-C",
148+
"--no-corr",
149+
dest="corr",
150+
action="store_false",
151+
help="ignore correlations between constants",
152+
)
153+
parser.add_argument(
154+
"fr", metavar="from", type=str, help="unit or quantity to convert from"
155+
)
156+
parser.add_argument("to", type=str, nargs="?", help="unit to convert to")
157+
try:
158+
args = parser.parse_args()
159+
except SystemExit:
160+
parser.print_help()
161+
raise
162+
163+
ureg = UnitRegistry()
164+
ureg.auto_reduce_dimensions = True
165+
ureg.autoconvert_offset_to_baseunit = True
166+
ureg.enable_contexts("Gau", "ESU", "sp", "energy", "boltzmann")
167+
ureg.default_system = args.system
168+
169+
u_from = args.fr
170+
u_to = args.to
171+
unc = None
172+
factor = None
174173
prec_unc = 0
175174
q = ureg.Quantity(u_from)
176175
fmt = f".{args.prec}g"
176+
177177
if unc:
178178
q = q.plus_minus(unc)
179+
179180
if u_to:
180181
nq = q.to(u_to)
181182
else:
182183
nq = q.to_base_units()
184+
183185
if factor:
184186
q *= ureg.Quantity(factor)
185187
nq *= ureg.Quantity(factor).to_base_units()
188+
186189
if args.unc:
187-
prec_unc = use_unc(nq.magnitude, fmt, args.prec_unc)
190+
if not HAS_UNCERTAINTIES:
191+
raise Exception(
192+
"Failed to import uncertainties library!\n Please install uncertainties package"
193+
)
194+
195+
_define_constants(ureg)
196+
197+
num = nq.magnitude
198+
fmt = fmt
199+
prec_unc = args.prec_unc
200+
201+
with contextlib.suppress(Exception):
202+
if isinstance(num, type(ufloat(1, 0))):
203+
full = ("{:" + fmt + "}").format(num)
204+
unc = re.search(r"\+/-[0.]*([\d.]*)", full).group(1)
205+
unc = len(unc.replace(".", ""))
206+
else:
207+
unc = 0
208+
209+
prec_unc = max(0, min(prec_unc, unc))
210+
else:
211+
prec_unc = 0
212+
188213
if prec_unc > 0:
189214
fmt = f".{prec_unc}uS"
190215
else:
@@ -193,22 +218,3 @@ def convert(u_from, u_to=None, unc=None, factor=None):
193218

194219
fmt = "{:" + fmt + "} {:~P}"
195220
print(("{:} = " + fmt).format(q, nq.magnitude, nq.units))
196-
197-
198-
def use_unc(num, fmt, prec_unc):
199-
unc = 0
200-
with contextlib.suppress(Exception):
201-
if isinstance(num, uncertainties.UFloat):
202-
full = ("{:" + fmt + "}").format(num)
203-
unc = re.search(r"\+/-[0.]*([\d.]*)", full).group(1)
204-
unc = len(unc.replace(".", ""))
205-
206-
return max(0, min(prec_unc, unc))
207-
208-
209-
def main():
210-
convert(args.fr, args.to)
211-
212-
213-
if __name__ == "__main__":
214-
main()

0 commit comments

Comments
 (0)