Skip to content

metadata

metadata

Metadata for actions and observations used across the codebase. dtype across all classes uses the zarr v3 type convention. zarr v3 allowed dtypes are defined here https://zarr-specs.readthedocs.io/en/latest/v3/data-types/index.html

BaseMetadata

BaseMetadata(dtype, is_numerical, needs_normalization)

Base metadata class.

Attributes:

Name Type Description
dtype

Zarr store data type.

is_numerical

Whether the observation is numerical (float or int) or not (e.g. string or categorical).

needs_normalization

Whether the data needs normalization at runtime.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    dtype: str,
    is_numerical: bool,
    needs_normalization: bool,
):
    if not is_numerical:
        if needs_normalization:
            raise ValueError(
                "Non-numerical observations should not need normalization."
            )
    else:
        if "float" not in dtype and "int" not in dtype:
            raise ValueError(
                f"dtype for numerical observations must be float or int type, got {dtype}"
            )
    self.dtype = dtype
    self.is_numerical = is_numerical
    self.needs_normalization = needs_normalization

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        self.dtype == other.dtype
        and self.is_numerical == other.is_numerical
        and self.needs_normalization == other.needs_normalization
    )

ObservationMetadata

ObservationMetadata(raw_data_column_keys, dimension, dtype, is_numerical, needs_normalization, slice_start=None, slice_end=None)

Bases: BaseMetadata

Base observation metadata.

Attributes:

Name Type Description
raw_data_column_keys

List of keys in the raw dataset corresponding to the observation.

dimension

Dimension that will be used to store the observation in the zarr store.

slice_start

Optional starting index for slicing a larger stored observation vector.

slice_end

Optional ending index (exclusive) for slicing a larger stored observation vector.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    raw_data_column_keys: list[str],
    dimension: int,
    dtype: str,
    is_numerical: bool,
    needs_normalization: bool,
    slice_start: int | None = None,
    slice_end: int | None = None,
):
    super().__init__(dtype, is_numerical, needs_normalization)
    if not raw_data_column_keys:
        raise ValueError("raw_data_column_keys cannot be empty")
    if dimension <= 0:
        raise ValueError(f"dimension must be positive, got {dimension}")
    if slice_start is not None and slice_end is not None:
        if slice_start < 0 or slice_end < 0:
            raise ValueError("slice_start and slice_end must be non-negative")
        if slice_start >= slice_end:
            raise ValueError(
                f"slice_start ({slice_start}) must be less than slice_end ({slice_end})"
            )
        if slice_end - slice_start != dimension:
            raise ValueError(
                f"Slice range ({slice_end - slice_start}) must equal dimension ({dimension})"
            )
    self.raw_data_column_keys = raw_data_column_keys
    self.dimension = dimension
    self.slice_start = slice_start
    self.slice_end = slice_end

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.raw_data_column_keys == other.raw_data_column_keys
        and self.dimension == other.dimension
        and self.slice_start == other.slice_start
        and self.slice_end == other.slice_end
    )

PositionObservationMetadata

PositionObservationMetadata(raw_data_column_keys, dimension, dtype, needs_normalization, frame=value, slice_start=None, slice_end=None)

Bases: ObservationMetadata

Robot position observation metadata.

Attributes:

Name Type Description
frame str

Coordinate frame of the position observation.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    raw_data_column_keys: list[str],
    dimension: int,
    dtype: str,
    needs_normalization: bool,
    frame: str = CoordinateSystem.ROBOT_BASE.value,
    slice_start: int | None = None,
    slice_end: int | None = None,
):
    if "float" not in dtype:
        raise ValueError("Position observations dtype must be a float type.")
    super().__init__(
        raw_data_column_keys=raw_data_column_keys,
        dimension=dimension,
        dtype=dtype,
        is_numerical=True,
        needs_normalization=needs_normalization,
        slice_start=slice_start,
        slice_end=slice_end,
    )
    valid_frames = [e.value for e in CoordinateSystem]
    if frame not in valid_frames:
        raise ValueError(f"frame must be one of {valid_frames}, got '{frame}'")
    self.frame: str = frame
    self.proprioception_type: str = ProprioceptiveType.POSITION.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return super().__eq__(other) and self.frame == other.frame

OrientationObservationMetadata

OrientationObservationMetadata(raw_data_column_keys, dimension, dtype, needs_normalization, frame=value, orientation_representation=value, slice_start=None, slice_end=None)

Bases: ObservationMetadata

Robot orientation observation metadata.

Attributes:

Name Type Description
frame

Coordinate frame of the orientation observation.

orientation_representation

Representation of the orientation.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    raw_data_column_keys: list[str],
    dimension: int,
    dtype: str,
    needs_normalization: bool,
    frame: str = CoordinateSystem.ROBOT_BASE.value,
    orientation_representation: str = OrientationRepresentation.ROLL.value,
    slice_start: int | None = None,
    slice_end: int | None = None,
):
    if "float" not in dtype:
        raise ValueError("Orientation observations dtype must be a float type.")
    super().__init__(
        raw_data_column_keys=raw_data_column_keys,
        dimension=dimension,
        dtype=dtype,
        is_numerical=True,
        needs_normalization=needs_normalization,
        slice_start=slice_start,
        slice_end=slice_end,
    )
    valid_frames = [e.value for e in CoordinateSystem]
    if frame not in valid_frames:
        raise ValueError(f"frame must be one of {valid_frames}, got '{frame}'")
    valid_methods = [e.value for e in OrientationRepresentation]
    if orientation_representation not in valid_methods:
        raise ValueError(
            f"orientation_representation must be one of {valid_methods}, got '{orientation_representation}'"
        )
    self.frame = frame
    self.orientation_representation = orientation_representation
    self.proprioception_type: str = ProprioceptiveType.ORIENTATION.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.frame == other.frame
        and self.orientation_representation == other.orientation_representation
    )

GripperObservationMetadata

GripperObservationMetadata(raw_data_column_keys, dimension, dtype, needs_normalization, gripper_type=value, binary_gripper_range=value, slice_start=None, slice_end=None)

Bases: ObservationMetadata

Gripper state observation metadata, representing the clamps state of the gripper.

Attributes:

Name Type Description
gripper_type str

Type of gripper ('binary' or 'continuous').

binary_gripper_range str

Range for binary gripper ('zero_one' or 'minus_one_one').

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    raw_data_column_keys: list[str],
    dimension: int,
    dtype: str,
    needs_normalization: bool,
    gripper_type: str = GripperType.BINARY.value,
    binary_gripper_range: str = BinaryGripperRange.ZERO_ONE.value,
    slice_start: int | None = None,
    slice_end: int | None = None,
):
    valid_types = [e.value for e in GripperType]
    if gripper_type not in valid_types:
        raise ValueError(
            f"gripper_type must be one of {valid_types}, got '{gripper_type}'"
        )
    valid_ranges = [e.value for e in BinaryGripperRange]
    if binary_gripper_range not in valid_ranges:
        raise ValueError(
            f"binary_gripper_range must be one of {valid_ranges}, got '{binary_gripper_range}'"
        )
    if gripper_type == GripperType.BINARY.value:
        if dimension != 1:
            raise ValueError("Binary gripper state dimension must be 1.")
        if needs_normalization:
            raise ValueError("Binary gripper state should not need normalization.")
        if "int" not in dtype:
            raise ValueError("Binary gripper state dtype must be an integer type.")
    else:
        if "float" not in dtype:
            raise ValueError("Continuous gripper state dtype must be a float type.")
    super().__init__(
        raw_data_column_keys=raw_data_column_keys,
        dimension=dimension,
        dtype=dtype,
        is_numerical=True,
        needs_normalization=needs_normalization,
        slice_start=slice_start,
        slice_end=slice_end,
    )
    self.gripper_type: str = gripper_type
    self.binary_gripper_range: str = binary_gripper_range
    self.proprioception_type: str = ProprioceptiveType.GRIPPER.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.gripper_type == other.gripper_type
        and self.binary_gripper_range == other.binary_gripper_range
    )

CameraMetadata

CameraMetadata(camera_key, dtype, channels, image_width, image_height, max_pixel_value=None)

Bases: BaseMetadata

Shared camera observation metadata.

Note

In the dataset schema context, image_width/image_height define storage dimensions. In the observation space context, they define training-time resize targets.

Attributes:

Name Type Description
raw_camera_key

Key in the raw dataset corresponding to the camera. It has to be one of data.constants.VALID_RAW_CAMERA_KEYS values.

channels

Number of image channels.

image_width

Target image width.

image_height

Target image height.

max_pixel_value

Optional value used to scale image tensors after resizing and channel reordering.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    camera_key: str,
    dtype: str,
    channels: int,
    image_width: int,
    image_height: int,
    max_pixel_value: float | None = None,
):
    super().__init__(dtype, is_numerical=True, needs_normalization=True)
    if camera_key not in RAW_TO_CAMERA_MAPPING:
        raise ValueError(
            f"camera_key must be a valid raw camera key. "
            f"Got '{camera_key}', expected one of "
            f"{list(RAW_TO_CAMERA_MAPPING.keys())}"
        )
    if max_pixel_value is not None and max_pixel_value <= 0:
        raise ValueError(
            f"max_pixel_value must be positive or None, got {max_pixel_value}"
        )
    self.raw_camera_key = camera_key
    self.channels = channels
    self.image_width = image_width
    self.image_height = image_height
    self.max_pixel_value = max_pixel_value

camera_key property

camera_key

Canonical VersatIL camera key for this raw camera.

is_single_channel property

is_single_channel

Whether this camera has a single channel (e.g. for depth maps).

is_rgb property

is_rgb

Whether this camera is an RGB camera (3 channels).

is_depth property

is_depth

Whether this camera stores depth values.

modality property

modality

Semantic camera modality for encoder compatibility checks.

__eq__

__eq__(other)

Structural equality — compares camera identity and format, not dimensions.

Dimensions are excluded because image_height/image_width have different semantics depending on context: storage size in the dataset schema vs training resize target in the observation space.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Structural equality — compares camera identity and format, not dimensions.

    Dimensions are excluded because image_height/image_width have different
    semantics depending on context: storage size in the dataset schema vs
    training resize target in the observation space.
    """
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.raw_camera_key == other.raw_camera_key
        and self.channels == other.channels
        and self.max_pixel_value == other.max_pixel_value
    )

RGBCameraMetadata

RGBCameraMetadata(camera_key, dtype, image_width, image_height, max_pixel_value=255.0)

Bases: CameraMetadata

RGB camera observation metadata.

Parameters:

Name Type Description Default
camera_key str

Key in the raw dataset corresponding to the RGB camera.

required
dtype str

Zarr storage dtype for RGB values.

required
image_width int

Target image width.

required
image_height int

Target image height.

required
max_pixel_value float | None

Value used to scale RGB image tensors after resizing and channel reordering.

255.0
Source code in src/versatil/data/metadata.py
def __init__(
    self,
    camera_key: str,
    dtype: str,
    image_width: int,
    image_height: int,
    max_pixel_value: float | None = 255.0,
):
    super().__init__(
        camera_key=camera_key,
        dtype=dtype,
        channels=3,
        image_width=image_width,
        image_height=image_height,
        max_pixel_value=max_pixel_value,
    )

is_rgb property

is_rgb

Whether this camera is an RGB camera.

modality property

modality

Semantic camera modality for encoder compatibility checks.

DepthCameraMetadata

DepthCameraMetadata(camera_key, dtype, image_width, image_height, max_pixel_value=None)

Bases: CameraMetadata

Depth camera observation metadata.

Parameters:

Name Type Description Default
camera_key str

Key in the raw dataset corresponding to the depth camera.

required
dtype str

Zarr storage dtype for depth values.

required
image_width int

Target image width.

required
image_height int

Target image height.

required
max_pixel_value float | None

Optional value used to scale depth image tensors after resizing and channel reordering.

None
Source code in src/versatil/data/metadata.py
def __init__(
    self,
    camera_key: str,
    dtype: str,
    image_width: int,
    image_height: int,
    max_pixel_value: float | None = None,
):
    if "float" not in dtype:
        raise ValueError(f"Depth camera dtype must be a float type, got {dtype}")
    super().__init__(
        camera_key=camera_key,
        dtype=dtype,
        channels=1,
        image_width=image_width,
        image_height=image_height,
        max_pixel_value=max_pixel_value,
    )

is_depth property

is_depth

Whether this camera stores depth values.

modality property

modality

Semantic camera modality for encoder compatibility checks.

ActionMetadata

ActionMetadata(prediction_dimension, is_numerical, needs_normalization, dtype, is_precomputed, requires_prediction_head=True)

Bases: BaseMetadata

Action metadata.

Attributes:

Name Type Description
prediction_dimension

Dimension for model prediction. May differ from storage, e.g., class labels stored as 1 column but predicted as n_classes logits.

requires_prediction_head

Whether this action requires a prediction head. Set to False for auxiliary/meta data that doesn't need prediction

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    prediction_dimension: int,
    is_numerical: bool,
    needs_normalization: bool,
    dtype: str,
    is_precomputed: bool,
    requires_prediction_head: bool = True,
):
    super().__init__(
        dtype=dtype,
        is_numerical=is_numerical,
        needs_normalization=needs_normalization,
    )
    if prediction_dimension <= 0:
        raise ValueError(
            f"prediction_dimension must be positive, got {prediction_dimension}"
        )
    self.prediction_dimension = prediction_dimension
    self.is_precomputed = is_precomputed
    self.action_type = ProprioceptiveType.CUSTOM.value
    self.requires_prediction_head = requires_prediction_head

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.prediction_dimension == other.prediction_dimension
        and self.is_precomputed == other.is_precomputed
        and self.action_type == other.action_type
    )

OnTheFlyActionMetadata

OnTheFlyActionMetadata(source_metadata, computation_method=value, requires_prediction_head=True)

Bases: ActionMetadata

Metadata for computing an action on-the-fly from a stored zarr observation group.

This defines how to derive an action from stored observations at runtime.

Parameters:

Name Type Description Default
source_metadata ProprioceptiveObservationMetadata

Metadata of the source observation used to compute the action.

required
computation_method str

Method to compute the action, default 'delta' for subtraction between consecutive observations.

value
Source code in src/versatil/data/metadata.py
def __init__(
    self,
    source_metadata: ProprioceptiveObservationMetadata,
    computation_method: str = ActionComputationMethod.DELTA.value,
    requires_prediction_head: bool = True,
):
    if not source_metadata.is_numerical:
        raise ValueError("Source metadata for on-the-fly action must be numerical.")
    super().__init__(
        prediction_dimension=source_metadata.dimension,
        is_numerical=True,
        needs_normalization=source_metadata.needs_normalization,
        dtype=source_metadata.dtype,
        is_precomputed=False,
        requires_prediction_head=requires_prediction_head,
    )
    valid_methods = [e.value for e in ActionComputationMethod]
    if computation_method not in valid_methods:
        raise ValueError(
            f"computation_method must be one of {valid_methods}, got '{computation_method}'"
        )
    self.source_metadata: ProprioceptiveObservationMetadata = source_metadata
    self.computation_method: str = computation_method
    self.action_type: str = source_metadata.proprioception_type

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.source_metadata == other.source_metadata
        and self.computation_method == other.computation_method
    )

PrecomputedActionMetadata

PrecomputedActionMetadata(raw_data_column_keys, storage_dimension, prediction_dimension, is_numerical, needs_normalization, dtype, slice_start=None, slice_end=None, requires_prediction_head=True)

Bases: ActionMetadata

Precomputed action metadata.

Attributes:

Name Type Description
raw_data_column_keys

List of keys in the raw dataset corresponding to the action.

storage_dimension

Dimension that will be used to store the action in the zarr store.

prediction_dimension

Dimension for model prediction. May differ from storage, e.g., class labels stored as 1 column but predicted as n_classes logits.

slice_start

Optional starting index for slicing a larger stored action vector.

slice_end

Optional ending index (exclusive) for slicing a larger stored action vector.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    raw_data_column_keys: list[str],
    storage_dimension: int,
    prediction_dimension: int,
    is_numerical: bool,
    needs_normalization: bool,
    dtype: str,
    slice_start: int | None = None,
    slice_end: int | None = None,
    requires_prediction_head: bool = True,
):
    super().__init__(
        prediction_dimension=prediction_dimension,
        is_numerical=is_numerical,
        needs_normalization=needs_normalization,
        dtype=dtype,
        is_precomputed=True,
        requires_prediction_head=requires_prediction_head,
    )
    if not raw_data_column_keys:
        raise ValueError("raw_data_column_keys cannot be empty")
    if storage_dimension <= 0:
        raise ValueError(
            f"storage_dimension must be positive, got {storage_dimension}"
        )
    if slice_start is not None and slice_end is not None:
        if slice_start < 0 or slice_end < 0:
            raise ValueError("slice_start and slice_end must be non-negative")
        if slice_start >= slice_end:
            raise ValueError(
                f"slice_start ({slice_start}) must be less than slice_end ({slice_end})"
            )
        if slice_end - slice_start != prediction_dimension:
            raise ValueError(
                f"Slice range ({slice_end - slice_start}) must equal prediction_dimension ({prediction_dimension})"
            )
    self.raw_data_column_keys = raw_data_column_keys
    self.storage_dimension = storage_dimension
    self.slice_start = slice_start
    self.slice_end = slice_end
    self.action_type = ProprioceptiveType.CUSTOM.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.raw_data_column_keys == other.raw_data_column_keys
        and self.storage_dimension == other.storage_dimension
        and self.slice_start == other.slice_start
        and self.slice_end == other.slice_end
    )

PositionActionMetadata

PositionActionMetadata(frame, raw_data_column_keys, storage_dimension, prediction_dimension, needs_normalization, dtype, slice_start=None, slice_end=None, computation_method=None)

Bases: PrecomputedActionMetadata

Precomputed position action metadata.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    frame: str,
    raw_data_column_keys: list[str],
    storage_dimension: int,
    prediction_dimension: int,
    needs_normalization: bool,
    dtype: str,
    slice_start: int | None = None,
    slice_end: int | None = None,
    computation_method: str | None = None,
):
    super().__init__(
        raw_data_column_keys=raw_data_column_keys,
        storage_dimension=storage_dimension,
        prediction_dimension=prediction_dimension,
        is_numerical=True,
        needs_normalization=needs_normalization,
        dtype=dtype,
        slice_start=slice_start,
        slice_end=slice_end,
    )
    valid_frames = [e.value for e in CoordinateSystem]
    if frame not in valid_frames:
        raise ValueError(f"frame must be one of {valid_frames}, got '{frame}'")
    if computation_method is not None:
        valid_methods = [e.value for e in ActionComputationMethod]
        if computation_method not in valid_methods:
            raise ValueError(
                "computation_method must be one of "
                f"{valid_methods}, got '{computation_method}'"
            )
    self.frame = frame
    self.computation_method = computation_method
    self.action_type = ProprioceptiveType.POSITION.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.frame == other.frame
        and getattr(self, "computation_method", None)
        == getattr(other, "computation_method", None)
    )

OrientationActionMetadata

OrientationActionMetadata(frame, orientation_representation, raw_data_column_keys, storage_dimension, prediction_dimension, needs_normalization, dtype, slice_start=None, slice_end=None)

Bases: PrecomputedActionMetadata

Precomputed orientation action metadata.

Attributes:

Name Type Description
orientation_representation

Representation of the orientation.

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    frame: str,
    orientation_representation: str,
    raw_data_column_keys: list[str],
    storage_dimension: int,
    prediction_dimension: int,
    needs_normalization: bool,
    dtype: str,
    slice_start: int | None = None,
    slice_end: int | None = None,
):
    super().__init__(
        raw_data_column_keys=raw_data_column_keys,
        storage_dimension=storage_dimension,
        prediction_dimension=prediction_dimension,
        is_numerical=True,
        needs_normalization=needs_normalization,
        dtype=dtype,
        slice_start=slice_start,
        slice_end=slice_end,
    )
    valid_frames = [e.value for e in CoordinateSystem]
    if frame not in valid_frames:
        raise ValueError(f"frame must be one of {valid_frames}, got '{frame}'")
    valid_methods = [e.value for e in OrientationRepresentation]
    if orientation_representation not in valid_methods:
        raise ValueError(
            f"orientation_representation must be one of {valid_methods}, got '{orientation_representation}'"
        )
    self.raw_data_column_keys = raw_data_column_keys
    self.storage_dimension = storage_dimension
    self.frame = frame
    self.orientation_representation = orientation_representation
    self.action_type = ProprioceptiveType.ORIENTATION.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.frame == other.frame
        and self.orientation_representation == other.orientation_representation
    )

GripperActionMetadata

GripperActionMetadata(gripper_type, raw_data_column_keys, storage_dimension, prediction_dimension, needs_normalization, dtype, binary_gripper_range=value, slice_start=None, slice_end=None)

Bases: PrecomputedActionMetadata

Precomputed gripper action metadata.

This class represents gripper actions, which can be either binary (open/close) or continuous (partial open).

Attributes:

Name Type Description
gripper_type str

Type of gripper action ('binary' or 'continuous').

binary_gripper_range str

Range for binary gripper action ('zero_one' or 'minus_one_one').

Source code in src/versatil/data/metadata.py
def __init__(
    self,
    gripper_type: str,
    raw_data_column_keys: list[str],
    storage_dimension: int,
    prediction_dimension: int,
    needs_normalization: bool,
    dtype: str,
    binary_gripper_range: str = BinaryGripperRange.ZERO_ONE.value,
    slice_start: int | None = None,
    slice_end: int | None = None,
):
    valid_types = [e.value for e in GripperType]
    if gripper_type not in valid_types:
        raise ValueError(
            f"gripper_type must be one of {valid_types}, got '{gripper_type}'"
        )
    valid_ranges = [e.value for e in BinaryGripperRange]
    if binary_gripper_range not in valid_ranges:
        raise ValueError(
            f"binary_gripper_range must be one of {valid_ranges}, got '{binary_gripper_range}'"
        )
    if gripper_type == GripperType.BINARY.value:
        if needs_normalization:
            raise ValueError("Binary gripper action should not need normalization.")
        if "int" not in dtype:
            raise ValueError("Binary gripper action dtype must be an integer type.")
    else:
        if "float" not in dtype:
            raise ValueError(
                "Continuous gripper action dtype must be a float type."
            )
    super().__init__(
        prediction_dimension=prediction_dimension,
        is_numerical=True,
        needs_normalization=needs_normalization,
        dtype=dtype,
        raw_data_column_keys=raw_data_column_keys,
        storage_dimension=storage_dimension,
        slice_start=slice_start,
        slice_end=slice_end,
    )
    self.gripper_type: str = gripper_type
    self.binary_gripper_range: str = binary_gripper_range
    self.raw_data_column_keys = raw_data_column_keys
    self.storage_dimension = storage_dimension
    self.action_type = ProprioceptiveType.GRIPPER.value

__eq__

__eq__(other)

Equality function.

Source code in src/versatil/data/metadata.py
def __eq__(self, other: object) -> bool:
    """Equality function."""
    if type(other) is not type(self):
        return NotImplemented
    return (
        super().__eq__(other)
        and self.gripper_type == other.gripper_type
        and self.binary_gripper_range == other.binary_gripper_range
    )

validate_camera_metadata_keys

validate_camera_metadata_keys(camera_metadata)

Validate that camera metadata matches its canonical observation key.

Parameters:

Name Type Description Default
camera_metadata Mapping[str, CameraMetadata]

Camera metadata indexed by canonical VersatIL camera key.

required

Raises:

Type Description
ValueError

If a metadata raw camera key maps to a different canonical camera key.

Source code in src/versatil/data/metadata.py
def validate_camera_metadata_keys(
    camera_metadata: Mapping[str, CameraMetadata],
) -> None:
    """Validate that camera metadata matches its canonical observation key.

    Args:
        camera_metadata: Camera metadata indexed by canonical VersatIL camera key.

    Raises:
        ValueError: If a metadata raw camera key maps to a different
            canonical camera key.
    """
    for key, metadata in camera_metadata.items():
        if metadata.camera_key != key:
            raise ValueError(
                f"Camera '{key}' has raw_camera_key '{metadata.raw_camera_key}' "
                f"which maps to '{metadata.camera_key}', not '{key}'"
            )