Skip to content

Commit 8a2631d

Browse files
chores: port and adapter for downloader and loader of ontologies
1 parent 82001b0 commit 8a2631d

15 files changed

Lines changed: 270 additions & 226 deletions

example_usage.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Example improved client usage
2+
from ontograph.api.client import OntologyClient
3+
4+
# Initialize client
5+
client = OntologyClient()
6+
7+
# List available ontologies
8+
ontologies = client.list_ontologies()
9+
10+
# Download and load in one step
11+
go = client.load("go", format="obo")
12+
13+
# Query operations
14+
parents = go.get_parents("GO:0008150")
15+
children = go.get_children("GO:0008150")
16+
17+
# Advanced query
18+
results = go.query("ancestors:GO:0008150")

ontograph/adapters/obo_foundry_registry.py renamed to ontograph/adapters/obo_registry_adapter.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from pathlib import Path
2-
from types import NoneType
32
from typing import Dict, List, Optional, Any
43
import yaml
54
from pooch import retrieve
65

76
from ontograph.config.settings import OBO_FOUNDRY_REGISTRY_URL
7+
from ontograph.ports.ontology_registry_port import OntologyRegistryPort
88

99

10-
class OBOFoundryRegistry:
10+
class OBORegistryAdapter(OntologyRegistryPort):
1111
"""Manages access to the OBO Foundry ontology registry."""
1212

1313
def __init__(self, cache_dir: Path):
@@ -153,7 +153,6 @@ def get_download_url(self, ontology_id: str, format: str = "obo") -> Optional[st
153153
products = metadata.get("products", [])
154154
for product in products:
155155
if product.get("id", "").lower() == f"{ontology_id.lower()}.{format.lower()}":
156-
print(f"ID: {product.get('id')}")
157156
return product.get("ontology_purl")
158157

159158
return None
@@ -189,8 +188,8 @@ def get_available_formats(self, ontology_id: str) -> List[str]:
189188
# Define the path to store the registry
190189
path = Path("./data/out")
191190

192-
# Create object registry
193-
obo_reg = OBOFoundryRegistry(cache_dir=path)
191+
# Create registry adapter object
192+
obo_reg = OBORegistryAdapter(cache_dir=path)
194193

195194
# Load the registry (in case of not having the registry it will be downloaded automatically)
196195
obo_reg.load_registry()
@@ -201,8 +200,10 @@ def get_available_formats(self, ontology_id: str) -> List[str]:
201200
# List of available ontologies
202201
print("Number of ontologies: {}".format(len(obo_reg.list_available_ontologies())))
203202

204-
# Print the link associated to that ontology
205-
print(obo_reg.get_download_url("chebiche", "obo"))
203+
# Print the link associated to a valid ontology (e.g., 'chebi')
204+
print(obo_reg.get_download_url("chebi", "obo"))
206205

207-
# Print available formats
208-
print(obo_reg.get_available_formats(ontology_id="chebicge"))
206+
# Print available formats for a valid ontology
207+
print(obo_reg.get_available_formats(ontology_id="chebi"))
208+
209+
# Tip: Use obo_reg.list_available_ontologies() to find valid ontology IDs.

ontograph/adapters/pooch_downloader.py renamed to ontograph/adapters/pooch_downloader_adapter.py

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,26 @@
33

44
from pooch import retrieve
55

6-
from ontograph.adapters.obo_foundry_registry import OBOFoundryRegistry
7-
from ontograph.ports.downloader import AbstractDownloader
6+
from ontograph.ports.downloader_port import DownloaderPort
7+
from ontograph.ports.ontology_registry_port import OntologyRegistryPort
88

99

10-
class PoochDownloader(AbstractDownloader):
10+
class PoochDownloaderAdapter(DownloaderPort):
1111
"""
1212
Concrete downloader using Pooch for caching ontology files.
1313
"""
1414

15-
def __init__(self, cache_dir: Path = Path.home() / ".ontograph_cache"):
15+
def __init__(self, cache_dir: Path, registry: OntologyRegistryPort):
16+
"""
17+
Initialize the downloader adapter.
18+
19+
Args:
20+
cache_dir (Path): Directory for caching downloaded files
21+
registry (OntologyRegistryPort): Registry port for resolving download URLs
22+
"""
1623
self.cache_dir = cache_dir
1724
self.cache_dir.mkdir(parents=True, exist_ok=True)
18-
self.registry = OBOFoundryRegistry(cache_dir)
25+
self.registry = registry
1926

2027
def _get_download_url(self, name_id: str, format: str) -> Optional[str]:
2128
"""Get download URL from registry."""
@@ -37,6 +44,7 @@ def fetch(self, url: str, filename: str) -> Path:
3744
known_hash=None, # Could later integrate SHA256 checksums
3845
fname=filename,
3946
path=self.cache_dir,
47+
progressbar=True,
4048
)
4149
return Path(local_file)
4250

