Skip to content

alicatlib.registry

Primer-verified registries of gases, units, statistics, and loop-control variables. Generated at build time from codes.json via scripts/gen_codes.py; a CI idempotency check guards against drift. See Design §5.3.

alicatlib.registry

Registry layer — gas / unit / statistic enums and alias registries.

codes.json is the source of truth; typed enums are generated by scripts/gen_codes.py into _codes_gen.py. See docs/design.md §5.3.

LOOP_CONTROL_VARIABLE_CODES module-attribute

LOOP_CONTROL_VARIABLE_CODES = frozenset(
    (value) for m in LoopControlVariable
)

Wire codes accepted by LV. Useful for pre-I/O gating on raw input.

AliasRegistry

AliasRegistry(enum_cls, *, aliases, by_code, error_cls)

Bases: _BaseAliasRegistry[E]

Registry for enums whose numeric code is unique across the enum.

Used by :data:gas_registry and :data:statistic_registry. Not used by units, whose codes collide across categories — see :class:UnitRegistry.

Source code in src/alicatlib/registry/aliases.py
def __init__(
    self,
    enum_cls: type[E],
    *,
    aliases: dict[str, E],
    by_code: dict[int, E],
    error_cls: _LookupErrorCls,
) -> None:
    super().__init__(enum_cls, aliases=aliases, error_cls=error_cls)
    self._by_code: dict[int, E] = dict(by_code)

by_code

by_code(code)

Resolve a numeric Alicat code to the typed enum.

Source code in src/alicatlib/registry/aliases.py
def by_code(self, code: int) -> E:
    """Resolve a numeric Alicat code to the typed enum."""
    try:
        return self._by_code[code]
    except KeyError:
        raise self._error_cls(code, suggestions=()) from None

Gas

Bases: StrEnum

Gas / gas mixture (Primer Appendix C).

code property

code

Numeric Alicat code (see Appendix A/B/C).

display_name property

display_name

Human-readable name from the primer.

LoopControlVariable

Bases: IntEnum

Statistics a controller's feedback loop can track.

Values are the primer's statistic codes, so LV <value> over the wire is a direct str(member.value). The members mirror the :class:Statistic names they correspond to — LoopControlVariable.MASS_FLOW_SETPT matches :data:Statistic.MASS_FLOW_SETPT (code 37).

statistic property

statistic

The :class:Statistic member that shares this wire code.

Statistic

Bases: StrEnum

Device statistic code (Primer Appendix A).

code property

code

Numeric Alicat code (see Appendix A/B/C).

display_name property

display_name

Human-readable name from the primer.

Unit

Bases: StrEnum

Engineering unit (Primer Appendix B).

categories property

categories

Primer Appendix B categories this unit belongs to.

code property

code

Numeric Alicat code (see Appendix A/B/C).

display_name property

display_name

Human-readable name from the primer.

UnitCategory

Bases: StrEnum

Unit category, per Primer Appendix B sections.

display_name property

display_name

Human-readable name for this category.

UnitRegistry

UnitRegistry(*, aliases, by_category_code, categories)

Bases: _BaseAliasRegistry[Unit]

Unit-specialised registry.

Alicat unit codes repeat across categories (code 7 = SLPM in std-flow but bar in pressure), so by_code requires an explicit :class:UnitCategory. Separate from :class:AliasRegistry on purpose — making category optional would silently pick the wrong unit.

Source code in src/alicatlib/registry/aliases.py
def __init__(
    self,
    *,
    aliases: dict[str, Unit],
    by_category_code: dict[tuple[UnitCategory, int], Unit],
    categories: dict[Unit, frozenset[UnitCategory]],
) -> None:
    super().__init__(Unit, aliases=aliases, error_cls=UnknownUnitError)
    self._by_category_code: dict[tuple[UnitCategory, int], Unit] = dict(by_category_code)
    self._categories: dict[Unit, frozenset[UnitCategory]] = dict(categories)

by_code

by_code(code, *, category)

Resolve a (category, code) pair to the typed :class:Unit.

A bare by_code(code) would be ambiguous — codes repeat across categories — so category is keyword-only and required.

Source code in src/alicatlib/registry/aliases.py
def by_code(self, code: int, *, category: UnitCategory) -> Unit:
    """Resolve a ``(category, code)`` pair to the typed :class:`Unit`.

    A bare ``by_code(code)`` would be ambiguous — codes repeat across
    categories — so ``category`` is keyword-only and required.
    """
    try:
        return self._by_category_code[(category, code)]
    except KeyError:
        raise UnknownUnitError(
            f"code={code} in category={category.value}",
            suggestions=(),
        ) from None

categories

categories(unit)

Return the categories (Primer Appendix B sections) this unit applies to.

Source code in src/alicatlib/registry/aliases.py
def categories(self, unit: Unit) -> frozenset[UnitCategory]:
    """Return the categories (Primer Appendix B sections) this unit applies to."""
    return self._categories[unit]

coerce_loop_control_variable

coerce_loop_control_variable(value)

Resolve value to a :class:LoopControlVariable.

Accepts:

  • a :class:LoopControlVariable member (returned unchanged);
  • a :class:Statistic member whose code is in the LV subset;
  • an int wire code (one of :data:LOOP_CONTROL_VARIABLE_CODES);
  • a str matching a member name case-insensitively ("mass_flow_setpt") or a :class:Statistic member value ("mass_flow_setpt").

Raises:

Type Description
AlicatValidationError

value is not one of the eight LV-eligible statistics. The error is validation-level (not UnknownStatisticError) because the surface is deliberately a restricted subset — the wider Statistic enum is fine, just not valid here.

Source code in src/alicatlib/registry/loop_control.py
def coerce_loop_control_variable(
    value: LoopControlVariable | Statistic | str | int,
) -> LoopControlVariable:
    """Resolve ``value`` to a :class:`LoopControlVariable`.

    Accepts:

    - a :class:`LoopControlVariable` member (returned unchanged);
    - a :class:`Statistic` member whose code is in the LV subset;
    - an ``int`` wire code (one of :data:`LOOP_CONTROL_VARIABLE_CODES`);
    - a ``str`` matching a member name case-insensitively (``"mass_flow_setpt"``)
      or a :class:`Statistic` member value (``"mass_flow_setpt"``).

    Raises:
        AlicatValidationError: ``value`` is not one of the eight LV-eligible
            statistics. The error is validation-level (not
            ``UnknownStatisticError``) because the surface is deliberately
            a restricted subset — the wider ``Statistic`` enum is fine,
            just not valid *here*.
    """
    if isinstance(value, LoopControlVariable):
        return value
    if isinstance(value, Statistic):
        code = _statistic_code(value)
        try:
            return LoopControlVariable(code)
        except ValueError:
            raise _not_eligible(value.value) from None
    if isinstance(value, int) and not isinstance(value, bool):
        try:
            return LoopControlVariable(value)
        except ValueError:
            raise _not_eligible(value) from None
    if isinstance(value, str):
        key = value.strip().lower()
        if key in _BY_NAME:
            return _BY_NAME[key]
        raise _not_eligible(value)
    raise TypeError(
        f"cannot coerce {type(value).__name__} to LoopControlVariable",
    )