diff --git a/src/sssom/context.py b/src/sssom/context.py index 71754497..6cff7db0 100644 --- a/src/sssom/context.py +++ b/src/sssom/context.py @@ -42,11 +42,15 @@ def _get_default_converter() -> Converter: return Converter(records) +def _load_sssom_context(): + with open(SSSOM_CONTEXT) as file: + return json.load(file, strict=False) + + @lru_cache(1) def _get_built_in_prefix_map() -> Converter: """Get URI prefixes for built-in prefixes.""" - with open(SSSOM_CONTEXT) as file: - context = json.load(file, strict=False) + context = _load_sssom_context() prefix_map = { prefix: uri_prefix for prefix, uri_prefix in context["@context"].items() diff --git a/src/sssom/writers.py b/src/sssom/writers.py index e30bbf70..4085e587 100644 --- a/src/sssom/writers.py +++ b/src/sssom/writers.py @@ -7,6 +7,7 @@ import pandas as pd import yaml +from curies import Converter from jsonasobj2 import JsonObj from linkml_runtime.dumpers import JSONDumper, rdflib_dumper from linkml_runtime.utils.schemaview import SchemaView @@ -17,6 +18,7 @@ from sssom.validators import check_all_prefixes_in_curie_map from .constants import CURIE_MAP, SCHEMA_YAML, SSSOM_URI_PREFIX +from .context import _load_sssom_context from .parsers import to_mapping_set_document from .util import ( RDF_FORMATS, @@ -433,10 +435,24 @@ def to_fhir_json(msdf: MappingSetDataFrame) -> Dict: return json_obj +def _update_sssom_context_with_prefixmap(converter: Converter): + """Prepare a JSON-LD context and dump to a string.""" + context = _load_sssom_context() + for k, v in converter.bimap.items(): + if k in context["@context"] and context["@context"][k] != v: + logging.info( + f"{k} namespace is already in the context, ({context['@context'][k]}, " + f"but with a different value than {v}. Overwriting!" + ) + context["@context"][k] = v + return context + + def to_json(msdf: MappingSetDataFrame) -> JsonObj: """Convert a mapping set dataframe to a JSON object.""" doc = to_mapping_set_document(msdf) - data = JSONDumper().dumps(doc.mapping_set, contexts={"@context": doc.prefix_map}) + context = _update_sssom_context_with_prefixmap(doc.converter) + data = JSONDumper().dumps(doc.mapping_set, contexts=json.dumps(context)) json_obj = json.loads(data) return json_obj diff --git a/tests/test_writers.py b/tests/test_writers.py index aea35383..82cf3e20 100644 --- a/tests/test_writers.py +++ b/tests/test_writers.py @@ -4,8 +4,23 @@ import os import unittest +import pandas as pd +from curies import Converter + +from sssom import MappingSetDataFrame +from sssom.constants import ( + CREATOR_ID, + OBJECT_ID, + OBJECT_LABEL, + PREDICATE_ID, + SEMAPV, + SUBJECT_ID, + SUBJECT_LABEL, +) from sssom.parsers import parse_sssom_json, parse_sssom_rdf, parse_sssom_table from sssom.writers import ( + _update_sssom_context_with_prefixmap, + to_json, write_fhir_json, write_json, write_ontoportal_json, @@ -67,6 +82,52 @@ def test_write_sssom_json(self): f"{path} has the wrong number of mappings.", ) + def test_write_sssom_json_context(self): + """Test when writing to JSON, the context is correctly written as well.""" + rows = [ + ( + "DOID:0050601", + "ADULT syndrome", + "skos:exactMatch", + "UMLS:C1863204", + "ADULT SYNDROME", + SEMAPV.ManualMappingCuration.value, + "orcid:0000-0003-4423-4370", + ) + ] + columns = [ + SUBJECT_ID, + SUBJECT_LABEL, + PREDICATE_ID, + OBJECT_ID, + OBJECT_LABEL, + SEMAPV.ManualMappingCuration.value, + CREATOR_ID, + ] + df = pd.DataFrame(rows, columns=columns) + msdf = MappingSetDataFrame(df) + msdf.clean_prefix_map() + json_object = to_json(msdf) + self.assertIn("@context", json_object) + self.assertIn("DOID", json_object["@context"]) + self.assertIn("mapping_set_id", json_object["@context"]) + + def test_update_sssom_context_with_prefixmap(self): + """Test when writing to JSON, the context is correctly written as well.""" + records = [ + { + "prefix": "SCTID", + "prefix_synonyms": ["snomed"], + "uri_prefix": "http://snomed.info/id/", + }, + ] + converter = Converter.from_extended_prefix_map(records) + context = _update_sssom_context_with_prefixmap(converter) + self.assertIn("@context", context) + self.assertIn("SCTID", context["@context"]) + self.assertNotIn("snomed", context["@context"]) + self.assertIn("mapping_set_id", context["@context"]) + def test_write_sssom_fhir(self): """Test writing as FHIR ConceptMap JSON.""" path = os.path.join(test_out_dir, "test_write_sssom_fhir.json")