@@ -47,15 +55,18 @@ def fetch_batch(self, resources: List[Dict[str, str]]) -> Dict[str, Path]:
4755
Args:
4856
resources (List[Dict[str, str]]): List of dictionaries containing:
4957
- name_id: The ontology identifier
50-
- format: The file format (e.g., 'obo', 'owl')
58+
- format: The file format (e.g., 'obo', 'owl'). Defaults to 'obo' if not specified.
5159
5260
Returns:
5361
Dict[str, Path]: Dictionary mapping ontology IDs to their cached paths
5462
5563
Raises:
56-
ValueError: If an ontology is not found or format is not supported
64+
ValueError: If resources list is empty, an ontology is not found, or format is not supported
5765
KeyError: If required keys are missing in the resource dictionary
5866
"""
67+
if not resources:
68+
raise ValueError("Resources list for batch download is empty.")
69+
5970
results = {}
6071

6172
for resource in resources:
@@ -79,35 +90,36 @@ def fetch_batch(self, resources: List[Dict[str, str]]) -> Dict[str, Path]:
7990

8091
return results
8192

82-
def list_available_ontologies(self) -> List[Dict[str, str]]:
83-
"""
84-
Get list of available ontologies from the registry.
8593

86-
Returns:
87-
List[Dict[str, str]]: List of available ontologies with their metadata
88-
"""
89-
return self.registry.list_available_ontologies()
94+
if __name__ == "__main__":
95+
from ontograph.adapters.obo_registry_adapter import OBORegistryAdapter
9096

91-
def get_available_formats(self, ontology_id: str) -> List[str]:
92-
"""
93-
Get available formats for an ontology.
97+
# Defines the cache directory
98+
cache_dir = Path("./data/out")
9499

95-
Args:
96-
ontology_id: The ontology identifier
100+
# Creates a registry object (real implementation OBORegistryAdapter)
101+
registry = OBORegistryAdapter(cache_dir=cache_dir)
102+
registry.load_registry()
97103

98-
Returns:
99-
List[str]: List of available formats
100-
"""
101-
return self.registry.get_available_formats(ontology_id)
104+
# Creates a downloader object
105+
downloader = PoochDownloaderAdapter(cache_dir=cache_dir, registry=registry)
102106

103-
def get_ontology_metadata(self, ontology_id: str) -> Optional[Dict]:
104-
"""
105-
Get detailed metadata for an ontology.
107+
## Example 1. Download a single ontology file from the registry
108+
ontology_id = "ado"
109+
format = "owl"
106110

107-
Args:
108-
ontology_id: The ontology identifier
111+
# Extract the url from the registry
112+
url = registry.get_download_url(ontology_id, format)
109113

