convert_angle accepts 'gon' as a valid output unit (it is a key in ANG_TO_RAD) but only special-cases deg/degree on the return path. For out='gon' it falls through and returns the value in radians, not gradians.
Affected files
subprojects/pygemc/src/pygemc/api/g4_units.py:12-14 (ANG_TO_RAD)
subprojects/pygemc/src/pygemc/api/g4_units.py:186-193 (convert_angle)
Details
ANG_TO_RAD = {
'rad': 1.0, 'deg': math.pi / 180.0, 'degree': math.pi / 180.0, 'gon': math.pi / 200.0
}
...
def convert_angle(expr: str, out: str = 'deg') -> float:
if out not in ANG_TO_RAD and out not in ('deg', 'degree', 'rad'):
raise ValueError(f"Unknown output angle unit: {out}")
names = {**ANG_TO_RAD}
val_rad = _safe_eval(expr, names)
if out in ('deg', 'degree'):
return val_rad * (180.0 / math.pi)
return val_rad
out='gon' passes the validation guard but is not handled in the return logic, so the function returns val_rad (radians) unchanged. Callers requesting gradians silently get radians.
Impact
Low severity (gon is rarely used), but a silent wrong-unit result for a documented-as-valid output. The asymmetric handling (only deg/degree converted) is the root cause.
Proposed fix
Convert generally using the ANG_TO_RAD table for any output unit rather than special-casing degrees. val_rad / ANG_TO_RAD[out] gives the value in the requested unit (and reduces to the existing deg/rad behavior).
def convert_angle(expr: str, out: str = 'deg') -> float:
- if out not in ANG_TO_RAD and out not in ('deg', 'degree', 'rad'):
+ if out not in ANG_TO_RAD:
raise ValueError(f"Unknown output angle unit: {out}")
names = {**ANG_TO_RAD}
val_rad = _safe_eval(expr, names)
- if out in ('deg', 'degree'):
- return val_rad * (180.0 / math.pi)
- return val_rad
+ # Convert radians to the requested output unit via the conversion table.
+ return val_rad / ANG_TO_RAD[out]
Check: out='deg' → val_rad / (pi/180) = val_rad * 180/pi (same as before); out='rad' → val_rad / 1.0 (unchanged); out='gon' → val_rad / (pi/200) (correct gradians). The redundant out not in ('deg', 'degree', 'rad') branch is removed since all three are already keys in ANG_TO_RAD.
Split out from #102 (one issue per bug). Found via an AI-assisted code review with manual verification against commit 5f8ce875.
convert_angleaccepts'gon'as a valid output unit (it is a key inANG_TO_RAD) but only special-casesdeg/degreeon the return path. Forout='gon'it falls through and returns the value in radians, not gradians.Affected files
subprojects/pygemc/src/pygemc/api/g4_units.py:12-14(ANG_TO_RAD)subprojects/pygemc/src/pygemc/api/g4_units.py:186-193(convert_angle)Details
out='gon'passes the validation guard but is not handled in the return logic, so the function returnsval_rad(radians) unchanged. Callers requesting gradians silently get radians.Impact
Low severity (gon is rarely used), but a silent wrong-unit result for a documented-as-valid output. The asymmetric handling (only deg/degree converted) is the root cause.
Proposed fix
Convert generally using the
ANG_TO_RADtable for any output unit rather than special-casing degrees.val_rad / ANG_TO_RAD[out]gives the value in the requested unit (and reduces to the existing deg/rad behavior).Check:
out='deg'→val_rad / (pi/180) = val_rad * 180/pi(same as before);out='rad'→val_rad / 1.0(unchanged);out='gon'→val_rad / (pi/200)(correct gradians). The redundantout not in ('deg', 'degree', 'rad')branch is removed since all three are already keys inANG_TO_RAD.Split out from #102 (one issue per bug). Found via an AI-assisted code review with manual verification against commit
5f8ce875.