Source code for betty.typing

"""
Providing typing utilities.
"""

from __future__ import annotations

from typing import TypeVar, TypeAlias, cast

from betty.docstring import append

_T = TypeVar("_T")


def _internal(target: _T) -> _T:
    target.__doc__ = append(
        target.__doc__ or "",
        "This is internal. It **MAY** be used anywhere in Betty's source code, but **MUST NOT** be used by third-party code.",
    )
    return target


[docs] @_internal def internal(target: _T) -> _T: """ Mark a target as internal to Betty. Anything decorated with ``@internal`` MAY be used anywhere in Betty's source code, but MUST be considered private by third-party code. """ return _internal(target)
[docs] @internal def public(target: _T) -> _T: """ Mark a target as publicly usable. This is intended for items nested inside something marked with :py:func:`betty.typing.internal`, such as class attributes: third-party code **SHOULD NOT** use a class marked ``@internal`` directly, but **MAY** use any of its attributes that are marked ``@public``. """ return target
[docs] class Void: """ A sentinel that describes the absence of a value. Using this sentinel allows for actual values to be ``None``. Like ``None``, ``Void`` is only ever used through its type, and never instantiated. """
[docs] def __new__(cls): # pragma: no cover # noqa D102 raise RuntimeError("The Void sentinel cannot be instantiated.")
Voidable: TypeAlias = _T | type[Void]
[docs] def void_none(value: _T | None) -> Voidable[_T]: """ Passthrough a value, but convert ``None`` to :py:class:`betty.typing.Void`. """ return Void if value is None else value
[docs] def none_void(value: Voidable[_T]) -> _T | None: """ Passthrough a value, but convert :py:class:`betty.typing.Void` to ``None``. """ return None if value is Void else cast(_T, value)