Skip to content

Structural Types

Structural types define complex data structures with heterogeneous elements, where different positions or attributes can have different types. Unlike collections, structural types allow mixing different types within the same structure.

πŸ€– AI-Generated Content

This documentation was generated with AI assistance and is still being audited. Some, or potentially a lot, of this information may be inaccurate. Learn more.

The structural types are: - CtyObject - A structure with named attributes, each having its own type (similar to a typed dictionary). Supports optional attributes that can be omitted from data. - CtyTuple - A fixed-length sequence where each position has a specific type (similar to a typed tuple). The number of elements and their types are defined at schema creation. - CtyDynamic - A special type that can represent any value, with the actual type determined at runtime. Useful for scenarios where the type structure isn't known until runtime.

Structural types are ideal for modeling complex domain objects, API responses, and configuration schemas where different fields have different meanings and types.

See also: User Guide: Structural Types for detailed usage examples.


pyvider.cty.types.structural

Classes

CtyDynamic

Bases: CtyType[object]

Represents a dynamic type that can hold any CtyValue.

Functions
validate
validate(value: object) -> CtyValue[Any]

Validates a raw Python value for a dynamic type. The result is always a CtyValue of type CtyDynamic, which wraps the inferred concrete value.

Source code in pyvider/cty/types/structural/dynamic.py
@with_recursion_detection
def validate(self, value: object) -> CtyValue[Any]:
    """
    Validates a raw Python value for a dynamic type. The result is always a
    CtyValue of type CtyDynamic, which wraps the inferred concrete value.
    """
    from pyvider.cty.conversion.raw_to_cty import infer_cty_type_from_raw
    from pyvider.cty.parser import parse_tf_type_to_ctytype
    from pyvider.cty.values import CtyValue

    if isinstance(value, CtyValue):
        if isinstance(value.type, CtyDynamic):
            return cast(CtyValue[Any], value)  # type: ignore[redundant-cast]
        return CtyValue(vtype=self, value=value)

    if value is None:
        return CtyValue.null(self)

    if isinstance(value, list) and len(value) == 2 and isinstance(value[0], bytes):
        try:
            type_spec = json.loads(value[0].decode("utf-8"))
            actual_type = parse_tf_type_to_ctytype(type_spec)
            concrete_value = actual_type.validate(value[1])
            return CtyValue(vtype=self, value=concrete_value)
        except json.JSONDecodeError as e:
            raise DeserializationError(
                "Failed to decode dynamic value type spec from JSON during validation"
            ) from e
        except CtyValidationError as e:
            raise e

    inferred_type = infer_cty_type_from_raw(value)
    concrete_value = inferred_type.validate(value)
    return CtyValue(vtype=self, value=concrete_value)