Skip to content

validation

validation #

Construction-time validation of a node's inputs, substeps, and settings.

Called once from Procedure.__post_init__ so an ill-typed DAG fails where it is built, with a message that names the field. The checks mirror the field roles ([.fields][]):

  • inputs must be procedures whose return type structurally matches the field's Input[T]Array[Image] and ImageSequence interchange; an Input[Path] accepts any Path (the precise target is checked by the navigation node itself); a bare/TypeVar input accepts any CGType.
  • substeps must each be a Procedure.
  • settings must match their Setting[T] at runtime (a backstop under the static check), handling unions, list[...], and type[...].

[check_type][] is that same "does this type fit that slot" question as a one-line assertion, so a node's own _resolve_type raises in the same voice as the field validator here.

check_type(actual, expected, context) #

Raise unless a value of type actual fits a slot expecting expected.

The one home for "does this type fit that slot", so every node's own _resolve_type reports a mismatch the same way the field validator does.

Parameters:

Name Type Description Default
actual object

The CGType a procedure produces.

required
expected object

The CGType the slot wants.

required
context str

What is being checked, named for the message — e.g. "Input 'image' for CaptureImage".

required

Raises:

Type Description
TypeError

If actual does not fit expected.

Source code in capturegraph-lib/capturegraph/procedures/procedure/type_checking/validation.py
def check_type(
    actual: object,
    expected: object,
    context: str,
) -> None:
    """Raise unless a value of type ``actual`` fits a slot expecting ``expected``.

    The one home for "does this type fit that slot", so every node's own
    ``_resolve_type`` reports a mismatch the same way the field validator does.

    Args:
        actual: The ``CGType`` a procedure produces.
        expected: The ``CGType`` the slot wants.
        context: What is being checked, named for the message — e.g.
            ``"Input 'image' for CaptureImage"``.

    Raises:
        TypeError: If ``actual`` does not fit ``expected``.
    """
    if not fits(actual, expected):
        raise TypeError(f"{context}: expected {type_name(expected)}, got {type_name(actual)}")

fits(actual, expected) #

Whether a value returning actual fits a slot expecting expected.

Compatibility is structural; a bare CGType/TypeVar bound accepts anything, and an Input[Path] accepts any Path.

Source code in capturegraph-lib/capturegraph/procedures/procedure/type_checking/validation.py
def fits(
    actual: object,
    expected: object,
) -> bool:
    """Whether a value returning ``actual`` fits a slot expecting ``expected``.

    Compatibility is structural; a bare ``CGType``/TypeVar bound accepts anything,
    and an ``Input[Path]`` accepts any ``Path``.
    """
    if not (isinstance(actual, type) and issubclass(actual, CGType)):
        return False
    if expected is CGType or not isinstance(expected, type):
        return True  # bare Input / unresolved TypeVar
    if issubclass(expected, Path):
        return issubclass(actual, Path)
    if expected in (Array, Map, Struct):
        # A bare composite base is a bound ("any array"): accept any subclass.
        return issubclass(actual, expected)
    return actual is expected or structural_eq(actual, expected)

type_name(cgtype) #

A CGType's name for an error message (str() for anything else).

Source code in capturegraph-lib/capturegraph/procedures/procedure/type_checking/validation.py
def type_name(
    cgtype: object,
) -> str:
    """A ``CGType``'s name for an error message (``str()`` for anything else)."""
    return getattr(cgtype, "__name__", str(cgtype))

validate(node) #

Type-check every field of node against its annotation; raise on mismatch.

Source code in capturegraph-lib/capturegraph/procedures/procedure/type_checking/validation.py
def validate(
    node: Procedure[Any],
) -> None:
    """Type-check every field of ``node`` against its annotation; raise on mismatch."""
    for name, role, annotation in field_roles(type(node)):
        value = getattr(node, name, None)
        if role is FieldRole.INPUT:
            _validate_input(node, name, annotation, value)
        elif role is FieldRole.SUBSTEPS:
            _validate_substeps(node, name, value)
        elif role is FieldRole.SETTING:
            _validate_setting(node, name, annotation, value)