Back to report index

Step 9 filteringsurface 8f58342: AI3D-379 Review fixes: null config sections fall back to defaults

Miroslav Simko <ms@iolabs.ch> 2026-09-02T08:59:21+02:00

Commit #54 ยท 5 snippets

 README.md                                      | 3 ++-
 src/iolabs_point_cloud_surface_mesh/_config.py | 6 ++++++
 tests/test_surface_mesh_config.py              | 7 +++++++
 3 files changed, 15 insertions(+), 1 deletion(-)
Importance #1: src/iolabs_point_cloud_surface_mesh/_config.py @@ -57,8 +57,14 @@
57 file_naming: SurfaceMeshFileNamingConfig = SurfaceMeshFileNamingConfig()57 file_naming: SurfaceMeshFileNamingConfig = SurfaceMeshFileNamingConfig()
58 surface_mesh_parameters: SurfaceMeshParametersConfig = SurfaceMeshParametersConfig()58 surface_mesh_parameters: SurfaceMeshParametersConfig = SurfaceMeshParametersConfig()
59 npz_blacklist_by_segment: dict[int, list[str]] = pydantic.Field(default_factory=dict)59 npz_blacklist_by_segment: dict[int, list[str]] = pydantic.Field(default_factory=dict)
6060
61 @pydantic.field_validator("file_naming", "surface_mesh_parameters", mode="before")
62 @classmethod
63 def _none_section_is_default(cls, value: object) -> object:
64 """Treat an explicit ``null`` section as "use the packaged defaults"."""
65 return {} if value is None else value
66
61 @pydantic.field_validator("npz_blacklist_by_segment", mode="before")67 @pydantic.field_validator("npz_blacklist_by_segment", mode="before")
62 @classmethod68 @classmethod
63 def _normalize_blacklist(cls, value: object) -> dict[int, list[str]]:69 def _normalize_blacklist(cls, value: object) -> dict[int, list[str]]:
64 """Accept ``segment_<idx>`` keys and string-or-list pattern values."""70 """Accept ``segment_<idx>`` keys and string-or-list pattern values."""
Importance #2: tests/test_surface_mesh_config.py @@ -116,4 +116,11 @@
116)116)
117def test_normalize_rejects_invalid_parameter_values(key, value):117def test_normalize_rejects_invalid_parameter_values(key, value):
118 with pytest.raises(SurfaceMeshConfigError, match=key):118 with pytest.raises(SurfaceMeshConfigError, match=key):
119 normalize_surface_mesh_config({"surface_mesh_parameters": {key: value}})119 normalize_surface_mesh_config({"surface_mesh_parameters": {key: value}})
120
121
122def test_normalize_treats_null_sections_as_defaults():
123 config = normalize_surface_mesh_config(
124 {"file_naming": None, "surface_mesh_parameters": None, "npz_blacklist_by_segment": None}
125 )
126 assert config == load_surface_mesh_config()
Importance #3: README.md @@ -31,9 +31,10 @@
31## Configuration31## Configuration
3232
33Packaged defaults in `surface_mesh.default.json` are validated by the pydantic33Packaged defaults in `surface_mesh.default.json` are validated by the pydantic
34`SurfaceMeshConfig` tree; unknown keys raise `SurfaceMeshConfigError`. To add a34`SurfaceMeshConfig` tree; unknown keys raise `SurfaceMeshConfigError`. To add a
35key, add the field to the model and the JSON default. Key tunables:35key, add the field to the model, the JSON default, and (for tunables)
36`params.SurfaceMeshParameters`. Key tunables:
36`cells_across` (5), `row_spacing_m` (3.0), `device` ("CUDA:0"),37`cells_across` (5), `row_spacing_m` (3.0), `device` ("CUDA:0"),
37`min_points_per_cell`, `z_trim_mad_factor`, `max_extrapolation_m`,38`min_points_per_cell`, `z_trim_mad_factor`, `max_extrapolation_m`,
38`min_measured_edge_fraction`, `edge_smoothing_window_m`. File naming lives39`min_measured_edge_fraction`, `edge_smoothing_window_m`. File naming lives
39under `file_naming`; per-segment NPZ exclusion under40under `file_naming`; per-segment NPZ exclusion under
Importance #4: src/iolabs_point_cloud_surface_mesh/_config.py @@ -57,8 +57,14 @@
57 file_naming: SurfaceMeshFileNamingConfig = SurfaceMeshFileNamingConfig()57 file_naming: SurfaceMeshFileNamingConfig = SurfaceMeshFileNamingConfig()
58 surface_mesh_parameters: SurfaceMeshParametersConfig = SurfaceMeshParametersConfig()58 surface_mesh_parameters: SurfaceMeshParametersConfig = SurfaceMeshParametersConfig()
59 npz_blacklist_by_segment: dict[int, list[str]] = pydantic.Field(default_factory=dict)59 npz_blacklist_by_segment: dict[int, list[str]] = pydantic.Field(default_factory=dict)
6060
61 @pydantic.field_validator("file_naming", "surface_mesh_parameters", mode="before")
62 @classmethod
63 def _none_section_is_default(cls, value: object) -> object:
64 """Treat an explicit ``null`` section as "use the packaged defaults"."""
65 return {} if value is None else value
66
61 @pydantic.field_validator("npz_blacklist_by_segment", mode="before")67 @pydantic.field_validator("npz_blacklist_by_segment", mode="before")
62 @classmethod68 @classmethod
63 def _normalize_blacklist(cls, value: object) -> dict[int, list[str]]:69 def _normalize_blacklist(cls, value: object) -> dict[int, list[str]]:
64 """Accept ``segment_<idx>`` keys and string-or-list pattern values."""70 """Accept ``segment_<idx>`` keys and string-or-list pattern values."""
Importance #5: tests/test_surface_mesh_config.py @@ -116,4 +116,11 @@
116)116)
117def test_normalize_rejects_invalid_parameter_values(key, value):117def test_normalize_rejects_invalid_parameter_values(key, value):
118 with pytest.raises(SurfaceMeshConfigError, match=key):118 with pytest.raises(SurfaceMeshConfigError, match=key):
119 normalize_surface_mesh_config({"surface_mesh_parameters": {key: value}})119 normalize_surface_mesh_config({"surface_mesh_parameters": {key: value}})
120
121
122def test_normalize_treats_null_sections_as_defaults():
123 config = normalize_surface_mesh_config(
124 {"file_naming": None, "surface_mesh_parameters": None, "npz_blacklist_by_segment": None}
125 )
126 assert config == load_surface_mesh_config()