Module pybeepop.beepop.parameters

Type and range specifications for numeric BeePop+ parameters.

Every numeric parameter accepted by VarroaPopSession.update_colony_parameters() is listed in PARAMETER_SPECS with the range it accepts. Values outside that range are rejected with an error rather than being passed on to the model.

Bounds are written the way they appear in the Min and Max columns of BeePop_exposed_parameters.csv: a bare number is inclusive, a number prefixed with '>' or '<' is exclusive, and an empty string means unbounded on that side. The two must agree; tests/test_parameter_validation.py compares them row by row.

Functions

def validate_parameter(name: str, value: str, display_name: str | None = None) ‑> tuple[bool, str, str | None]
Expand source code
def validate_parameter(
    name: str, value: str, display_name: str | None = None
) -> tuple[bool, str, str | None]:
    """Check one parameter value against its spec.

    Args:
        name: Parameter name, lowercased.
        value: Raw parameter value as a string.
        display_name: Name to use in error messages. Defaults to ``name``.

    Returns:
        ``(ok, normalized_value, error)``. When ``ok`` is False, ``error`` explains why
        the value was rejected. Integer parameters are normalized to a whole-number
        string so downstream parsing accepts them.
    """
    spec = PARAMETER_SPECS.get(name)
    if spec is None:
        return True, value, None

    label = display_name if display_name is not None else name

    try:
        number = float(value)
    except (TypeError, ValueError):
        return False, value, f"{label} must be a number, got '{value}'."

    if math.isnan(number) or math.isinf(number):
        return False, value, f"{label} must be a finite number, got '{value}'."

    low = _parse_bound(spec.minimum)
    high = _parse_bound(spec.maximum)
    below = low is not None and (number < low[0] or (low[1] and number == low[0]))
    above = high is not None and (number > high[0] or (high[1] and number == high[0]))
    if below or above:
        return (
            False,
            value,
            f"{label} is out of range: {value}. Must be {_describe_range(spec)}.",
        )

    if spec.kind == INTEGER:
        if number != int(number):
            return False, value, f"{label} must be a whole number, got '{value}'."
        return True, str(int(number)), None

    return True, value, None

Check one parameter value against its spec.

Args
-----=
name
Parameter name, lowercased.
value
Raw parameter value as a string.
display_name
Name to use in error messages. Defaults to name.

Returns -----= (ok, normalized_value, error). When ok is False, error explains why the value was rejected. Integer parameters are normalized to a whole-number string so downstream parsing accepts them.

Classes

class ParameterSpec (kind: str, minimum: str = '', maximum: str = '')
Expand source code
@dataclass(frozen=True)
class ParameterSpec:
    """The accepted type and range for one parameter."""

    kind: str
    minimum: str = ""
    maximum: str = ""

The accepted type and range for one parameter.

Instance variables

var kind : str

The type of the None singleton.

var maximum : str

The type of the None singleton.

var minimum : str

The type of the None singleton.