diff --git a/.gitignore b/.gitignore index 7bc089e..e75ca98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,12 @@ # Boilerplate /*.json +/*.owl /env/* !/env/.env.example /.idea/ /.run/ /venv/ -*/cache/* -!*/cache/.keep +cache/* __pycache__/ _archive/ _dev/ diff --git a/owl-on-fhir-1.0.0/MANIFEST.in b/owl-on-fhir-1.0.0/MANIFEST.in new file mode 100644 index 0000000..e76252b --- /dev/null +++ b/owl-on-fhir-1.0.0/MANIFEST.in @@ -0,0 +1,3 @@ +include README.md +include owl_on_fhir/robot.jar +include owl_on_fhir/convert_owl_ncbo2owl.pl diff --git a/owl-on-fhir-1.0.0/PKG-INFO b/owl-on-fhir-1.0.0/PKG-INFO new file mode 100644 index 0000000..599cf23 --- /dev/null +++ b/owl-on-fhir-1.0.0/PKG-INFO @@ -0,0 +1,60 @@ +Metadata-Version: 2.1 +Name: owl-on-fhir +Version: 1.0.0 +Summary: Python-based non-minimalistic OWL to FHIR converter. +Home-page: https://github.com/HOT-Ecosystem/owl-on-fhir/ +Author: Joe Flack +Author-email: jflack@jhu.edu +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=3.9.0 +Description-Content-Type: text/markdown + + +# OWL-on-FHIR +![owl-on-fhir logo](https://github.com/hot-ecosystem/owl-on-fhir/blob/master/docs/owl-on-fhir%20logo%20v2.png?raw=true "OWL on FHIR") + +A Python-based non-minimalistic OWL to FHIR converter. + +## Installation +`pip install owl-on-fhir` + +## Usage +### Syntax +`owl-on-fhir --input-path-or-url FILENAME --code-system-id ID --native-uri-stems "URL_1,...,URL_N" --code-system-url URL [NON_REQUIRED_OPTIONS]` + +### Examples +`owl-on-fhir --input-path-or-url comploinc.owl --code-system-id comploinc --native-uri-stems "https://loinc.org/" --code-system-url https://github.com/loinc/comp-loinc/releases/latest/download/merged_reasoned_loinc.owl` + +### CLI options +| Short Flag | Long Flag | Required | Description | +|:-----------|:----------|:------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -h | --help | | Show this help message and exit. | +| -i | --input-path-or-url | True | URL or path to OWL file to convert. | +| -s | --code-system-id | True | For `fhirjson` only. The code system ID to use for identification on the server uploaded to. See: https://hl7.org/fhir/resource-definitions.html#Resource.id | +| -S | --code-system-url | True | For `fhirjson` only. Canonical URL for the code system. See: https://hl7.org/fhir/codesystem-definitions.html#CodeSystem.url | +| -u | --native-uri-stems | True | A comma-separated list of URI stems that will be used to determine whether a concept is native to the CodeSystem. For example, for OMIM, the following URI stems are native: https://omim.org/entry/,https://omim.org/phenotypicSeries/PS". As of 2023-01-15, there is still a bug in the Obographs spec and/or `robot` where certain nodes are not being converted. This converter adds back the nodes, but to know which ones belong to the CodeSystem itself and are not foreign concepts, this parameter is necessary. OAK also makes use of this parameter. See also: https://github.com/geneontology/obographs/issues/90 | +| -o | --out-dir | False | The directory where results should be saved. | +| -n | --out-filename | False | Filename for the primary file converted, e.g. CodeSystem. | +| -p | --include-only-critical-predicates | False | If present, includes only critical predicates (is_a/parent) rather than all predicates in CodeSystem.property and CodeSystem.concept.property. | +| -t | --intermediary-type | False | Which type of intermediary to use? First, we convert OWL to that intermediary format, and then we convert that to FHIR. | +| -c | --use-cached-intermediaries | False | Use cached intermediaries if they exist? | +| -r | --retain-intermediaries | False | Retain intermediary files created during conversion process (e.g. Obograph JSON)? | +| -I | --convert-intermediaries-only | False | Convert intermediaries only? | +| -d | --dev-oak-path | False | If you want to use a local development version of OAK, specify the path to the OAK directory here. Must be used with --dev-oak-interpreter-path. | +| -D | --dev-oak-interpreter-path | False | If you want to use a local development version of OAK, specify the path to the Python interpreter where its dependencies are installed (i.e. its virtual environment). Must be used with --dev-oak-path. | + +## More +### Alternative OWL to FHIR converters +### FHIR-OWL +https://github.com/aehrc/fhir-owl +Takes a minimalistic approach. Can convert top-level CodeSystem properties, concepts, and also supports some predicates, such as synonyms. Uses Java `owl-api`. + +### Ontology Access Kit (OAK) +https://github.com/INCATools/ontology-access-kit/ +OWL-on-FHIR is largely a wrapper around [Ontology Access Kit](https://github.com/INCATools/ontology-access-kit/) (OAK)'s FHIR converter. It adds some extra automation such as an intermediary conversion to Obographs JSON, which is currently a required input for OAK for most ontologies, given the current state of development. diff --git a/owl-on-fhir-1.0.0/README.md b/owl-on-fhir-1.0.0/README.md new file mode 100644 index 0000000..6ea25c4 --- /dev/null +++ b/owl-on-fhir-1.0.0/README.md @@ -0,0 +1,42 @@ +# OWL-on-FHIR +![owl-on-fhir logo](https://github.com/hot-ecosystem/owl-on-fhir/blob/master/docs/owl-on-fhir%20logo%20v2.png?raw=true "OWL on FHIR") + +A Python-based non-minimalistic OWL to FHIR converter. + +## Installation +`pip install owl-on-fhir` + +## Usage +### Syntax +`owl-on-fhir --input-path-or-url FILENAME --code-system-id ID --native-uri-stems "URL_1,...,URL_N" --code-system-url URL [NON_REQUIRED_OPTIONS]` + +### Examples +`owl-on-fhir --input-path-or-url comploinc.owl --code-system-id comploinc --native-uri-stems "https://loinc.org/" --code-system-url https://github.com/loinc/comp-loinc/releases/latest/download/merged_reasoned_loinc.owl` + +### CLI options +| Short Flag | Long Flag | Required | Description | +|:-----------|:----------|:------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -h | --help | | Show this help message and exit. | +| -i | --input-path-or-url | True | URL or path to OWL file to convert. | +| -s | --code-system-id | True | For `fhirjson` only. The code system ID to use for identification on the server uploaded to. See: https://hl7.org/fhir/resource-definitions.html#Resource.id | +| -S | --code-system-url | True | For `fhirjson` only. Canonical URL for the code system. See: https://hl7.org/fhir/codesystem-definitions.html#CodeSystem.url | +| -u | --native-uri-stems | True | A comma-separated list of URI stems that will be used to determine whether a concept is native to the CodeSystem. For example, for OMIM, the following URI stems are native: https://omim.org/entry/,https://omim.org/phenotypicSeries/PS". As of 2023-01-15, there is still a bug in the Obographs spec and/or `robot` where certain nodes are not being converted. This converter adds back the nodes, but to know which ones belong to the CodeSystem itself and are not foreign concepts, this parameter is necessary. OAK also makes use of this parameter. See also: https://github.com/geneontology/obographs/issues/90 | +| -o | --out-dir | False | The directory where results should be saved. | +| -n | --out-filename | False | Filename for the primary file converted, e.g. CodeSystem. | +| -p | --include-only-critical-predicates | False | If present, includes only critical predicates (is_a/parent) rather than all predicates in CodeSystem.property and CodeSystem.concept.property. | +| -t | --intermediary-type | False | Which type of intermediary to use? First, we convert OWL to that intermediary format, and then we convert that to FHIR. | +| -c | --use-cached-intermediaries | False | Use cached intermediaries if they exist? | +| -r | --retain-intermediaries | False | Retain intermediary files created during conversion process (e.g. Obograph JSON)? | +| -I | --convert-intermediaries-only | False | Convert intermediaries only? | +| -d | --dev-oak-path | False | If you want to use a local development version of OAK, specify the path to the OAK directory here. Must be used with --dev-oak-interpreter-path. | +| -D | --dev-oak-interpreter-path | False | If you want to use a local development version of OAK, specify the path to the Python interpreter where its dependencies are installed (i.e. its virtual environment). Must be used with --dev-oak-path. | + +## More +### Alternative OWL to FHIR converters +### FHIR-OWL +https://github.com/aehrc/fhir-owl +Takes a minimalistic approach. Can convert top-level CodeSystem properties, concepts, and also supports some predicates, such as synonyms. Uses Java `owl-api`. + +### Ontology Access Kit (OAK) +https://github.com/INCATools/ontology-access-kit/ +OWL-on-FHIR is largely a wrapper around [Ontology Access Kit](https://github.com/INCATools/ontology-access-kit/) (OAK)'s FHIR converter. It adds some extra automation such as an intermediary conversion to Obographs JSON, which is currently a required input for OAK for most ontologies, given the current state of development. diff --git a/owl-on-fhir-1.0.0/owl_on_fhir/__init__.py b/owl-on-fhir-1.0.0/owl_on_fhir/__init__.py new file mode 100644 index 0000000..e8e0426 --- /dev/null +++ b/owl-on-fhir-1.0.0/owl_on_fhir/__init__.py @@ -0,0 +1,6 @@ +"""OWL-on-FHIR""" +from owl_on_fhir.__main__ import cli + + +if __name__ == '__main__': + cli() diff --git a/owl-on-fhir-1.0.0/owl_on_fhir/__main__.py b/owl-on-fhir-1.0.0/owl_on_fhir/__main__.py new file mode 100644 index 0000000..932b147 --- /dev/null +++ b/owl-on-fhir-1.0.0/owl_on_fhir/__main__.py @@ -0,0 +1,326 @@ +"""Convert OWL to FHIR""" +import json +import os +import shutil +import subprocess +from argparse import ArgumentParser +from typing import Dict, List + +import curies +import requests +from linkml_runtime.loaders import json_loader +from oaklib.converters.obo_graph_to_fhir_converter import OboGraphToFHIRConverter +from oaklib.datamodels.obograph import GraphDocument +from oaklib.interfaces.basic_ontology_interface import get_default_prefix_map +from urllib.parse import urlparse + + +# Vars +# - Vars: Static +SRC_DIR = os.path.dirname(os.path.realpath(__file__)) +BIN_DIR = SRC_DIR +PROJECT_DIR = os.path.join(SRC_DIR, '..') +CACHE_DIR = os.path.join(PROJECT_DIR, 'cache') +ROBOT_PATH = os.path.join(BIN_DIR, 'robot') +INTERMEDIARY_TYPES = ['obographs', 'semsql'] + + +# Functions +def _run_shell_command(command: str, cwd_outdir: str = None) -> subprocess.CompletedProcess: + """Runs a command in the shell, and handles some common errors""" + args = command.split(' ') + if cwd_outdir: + result = subprocess.run(args, capture_output=True, text=True, cwd=cwd_outdir) + else: + result = subprocess.run(args, capture_output=True, text=True) + stderr, stdout = result.stderr, result.stdout + if stderr and 'Unable to create a system terminal, creating a dumb terminal' not in stderr: + raise RuntimeError(stderr) + elif stdout and 'error' in stdout or 'ERROR' in stdout: + raise RuntimeError(stdout) + elif stdout and 'make: Nothing to be done' in stdout: + raise RuntimeError(stdout) + elif stdout and ".db' is up to date" in stdout: + raise FileExistsError(stdout) + return result + + +def _preprocess_rxnorm(path: str) -> str: + """Preprocess RXNORM + If detects a Bioportal rxnorm TTL, makes some modifications to standardize it to work with OAK, etc. + See: https://github.com/INCATools/ontology-access-kit/issues/427 + If using --use-cached-intermediaries or --retain-intermediaries, those are used for SemSQL or Obographs + intermediaries, but not the intermediary created by this function. + """ + if '-fixed' in path: + return path + print('INFO: RXNORM.ttl from Bioportal detected. Doing some preprocessing.') + outpath = path.replace(".ttl", "-fixed.ttl") + _run_shell_command(f'cp {path} {outpath}') + command_str = f'perl -i {os.path.join(BIN_DIR, "convert_owl_ncbo2owl.pl")} {outpath}' + _run_shell_command(command_str) + return outpath + + +def download(url: str, path: str, save_to_cache=False, download_if_cached=True): + """Download file at url to local path + + :param download_if_cached: If True and file at `path` already exists, download anyway.""" + _dir = os.path.dirname(path) + if not os.path.exists(_dir): + os.makedirs(_dir) + if download_if_cached or not os.path.exists(path): + with open(path, 'wb') as f: + response = requests.get(url, verify=False) + f.write(response.content) + if save_to_cache: + cache_path = os.path.join(CACHE_DIR, os.path.basename(path)) + shutil.copy(path, cache_path) + + +# todo: owl_to_semsql: this may need similar updates to caching that were done for obographs on 2023/04/15 +def owl_to_semsql(inpath: str, use_cache=False) -> str: + """Converts OWL (or RDF, I think) to a SemanticSQL sqlite DB. + Docs: https://incatools.github.io/ontology-access-kit/intro/tutorial07.html?highlight=semsql + - Had to change "--rm -ti" --> "--rm" + todo: consider using linkml/semantic-sql image which is more up-to-date instead + https://github.com/INCATools/semantic-sql + docker run -v $PWD:/work -w /work -ti linkml/semantic-sql semsql make foo.db + todo: RDF also supported? not just OWL? (TTL not supported) + """ + # Vars + _dir = os.path.dirname(inpath) + output_filename = os.path.basename(inpath).replace('.owl', '.db').replace('.rdf', '.db').replace('.ttl', '.db') + outpath = os.path.join(_dir, output_filename) + command_str = f'docker run -w /work -v {_dir}:/work --rm obolibrary/odkfull:dev semsql make {output_filename}' + + # Convert + if use_cache and os.path.exists(outpath): + return outpath + try: + _run_shell_command(command_str, cwd_outdir=_dir) + except FileExistsError: + if not use_cache: + os.remove(outpath) + _run_shell_command(command_str, cwd_outdir=_dir) + return outpath + + +def owl_to_obograph(inpath: str, out_dir: str, use_cache=False, cache_output=False) -> str: + """Convert OWL to Obograph + todo: TTL and RDF also supported? not just OWL?""" + # Vars + infile = os.path.basename(inpath) + cache_path = os.path.join(CACHE_DIR, infile + '.obographs.json') + outpath = os.path.join(out_dir, infile + '.obographs.json') + command = f'java -jar {ROBOT_PATH}.jar convert -i {inpath} -o {outpath} --format json' + + # Convert + if not os.path.exists(out_dir): + os.makedirs(out_dir) + if use_cache and os.path.exists(cache_path): + return cache_path + # todo: Switch back to `bioontologies` when complete: https://github.com/biopragmatics/bioontologies/issues/9 + # from bioontologies import robot + # parse_results: robot.ParseResults = robot.convert_to_obograph_local(inpath) + # graph = parse_results.graph_document.graphs[0] + _run_shell_command(command) + + if cache_output: + shutil.copy(outpath, cache_path) + + return outpath + + +# todo: This doesn't work until following Obographs issues solved. Moved to semsql intermediary for now. +# - https://github.com/linkml/linkml/issues/1156 +# - https://github.com/ontodev/robot/issues/1079 +# - https://github.com/geneontology/obographs/issues/89 +def obograph_to_fhir( + inpath: str, out_dir: str, out_filename: str = None, code_system_id: str = None, code_system_url: str = None, + include_all_predicates=True, native_uri_stems: List[str] = None, dev_oak_path: str = None, + dev_oak_interpreter_path: str = None +) -> str: + """Convert Obograph to FHIR""" + out_path = os.path.join(out_dir, out_filename) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + local_dev_exists: bool = (os.path.exists(dev_oak_path) if dev_oak_path else False) and ( + os.path.exists(dev_oak_interpreter_path) if dev_oak_interpreter_path else False) + native_uri_stems_str = '"' + ','.join(native_uri_stems) + '"' if native_uri_stems else None + if dev_oak_path and local_dev_exists: # Params last updated: 2023/01/15 + dev_oak_cli_path = os.path.join(dev_oak_path, 'src', 'oaklib', 'cli.py') + command_str = \ + f'{dev_oak_interpreter_path} {dev_oak_cli_path} -i {inpath} dump -o {out_path} -O fhirjson' + \ + ' --include-all-predicates' if include_all_predicates else '' + \ + f' --code-system-id {code_system_id}' if code_system_id else '' + \ + f' --code-system-url {code_system_url}' if code_system_url else '' + \ + f' --native-uri-stems {native_uri_stems_str}' if native_uri_stems_str else '' + _run_shell_command(command_str) + + elif dev_oak_path and not local_dev_exists: + print('Warning: Tried to use local dev OAK, but one of paths does not exist. Using installed OAK release.') + else: + converter = OboGraphToFHIRConverter() + converter.curie_converter = curies.Converter.from_prefix_map(get_default_prefix_map()) + gd: GraphDocument = json_loader.load(str(inpath), target_class=GraphDocument) + converter.dump( + gd, + out_path, + code_system_id=code_system_id, + code_system_url=code_system_url, + include_all_predicates=include_all_predicates, + native_uri_stems=native_uri_stems) + # TODO: add these params once supported: use_curies_native_concepts, use_curies_foreign_concepts + # converter.dump( + # gd, out_path, code_system_id='', code_system_url='', include_all_predicates=include_all_predicates, + # native_uri_stems=native_uri_stems, use_curies_native_concepts=False, use_curies_foreign_concepts=True) + return out_path + + +# todo: add local dev oak params to this and abstract a general 'run oak' func for this and obographs_to_fhir +def semsql_to_fhir(inpath: str, out_dir: str, out_filename: str = None, include_all_predicates=False) -> str: + """Convert SemanticSQL sqlite DB to FHIR""" + # todo: any way to do this using Python API? + # todo: do I need some way of supplying prefix_map? check: are outputs all URIs? + # converter.curie_converter = curies.Converter.from_prefix_map(get_default_prefix_map()) + out_path = os.path.join(out_dir, out_filename) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + preds_flag = ' --include-all-predicates' if include_all_predicates else '' + command_str = f'runoak -i sqlite:{inpath} dump -o {out_path} -O fhirjson{preds_flag}' + _run_shell_command(command_str) + return out_path # todo: When OAK changes to save multiple files, return out_dir + + +def owl_to_fhir( + input_path_or_url: str, out_dir: str = None, out_filename: str = None, include_only_critical_predicates=False, + retain_intermediaries=False, intermediary_type=['obographs', 'semsql'][0], use_cached_intermediaries=False, + intermediary_outdir: str = None, convert_intermediaries_only=False, native_uri_stems: List[str] = None, + code_system_id: str = None, code_system_url: str = None, dev_oak_path: str = None, + dev_oak_interpreter_path: str = None +) -> str: + """Run conversion""" + include_all_predicates = not include_only_critical_predicates + + if not os.path.exists(CACHE_DIR): + os.makedirs(CACHE_DIR) + + # Download if necessary & determine outpaths + # todo: this section w/ urls, names, and IDs has too many possible branches and is error prone. simplify by + # updating CLI params to require url or path separately, and maybe require codesystem id + input_path = input_path_or_url + url = None + maybe_url = urlparse(input_path_or_url) + out_dir = out_dir if out_dir else os.getcwd() + if out_dir.startswith('~'): + out_dir = os.path.expanduser('~/Desktop') + if maybe_url.scheme and maybe_url.netloc: + url = input_path_or_url + if url: + download_path = os.path.join(out_dir, out_filename.replace('.json', '.owl')) + input_path = download_path + download(url, download_path, use_cached_intermediaries) + if not out_filename: + if not code_system_id: + code_system_id = '.'.join(os.path.basename(input_path).split('.')[0:-1]) # removes file extension + out_filename = f'CodeSystem-{code_system_id}.json' + if not code_system_id and out_filename and out_filename.startswith('CodeSystem-'): + code_system_id = out_filename.split('-')[1].split('.')[0] + out_dir = os.path.realpath(out_dir if out_dir else os.path.dirname(input_path)) + intermediary_outdir = intermediary_outdir if intermediary_outdir else out_dir + + # Preprocessing: Special cases + if 'rxnorm' in input_path.lower() or 'rxnorm' in out_filename.lower(): + input_path = _preprocess_rxnorm(input_path) + + # Convert + if intermediary_type == 'obographs' or input_path.endswith('.ttl'): # semsql only supports .owl + intermediary_path = owl_to_obograph(input_path, out_dir, use_cached_intermediaries, use_cached_intermediaries) + obograph_to_fhir( + inpath=intermediary_path, out_dir=intermediary_outdir, out_filename=out_filename, + code_system_id=code_system_id, code_system_url=code_system_url, native_uri_stems=native_uri_stems, + include_all_predicates=include_all_predicates, dev_oak_path=dev_oak_path, + dev_oak_interpreter_path=dev_oak_interpreter_path) + else: # semsql + # todo: owl_to_semsql: this may need similar updates to caching that were done for obographs on 2023/04/15 + intermediary_path = owl_to_semsql(input_path, use_cached_intermediaries) + semsql_to_fhir( + inpath=intermediary_path, out_dir=intermediary_outdir, out_filename=out_filename, + include_all_predicates=include_all_predicates) + if convert_intermediaries_only: + return intermediary_path + + # Cleanup + indir = os.path.dirname(input_path) + template_db_path = os.path.join(indir, '.template.db') + if os.path.exists(template_db_path): + os.remove(template_db_path) + if not retain_intermediaries: + # noinspection PyUnboundLocalVariable + os.remove(intermediary_path) + if intermediary_type == 'semsql': + # More semsql intermediaries + intermediary_filename = os.path.basename(intermediary_path) + os.remove(os.path.join(indir, intermediary_filename.replace('.db', '-relation-graph.tsv.gz'))) + return os.path.join(out_dir, out_filename) + + +def cli(): + """Command line interface.""" + parser = ArgumentParser(prog='OWL on FHIR', description='Python-based non-minimalistic OWL to FHIR converter.') + parser.add_argument('-i', '--input-path-or-url', required=True, help='URL or path to OWL file to convert.') + parser.add_argument( + '-s', '--code-system-id', required=True, default=False, + help="For `fhirjson` only. The code system ID to use for identification on the server uploaded to. " + "See: https://hl7.org/fhir/resource-definitions.html#Resource.id") + parser.add_argument( + '-S', '--code-system-url', required=True, default=False, + help="For `fhirjson` only. Canonical URL for the code system. " + "See: https://hl7.org/fhir/codesystem-definitions.html#CodeSystem.url") + parser.add_argument( + '-u', '--native-uri-stems', required=True, nargs='+', + help='A comma-separated list of URI stems that will be used to determine whether a concept is native to ' + 'the CodeSystem. For example, for OMIM, the following URI stems are native: ' + 'https://omim.org/entry/,https://omim.org/phenotypicSeries/PS". ' + 'As of 2023-01-15, there is still a bug in the Obographs spec and/or `robot` where certain nodes are not' + ' being converted. This converter adds back the nodes, but to know which ones belong to the CodeSystem ' + 'itself and are not foreign concepts, this parameter is necessary. OAK also makes use of this parameter. ' + 'See also: https://github.com/geneontology/obographs/issues/90') + parser.add_argument( + '-o', '--out-dir', required=False, help='The directory where results should be saved.') + parser.add_argument( + '-n', '--out-filename', required=False, help='Filename for the primary file converted, e.g. CodeSystem.') + parser.add_argument( + '-p', '--include-only-critical-predicates', action='store_true', required=False, default=False, + help='If present, includes only critical predicates (is_a/parent) rather than all predicates in ' + 'CodeSystem.property and CodeSystem.concept.property.') + parser.add_argument( + '-t', '--intermediary-type', choices=INTERMEDIARY_TYPES, default='obographs', required=False, + help='Which type of intermediary to use? First, we convert OWL to that intermediary format, and then we ' + 'convert that to FHIR.') + parser.add_argument( + '-c', '--use-cached-intermediaries', action='store_true', required=False, default=False, + help='Use cached intermediaries if they exist? Also will save intermediaries to owl-on-fhir\'s cache/ dir.') + parser.add_argument( + '-r', '--retain-intermediaries', action='store_true', default=False, required=False, + help='Retain intermediary files created during conversion process (e.g. Obograph JSON)?') + parser.add_argument( + '-I', '--convert-intermediaries-only', action='store_true', default=False, required=False, + help='Convert intermediaries only?') + parser.add_argument( + '-d', '--dev-oak-path', default=False, required=False, + help='If you want to use a local development version of OAK, specify the path to the OAK directory here. ' + 'Must be used with --dev-oak-interpreter-path.') + parser.add_argument( + '-D', '--dev-oak-interpreter-path', default=False, required=False, + help='If you want to use a local development version of OAK, specify the path to the Python interpreter where ' + 'its dependencies are installed (i.e. its virtual environment). Must be used with --dev-oak-path.') + + d: Dict = vars(parser.parse_args()) + owl_to_fhir(**d) + + +# Execution +if __name__ == '__main__': + cli() diff --git a/owl-on-fhir-1.0.0/owl_on_fhir/convert_owl_ncbo2owl.pl b/owl-on-fhir-1.0.0/owl_on_fhir/convert_owl_ncbo2owl.pl new file mode 100644 index 0000000..0acfb32 --- /dev/null +++ b/owl-on-fhir-1.0.0/owl_on_fhir/convert_owl_ncbo2owl.pl @@ -0,0 +1,8 @@ +#!/usr/bin/perl -np +# See: https://github.com/INCATools/ontology-access-kit/issues/427 +# See: https://github.com/INCATools/semantic-sql/blob/main/utils/ncbo2owl.pl +s@skos:prefLabel @rdfs:label @; +s@ @rdfs:subClassOf @; +s@umls:cui """(\w+)"""\^\^xsd:string@skos:exactMatch umls:$1@; +s@umls:cui """(\w+)"""\^\^xsd:string@skos:exactMatch umls:$1@; +s@() ()@rdfs:subClassOf [a owl:Restriction; owl:onProperty $1; owl:someValuesFrom $3]@; diff --git a/owl-on-fhir-1.0.0/owl_on_fhir/favorites.py b/owl-on-fhir-1.0.0/owl_on_fhir/favorites.py new file mode 100644 index 0000000..4c6408a --- /dev/null +++ b/owl-on-fhir-1.0.0/owl_on_fhir/favorites.py @@ -0,0 +1,118 @@ +"""Convert favorite code systems""" +import os +from argparse import ArgumentParser +from collections import OrderedDict +from typing import Dict + +from owl_on_fhir.__main__ import PROJECT_DIR, owl_to_fhir + + +# Vars +DESCRIPTION = \ + 'If present, will run all favorite ontologies found in pre-baked config variable `FAVORITE_ONTOLOGIES` in ' \ + '`owl_on_fhir/__main__.py`. . If using `--favorites`, the other CLI flags are not relevant. Instead, you '\ + 'can customize by editing `FAVORITE_DEFAULTS` in `owl_on_fhir/__main__.py` if you are running a clone of '\ + 'the project. Presently, the configure these favorites is not possible if running the installation from pip / PyPi.' +# - Vars: Config +# TODO: owl-on-fhir-content needs some configuration / setup instructions, or a git submodule +OWL_ON_FHIR_CONTENT_REPO_PATH = os.path.join(PROJECT_DIR, '..', 'owl-on-fhir-content') +# todo: consider 1+ changes: (i) external config JSON / env vars, (ii) accept overrides from CLI +FAVORITE_DEFAULTS = { + 'out_dir': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'output'), + 'intermediary_outdir': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'input'), + 'include_all_predicates': True, + 'intermediary_type': 'obographs', + 'use_cached_intermediaries': True, + 'retain_intermediaries': True, + 'convert_intermediaries_only': False, +} +FAVORITE_ONTOLOGIES = OrderedDict({ + 'mondo': { + 'download_url': 'https://github.com/monarch-initiative/mondo/releases/latest/download/mondo.owl', + 'code_system_url': 'http://purl.obolibrary.org/obo/mondo.owl', + 'input_path': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'input', 'mondo.owl'), + 'code_system_id': 'mondo', + 'native_uri_stems': ['http://purl.obolibrary.org/obo/MONDO_'], + }, + 'comp-loinc': { + 'download_url': 'https://github.com/loinc/comp-loinc/releases/latest/download/merged_reasoned_loinc.owl', + 'code_system_url': 'https://github.com/loinc/comp-loinc/releases/latest/download/merged_reasoned_loinc.owl', + 'input_path': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'input', 'comploinc.owl'), + 'code_system_id': 'comp-loinc', + 'native_uri_stems': ['https://loinc.org/'], + }, + 'HPO': { + 'download_url': 'https://github.com/obophenotype/human-phenotype-ontology/releases/latest/download/hp-full.owl', + 'code_system_url': 'http://purl.obolibrary.org/obo/hp.owl', + 'input_path': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'input', 'hpo.owl'), + 'code_system_id': 'HPO', + 'native_uri_stems': ['http://purl.obolibrary.org/obo/HP_'], + }, + 'rxnorm': { + 'download_url': 'https://data.bioontology.org/' + 'ontologies/RXNORM/submissions/23/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb', + 'code_system_url': 'http://purl.bioontology.org/ontology/RXNORM', + 'input_path': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'input', 'RXNORM.ttl'), + 'code_system_id': 'rxnorm', + 'native_uri_stems': ['http://purl.bioontology.org/ontology/RXNORM/'], + }, + 'sequence-ontology': { + 'download_url': 'https://data.bioontology.org/' + 'ontologies/SO/submissions/304/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb', + 'code_system_url': 'http://purl.bioontology.org/ontology/SO', + 'input_path': os.path.join(OWL_ON_FHIR_CONTENT_REPO_PATH, 'input', 'so.owl'), + 'code_system_id': 'sequence-ontology', + 'native_uri_stems': ['http://purl.obolibrary.org/obo/SO_'], + }, +}) + + +def _run_favorites( + use_cached_intermediaries: bool = None, retain_intermediaries: bool = None, include_all_predicates: bool = None, + intermediary_type: str = None, out_dir: str = None, intermediary_outdir: str = None, + convert_intermediaries_only: bool = None, dev_oak_path: str = None, dev_oak_interpreter_path: str = None, + favorites: Dict = FAVORITE_ONTOLOGIES +): + """Convert favorite ontologies""" + kwargs = {k: v for k, v in locals().items() if v is not None and not k.startswith('__') and k != 'favorites'} + fails = [] + successes = [] + n = len(favorites) + i = 0 + for d in favorites.values(): + i += 1 + print('Converting {} of {}: {}'.format(i, n, d['code_system_id'])) + try: + owl_to_fhir( + out_filename=f'CodeSystem-{d["code_system_id"]}.json', + input_path_or_url=d['input_path'] if d['input_path'] else d['download_url'], **kwargs) + successes.append(d['id']) + except Exception as e: + fails.append(d['code_system_id']) + print('Failed to convert {}: \n{}'.format(d['code_system_id'], e)) + print('SUMMARY') + print('Successes: ' + str(successes)) + print('Failures: ' + str(fails)) + + +def favs_cli(): + """Command line interface.""" + parser = ArgumentParser(prog='OWL on FHIR: Favorites', description=DESCRIPTION) + parser.add_argument( + '-d', '--dev-oak-path', default=False, required=False, + help='If you want to use a local development version of OAK, specify the path to the OAK directory here. ' + 'Must be used with --dev-oak-interpreter-path.') + parser.add_argument( + '-D', '--dev-oak-interpreter-path', default=False, required=False, + help='If you want to use a local development version of OAK, specify the path to the Python interpreter where ' + 'its dependencies are installed (i.e. its virtual environment). Must be used with --dev-oak-path.') + + d: Dict = vars(parser.parse_args()) + _run_favorites( + dev_oak_path=d['dev_oak_path'], dev_oak_interpreter_path=d['dev_oak_interpreter_path'], + **{**FAVORITE_DEFAULTS, **{'favorites': FAVORITE_ONTOLOGIES}}) + + +# Execution +if __name__ == '__main__': + favs_cli() diff --git a/owl-on-fhir-1.0.0/owl_on_fhir/robot.jar b/owl-on-fhir-1.0.0/owl_on_fhir/robot.jar new file mode 100644 index 0000000..4580c09 Binary files /dev/null and b/owl-on-fhir-1.0.0/owl_on_fhir/robot.jar differ diff --git a/owl-on-fhir-1.0.0/setup.cfg b/owl-on-fhir-1.0.0/setup.cfg new file mode 100644 index 0000000..8bfd5a1 --- /dev/null +++ b/owl-on-fhir-1.0.0/setup.cfg @@ -0,0 +1,4 @@ +[egg_info] +tag_build = +tag_date = 0 + diff --git a/owl-on-fhir-1.0.0/setup.py b/owl-on-fhir-1.0.0/setup.py new file mode 100644 index 0000000..dc6cd52 --- /dev/null +++ b/owl-on-fhir-1.0.0/setup.py @@ -0,0 +1,110 @@ +"""Setup for packaging""" +import io +import os +import sys +from setuptools import find_packages, setup, Command +from shutil import rmtree + + +PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) + +# Package meta-data. +NAME = 'owl-on-fhir' +DESCRIPTION = 'Python-based non-minimalistic OWL to FHIR converter.' +URL = 'https://github.com/HOT-Ecosystem/owl-on-fhir/' +EMAIL = 'jflack@jhu.edu' +AUTHOR = 'Joe Flack' +REQUIRES_PYTHON = '>=3.9.0' +VERSION = '1.0.0' + +# Requirements +REQUIRED = [ + 'bioontologies', + 'oaklib>=0.5.1', + 'requests', +] + +# Description +with io.open(os.path.join(PROJECT_ROOT, 'README.md'), encoding='utf-8') as f: + long_description = '\n' + f.read() + + +# As of 3.5 I believe, this doesn't work. Use `make pypi` and `make pypi-test`, which use twine. +class UploadCommand(Command): + """Support setup.py upload.""" + + description = 'Build and publish the package.' + user_options = [] + + @staticmethod + def status(s): + """Prints things in bold.""" + print('\033[1m{0}\033[0m'.format(s)) + + def initialize_options(self): + """Init options""" + pass + + def finalize_options(self): + """Finalize options""" + pass + + def run(self): + """Run upload""" + self.status('Removing previous builds…') + dist_dir = os.path.join(PROJECT_ROOT, 'dist') + if os.path.exists(dist_dir): + rmtree(dist_dir) + self.status('Building Source and Wheel (universal) distribution…') + os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + self.status('Uploading the package to PyPI via Twine…') + os.system('twine upload dist/*') + self.status('Pushing git tags…') + os.system('git tag v{0}'.format(VERSION)) + os.system('git push --tags') + sys.exit() + + +setup( + name=NAME, + version=VERSION, + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=EMAIL, + python_requires=REQUIRES_PYTHON, + url=URL, + packages=find_packages(exclude=('test',)), + package_data={ + 'owl_on_fhir': [ + 'owl_on_fhir/robot.jar', + 'owl_on_fhir/convert_owl_ncbo2owl.pl', + ] + }, + install_requires=REQUIRED, + # extras_require=EXTRAS, + include_package_data=True, + # license='MIT', # todo: add LICENSE.md from GitHub and add license + classifiers=[ + # todo: does this really qualify? + # Trove classifiers + # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy' + ], + # $ setup.py publish support. + cmdclass={ + 'upload': UploadCommand, + }, + entry_points={ + 'console_scripts': [ + 'owl-on-fhir = owl_on_fhir.__main__:cli' + ] + }, +) diff --git a/owl_on_fhir/__main__.py b/owl_on_fhir/__main__.py index dbb3a0d..932b147 100644 --- a/owl_on_fhir/__main__.py +++ b/owl_on_fhir/__main__.py @@ -1,6 +1,7 @@ """Convert OWL to FHIR""" import json import os +import shutil import subprocess from argparse import ArgumentParser from typing import Dict, List @@ -61,7 +62,7 @@ def _preprocess_rxnorm(path: str) -> str: return outpath -def download(url: str, path: str, download_if_cached=True): +def download(url: str, path: str, save_to_cache=False, download_if_cached=True): """Download file at url to local path :param download_if_cached: If True and file at `path` already exists, download anyway.""" @@ -72,8 +73,12 @@ def download(url: str, path: str, download_if_cached=True): with open(path, 'wb') as f: response = requests.get(url, verify=False) f.write(response.content) + if save_to_cache: + cache_path = os.path.join(CACHE_DIR, os.path.basename(path)) + shutil.copy(path, cache_path) +# todo: owl_to_semsql: this may need similar updates to caching that were done for obographs on 2023/04/15 def owl_to_semsql(inpath: str, use_cache=False) -> str: """Converts OWL (or RDF, I think) to a SemanticSQL sqlite DB. Docs: https://incatools.github.io/ontology-access-kit/intro/tutorial07.html?highlight=semsql @@ -101,46 +106,28 @@ def owl_to_semsql(inpath: str, use_cache=False) -> str: return outpath -def owl_to_obograph(inpath: str, native_uri_stems: List[str] = None, use_cache=False) -> str: +def owl_to_obograph(inpath: str, out_dir: str, use_cache=False, cache_output=False) -> str: """Convert OWL to Obograph - # todo: TTL and RDF also supported? not just OWL?""" + todo: TTL and RDF also supported? not just OWL?""" # Vars - outpath = os.path.join(CACHE_DIR, inpath + '.obographs.json') - outdir = os.path.realpath(os.path.dirname(outpath)) + infile = os.path.basename(inpath) + cache_path = os.path.join(CACHE_DIR, infile + '.obographs.json') + outpath = os.path.join(out_dir, infile + '.obographs.json') command = f'java -jar {ROBOT_PATH}.jar convert -i {inpath} -o {outpath} --format json' # Convert - if not os.path.exists(outdir): - os.makedirs(outdir) - if use_cache and os.path.exists(outpath): - return outpath + if not os.path.exists(out_dir): + os.makedirs(out_dir) + if use_cache and os.path.exists(cache_path): + return cache_path # todo: Switch back to `bioontologies` when complete: https://github.com/biopragmatics/bioontologies/issues/9 # from bioontologies import robot # parse_results: robot.ParseResults = robot.convert_to_obograph_local(inpath) # graph = parse_results.graph_document.graphs[0] _run_shell_command(command) - # Patch missing roots / etc issue (until resolved: https://github.com/ontodev/robot/issues/1082) - if native_uri_stems: - with open(outpath, 'r') as f: - data = json.load(f) - nodes = data['graphs'][0]['nodes'] - node_ids = set([node['id'] for node in nodes]) - edges = data['graphs'][0]['edges'] - # edges = [x for x in edges if x['pred'] in missing_nodes_from_important_edge_preds] - edge_subs = set([edge['sub'] for edge in edges]) - edge_objs = set([edge['obj'] for edge in edges]) - edge_ids = edge_subs.union(edge_objs) - missing = set([x for x in edge_ids if x not in node_ids]) # all missing - missing = [x for x in missing if any([x.startswith(y) for y in native_uri_stems])] # filter - - if missing: - print(f'INFO: The following nodes were found in Obographs edges, but not nodes. Adding missing ' - f'declarations: {missing}') - for node_id in missing: - nodes.append({'id': node_id}) - with open(outpath, 'w') as f: - json.dump(data, f) + if cache_output: + shutil.copy(outpath, cache_path) return outpath @@ -151,7 +138,7 @@ def owl_to_obograph(inpath: str, native_uri_stems: List[str] = None, use_cache=F # - https://github.com/geneontology/obographs/issues/89 def obograph_to_fhir( inpath: str, out_dir: str, out_filename: str = None, code_system_id: str = None, code_system_url: str = None, - include_all_predicates=False, native_uri_stems: List[str] = None, dev_oak_path: str = None, + include_all_predicates=True, native_uri_stems: List[str] = None, dev_oak_path: str = None, dev_oak_interpreter_path: str = None ) -> str: """Convert Obograph to FHIR""" @@ -176,9 +163,15 @@ def obograph_to_fhir( else: converter = OboGraphToFHIRConverter() converter.curie_converter = curies.Converter.from_prefix_map(get_default_prefix_map()) - gd: GraphDocument = json_loader.load(inpath, target_class=GraphDocument) - converter.dump(gd, out_path, include_all_predicates=include_all_predicates) - # todo: update w/ these params when released + gd: GraphDocument = json_loader.load(str(inpath), target_class=GraphDocument) + converter.dump( + gd, + out_path, + code_system_id=code_system_id, + code_system_url=code_system_url, + include_all_predicates=include_all_predicates, + native_uri_stems=native_uri_stems) + # TODO: add these params once supported: use_curies_native_concepts, use_curies_foreign_concepts # converter.dump( # gd, out_path, code_system_id='', code_system_url='', include_all_predicates=include_all_predicates, # native_uri_stems=native_uri_stems, use_curies_native_concepts=False, use_curies_foreign_concepts=True) @@ -219,18 +212,21 @@ def owl_to_fhir( input_path = input_path_or_url url = None maybe_url = urlparse(input_path_or_url) + out_dir = out_dir if out_dir else os.getcwd() + if out_dir.startswith('~'): + out_dir = os.path.expanduser('~/Desktop') if maybe_url.scheme and maybe_url.netloc: url = input_path_or_url if url: - input_path = os.path.join(CACHE_DIR, out_filename.replace('.json', '.owl')) - download(url, input_path) + download_path = os.path.join(out_dir, out_filename.replace('.json', '.owl')) + input_path = download_path + download(url, download_path, use_cached_intermediaries) if not out_filename: if not code_system_id: code_system_id = '.'.join(os.path.basename(input_path).split('.')[0:-1]) # removes file extension out_filename = f'CodeSystem-{code_system_id}.json' if not code_system_id and out_filename and out_filename.startswith('CodeSystem-'): code_system_id = out_filename.split('-')[1].split('.')[0] - input_path = input_path if os.path.exists(input_path) else os.path.join(os.getcwd(), input_path) out_dir = os.path.realpath(out_dir if out_dir else os.path.dirname(input_path)) intermediary_outdir = intermediary_outdir if intermediary_outdir else out_dir @@ -240,13 +236,14 @@ def owl_to_fhir( # Convert if intermediary_type == 'obographs' or input_path.endswith('.ttl'): # semsql only supports .owl - intermediary_path = owl_to_obograph(input_path, native_uri_stems, use_cached_intermediaries) + intermediary_path = owl_to_obograph(input_path, out_dir, use_cached_intermediaries, use_cached_intermediaries) obograph_to_fhir( inpath=intermediary_path, out_dir=intermediary_outdir, out_filename=out_filename, code_system_id=code_system_id, code_system_url=code_system_url, native_uri_stems=native_uri_stems, include_all_predicates=include_all_predicates, dev_oak_path=dev_oak_path, dev_oak_interpreter_path=dev_oak_interpreter_path) else: # semsql + # todo: owl_to_semsql: this may need similar updates to caching that were done for obographs on 2023/04/15 intermediary_path = owl_to_semsql(input_path, use_cached_intermediaries) semsql_to_fhir( inpath=intermediary_path, out_dir=intermediary_outdir, out_filename=out_filename, @@ -304,7 +301,7 @@ def cli(): 'convert that to FHIR.') parser.add_argument( '-c', '--use-cached-intermediaries', action='store_true', required=False, default=False, - help='Use cached intermediaries if they exist?') + help='Use cached intermediaries if they exist? Also will save intermediaries to owl-on-fhir\'s cache/ dir.') parser.add_argument( '-r', '--retain-intermediaries', action='store_true', default=False, required=False, help='Retain intermediary files created during conversion process (e.g. Obograph JSON)?') diff --git a/requirements.txt b/requirements.txt index 3716289..75c2437 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,45 +1,57 @@ aiohttp==3.8.3 aiosignal==1.3.1 -alabaster==0.7.12 +airium==0.2.5 +alabaster==0.7.13 antlr4-python3-runtime==4.9.3 appdirs==1.4.4 arrow==1.2.3 async-timeout==4.0.2 -attrs==22.1.0 +attrs==22.2.0 Babel==2.11.0 bcp47==0.0.4 +beautifulsoup4==4.12.2 bioontologies==0.2.1 -bioregistry==0.5.143 -certifi==2022.9.24 +bioregistry==0.6.99 +bleach==6.0.0 +certifi==2022.12.7 CFGraph==0.2.1 -chardet==4.0.0 +chardet==5.1.0 charset-normalizer==2.1.1 -class-resolver==0.3.10 +class-resolver==0.4.2 click==8.1.3 -curies==0.4.0 +colorama==0.4.6 +contourpy==1.0.7 +curies==0.4.2 +cycler==0.11.0 decorator==5.1.1 Deprecated==1.2.13 deprecation==2.1.0 distlib==0.3.6 docutils==0.17.1 +EditorConfig==0.12.3 et-xmlfile==1.1.0 -exceptiongroup==1.0.4 +exceptiongroup==1.1.0 fastobo==0.12.2 -filelock==3.8.2 +filelock==3.9.0 +fonttools==4.39.3 fqdn==1.5.1 frozenlist==1.3.3 -fsspec==2022.11.0 -funowl==0.1.12 +fsspec==2023.1.0 +funowl==0.1.13 +ghp-import==2.1.0 graphviz==0.20.1 -greenlet==2.0.1 +greenlet==2.0.2 hbreader==0.9.1 idna==3.4 +ijson==3.2.0.post0 imagesize==1.4.1 importlib-metadata==4.13.0 -iniconfig==1.1.1 +iniconfig==2.0.0 isodate==0.6.1 isoduration==20.11.0 +jaraco.classes==3.2.3 Jinja2==3.1.2 +jsbeautifier==1.14.7 json-flattener==0.1.9 jsonasobj==1.3.1 jsonasobj2==1.0.4 @@ -47,94 +59,120 @@ jsonpatch==1.32 jsonpath-ng==1.5.3 jsonpointer==2.3 jsonschema==4.17.3 +keyring==23.13.1 kgcl-rdflib==0.3.0 -kgcl-schema==0.3.1 +kgcl-schema==0.3.6 +kiwisolver==1.4.4 lark==1.1.5 -linkml==1.3.15 +linkml==1.4.3 linkml-dataops==0.1.0 -linkml-runtime==1.3.7 -markdown-it-py==2.1.0 -MarkupSafe==2.1.1 +linkml-renderer==0.1.2 +linkml-runtime==1.4.3 +Markdown==3.3.7 +markdown-it-py==2.2.0 +MarkupSafe==2.1.2 +matplotlib==3.7.1 mdit-py-plugins==0.3.3 mdurl==0.1.2 +mergedeep==1.3.4 +mkdocs==1.4.2 +mkdocs-material==9.1.6 +mkdocs-material-extensions==1.1.1 +mkdocs-mermaid2-plugin==0.6.0 more-click==0.1.2 -multidict==6.0.3 +more-itertools==9.1.0 +multidict==6.0.4 myst-parser==0.18.1 +ndex2==3.5.1 networkx==2.8.8 -numpy==1.23.5 +numpy==1.24.1 nxontology==0.4.1 -oaklib==0.1.67 +oaklib==0.5.1 ols-client==0.1.2 ontoportal-client==0.0.3 openpyxl==3.0.10 -packaging==21.3 -pandas==1.5.2 +packaging==23.0 +pandas==1.5.3 pandasql==0.7.3 +pansql==0.0.1 parse==1.19.0 -pbr==5.11.0 -platformdirs==2.5.4 +pbr==5.11.1 +Pillow==9.5.0 +pkginfo==1.9.6 +platformdirs==2.6.2 pluggy==1.0.0 ply==3.11 prefixcommons==0.1.12 prefixmaps==0.1.4 -pronto==2.5.1 +pronto==2.5.3 py==1.11.0 -pydantic==1.10.2 -Pygments==2.13.0 +pydantic==1.10.4 +Pygments==2.14.0 PyJSG==0.11.10 +pymdown-extensions==9.11 pyparsing==3.0.9 -pyrsistent==0.19.2 +pyrsistent==0.19.3 PyShEx==0.8.1 PyShExC==0.9.1 -pystow==0.4.7 -pytest==7.2.0 +pystow==0.5.0 +pytest==7.2.1 pytest-logging==2015.11.4 python-dateutil==2.8.2 PyTrie==0.4.0 -pytz==2022.6 +pytz==2022.7.1 PyYAML==6.0 +pyyaml_env_tag==0.1 ratelimit==2.2.1 rdflib==6.2.0 rdflib-jsonld==0.6.1 rdflib-shim==1.0.3 -requests==2.28.1 +readme-renderer==37.3 +regex==2023.3.23 +requests==2.28.2 +requests-toolbelt==0.10.1 rfc3339-validator==0.1.4 +rfc3986==2.0.0 rfc3987==1.3.8 +rich==13.3.2 ruamel.yaml==0.17.21 ruamel.yaml.clib==0.2.7 -scipy==1.9.3 -semsql==0.2.5 +scipy==1.10.0 +semsql==0.3.2 ShExJSG==0.8.2 six==1.16.0 snowballstemmer==2.2.0 sortedcontainers==2.4.0 +soupsieve==2.4 sparqlslurper==0.5.1 SPARQLWrapper==2.0.0 Sphinx==5.3.0 sphinx-click==4.4.0 sphinx-rtd-theme==1.1.1 -sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 -SQLAlchemy==1.4.44 +SQLAlchemy==1.4.46 SQLAlchemy-Utils==0.38.3 -sssom==0.3.17 -sssom-schema==0.9.4 +sssom==0.3.28 +sssom-schema==0.11.0 stevedore==4.1.1 tomli==2.0.1 -tox==3.27.1 +tox==3.28.0 tqdm==4.64.1 +twine==4.0.2 typing_extensions==4.4.0 +UpSetPlot==0.8.0 uri-template==1.2.0 -urllib3==1.26.13 +urllib3==1.26.14 validators==0.20.0 virtualenv==20.17.1 virtualenv-clone==0.5.7 -watchdog==2.2.0 +watchdog==2.2.1 webcolors==1.12 +webencodings==0.5.1 wrapt==1.14.1 yarl==1.8.2 -zipp==3.11.0 +zipp==3.12.0 diff --git a/setup.py b/setup.py index d888c03..dc6cd52 100644 --- a/setup.py +++ b/setup.py @@ -15,12 +15,12 @@ EMAIL = 'jflack@jhu.edu' AUTHOR = 'Joe Flack' REQUIRES_PYTHON = '>=3.9.0' -VERSION = '0.1.11' +VERSION = '1.0.0' # Requirements REQUIRED = [ 'bioontologies', - 'oaklib>=0.1.58', + 'oaklib>=0.5.1', 'requests', ]