Source code for diveplan.utils.conversions
"""Argument-coercion helpers shared across the user-facing API.
These power the "friendly notation" accepted by the fluent profile builders,
:class:`~diveplan.planning.gas_plan.GasPlan`, and
:func:`~diveplan.planning.ascent_plan.plan_ascent`: depths as ``"40 m"``
strings or bare metres, gases by name. Library code coerces at its public
boundary and works with :class:`Pressure`/:class:`Gas` values internally.
"""
from diveplan.core.gas import Gas
from diveplan.core.pressure import Pressure
__all__ = [
"coerce_depth_to_pressure",
"coerce_gas",
"duration_from_rate",
"DEPTH_TYPES",
"GAS_TYPES",
]
DEPTH_TYPES = float | int | str | Pressure
"""Accepted spellings of a depth: metres, a parseable string, or a Pressure."""
GAS_TYPES = str | Gas
"""Accepted spellings of a gas: a name like ``"ean50"`` or a Gas."""
[docs]
def coerce_depth_to_pressure(value: DEPTH_TYPES) -> Pressure:
"""Convert a user-facing depth argument to an absolute :class:`Pressure`.
Args:
value: A :class:`Pressure` (returned as-is), a string parsed by
:meth:`Pressure.from_str` (``"40 m"``, ``"4.5 bar"``, ``"130 ft"``…),
or a bare number interpreted as metres of depth.
Returns:
The corresponding absolute pressure under the current config.
Raises:
ValueError: If the value is a string that cannot be parsed, or an
unsupported type.
"""
if isinstance(value, Pressure):
return value
if isinstance(value, (float, int)):
return Pressure.from_depth_m(value)
if isinstance(value, str):
return Pressure.from_str(value)
raise ValueError(f"Invalid depth type: {type(value)}")
[docs]
def coerce_gas(value: GAS_TYPES) -> Gas:
"""Convert a user-facing gas argument to a :class:`Gas`.
Args:
value: A :class:`Gas` (returned as-is) or a name parsed by
:meth:`Gas.from_name` (``"air"``, ``"ean50"``, ``"tx21/35"``…).
Returns:
The corresponding gas mixture.
Raises:
ValueError: If the value is a string that cannot be parsed, or an
unsupported type.
"""
if isinstance(value, Gas):
return value
if isinstance(value, str):
return Gas.from_name(value)
raise ValueError(f"Invalid gas type: {type(value)}")
[docs]
def duration_from_rate(
rate: float, start_pressure: Pressure, end_pressure: Pressure
) -> float:
"""Traverse duration implied by a rate of pressure change.
Args:
rate: Rate of pressure change in mbar per minute (always positive;
direction is taken from the pressures).
start_pressure: Pressure at the start of the traverse.
end_pressure: Pressure at the end of the traverse.
Returns:
Duration in minutes.
"""
return abs(end_pressure - start_pressure) / rate