diff --git a/isic_metadata/__init__.py b/isic_metadata/__init__.py index 55c3ace..8bc92a2 100644 --- a/isic_metadata/__init__.py +++ b/isic_metadata/__init__.py @@ -4,7 +4,6 @@ from isic_metadata.diagnosis_hierarchical import DiagnosisEnum from isic_metadata.fields import ( Age, - AnatomSiteGeneralEnum, AnatomSiteSpecialEnum, ClinSizeLongDiamMm, ColorTintEnum, @@ -26,7 +25,6 @@ "FIELD_REGISTRY", "Age", "AnatomSiteEnum", - "AnatomSiteGeneralEnum", "AnatomSiteSpecialEnum", "ClinSizeLongDiamMm", "ColorTintEnum", diff --git a/isic_metadata/fields.py b/isic_metadata/fields.py index 585f828..304aa41 100644 --- a/isic_metadata/fields.py +++ b/isic_metadata/fields.py @@ -137,17 +137,6 @@ class MelMitoticIndexEnum(StrEnum): gt_4 = ">4/mm^2" -class AnatomSiteGeneralEnum(StrEnum): - head_neck = "head/neck" - upper_extremity = "upper extremity" - lower_extremity = "lower extremity" - anterior_torso = "anterior torso" - posterior_torso = "posterior torso" - palms_soles = "palms/soles" - lateral_torso = "lateral torso" - oral_genital = "oral/genital" - - class AnatomSiteSpecialEnum(StrEnum): acral_nos = "acral NOS" nail_nos = "nail NOS" diff --git a/isic_metadata/metadata.py b/isic_metadata/metadata.py index e3023e2..5683f59 100644 --- a/isic_metadata/metadata.py +++ b/isic_metadata/metadata.py @@ -22,7 +22,6 @@ from isic_metadata.diagnosis_hierarchical import DiagnosisEnum from isic_metadata.fields import ( Age, - AnatomSiteGeneralEnum, AnatomSiteSpecialEnum, ClinSizeLongDiamMm, ColorTintEnum, @@ -194,7 +193,6 @@ class MetadataRow(BaseModel): | None ) = None sex: Literal["male", "female"] | None = None - anatom_site_general: AnatomSiteGeneralEnum | None = None anatom_site_special: AnatomSiteSpecialEnum | None = None anatom_site: ( Annotated[ @@ -374,7 +372,6 @@ def strip[T](cls, v: T) -> T | None: return None if v == "" else v @field_validator( - "anatom_site_general", "clin_size_long_diam_mm", "diagnosis_confirm_type", "mel_mitotic_index", @@ -447,60 +444,6 @@ def validate_dermoscopic_fields(self) -> MetadataRow: return self - @model_validator(mode="after") - def validate_anatom_site_special(self) -> MetadataRow: - if not self.anatom_site_special: - return self - - if not self.anatom_site_general: - raise _error_missing_field("anatom_site_special", "anatom_site_general") - - valid_combinations = { - AnatomSiteSpecialEnum.acral_nos: [ - AnatomSiteGeneralEnum.upper_extremity, - AnatomSiteGeneralEnum.lower_extremity, - AnatomSiteGeneralEnum.palms_soles, - ], - AnatomSiteSpecialEnum.nail_nos: [ - AnatomSiteGeneralEnum.upper_extremity, - AnatomSiteGeneralEnum.lower_extremity, - AnatomSiteGeneralEnum.palms_soles, - ], - AnatomSiteSpecialEnum.fingernail: [ - AnatomSiteGeneralEnum.upper_extremity, - AnatomSiteGeneralEnum.palms_soles, - ], - AnatomSiteSpecialEnum.toenail: [ - AnatomSiteGeneralEnum.lower_extremity, - AnatomSiteGeneralEnum.palms_soles, - ], - AnatomSiteSpecialEnum.acral_palms_soles: [ - AnatomSiteGeneralEnum.upper_extremity, - AnatomSiteGeneralEnum.lower_extremity, - AnatomSiteGeneralEnum.palms_soles, - ], - AnatomSiteSpecialEnum.oral_genital: [ - AnatomSiteGeneralEnum.head_neck, - AnatomSiteGeneralEnum.oral_genital, - AnatomSiteGeneralEnum.lower_extremity, - AnatomSiteGeneralEnum.anterior_torso, - AnatomSiteGeneralEnum.posterior_torso, - ], - } - - if self.anatom_site_special not in valid_combinations: - return self - - if self.anatom_site_general not in valid_combinations[self.anatom_site_special]: - raise _error_incompatible_fields( - "anatom_site_special", - "anatom_site_general", - self.anatom_site_special.value, - self.anatom_site_general.value, - ) - - return self - @model_validator(mode="after") def validate_tbp_tile_fields(self) -> MetadataRow: if not self.tbp_tile_type: diff --git a/isic_metadata/registry.py b/isic_metadata/registry.py index 490373f..ab640b3 100644 --- a/isic_metadata/registry.py +++ b/isic_metadata/registry.py @@ -46,7 +46,6 @@ class Field: "dermoscopic_type", "tbp_tile_type", "mel_mitotic_index", - "anatom_site_general", "anatom_site_special", "color_tint", "patient_id", @@ -201,8 +200,3 @@ class Field: FIELD_REGISTRY[field].type = "acquisition" else: FIELD_REGISTRY[field].type = "clinical" - -for field, label in [ - ("anatom_site_general", "Anatomic Site"), -]: - FIELD_REGISTRY[field].label = label diff --git a/tests/test_fields.py b/tests/test_fields.py index 03dd45e..bc56b04 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -9,7 +9,6 @@ import pytest from isic_metadata.diagnosis_hierarchical import DiagnosisEnum -from isic_metadata.fields import AnatomSiteGeneralEnum from isic_metadata.metadata import MetadataRow, convert_errors @@ -118,50 +117,3 @@ def test_clin_size_long_diam_mm_invalid() -> None: MetadataRow.model_validate({"clin_size_long_diam_mm": "foo"}) assert len(excinfo.value.errors()) == 1 assert "Unable to parse value as a number" in convert_errors(excinfo.value)[0]["msg"] - - -@pytest.mark.parametrize( - ("anatom_site_special", "anatom_site_general_values"), - [ - ("acral NOS", ["upper extremity", "lower extremity", "palms/soles"]), - ("nail NOS", ["upper extremity", "lower extremity", "palms/soles"]), - ("fingernail", ["upper extremity", "palms/soles"]), - ("toenail", ["lower extremity", "palms/soles"]), - ("acral palms or soles", ["upper extremity", "lower extremity", "palms/soles"]), - ( - "oral or genital", - ["head/neck", "oral/genital", "lower extremity", "anterior torso", "posterior torso"], - ), - ], -) -def test_anatom_site_special( - anatom_site_special: str, anatom_site_general_values: list[str] -) -> None: - for anatom_site_general_value in anatom_site_general_values: - metadata = MetadataRow.model_validate( - { - "anatom_site_special": anatom_site_special, - "anatom_site_general": anatom_site_general_value, - } - ) - assert metadata.anatom_site_special == anatom_site_special - assert metadata.anatom_site_general == anatom_site_general_value - - for invalid_anatom_site_general in AnatomSiteGeneralEnum: - if invalid_anatom_site_general.value not in anatom_site_general_values: - with pytest.raises(ValidationError) as excinfo: - MetadataRow.model_validate( - { - "anatom_site_special": anatom_site_special, - "anatom_site_general": invalid_anatom_site_general.value, - } - ) - assert len(excinfo.value.errors()) == 1 - assert "is incompatible with anatom_site_general" in excinfo.value.errors()[0]["msg"] - - -def test_anatom_site_special_requires_anatom_site_general() -> None: - with pytest.raises(ValidationError) as excinfo: - MetadataRow.model_validate({"anatom_site_special": "acral NOS"}) - assert len(excinfo.value.errors()) == 1 - assert "requires setting anatom_site_general" in excinfo.value.errors()[0]["msg"] diff --git a/tests/test_hierarchical_anatom_site.py b/tests/test_hierarchical_anatom_site.py index 8ee11e7..2b268f5 100644 --- a/tests/test_hierarchical_anatom_site.py +++ b/tests/test_hierarchical_anatom_site.py @@ -110,29 +110,6 @@ def test_anatom_site_validation_is_idempotent() -> None: assert metadata == metadata_2 -def test_anatom_site_general_and_special_unaffected() -> None: - metadata = MetadataRow.model_validate( - { - "anatom_site_general": "head/neck", - "anatom_site_special": "oral or genital", - } - ) - assert metadata.anatom_site_general == "head/neck" - assert metadata.anatom_site_special == "oral or genital" - - -def test_anatom_site_general_coexists_with_hierarchical() -> None: - metadata = MetadataRow.model_validate( - { - "anatom_site_general": "head/neck", - "anatom_site": "Head and neck:Head:Scalp", - } - ) - assert metadata.anatom_site_general == "head/neck" - assert metadata.anatom_site_1 == "Head and neck" - assert metadata.anatom_site_3 == "Scalp" - - def test_invalid_anatom_site_raises_error() -> None: with pytest.raises(ValidationError): MetadataRow.model_validate({"anatom_site": "Not a real site"})