110-
Returns:
111-
Optional[Dict]: The ontology metadata or None if not found
112-
"""
113-
return self.registry.get_ontology_metadata(ontology_id)
114+
if url:
115+
# Downloads the file
116+
local_path = downloader.fetch(url=url, filename=f"{ontology_id}.{format}")
117+
print(f"Downloaded {ontology_id}.{format} to: {local_path}")
118+
119+
## Example 2. Batch download
120+
resources = [
121+
{"name_id": "chebi", "format": "owl"},
122+
{"name_id": "go", "format": "obo"},
123+
]
124+
batch_results = downloader.fetch_batch(resources)
125+
print("Batch download results:", batch_results)

ontograph/adapters/pronto_graph.py renamed to ontograph/adapters/pronto_graph_adapter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from typing import Any, List, Optional
22

3-
from ontograph.ports.graph_backend import GraphBackend
3+
from ontograph.ports.graph_backend_port import GraphBackendPort
44

55

6-
class ProntoGraph(GraphBackend):
6+
class ProntoGraphAdapter(GraphBackendPort):
77
"""Adapter implementing graph operations using Pronto."""
88

99
def __init__(self, ontology):

ontograph/adapters/pronto_loader.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from typing import Union
44

55
import pronto
6-
from ontograph.ports.ontology_loader import OntologyLoaderPort
6+
from ontograph.ports.ontology_loader_port import OntologyLoaderPort
77

88

9-
class ProntoOntologyLoader(OntologyLoaderPort):
9+
class ProntoLoaderAdapter(OntologyLoaderPort):
1010
"""Adapter that loads ontologies using pronto."""
1111

1212
def __init__(self, cache_dir: Union[str, Path] = None):
@@ -41,3 +41,21 @@ def load(self, name_id: str, format: str = "obo"):
4141
)
4242

4343
return pronto.Ontology(str(file_path))
44+
45+
46+
if __name__ == "__main__":
47+
# Example usage of ProntoLoaderAdapter
48+
cache_dir = "data/out" # or any directory where ontology files are cached
49+
loader = ProntoLoaderAdapter(cache_dir=cache_dir)
50+
51+
# Example: Load a cached ontology file (must exist in cache_dir)
52+
ontology_id = "go" # Use a valid ontology ID
53+
format = "obo"
54+
try:
55+
ontology = loader.load(ontology_id, format)
56+
print(f"Loaded ontology: {ontology_id}.{format}")
57+
print(f"Number of terms: {len(ontology.terms())}")
58+
except FileNotFoundError as e:
59+
print(e)
60+
except ValueError as e:
61+
print(e)

ontograph/api/client.py

Lines changed: 14 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,60 @@
11
from pathlib import Path
22
from typing import Any, Dict, List, Optional, Union
33

4-
from ontograph.config.container import OntographContainer
54
from ontograph.core.ontology_graph import OntologyGraph
6-
from ontograph.ports.downloader import AbstractDownloader
7-
from ontograph.ports.ontology_loader import OntologyLoaderPort
5+
from ontograph.ports.downloader_port import DownloaderPort
6+
from ontograph.ports.ontology_loader_port import OntologyLoaderPort
87

98

109
class OntologyClient:
1110
"""Facade for interacting with ontologies."""
1211

13-
def __init__(self, cache_dir: Union[str, Path] = None):
12+
def __init__(self, downloader: DownloaderPort, loader: OntologyLoaderPort):
1413
"""
1514
Initialize the client.
1615
1716
Args:
18-
cache_dir: Optional directory for caching ontology files
17+
downloader: The downloader port to use for fetching ontologies
18+
loader: The loader port to use for loading ontologies
1919
"""
20-
cache_dir = Path(cache_dir) if cache_dir else None
21-
self.loader: OntologyLoaderPort = OntographContainer.get_loader(cache_dir)
22-
self.downloader: AbstractDownloader = OntographContainer.get_downloader(cache_dir)
20+
self.downloader = downloader
21+
self.loader = loader
2322
self.ontology_graph = None
2423

2524
def list_ontologies(self) -> List[Dict[str, str]]:
26-
"""
27-
Get a list of all available ontologies from OBO Foundry.
28-
29-
Returns:
30-
List[Dict[str, str]]: List of ontologies with their metadata
31-
"""
25+
"""Get a list of all available ontologies from OBO Foundry."""
3226
return self.downloader.list_available_ontologies()
3327

3428
def get_ontology_formats(self, ontology_id: str) -> List[str]:
35-
"""
36-
Get available formats for an ontology.
37-
38-
Args:
39-
ontology_id: The ontology identifier
40-
41-
Returns:
42-
List[str]: Available formats
43-
"""
29+
"""Get available formats for an ontology."""
4430
return self.downloader.get_available_formats(ontology_id)
4531

4632
def get_ontology_info(self, ontology_id: str) -> Optional[Dict]:
47-
"""
48-
Get detailed metadata about an ontology.
49-
50-
Args:
51-
ontology_id: The ontology identifier
52-
53-
Returns:
54-
Optional[Dict]: Ontology metadata or None if not found
55-
"""
33+
"""Get detailed metadata about an ontology."""
5634
return self.downloader.get_ontology_metadata(ontology_id)
5735

5836
def download(
5937
self, name_id: Union[str, List[Dict[str, str]]], format: str = "obo"
6038
) -> Union[Path, Dict[str, Path]]:
61-
"""
62-
Download ontology file(s).
63-
64-
Args:
65-
name_id: Either a string identifier (e.g., 'go' for Gene Ontology)
66-
or a list of dictionaries with 'name_id' and 'format' keys
67-
format: The file format ('obo' or 'owl'), used only when name_id is a string
68-
69-
Returns:
70-
Union[Path, Dict[str, Path]]: Either a single path or a dictionary of paths
71-
mapping ontology IDs to their cached locations
72-
73-
Examples:
74-
# List available ontologies
75-
client.list_ontologies()
76-
77-
# Check available formats
78-
client.get_ontology_formats("go")
79-
80-
# Get ontology metadata
81-
client.get_ontology_info("go")
82-
83-
# Single download
84-
client.download("go", format="obo")
85-
86-
# Batch download
87-
client.download([
88-
{"name_id": "go", "format": "obo"},
89-
{"name_id": "chebi", "format": "owl"}
90-
])
91-
"""
39+
"""Download ontology file(s)."""
9240
if isinstance(name_id, str):
93-
# Single download
94-
url = self.downloader._get_download_url(name_id, format)
41+
url = self.downloader.get_download_url(name_id, format)
9542
if not url:
9643
raise ValueError(
9744
f"Cannot find download URL for ontology {name_id} in format {format}"
9845
)
9946
return self.downloader.fetch(url, f"{name_id}.{format}")
10047
else:
101-
# Batch download
10248
return self.downloader.fetch_batch(name_id)
10349

10450
def load(self, name_id: str, format: str = "obo") -> OntologyGraph:
105-
"""
106-
Load an ontology and return an OntologyGraph instance.
107-
108-
Args:
109-
name_id: The ontology identifier
110-
format: The file format
111-
112-
Returns:
113-
OntologyGraph: The loaded ontology graph
114-
"""
51+
"""Load an ontology and return an OntologyGraph instance."""
11552
pronto_ontology = self.loader.load(name_id, format)
11653
self.ontology_graph = OntologyGraph(pronto_ontology)
11754
return self.ontology_graph
11855

11956
def load_batch(self, resources: List[Dict[str, str]]) -> Dict[str, OntologyGraph]:
120-
"""
121-
Load multiple ontologies and return their graph instances.
122-
123-
Args:
124-
resources: List of dictionaries with 'name_id' and optional 'format' keys
125-
126-
Returns:
127-
Dict[str, OntologyGraph]: Dictionary mapping ontology IDs to their graph instances
128-
"""
57+
"""Load multiple ontologies and return their graph instances."""
12958
graphs = {}
13059
for resource in resources:
13160
name_id = resource["name_id"]

0 commit comments

Comments
 (0)