Skip to content

Commit 306e515

Browse files
authored
Refactor OBO Graph JSON parser (#474)
This PR does the following: 1. massively reduces indentation 2. renames variables in a nice way 3. refactors out shared code into a helper function 4. It also changes so it doesn't add an empty string for subject or object label, and instead doesn't add anything
1 parent 3fad8e2 commit 306e515

1 file changed

Lines changed: 90 additions & 101 deletions

File tree

src/sssom/parsers.py

Lines changed: 90 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
OBJECT_LABEL,
3434
OBJECT_SOURCE,
3535
OBJECT_SOURCE_ID,
36+
OBO_HAS_DB_XREF_URI,
3637
OWL_EQUIV_CLASS_URI,
3738
PREDICATE_ID,
3839
RDF_TYPE,
@@ -566,118 +567,106 @@ def from_obographs(
566567
converter = ensure_converter(prefix_map)
567568
ms = _init_mapping_set(meta)
568569
mlist: List[Mapping] = []
569-
# bad_attrs = {}
570570

571571
if not mapping_predicates:
572572
mapping_predicates = DEFAULT_MAPPING_PROPERTIES
573573

574-
labels = {}
575-
576-
# Build a dictionary of labels to populate _label columns
577-
if "graphs" in jsondoc:
578-
for g in jsondoc["graphs"]:
579-
if "nodes" in g:
580-
for n in g["nodes"]:
581-
nid = n["id"]
582-
if "lbl" in n:
583-
label = n["lbl"]
584-
else:
585-
label = ""
586-
labels[nid] = label
587-
588-
if "graphs" in jsondoc:
589-
for g in jsondoc["graphs"]:
590-
if "nodes" in g:
591-
for n in g["nodes"]:
592-
nid = n["id"]
593-
if "lbl" in n:
594-
label = n["lbl"]
595-
else:
596-
label = ""
597-
if "meta" in n:
598-
if (
599-
"xrefs" in n["meta"]
600-
and "http://www.geneontology.org/formats/oboInOwl#hasDbXref"
601-
in mapping_predicates
602-
):
603-
for xref in n["meta"]["xrefs"]:
604-
xref_id = xref["val"]
605-
mdict: Dict[str, Any] = {}
606-
try:
607-
mdict[SUBJECT_ID] = safe_compress(nid, converter)
608-
mdict[OBJECT_ID] = safe_compress(xref_id, converter)
609-
mdict[SUBJECT_LABEL] = label
610-
mdict[PREDICATE_ID] = converter.compress(
611-
"http://www.geneontology.org/formats/oboInOwl#hasDbXref"
612-
)
613-
mdict[MAPPING_JUSTIFICATION] = MAPPING_JUSTIFICATION_UNSPECIFIED
614-
_add_valid_mapping_to_list(mdict, mlist)
615-
except ValueError as e:
616-
logging.debug(e)
617-
if "basicPropertyValues" in n["meta"]:
618-
for value in n["meta"]["basicPropertyValues"]:
619-
pred = value["pred"]
620-
if pred in mapping_predicates:
621-
xref_id = value["val"]
622-
mdict = {}
623-
try:
624-
mdict[SUBJECT_ID] = safe_compress(nid, converter)
625-
mdict[OBJECT_ID] = safe_compress(xref_id, converter)
626-
mdict[SUBJECT_LABEL] = label
627-
mdict[PREDICATE_ID] = safe_compress(pred, converter)
628-
mdict[
629-
MAPPING_JUSTIFICATION
630-
] = MAPPING_JUSTIFICATION_UNSPECIFIED
631-
_add_valid_mapping_to_list(mdict, mlist)
632-
except ValueError as e:
633-
# FIXME this will cause ragged mappings
634-
logging.warning(e)
635-
if "edges" in g:
636-
for edge in g["edges"]:
637-
mdict = {}
638-
subject_id = edge["sub"]
639-
predicate_id = _get_obographs_predicate_id(edge["pred"])
640-
object_id = edge["obj"]
641-
if predicate_id in mapping_predicates:
642-
mdict[SUBJECT_ID] = safe_compress(subject_id, converter)
643-
mdict[OBJECT_ID] = safe_compress(object_id, converter)
644-
mdict[SUBJECT_LABEL] = (
645-
labels[subject_id] if subject_id in labels.keys() else ""
646-
)
647-
mdict[OBJECT_LABEL] = (
648-
labels[object_id] if object_id in labels.keys() else ""
649-
)
650-
mdict[PREDICATE_ID] = safe_compress(predicate_id, converter)
651-
mdict[MAPPING_JUSTIFICATION] = MAPPING_JUSTIFICATION_UNSPECIFIED
652-
_add_valid_mapping_to_list(mdict, mlist)
653-
if "equivalentNodesSets" in g and OWL_EQUIV_CLASS_URI in mapping_predicates:
654-
for equivalents in g["equivalentNodesSets"]:
655-
if "nodeIds" in equivalents:
656-
for ec1 in equivalents["nodeIds"]:
657-
for ec2 in equivalents["nodeIds"]:
658-
if ec1 != ec2:
659-
mdict = {}
660-
mdict[SUBJECT_ID] = safe_compress(ec1, converter)
661-
mdict[OBJECT_ID] = safe_compress(ec2, converter)
662-
mdict[PREDICATE_ID] = safe_compress(
663-
OWL_EQUIV_CLASS_URI, converter
664-
)
665-
mdict[MAPPING_JUSTIFICATION] = MAPPING_JUSTIFICATION_UNSPECIFIED
666-
mdict[SUBJECT_LABEL] = (
667-
labels[ec1] if ec1 in labels.keys() else ""
668-
)
669-
mdict[OBJECT_LABEL] = (
670-
labels[ec2] if ec2 in labels.keys() else ""
671-
)
672-
_add_valid_mapping_to_list(mdict, mlist)
673-
else:
574+
graphs = jsondoc.get("graphs")
575+
if not graphs:
674576
raise Exception("No graphs element in obographs file, wrong format?")
675577

578+
#: A dictionary of node URIs to node labels
579+
labels: Mapping[str, str] = {
580+
node["id"]: node.get("lbl")
581+
for graph in graphs
582+
for node in graph.get("nodes", [])
583+
if node.get("lbl")
584+
}
585+
586+
for graph in graphs:
587+
for node in graph.get("nodes", []):
588+
meta = node.get("meta")
589+
if not meta:
590+
continue
591+
592+
node_uri = node["id"]
593+
if OBO_HAS_DB_XREF_URI in mapping_predicates:
594+
for xref in meta.get("xrefs", []):
595+
mdict = _make_mdict(
596+
node_uri, OBO_HAS_DB_XREF_URI, xref["val"], converter, labels
597+
)
598+
_add_valid_mapping_to_list(mdict, mlist)
599+
600+
for value in meta.get("basicPropertyValues", []):
601+
predicate_uri = value["pred"]
602+
if predicate_uri not in mapping_predicates:
603+
continue
604+
mdict = _make_mdict(node_uri, predicate_uri, value["val"], converter, labels)
605+
_add_valid_mapping_to_list(mdict, mlist)
606+
607+
for edge in graph.get("edges", []):
608+
predicate_uri = _get_obographs_predicate_id(edge["pred"])
609+
if predicate_uri not in mapping_predicates:
610+
continue
611+
mdict = _make_mdict(edge["sub"], predicate_uri, edge["obj"], converter, labels)
612+
_add_valid_mapping_to_list(mdict, mlist)
613+
614+
if OWL_EQUIV_CLASS_URI in mapping_predicates:
615+
for equivalents in graph.get("equivalentNodesSets", []):
616+
node_uris = equivalents.get("nodeIds")
617+
if not node_uris:
618+
continue
619+
for subject_uri, object_uri in itt.product(node_uris, repeat=2):
620+
if subject_uri == object_uri:
621+
continue
622+
mdict = _make_mdict(
623+
subject_uri, OWL_EQUIV_CLASS_URI, object_uri, converter, labels
624+
)
625+
_add_valid_mapping_to_list(mdict, mlist)
626+
676627
ms.mappings = mlist # type: ignore
677628
mdoc = MappingSetDocument(mapping_set=ms, converter=converter)
678629
return to_mapping_set_dataframe(mdoc)
679630

680631

632+
def _make_mdict(
633+
subject_id: str,
634+
predicate_id: str,
635+
object_id: str,
636+
converter: Converter,
637+
labels: typing.Mapping[str, str],
638+
):
639+
mdict = {
640+
MAPPING_JUSTIFICATION: MAPPING_JUSTIFICATION_UNSPECIFIED,
641+
}
642+
try:
643+
subject_curie = safe_compress(subject_id, converter)
644+
except ValueError as e:
645+
logging.debug("could not parse subject %s - %s", subject_id, e)
646+
else:
647+
mdict[SUBJECT_ID] = subject_curie
648+
649+
try:
650+
predicate_curie = safe_compress(predicate_id, converter)
651+
except ValueError as e:
652+
logging.debug("could not parse predicate %s - %s", predicate_id, e)
653+
else:
654+
mdict[PREDICATE_ID] = predicate_curie
655+
656+
try:
657+
object_curie = safe_compress(object_id, converter)
658+
except ValueError as e:
659+
logging.debug("could not parse object %s - %s", object_id, e)
660+
else:
661+
mdict[OBJECT_ID] = object_curie
662+
663+
if subject_id in labels:
664+
mdict[SUBJECT_LABEL] = labels[subject_id]
665+
if object_id in labels:
666+
mdict[OBJECT_LABEL] = labels[object_id]
667+
return mdict
668+
669+
681670
# All from_* take as an input a python object (data frame, json, etc.) and return a MappingSetDataFrame
682671
# All read_* take as an input a file handle and return a MappingSetDataFrame (usually wrapping a from_* method)
683672

0 commit comments

Comments
 (0)