Skip to content
Open
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
20 changes: 16 additions & 4 deletions dandi/metadata/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,18 @@ def timedelta2duration(delta: timedelta) -> str:
return s


# Names for the sex IRIs which ``extract_sex`` produces itself
SEX_NAMES_BY_IRI = {
"http://purl.obolibrary.org/obo/PATO_0000384": "Male",
"http://purl.obolibrary.org/obo/PATO_0000383": "Female",
}


def extract_sex(metadata: dict) -> models.SexType | None:
value = metadata.get("sex", None)
if value is not None and value != "":
value = value.lower()
value_orig = value.strip()
value = value_orig.lower()
if value in ["m", "male"]:
value_id = "http://purl.obolibrary.org/obo/PATO_0000384"
value = "Male"
Expand All @@ -305,8 +313,11 @@ def extract_sex(metadata: dict) -> models.SexType | None:
value_id = None
value = "Other"
elif value.startswith("http"):
value_id = value
value = None
value_id = value_orig
# dandischema requires a name; fall back to the IRI itself
value = {k.lower(): v for k, v in SEX_NAMES_BY_IRI.items()}.get(
value, value_id
)
else:
raise ValueError(f"Cannot interpret sex field: {value}")
return models.SexType(identifier=value_id, name=value)
Expand Down Expand Up @@ -597,7 +608,8 @@ def extract_species(metadata: dict) -> models.SpeciesType | None:
value = " - ".join(
[result[key] for key in lookup if key in result]
)
value_matches.append((value_id, value))
# dandischema requires a name; fall back to the IRI itself
value_matches.append((value_id, value or value_id))
else:
lower_value = value_orig.lower().strip()
for record in species_map:
Expand Down
49 changes: 49 additions & 0 deletions dandi/tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
SpeciesRecord,
extract_age,
extract_cellLine,
extract_sex,
extract_species,
parse_age,
parse_purlobourl,
Expand Down Expand Up @@ -887,6 +888,54 @@ def test_species_rat(species: str) -> None:
}


@pytest.mark.ai_generated
def test_species_unknown_iri_lookup_fails(monkeypatch: pytest.MonkeyPatch) -> None:
# An NCBITaxon IRI not in species_map whose label cannot be looked up
# still gets a name, as dandischema requires one
iri = "http://purl.obolibrary.org/obo/NCBITaxon_999999999"

def fail(*_args: Any, **_kwargs: Any) -> None:
raise ConnectionError("no network")

monkeypatch.setattr("dandi.metadata.util.parse_purlobourl", fail)
species_rec = extract_species({"species": iri})
assert species_rec is not None
assert str(species_rec.identifier) == iri
assert species_rec.name == iri


@pytest.mark.ai_generated
@pytest.mark.parametrize(
"sex,identifier,name",
[
("M", "http://purl.obolibrary.org/obo/PATO_0000384", "Male"),
("female", "http://purl.obolibrary.org/obo/PATO_0000383", "Female"),
("U", None, "Unknown"),
(
"http://purl.obolibrary.org/obo/PATO_0000384",
"http://purl.obolibrary.org/obo/PATO_0000384",
"Male",
),
(
"http://purl.obolibrary.org/obo/PATO_0000383",
"http://purl.obolibrary.org/obo/PATO_0000383",
"Female",
),
# unknown IRI: kept as is (not lowercased) and used as the name
(
"http://purl.obolibrary.org/obo/PATO_0001340",
"http://purl.obolibrary.org/obo/PATO_0001340",
"http://purl.obolibrary.org/obo/PATO_0001340",
),
],
)
def test_extract_sex(sex: str, identifier: str | None, name: str) -> None:
rec = extract_sex({"sex": sex})
assert rec is not None
assert (None if rec.identifier is None else str(rec.identifier)) == identifier
assert rec.name == name


@pytest.mark.parametrize(
"species",
[
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ dependencies = [
# Exclude 0.13.0: it lacks the downgrade migrations (SIMPLE_DOWNGRADES
# entries for releaseNotes / sameAs) that the client relies on to talk
# to older Archive servers. 0.14.0 restored them.
"dandischema >= 0.12.0, != 0.13.0, < 0.15.0",
"dandischema >= 0.12.0, != 0.13.0, < 0.16.0",
"etelemetry >= 0.2.2",
"fasteners >= 0.19",
"fscacher >= 0.3.0",
Expand Down
Loading