Skip to content

[Low] convert_angle(out='gon') returns radians instead of gradians #139

@zhaozhiwen

Description

@zhaozhiwen

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Planned

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions