Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 8 additions & 21 deletions src/hflow/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,18 @@
import hashlib
import json
import logging
import math
from collections.abc import Callable, Mapping, Sequence
from copy import copy
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Literal

from hflow import video as video_module
from hflow._field_guards import (
require_int_in_range,
require_positive_float,
require_positive_int,
)
from hflow._grouped_mcap_writer import (
NO_SCHEMA_ID,
ChannelId,
Expand Down Expand Up @@ -156,28 +160,11 @@ class TransformConfig:

def __post_init__(self) -> None:
"""Reject invalid settings before they become a pipeline identity."""
if isinstance(self.crf, bool) or not isinstance(self.crf, int):
raise ValueError(f"crf must be an int, got {type(self.crf).__name__}")
if not 0 <= self.crf <= 51:
raise ValueError(f"crf must be between 0 and 51, got {self.crf}")

require_int_in_range(self.crf, "crf", minimum=0, maximum=51)
if self.gop_seconds is not None:
if isinstance(self.gop_seconds, bool) or not isinstance(self.gop_seconds, int | float):
raise ValueError(
f"gop_seconds must be an int or float, got {type(self.gop_seconds).__name__}"
)
if not math.isfinite(self.gop_seconds) or self.gop_seconds <= 0:
raise ValueError(f"gop_seconds must be positive and finite, got {self.gop_seconds}")

require_positive_float(self.gop_seconds, "gop_seconds")
if self.chunk_size_bytes is not None:
if isinstance(self.chunk_size_bytes, bool) or not isinstance(
self.chunk_size_bytes, int
):
raise ValueError(
f"chunk_size_bytes must be an int, got {type(self.chunk_size_bytes).__name__}"
)
if self.chunk_size_bytes <= 0:
raise ValueError(f"chunk_size_bytes must be positive, got {self.chunk_size_bytes}")
require_positive_int(self.chunk_size_bytes, "chunk_size_bytes")


@dataclass(frozen=True)
Expand Down
29 changes: 16 additions & 13 deletions tests/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,27 @@ def test_pipeline_version_is_a_content_hash() -> None:


@pytest.mark.parametrize(
("construct", "field"),
("construct", "message"),
[
(lambda: TransformConfig(crf=True), "crf"),
(lambda: TransformConfig(crf=-1), "crf"),
(lambda: TransformConfig(crf=52), "crf"),
(lambda: TransformConfig(gop_seconds=True), "gop_seconds"),
(lambda: TransformConfig(gop_seconds=0), "gop_seconds"),
(lambda: TransformConfig(gop_seconds=float("nan")), "gop_seconds"),
(lambda: TransformConfig(gop_seconds=float("inf")), "gop_seconds"),
(lambda: TransformConfig(chunk_size_bytes=True), "chunk_size_bytes"),
(lambda: TransformConfig(chunk_size_bytes=0), "chunk_size_bytes"),
(lambda: TransformConfig(chunk_size_bytes=-1), "chunk_size_bytes"),
(lambda: TransformConfig(crf=True), "crf must be an int, got bool"),
(lambda: TransformConfig(crf=-1), "crf must be in [0, 51], got -1"),
(lambda: TransformConfig(crf=52), "crf must be in [0, 51], got 52"),
(lambda: TransformConfig(gop_seconds=True), "gop_seconds must be an int or float, got bool"),
(lambda: TransformConfig(gop_seconds=0), "gop_seconds must be > 0, got 0"),
(lambda: TransformConfig(gop_seconds=float("nan")), "gop_seconds must be finite, got nan"),
(lambda: TransformConfig(gop_seconds=float("inf")), "gop_seconds must be finite, got inf"),
(
lambda: TransformConfig(chunk_size_bytes=True),
"chunk_size_bytes must be an int, got bool",
),
(lambda: TransformConfig(chunk_size_bytes=0), "chunk_size_bytes must be > 0, got 0"),
(lambda: TransformConfig(chunk_size_bytes=-1), "chunk_size_bytes must be > 0, got -1"),
],
)
def test_transform_config_rejects_invalid_numeric_settings(
construct: Callable[[], TransformConfig], field: str
construct: Callable[[], TransformConfig], message: str
) -> None:
with pytest.raises(ValueError, match=field):
with pytest.raises(ValueError, match=f"^{message}$"):
construct()


Expand Down
Loading