Skip to content

Commit a664dbd

Browse files
Implement SEG-Y header validation for required template keys (#705)
* Implement validation for all required fields * Update logic to use sets * Add requested unit tests * Pre-commit * use magic mock * also print template name in error --------- Co-authored-by: Altay Sansal <[email protected]>
1 parent fd61ec4 commit a664dbd

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/mdio/converters/segy.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,21 @@ def determine_target_size(var_type: str) -> int:
482482
ds.variables[index].metadata.chunk_grid = chunk_grid
483483

484484

485+
def _validate_spec_in_template(segy_spec: SegySpec, mdio_template: AbstractDatasetTemplate) -> None:
486+
"""Validate that the SegySpec has all required fields in the MDIO template."""
487+
header_fields = {field.name for field in segy_spec.trace.header.fields}
488+
489+
required_fields = set(mdio_template._dim_names[:-1]) | set(mdio_template._coord_names)
490+
missing_fields = required_fields - header_fields
491+
492+
if missing_fields:
493+
err = (
494+
f"Required fields {sorted(missing_fields)} for template {mdio_template.name} "
495+
f"not found in the provided segy_spec"
496+
)
497+
raise ValueError(err)
498+
499+
485500
def segy_to_mdio( # noqa PLR0913
486501
segy_spec: SegySpec,
487502
mdio_template: AbstractDatasetTemplate,
@@ -507,6 +522,8 @@ def segy_to_mdio( # noqa PLR0913
507522
Raises:
508523
FileExistsError: If the output location already exists and overwrite is False.
509524
"""
525+
_validate_spec_in_template(segy_spec, mdio_template)
526+
510527
input_path = _normalize_path(input_path)
511528
output_path = _normalize_path(output_path)
512529

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""Tests for SEG-Y spec validation against MDIO templates."""
2+
3+
from __future__ import annotations
4+
5+
from unittest.mock import MagicMock
6+
7+
import pytest
8+
from segy.schema import HeaderField
9+
from segy.standards import get_segy_standard
10+
11+
from mdio.converters.segy import _validate_spec_in_template
12+
13+
14+
class TestValidateSpecInTemplate:
15+
"""Test cases for _validate_spec_in_template function."""
16+
17+
def test_validation_passes_with_all_required_fields(self) -> None:
18+
"""Test that validation passes when all required fields are present."""
19+
template = MagicMock()
20+
template._dim_names = ("inline", "crossline", "time")
21+
template._coord_names = ("cdp_x", "cdp_y")
22+
23+
# SegySpec with all required fields
24+
spec = get_segy_standard(1.0)
25+
header_fields = [
26+
HeaderField(name="inline", byte=189, format="int32"),
27+
HeaderField(name="crossline", byte=193, format="int32"),
28+
HeaderField(name="cdp_x", byte=181, format="int32"),
29+
HeaderField(name="cdp_y", byte=185, format="int32"),
30+
]
31+
segy_spec = spec.customize(trace_header_fields=header_fields)
32+
33+
# Should not raise any exception
34+
_validate_spec_in_template(segy_spec, template)
35+
36+
def test_validation_fails_with_missing_fields(self) -> None:
37+
"""Test that validation fails when required fields are missing."""
38+
# Template requiring custom fields not in standard spec
39+
template = MagicMock()
40+
template.name = "CustomTemplate"
41+
template._dim_names = ("custom_dim1", "custom_dim2", "time")
42+
template._coord_names = ("custom_coord_x", "custom_coord_y")
43+
44+
# SegySpec with only one of the required custom fields
45+
spec = get_segy_standard(1.0)
46+
header_fields = [
47+
HeaderField(name="custom_dim1", byte=189, format="int32"),
48+
]
49+
segy_spec = spec.customize(trace_header_fields=header_fields)
50+
51+
# Should raise ValueError listing the missing fields
52+
with pytest.raises(ValueError, match=r"Required fields.*not found in.*segy_spec") as exc_info:
53+
_validate_spec_in_template(segy_spec, template)
54+
55+
error_message = str(exc_info.value)
56+
assert "custom_dim2" in error_message
57+
assert "custom_coord_x" in error_message
58+
assert "custom_coord_y" in error_message
59+
assert "CustomTemplate" in error_message

0 commit comments

Comments
 (0)