Spaces:
Sleeping
Sleeping
| """Sprint A14-S6 β ``PipelineStep``, ``PipelineSpec`` (dΓ©claratifs).""" | |
| from __future__ import annotations | |
| import pytest | |
| from picarones.domain import ArtifactType, PicaronesError | |
| from picarones.pipeline import INITIAL_STEP_ID, PipelineSpec, PipelineStep | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PipelineStep β validation des id et champs | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class TestPipelineStep: | |
| def test_minimal_step(self) -> None: | |
| s = PipelineStep( | |
| id="ocr", | |
| kind="ocr", | |
| adapter_name="tesseract", | |
| input_types=(ArtifactType.IMAGE,), | |
| output_types=(ArtifactType.RAW_TEXT,), | |
| ) | |
| assert s.id == "ocr" | |
| assert s.params == {} | |
| assert s.inputs_from == {} | |
| def test_step_with_inputs_from(self) -> None: | |
| s = PipelineStep( | |
| id="correction", | |
| kind="post_correction", | |
| adapter_name="openai:gpt-4o", | |
| input_types=(ArtifactType.RAW_TEXT,), | |
| output_types=(ArtifactType.CORRECTED_TEXT,), | |
| inputs_from={ArtifactType.RAW_TEXT: "ocr"}, | |
| ) | |
| assert s.inputs_from[ArtifactType.RAW_TEXT] == "ocr" | |
| def test_step_with_params(self) -> None: | |
| s = PipelineStep( | |
| id="ocr", | |
| kind="ocr", | |
| adapter_name="tesseract", | |
| params={"lang": "fra", "psm": 6, "preserve_interword_spaces": True}, | |
| ) | |
| assert s.params["lang"] == "fra" | |
| assert s.params["psm"] == 6 | |
| def test_id_validation_rejects_space(self) -> None: | |
| with pytest.raises(PicaronesError, match="step id invalide"): | |
| PipelineStep(id="bad id", kind="x", adapter_name="y") | |
| def test_id_validation_rejects_dot(self) -> None: | |
| with pytest.raises(PicaronesError, match="step id invalide"): | |
| PipelineStep(id="bad.id", kind="x", adapter_name="y") | |
| def test_id_validation_rejects_initial_sentinel(self) -> None: | |
| """``__initial__`` est rΓ©servΓ© pour dΓ©signer les entrΓ©es | |
| initiales du runner β un step ne peut pas porter ce nom.""" | |
| with pytest.raises(PicaronesError, match="rΓ©servΓ©"): | |
| PipelineStep(id=INITIAL_STEP_ID, kind="x", adapter_name="y") | |
| def test_id_accepts_alphanum_underscore_dash(self) -> None: | |
| s = PipelineStep(id="step_1-final", kind="x", adapter_name="y") | |
| assert s.id == "step_1-final" | |
| def test_frozen(self) -> None: | |
| from pydantic import ValidationError | |
| s = PipelineStep(id="a", kind="b", adapter_name="c") | |
| with pytest.raises(ValidationError): | |
| s.id = "d" # type: ignore[misc] | |
| def test_extra_field_rejected(self) -> None: | |
| from pydantic import ValidationError | |
| with pytest.raises(ValidationError): | |
| PipelineStep( # type: ignore[call-arg] | |
| id="a", kind="b", adapter_name="c", bogus=42, | |
| ) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PipelineSpec | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class TestPipelineSpec: | |
| def test_minimal_spec(self) -> None: | |
| s = PipelineSpec(name="empty") | |
| assert s.name == "empty" | |
| assert s.steps == () | |
| assert s.initial_inputs == () | |
| def test_spec_with_steps(self) -> None: | |
| s = PipelineSpec( | |
| name="ocr_only", | |
| initial_inputs=(ArtifactType.IMAGE,), | |
| steps=( | |
| PipelineStep( | |
| id="ocr", | |
| kind="ocr", | |
| adapter_name="tesseract", | |
| input_types=(ArtifactType.IMAGE,), | |
| output_types=(ArtifactType.RAW_TEXT,), | |
| ), | |
| ), | |
| ) | |
| assert len(s.steps) == 1 | |
| assert s.step_by_id("ocr") is not None | |
| assert s.step_by_id("missing") is None | |
| def test_frozen(self) -> None: | |
| from pydantic import ValidationError | |
| s = PipelineSpec(name="x") | |
| with pytest.raises(ValidationError): | |
| s.name = "y" # type: ignore[misc] | |