Skip to content

CTY Types

The pyvider.cty.types module provides the core type system for defining and validating data structures. Types act as schemas that describe the shape, structure, and constraints of your data.

🤖 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.

All types inherit from the CtyType base class and provide a validate() method that converts raw Python data into immutable, type-safe CtyValue instances. The type system includes primitives (String, Number, Bool), collections (List, Map, Set), structural types (Object, Tuple), and special types (Dynamic, Capsule).

For detailed information about each type category, see: - Primitive Types - String, Number, Bool - Collection Types - List, Map, Set - Structural Types - Object, Tuple, Dynamic - Capsule Types - Opaque data containers


pyvider.cty.types

Attributes

BytesCapsule module-attribute

BytesCapsule = CtyCapsule('Bytes', bytes)

A capsule type for wrapping raw bytes.

Classes

CtyType

Bases: CtyTypeProtocol[T], Generic[T], ABC

Generic abstract base class for all Cty types.

Functions
is_dynamic_type
is_dynamic_type() -> bool

Returns True if this type is CtyDynamic.

Source code in pyvider/cty/types/base.py
def is_dynamic_type(self) -> bool:
    """Returns True if this type is CtyDynamic."""
    return False

CtyCapsule

CtyCapsule(capsule_name: str, py_type: type)

Bases: CtyType[Any]

Represents a capsule type in the Cty type system. Capsule types are opaque types that can be used to wrap arbitrary Python objects.

Source code in pyvider/cty/types/capsule.py
def __init__(self, capsule_name: str, py_type: type) -> None:
    super().__init__()
    self.name = capsule_name
    self._py_type = py_type

CtyCapsuleWithOps

CtyCapsuleWithOps(
    capsule_name: str,
    py_type: type,
    *,
    equal_fn: Callable[[Any, Any], bool] | None = None,
    hash_fn: Callable[[Any], int] | None = None,
    convert_fn: Callable[
        [Any, CtyType[Any]], CtyValue[Any] | None
    ]
    | None = None,
)

Bases: CtyCapsule

A CtyCapsule that supports custom operations like equality, hashing, and conversion.

Initializes a CtyCapsule with custom operational functions.

Source code in pyvider/cty/types/capsule.py
def __init__(
    self,
    capsule_name: str,
    py_type: type,
    *,
    equal_fn: Callable[[Any, Any], bool] | None = None,
    hash_fn: Callable[[Any], int] | None = None,
    convert_fn: Callable[[Any, CtyType[Any]], CtyValue[Any] | None] | None = None,
) -> None:
    """
    Initializes a CtyCapsule with custom operational functions.
    """
    super().__init__(capsule_name, py_type)
    self.equal_fn = equal_fn
    self.hash_fn = hash_fn
    self.convert_fn = convert_fn
    self._validate_ops_arity()
Functions

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)