"""Helper class for tagging families."""
from collections.abc import Iterable
from typing import Any, Callable
from dae.pedigrees.family import Family, FamilyTag, Person
from dae.variants.attributes import Role, Sex, Status
def _get_mom(family: Family) -> Person | None:
for person in family.members_in_order:
if person.role == Role.mom:
return person
return None
def _get_dad(family: Family) -> Person | None:
for person in family.members_in_order:
if person.role == Role.dad:
return person
return None
def _get_prb(family: Family) -> Person | None:
for person in family.members_in_order:
if person.role == Role.prb:
return person
return None
def _get_sibs(family: Family) -> Iterable[Person]:
result = []
for person in family.members_in_order:
if person.role == Role.sib:
result.append(person)
return result
[docs]
def set_tag(family: Family, tag: FamilyTag) -> None:
for person in family.persons.values():
person.set_tag(tag)
family.set_tag(tag)
[docs]
def unset_tag(family: Family, tag: FamilyTag) -> None:
for person in family.persons.values():
person.unset_tag(tag)
family.unset_tag(tag)
[docs]
def set_attr(family: Family, label: str, value: Any) -> None:
for person in family.persons.values():
person.set_attr(label, value)
[docs]
def check_tag(family: Family, tag: FamilyTag) -> bool:
for person in family.persons.values():
if not person.has_tag(tag):
return False
return True
[docs]
def check_nuclear_family(family: Family) -> bool:
"""Check if the family is a nuclear family."""
if len(family) < 3:
return False
mom = _get_mom(family)
dad = _get_dad(family)
if mom is None or dad is None:
return False
children = [
person for person in family.members_in_order
if person.is_child()
]
if not children:
return False
if not _get_prb(family) and not _get_sibs(family):
return False
for person in family.persons.values():
if person.person_id in {mom.person_id, dad.person_id}:
continue
if not person.has_both_parents():
return False
if person.mom_id != mom.person_id \
or person.dad_id != dad.person_id:
return False
return True
[docs]
def tag_nuclear_family(family: Family) -> bool:
"""Set nuclear family tag to the family."""
if check_nuclear_family(family):
set_tag(family, FamilyTag.NUCLEAR)
return True
unset_tag(family, FamilyTag.NUCLEAR)
return False
[docs]
def check_quad_family(family: Family) -> bool:
if len(family) != 4:
return False
if not check_nuclear_family(family):
return False
return True
[docs]
def tag_quad_family(family: Family) -> bool:
"""Set quad family tag to the family."""
if check_quad_family(family):
set_tag(family, FamilyTag.QUAD)
return True
unset_tag(family, FamilyTag.QUAD)
return False
[docs]
def check_trio_family(family: Family) -> bool:
if len(family) != 3:
return False
if not check_nuclear_family(family):
return False
return True
[docs]
def tag_trio_family(family: Family) -> bool:
"""Set trio family tag to the family."""
if check_trio_family(family):
set_tag(family, FamilyTag.TRIO)
return True
unset_tag(family, FamilyTag.TRIO)
return False
[docs]
def check_simplex_family(family: Family) -> bool:
return len(list(filter(
lambda p: p.status == Status.affected,
family.persons.values()))) == 1
[docs]
def tag_simplex_family(family: Family) -> bool:
"""Set simplex family tag to the family."""
if check_simplex_family(family):
set_tag(family, FamilyTag.SIMPLEX)
return True
unset_tag(family, FamilyTag.SIMPLEX)
return False
[docs]
def check_multiplex_family(family: Family) -> bool:
return len(list(filter(
lambda p: p.status == Status.affected,
family.persons.values()))) > 1
[docs]
def tag_multiplex_family(family: Family) -> bool:
"""Set multiplex family tag to the family."""
if check_multiplex_family(family):
set_tag(family, FamilyTag.MULTIPLEX)
return True
unset_tag(family, FamilyTag.MULTIPLEX)
return False
[docs]
def check_control_family(family: Family) -> bool:
return len(list(filter(
lambda p: p.status == Status.affected,
family.persons.values()))) == 0
[docs]
def tag_control_family(family: Family) -> bool:
"""Set control family tag to the family."""
if check_control_family(family):
set_tag(family, FamilyTag.CONTROL)
return True
unset_tag(family, FamilyTag.CONTROL)
return False
[docs]
def check_affected_dad_family(family: Family) -> bool:
dad = _get_dad(family)
if dad is None:
return False
return bool(dad.status == Status.affected)
[docs]
def tag_affected_dad_family(family: Family) -> bool:
"""Set affected dad family tag to the family."""
if check_affected_dad_family(family):
set_tag(family, FamilyTag.AFFECTED_DAD)
return True
unset_tag(family, FamilyTag.AFFECTED_DAD)
return False
[docs]
def check_affected_mom_family(family: Family) -> bool:
mom = _get_mom(family)
if mom is None:
return False
return bool(mom.status == Status.affected)
[docs]
def tag_affected_mom_family(family: Family) -> bool:
"""Set affected mom family tag to the family."""
if check_affected_mom_family(family):
set_tag(family, FamilyTag.AFFECTED_MOM)
return True
unset_tag(family, FamilyTag.AFFECTED_MOM)
return False
[docs]
def check_affected_prb_family(family: Family) -> bool:
prb = _get_prb(family)
if prb is None:
return False
return bool(prb.status == Status.affected)
[docs]
def tag_affected_prb_family(family: Family) -> bool:
"""Set affected proband family tag to the family."""
if check_affected_prb_family(family):
set_tag(family, FamilyTag.AFFECTED_PRB)
return True
unset_tag(family, FamilyTag.AFFECTED_PRB)
return False
[docs]
def check_affected_sib_family(family: Family) -> bool:
for sib in _get_sibs(family):
if sib.status == Status.affected:
return True
return False
[docs]
def tag_affected_sib_family(family: Family) -> bool:
"""Set affected sibling family tag to the family."""
if check_affected_sib_family(family):
set_tag(family, FamilyTag.AFFECTED_SIB)
return True
unset_tag(family, FamilyTag.AFFECTED_SIB)
return False
[docs]
def check_unaffected_dad_family(family: Family) -> bool:
dad = _get_dad(family)
if dad is None:
return False
return bool(dad.status == Status.unaffected)
[docs]
def tag_unaffected_dad_family(family: Family) -> bool:
"""Set unaffected dad family tag to the family."""
if check_unaffected_dad_family(family):
set_tag(family, FamilyTag.UNAFFECTED_DAD)
return True
unset_tag(family, FamilyTag.UNAFFECTED_DAD)
return False
[docs]
def check_unaffected_mom_family(family: Family) -> bool:
mom = _get_mom(family)
if mom is None:
return False
return bool(mom.status == Status.unaffected)
[docs]
def tag_unaffected_mom_family(family: Family) -> bool:
"""Set unaffected mom family tag to the family."""
if check_unaffected_mom_family(family):
set_tag(family, FamilyTag.UNAFFECTED_MOM)
return True
unset_tag(family, FamilyTag.UNAFFECTED_MOM)
return False
[docs]
def check_unaffected_prb_family(family: Family) -> bool:
prb = _get_prb(family)
if prb is None:
return False
return bool(prb.status == Status.unaffected)
[docs]
def tag_unaffected_prb_family(family: Family) -> bool:
"""Set unaffected proband family tag to the family."""
if check_unaffected_prb_family(family):
set_tag(family, FamilyTag.UNAFFECTED_PRB)
return True
unset_tag(family, FamilyTag.UNAFFECTED_PRB)
return False
[docs]
def check_unaffected_sib_family(family: Family) -> bool:
for sib in _get_sibs(family):
if sib.status == Status.unaffected:
return True
return False
[docs]
def tag_unaffected_sib_family(family: Family) -> bool:
"""Set unaffected sibling family tag to the family."""
if check_unaffected_sib_family(family):
set_tag(family, FamilyTag.UNAFFECTED_SIB)
return True
unset_tag(family, FamilyTag.UNAFFECTED_SIB)
return False
[docs]
def check_male_prb_family(family: Family) -> bool:
prb = _get_prb(family)
if prb is None:
return False
return bool(prb.sex == Sex.male)
[docs]
def tag_male_prb_family(family: Family) -> bool:
"""Set male proband family tag to the family."""
if check_male_prb_family(family):
set_tag(family, FamilyTag.MALE_PRB)
return True
unset_tag(family, FamilyTag.MALE_PRB)
return False
[docs]
def check_female_prb_family(family: Family) -> bool:
prb = _get_prb(family)
if prb is None:
return False
return bool(prb.sex == Sex.female)
[docs]
def tag_female_prb_family(family: Family) -> bool:
"""Set female proband family tag to the family."""
if check_female_prb_family(family):
set_tag(family, FamilyTag.FEMALE_PRB)
return True
unset_tag(family, FamilyTag.FEMALE_PRB)
return False
[docs]
def check_missing_mom_family(family: Family) -> bool:
if _get_mom(family) is None:
return True
return False
[docs]
def tag_missing_mom_family(family: Family) -> bool:
"""Set missing mom family tag to the family."""
if check_missing_mom_family(family):
set_tag(family, FamilyTag.MISSING_MOM)
return True
unset_tag(family, FamilyTag.MISSING_MOM)
return False
[docs]
def check_missing_dad_family(family: Family) -> bool:
if _get_dad(family) is None:
return True
return False
[docs]
def tag_missing_dad_family(family: Family) -> bool:
"""Set missing dad family tag to the family."""
if check_missing_dad_family(family):
set_tag(family, FamilyTag.MISSING_DAD)
return True
unset_tag(family, FamilyTag.MISSING_DAD)
return False
def _build_family_type_full(family: Family) -> str:
family_type = []
family_type.append(str(len(family.members_in_order)))
members_by_role_and_sex = sorted(
family.members_in_order, key=lambda p: f"{p.role}.{p.sex}")
for person in members_by_role_and_sex:
family_type.append(
f"{person.role}.{person.sex}.{person.status}",
)
return ":".join(family_type)