1515from collections .abc import Callable , Iterable , Mapping , Sequence
1616from pathlib import Path
1717from textwrap import indent
18- from typing import Any , Literal , TypeAlias , TypeVar
18+ from typing import Any , TypeVar
1919
2020import bioontologies .robot
2121import bioregistry
3030 DATABASE_DIRECTORY ,
3131 GetOntologyKwargs ,
3232 IterHelperHelperDict ,
33+ OntologyFormat ,
34+ OntologyPathPack ,
3335 SlimGetOntologyKwargs ,
3436)
3537from .identifier_utils import ParseError , wrap_norm_prefix
3638from .plugins import has_nomenclature_plugin , run_nomenclature_plugin
3739from .struct import Obo
3840from .struct .obo import from_obo_path , from_obonet
3941from .utils .io import safe_open_writer
42+ from .utils .misc import VERSION_GETTERS , cleanup_version
4043from .utils .path import ensure_path , prefix_directory_join
4144from .version import get_git_hash , get_version
4245
4346__all__ = [
4447 "NoBuildError" ,
45- "OntologyFormat" ,
4648 "get_ontology" ,
4749]
4850
@@ -125,10 +127,20 @@ def get_ontology(
125127 """
126128 if force :
127129 force_process = True
130+ if has_nomenclature_plugin (prefix ):
131+ obo = run_nomenclature_plugin (prefix , version = version )
132+ if cache :
133+ logger .debug ("[%s] caching nomenclature plugin" , prefix )
134+ obo .write_default (force = force_process )
135+ return obo
136+
128137 if prefix == "uberon" :
129138 logger .info ("UBERON has so much garbage in it that defaulting to non-strict parsing" )
130139 strict = False
131140
141+ if version is None :
142+ version = _get_version_from_artifact (prefix )
143+
132144 if force_process :
133145 obonet_json_gz_path = None
134146 elif not cache :
@@ -157,17 +169,11 @@ def get_ontology(
157169 else :
158170 logger .debug ("[%s] no obonet cache found at %s" , prefix , obonet_json_gz_path )
159171
160- if has_nomenclature_plugin (prefix ):
161- obo = run_nomenclature_plugin (prefix , version = version )
162- if cache :
163- logger .debug ("[%s] caching nomenclature plugin" , prefix )
164- obo .write_default (force = force_process )
165- return obo
166-
167- ontology_format , path = _ensure_ontology_path (prefix , force = force , version = version )
168- if path is None :
172+ path_pack = _ensure_ontology_path (prefix , force = force , version = version )
173+ if path_pack is None :
169174 raise NoBuildError (prefix )
170- elif ontology_format == "obo" :
175+ ontology_format , path = path_pack
176+ if ontology_format == "obo" :
171177 pass # all gucci
172178 elif ontology_format in {"owl" , "rdf" }:
173179 path = _convert_to_obo (path )
@@ -195,7 +201,6 @@ def get_ontology(
195201 return obo
196202
197203
198- OntologyFormat : TypeAlias = Literal ["obo" , "owl" , "json" , "rdf" ]
199204# order matters in this list, since order implicitly defines priority
200205_ONTOLOGY_GETTERS : list [tuple [OntologyFormat , Callable [[str ], str | None ]]] = [
201206 ("obo" , bioregistry .get_obo_download ),
@@ -206,8 +211,8 @@ def get_ontology(
206211
207212
208213def _ensure_ontology_path (
209- prefix : str , force : bool , version : str | None
210- ) -> tuple [ OntologyFormat , Path ] | tuple [ None , None ] :
214+ prefix : str , * , force : bool , version : str | None
215+ ) -> OntologyPathPack | None :
211216 for ontology_format , getter in _ONTOLOGY_GETTERS :
212217 url = getter (prefix )
213218 if url is None :
@@ -219,8 +224,8 @@ def _ensure_ontology_path(
219224 except pystow .utils .UnexpectedDirectoryError :
220225 continue # TODO report more info about the URL and the name it tried to make
221226 else :
222- return ontology_format , path
223- return None , None
227+ return OntologyPathPack ( ontology_format , path )
228+ return None
224229
225230
226231SKIP = {
@@ -519,3 +524,20 @@ def db_output_helper(
519524 click .echo ()
520525
521526 return [path for _ , path in rv ]
527+
528+
529+ def _get_version_from_artifact (prefix : str ) -> str | None :
530+ # assume that all possible files that can be downloaded
531+ # are in sync and have the same version
532+ for ontology_format , func in _ONTOLOGY_GETTERS :
533+ url = func (prefix )
534+ if url is None :
535+ continue
536+ # Try to peak into the file to get the version without fully downloading
537+ version_func = VERSION_GETTERS .get (ontology_format )
538+ if version_func is None :
539+ continue
540+ version = version_func (prefix , url )
541+ if version :
542+ return cleanup_version (version , prefix = prefix )
543+ return None
0 commit comments