Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
xfail_strict = true
filterwarnings = [
"error",
"ignore:Unsupported Windows version.*ONNX Runtime supports Windows 10 and above, only.:UserWarning",
"ignore:Unsupported Windows version.*ONNX Runtime supports Windows 10 and above, only.:UserWarning"
]
log_cli_level = "INFO"
testpaths = [
Expand Down
23 changes: 18 additions & 5 deletions src/openlifu/seg/seg_method.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import copy
import inspect
import logging
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Annotated, Any
from typing import Annotated, Any, Literal

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -42,7 +44,7 @@ def to_dict(self) -> dict[str, Any]:
return d

@staticmethod
def from_dict(d: dict) -> SegmentationMethod:
def from_dict(d: dict, on_keyword_mismatch: Literal['warn', 'raise', 'ignore'] = 'warn') -> SegmentationMethod:
from openlifu.seg import seg_methods
if not isinstance(d, dict): # previous implementations might pass str
raise TypeError(f"Expected dict for from_dict, got {type(d).__name__}")
Expand All @@ -58,10 +60,21 @@ def from_dict(d: dict) -> SegmentationMethod:
for k, v in materials_dict.items()
}

# Ignore ref_material if class is `UniformWater` or `UniformTissue`
if short_classname in ["UniformWater", "UniformTissue"]:
d.pop("ref_material")
class_constructor = getattr(seg_methods, short_classname)

# Filter out unexpected keywords
sig = inspect.signature(class_constructor)
expected_keywords = [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
unexpected_keywords = [k for k in d if k not in expected_keywords]

if unexpected_keywords:
if on_keyword_mismatch == 'raise':
raise TypeError(f"Unexpected keyword arguments for {short_classname}: {unexpected_keywords}")
elif on_keyword_mismatch == 'warn':
logging.warning(f"Ignoring unexpected keyword arguments for {short_classname}: {unexpected_keywords}")
for k in unexpected_keywords:
d.pop(k)

return class_constructor(**d)

def _material_indices(self, materials: dict | None = None):
Expand Down
11 changes: 11 additions & 0 deletions src/openlifu/seg/seg_methods/uniform.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ def to_table(self) -> pd.DataFrame:
records = [{"Name": "Type", "Value": "Uniform Tissue", "Unit": ""}]
return pd.DataFrame.from_records(records)

def to_dict(self):
d = super().to_dict()
d.pop("ref_material")
return d


class UniformWater(UniformSegmentation):
""" Assigns the water material to all voxels in the volume. """
def __init__(self, materials: dict[str, Material] | None = None):
Expand All @@ -52,3 +58,8 @@ def to_table(self) -> pd.DataFrame:
"""
records = [{"Name": "Type", "Value": "Uniform Water", "Unit": ""}]
return pd.DataFrame.from_records(records)

def to_dict(self):
d = super().to_dict()
d.pop("ref_material")
return d
22 changes: 22 additions & 0 deletions tests/test_seg_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,25 @@ def test_uniformwater_errors_when_specify_ref_material():
def test_materials_as_none_gets_default_materials():
seg_method = seg_methods.UniformSegmentation(materials=None) # pyright: ignore[reportArgumentType]
assert seg_method.materials == MATERIALS.copy()

def test_from_dict_on_keyword_mismatch():
d = {
"class": "UniformWater",
"materials": {
"water": {
"name": "water",
"sound_speed": 1500,
"density": 1000,
"attenuation": 0.0022,
"specific_heat": 4182,
"thermal_conductivity": 0.598
}
},
"ref_material": "water"
}

with pytest.raises(TypeError, match=r"Unexpected keyword arguments for UniformWater: \['ref_material'\]"):
SegmentationMethod.from_dict(d, on_keyword_mismatch='raise')

# This should not raise any warning or exception
SegmentationMethod.from_dict(d, on_keyword_mismatch='ignore')
Loading