-
Notifications
You must be signed in to change notification settings - Fork 33
FHIR: Output NPM format #511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,7 +2,6 @@ | |||||||||||||||||||
| .tox/ | ||||||||||||||||||||
| __pycache__/ | ||||||||||||||||||||
| .ipynb_checkpoints/ | ||||||||||||||||||||
| tests/output/ | ||||||||||||||||||||
| dist/ | ||||||||||||||||||||
| db/ | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -25,7 +24,8 @@ notebooks/api-key.txt | |||||||||||||||||||
| .coverage.* | ||||||||||||||||||||
| .coverage | ||||||||||||||||||||
| coverage.* | ||||||||||||||||||||
| tests/input/fhirjson_conf.json | ||||||||||||||||||||
| tests/input/*_conf.json | ||||||||||||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||
| fhir_conf = { | |
| "code_system_id": "test", | |
| "code_system_url": "http://purl.obolibrary.org/obo/go.owl", | |
| "native_uri_stems": ["http://purl.obolibrary.org/obo/GO_"], | |
| } |
ontology-access-kit/tests/test_cli.py
Line 525 in b42d286
| output_path = str(OUTPUT_DIR / f"test_dump-{output_format}.out") |
Details 2023/04/05
@hrshdhgd I should have made a 'review comment' earlier when tagging you. I like being able to hit 'resolve' to clean the page up a bit.
Regarding fhirjson_conf.json, I located the source. It's from a (very helpful) unit test that @cmungall added in another PR recently. Basically, in order to keep the CLI clean, we're planning on having some dumpers, etc, pull their parameters from a config file rather than declaring them in cli.py in the normal click way. Right now, the only such dumper output_type that has such a config is fhirjson.
ontology-access-kit/tests/test_cli.py
Lines 477 to 479 in 22eebdf
| conf_path = INPUT_DIR / f"{output_format}_conf.json" | |
| with open(conf_path, "w", encoding="utf-8") as f: | |
| json.dump(conf_object, f) |
@cmungall It does look like this probably should be in the .gitignore, so I've added the following entry (though let me know if you actually do want to have these committed):
tests/input/*_conf.json
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,7 +125,10 @@ | |
| from oaklib.io.rollup_report_writer import write_report | ||
| from oaklib.io.streaming_axiom_writer import StreamingAxiomWriter | ||
| from oaklib.io.streaming_csv_writer import StreamingCsvWriter | ||
| from oaklib.io.streaming_fhir_writer import StreamingFHIRWriter | ||
| from oaklib.io.streaming_fhir_writer import ( | ||
| StreamingFhirJsonWriter, | ||
| StreamingFhirNpmWriter, | ||
| ) | ||
| from oaklib.io.streaming_info_writer import StreamingInfoWriter | ||
| from oaklib.io.streaming_json_writer import StreamingJsonWriter | ||
| from oaklib.io.streaming_kgcl_writer import StreamingKGCLWriter | ||
|
|
@@ -212,6 +215,7 @@ | |
| NL_FORMAT = "nl" | ||
| KGCL_FORMAT = "kgcl" | ||
| FHIR_JSON_FORMAT = "fhirjson" | ||
| FHIR_NPM_FORMAT = "fhirnpm" | ||
| HEATMAP_FORMAT = "heatmap" | ||
|
|
||
| ONT_FORMATS = [ | ||
|
|
@@ -222,6 +226,7 @@ | |
| JSON_FORMAT, | ||
| YAML_FORMAT, | ||
| FHIR_JSON_FORMAT, | ||
| FHIR_NPM_FORMAT, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CLI & documenting config @joeflack4I think this may still need:
Details
Tasks1. CLIIt can call the dumper for 2. Docs about the FHIR config JSONShould probably document the config for that as with the DiscussionJoe 4/5/2023: Joe 9/2023: Joe 11/26/2023:
This comment was marked as duplicate.
Sorry, something went wrong. |
||
| CSV_FORMAT, | ||
| NL_FORMAT, | ||
| ] | ||
|
|
@@ -238,7 +243,8 @@ | |
| JSONL_FORMAT: StreamingJsonWriter, | ||
| YAML_FORMAT: StreamingYamlWriter, | ||
| SSSOM_FORMAT: StreamingSssomWriter, | ||
| FHIR_JSON_FORMAT: StreamingFHIRWriter, | ||
| FHIR_JSON_FORMAT: StreamingFhirJsonWriter, | ||
| FHIR_NPM_FORMAT: StreamingFhirNpmWriter, | ||
| INFO_FORMAT: StreamingInfoWriter, | ||
| NL_FORMAT: StreamingNaturalLanguageWriter, | ||
| KGCL_FORMAT: StreamingKGCLWriter, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,12 @@ | |
| - Updates issue: https://github.com/INCATools/ontology-access-kit/issues/369 | ||
| - Conversion examples: https://drive.google.com/drive/folders/1lwGQ63_fedfWlGlRemq8OeZhZsvIXN01 | ||
| """ | ||
| import json | ||
| import logging | ||
| import os | ||
| import shutil | ||
| import tarfile | ||
| import tempfile | ||
| from dataclasses import dataclass | ||
| from typing import Any, Dict, List, Tuple, Union | ||
|
|
||
|
|
@@ -52,7 +57,7 @@ | |
|
|
||
|
|
||
| @dataclass | ||
| class OboGraphToFHIRConverter(DataModelConverter): | ||
| class OboGraphToFhirJsonConverter(DataModelConverter): | ||
| """Converts from OboGraph to FHIR. | ||
|
|
||
| - An ontology is mapped to a FHIR `CodeSystem <https://build.fhir.org/codesystem.html>`_. | ||
|
|
@@ -86,7 +91,7 @@ def dump( | |
| Dump an OBO Graph Document to a FHIR CodeSystem. | ||
|
|
||
| :param source: Source serialization. | ||
| :param target: Target serialization. | ||
| :param target: Target outpath. | ||
| :param kwargs: Additional keyword arguments passed to :ref:`convert`. | ||
| """ | ||
| cs = self.convert( | ||
|
|
@@ -119,11 +124,11 @@ def convert( | |
|
|
||
| To use: | ||
|
|
||
| >>> from oaklib.converters.obo_graph_to_fhir_converter import OboGraphToFHIRConverter | ||
| >>> from oaklib.converters.obo_graph_to_fhir_converter import OboGraphToFhirJsonConverter | ||
| >>> from oaklib.datamodels.obograph import GraphDocument | ||
| >>> from linkml_runtime.dumpers import json_dumper | ||
| >>> from linkml_runtime.loaders import json_loader | ||
| >>> converter = OboGraphToFHIRConverter() | ||
| >>> converter = OboGraphToFhirJsonConverter() | ||
| >>> graph = json_loader.load("tests/input/hp_test.json", target_class=GraphDocument) | ||
| >>> code_system = converter.convert(graph) | ||
| >>> print(json_dumper.dumps(code_system)) | ||
|
|
@@ -205,6 +210,7 @@ def _convert_graph( | |
| predicate_period_replacement: bool = False, | ||
| ) -> CodeSystem: | ||
| target.id = source.id | ||
| target.version = source.meta.version | ||
| edges_by_subject = index_graph_edges_by_subject(source) | ||
| logging.info(f"Converting graph to obo: {source.id}, nodes={len(source.nodes)}") | ||
| self.predicates_to_export = set() | ||
|
|
@@ -286,3 +292,71 @@ def _convert_meta(self, source: Node, concept: Concept): | |
| value=synonym.val, | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| @dataclass | ||
| class OboGraphToFhirNpmConverter(OboGraphToFhirJsonConverter): | ||
|
joeflack4 marked this conversation as resolved.
|
||
| """Converts an OBO Graph to a FHIR NPM package. | ||
|
|
||
| Plays the same role as OboGraphToFhirJsonConverter, but also packages the outpus. | ||
| """ | ||
|
|
||
| def dump( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| self, | ||
| source: GraphDocument, | ||
| target: str, | ||
| manifest_path: str, | ||
| **kwargs, | ||
| ) -> str: | ||
| """ | ||
| Dump an OBO Graph Document to a FHIR CodeSystem. | ||
|
|
||
| :param source: Source serialization. | ||
| :param target: Target directory to save the output. | ||
| :param manifest_path: Path to a manifest JSON. Required fields:'name', 'version', 'description', and 'author'. | ||
| See: https://confluence.hl7.org/display/FHIR/NPM+Package+Specification | ||
| :param kwargs: Additional keyword arguments passed to :ref:`convert`. | ||
| """ | ||
| cs = self.convert( | ||
| source, | ||
| **kwargs, | ||
| ) | ||
| cs_filename = "CodeSystem-" + kwargs["code_system_id"] + ".json" | ||
|
|
||
| outpath = os.path.join(target, cs_filename.replace(".json", ".tgz")) | ||
|
|
||
| # Create directory structure | ||
| temp_dir = tempfile.mkdtemp() | ||
| package_dir = os.path.join(temp_dir, "package") | ||
| os.mkdir(package_dir) | ||
|
|
||
| # Save FHIR resources | ||
| cs_str = json_dumper.dumps(cs, inject_type=False) | ||
| with open(os.path.join(package_dir, cs_filename), "w", encoding="UTF-8") as f: | ||
| f.write(cs_str) | ||
|
|
||
| # Save manifest package.json | ||
| shutil.copyfile(manifest_path, os.path.join(package_dir, "package.json")) | ||
|
|
||
| # Create and save .index.json | ||
| package_index = { | ||
| "index-version": 1, | ||
| "files": [ | ||
| { | ||
| "filename": cs_filename, | ||
| "resourceType": "CodeSystem", | ||
| "id": kwargs["code_system_id"], | ||
| "url": kwargs["code_system_url"], | ||
| "version": cs.version, | ||
| }, | ||
| ], | ||
| } | ||
| with open(os.path.join(package_dir, ".index.json"), "w", encoding="UTF-8") as f: | ||
| json.dump(package_index, f) | ||
|
|
||
| # Save zipfile and remove temp dir | ||
| with tarfile.open(outpath, "w:gz") as tar: | ||
| tar.add(package_dir, arcname="package") | ||
| shutil.rmtree(temp_dir) | ||
|
|
||
| return outpath | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,15 +4,15 @@ | |
|
|
||
| from linkml_runtime.dumpers import json_dumper | ||
|
|
||
| from oaklib.converters.obo_graph_to_fhir_converter import OboGraphToFHIRConverter | ||
| from oaklib.converters.obo_graph_to_fhir_converter import OboGraphToFhirJsonConverter | ||
| from oaklib.datamodels.obograph import GraphDocument | ||
| from oaklib.interfaces.obograph_interface import OboGraphInterface | ||
| from oaklib.io.streaming_writer import StreamingWriter | ||
| from oaklib.types import CURIE | ||
|
|
||
|
|
||
| @dataclass | ||
| class StreamingFHIRWriter(StreamingWriter): | ||
| class StreamingFhirJsonWriter(StreamingWriter): | ||
| """ | ||
| A writer that emits FHIR CodeSystem objects or Concept objects | ||
| """ | ||
|
|
@@ -24,10 +24,31 @@ def emit_multiple(self, entities: Iterable[CURIE], **kwargs): | |
| g = oi.extract_graph(list(entities), include_metadata=True) | ||
| gd = GraphDocument(graphs=[g]) | ||
| logging.info(f"Converting {len(g.nodes)} nodes to OBO") | ||
| converter = OboGraphToFHIRConverter() | ||
| converter = OboGraphToFhirJsonConverter() | ||
| converter.curie_converter = oi.converter | ||
| code_system = converter.convert(gd) | ||
| logging.info(f"Writing {len(code_system.concept)} Concepts") | ||
| # TODO: Should not this call OboGraphToFhirJsonConverter.dump()? | ||
| self.file.write(json_dumper.dumps(code_system)) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| else: | ||
| super().emit_multiple(entities, **kwargs) | ||
|
|
||
|
|
||
| # TODO: | ||
| @dataclass | ||
| class StreamingFhirNpmWriter(StreamingWriter): | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| """ | ||
| A writer that emits FHIR CodeSystem objects or Concept objects | ||
| """ | ||
|
|
||
| def emit_multiple(self, entities: Iterable[CURIE], **kwargs): | ||
| oi = self.ontology_interface | ||
| if isinstance(oi, OboGraphInterface): | ||
| logging.info("Extracting graph") | ||
| g = oi.extract_graph(list(entities), include_metadata=True) | ||
| gd = GraphDocument(graphs=[g]) | ||
| logging.info(f"Converting {len(g.nodes)} nodes to OBO") | ||
| converter = None | ||
| print(gd, converter) | ||
| else: | ||
| super().emit_multiple(entities, **kwargs) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| { | ||
|
joeflack4 marked this conversation as resolved.
|
||
| "name": "sequence-ontology", | ||
| "version": "0.1.0", | ||
| "canonical": "http://purl.obolibrary.org/obo/so.owl", | ||
| "title": "Sequence Ontology", | ||
| "description": "The Sequence Ontology is a set of terms and relationships used to describe the features and attributes of biological sequence.", | ||
| "homepage": "http://www.sequenceontology.org/", | ||
| "keywords": [ | ||
| "SO", | ||
| "Sequence Ontology" | ||
| ], | ||
| "author": "TIMS", | ||
| "maintainers": [ | ||
| { | ||
| "name": "Joe Flack", | ||
| "email": "jflack@jhu.edu" | ||
| }, | ||
| { | ||
| "name": "Shahim Essaid", | ||
| "email": "shahim@essaid.com" | ||
| } | ||
| ], | ||
| "license": "MIT" | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.