tooluniverse 1.0.10__py3-none-any.whl → 1.0.11.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tooluniverse might be problematic. Click here for more details.
- tooluniverse/__init__.py +57 -1
- tooluniverse/blast_tool.py +132 -0
- tooluniverse/boltz_tool.py +2 -2
- tooluniverse/cbioportal_tool.py +42 -0
- tooluniverse/clinvar_tool.py +268 -74
- tooluniverse/compose_scripts/tool_discover.py +1941 -443
- tooluniverse/data/agentic_tools.json +0 -370
- tooluniverse/data/alphafold_tools.json +6 -6
- tooluniverse/data/blast_tools.json +112 -0
- tooluniverse/data/cbioportal_tools.json +87 -0
- tooluniverse/data/clinvar_tools.json +235 -0
- tooluniverse/data/compose_tools.json +0 -89
- tooluniverse/data/dbsnp_tools.json +275 -0
- tooluniverse/data/emdb_tools.json +61 -0
- tooluniverse/data/ensembl_tools.json +259 -0
- tooluniverse/data/file_download_tools.json +275 -0
- tooluniverse/data/geo_tools.json +200 -48
- tooluniverse/data/gnomad_tools.json +109 -0
- tooluniverse/data/gtopdb_tools.json +68 -0
- tooluniverse/data/gwas_tools.json +32 -0
- tooluniverse/data/interpro_tools.json +199 -0
- tooluniverse/data/jaspar_tools.json +70 -0
- tooluniverse/data/kegg_tools.json +356 -0
- tooluniverse/data/mpd_tools.json +87 -0
- tooluniverse/data/ols_tools.json +314 -0
- tooluniverse/data/package_discovery_tools.json +64 -0
- tooluniverse/data/packages/categorized_tools.txt +0 -1
- tooluniverse/data/packages/machine_learning_tools.json +0 -47
- tooluniverse/data/paleobiology_tools.json +91 -0
- tooluniverse/data/pride_tools.json +62 -0
- tooluniverse/data/pypi_package_inspector_tools.json +158 -0
- tooluniverse/data/python_executor_tools.json +341 -0
- tooluniverse/data/regulomedb_tools.json +50 -0
- tooluniverse/data/remap_tools.json +89 -0
- tooluniverse/data/screen_tools.json +89 -0
- tooluniverse/data/tool_discovery_agents.json +428 -0
- tooluniverse/data/tool_discovery_agents.json.backup +1343 -0
- tooluniverse/data/uniprot_tools.json +77 -0
- tooluniverse/data/web_search_tools.json +250 -0
- tooluniverse/data/worms_tools.json +55 -0
- tooluniverse/dbsnp_tool.py +196 -58
- tooluniverse/default_config.py +35 -2
- tooluniverse/emdb_tool.py +30 -0
- tooluniverse/ensembl_tool.py +140 -47
- tooluniverse/execute_function.py +78 -14
- tooluniverse/file_download_tool.py +269 -0
- tooluniverse/geo_tool.py +81 -28
- tooluniverse/gnomad_tool.py +100 -52
- tooluniverse/gtopdb_tool.py +41 -0
- tooluniverse/interpro_tool.py +72 -0
- tooluniverse/jaspar_tool.py +30 -0
- tooluniverse/kegg_tool.py +230 -0
- tooluniverse/mpd_tool.py +42 -0
- tooluniverse/ncbi_eutils_tool.py +96 -0
- tooluniverse/ols_tool.py +435 -0
- tooluniverse/package_discovery_tool.py +217 -0
- tooluniverse/paleobiology_tool.py +30 -0
- tooluniverse/pride_tool.py +30 -0
- tooluniverse/pypi_package_inspector_tool.py +593 -0
- tooluniverse/python_executor_tool.py +711 -0
- tooluniverse/regulomedb_tool.py +30 -0
- tooluniverse/remap_tool.py +44 -0
- tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +1 -1
- tooluniverse/screen_tool.py +44 -0
- tooluniverse/smcp.py +10 -2
- tooluniverse/smcp_server.py +3 -3
- tooluniverse/tool_finder_embedding.py +3 -1
- tooluniverse/tool_finder_keyword.py +3 -1
- tooluniverse/tool_finder_llm.py +6 -2
- tooluniverse/tools/{UCSC_get_genes_by_region.py → BLAST_nucleotide_search.py} +22 -26
- tooluniverse/tools/BLAST_protein_search.py +63 -0
- tooluniverse/tools/ClinVar_search_variants.py +26 -15
- tooluniverse/tools/CodeQualityAnalyzer.py +3 -3
- tooluniverse/tools/EMDB_get_structure.py +46 -0
- tooluniverse/tools/GtoPdb_get_targets.py +52 -0
- tooluniverse/tools/InterPro_get_domain_details.py +46 -0
- tooluniverse/tools/InterPro_get_protein_domains.py +49 -0
- tooluniverse/tools/InterPro_search_domains.py +52 -0
- tooluniverse/tools/JASPAR_get_transcription_factors.py +52 -0
- tooluniverse/tools/MPD_get_phenotype_data.py +59 -0
- tooluniverse/tools/PRIDE_search_proteomics.py +52 -0
- tooluniverse/tools/PackageAnalyzer.py +55 -0
- tooluniverse/tools/Paleobiology_get_fossils.py +52 -0
- tooluniverse/tools/PyPIPackageInspector.py +59 -0
- tooluniverse/tools/ReMap_get_transcription_factor_binding.py +59 -0
- tooluniverse/tools/ReferenceInfoAnalyzer.py +55 -0
- tooluniverse/tools/RegulomeDB_query_variant.py +46 -0
- tooluniverse/tools/SCREEN_get_regulatory_elements.py +59 -0
- tooluniverse/tools/{ArgumentDescriptionOptimizer.py → TestResultsAnalyzer.py} +13 -13
- tooluniverse/tools/ToolDiscover.py +11 -11
- tooluniverse/tools/UniProt_id_mapping.py +63 -0
- tooluniverse/tools/UniProt_search.py +63 -0
- tooluniverse/tools/UnifiedToolGenerator.py +59 -0
- tooluniverse/tools/WoRMS_search_species.py +49 -0
- tooluniverse/tools/XMLToolOptimizer.py +55 -0
- tooluniverse/tools/__init__.py +119 -29
- tooluniverse/tools/alphafold_get_annotations.py +3 -3
- tooluniverse/tools/alphafold_get_prediction.py +3 -3
- tooluniverse/tools/alphafold_get_summary.py +3 -3
- tooluniverse/tools/cBioPortal_get_cancer_studies.py +46 -0
- tooluniverse/tools/cBioPortal_get_mutations.py +52 -0
- tooluniverse/tools/{gnomAD_query_variant.py → clinvar_get_clinical_significance.py} +8 -11
- tooluniverse/tools/clinvar_get_variant_details.py +49 -0
- tooluniverse/tools/dbSNP_get_variant_by_rsid.py +7 -7
- tooluniverse/tools/dbsnp_get_frequencies.py +46 -0
- tooluniverse/tools/dbsnp_search_by_gene.py +52 -0
- tooluniverse/tools/download_binary_file.py +66 -0
- tooluniverse/tools/download_file.py +71 -0
- tooluniverse/tools/download_text_content.py +55 -0
- tooluniverse/tools/dynamic_package_discovery.py +59 -0
- tooluniverse/tools/ensembl_get_sequence.py +52 -0
- tooluniverse/tools/{Ensembl_lookup_gene_by_symbol.py → ensembl_get_variants.py} +11 -11
- tooluniverse/tools/ensembl_lookup_gene.py +46 -0
- tooluniverse/tools/geo_get_dataset_info.py +46 -0
- tooluniverse/tools/geo_get_sample_info.py +46 -0
- tooluniverse/tools/geo_search_datasets.py +67 -0
- tooluniverse/tools/gnomad_get_gene_constraints.py +49 -0
- tooluniverse/tools/kegg_find_genes.py +52 -0
- tooluniverse/tools/kegg_get_gene_info.py +46 -0
- tooluniverse/tools/kegg_get_pathway_info.py +46 -0
- tooluniverse/tools/kegg_list_organisms.py +44 -0
- tooluniverse/tools/kegg_search_pathway.py +46 -0
- tooluniverse/tools/ols_find_similar_terms.py +63 -0
- tooluniverse/tools/{get_hyperopt_info.py → ols_get_ontology_info.py} +13 -10
- tooluniverse/tools/ols_get_term_ancestors.py +67 -0
- tooluniverse/tools/ols_get_term_children.py +67 -0
- tooluniverse/tools/{TestCaseGenerator.py → ols_get_term_info.py} +12 -9
- tooluniverse/tools/{CodeOptimizer.py → ols_search_ontologies.py} +22 -14
- tooluniverse/tools/ols_search_terms.py +71 -0
- tooluniverse/tools/python_code_executor.py +79 -0
- tooluniverse/tools/python_script_runner.py +79 -0
- tooluniverse/tools/web_api_documentation_search.py +63 -0
- tooluniverse/tools/web_search.py +71 -0
- tooluniverse/uniprot_tool.py +219 -16
- tooluniverse/url_tool.py +18 -0
- tooluniverse/utils.py +2 -2
- tooluniverse/web_search_tool.py +229 -0
- tooluniverse/worms_tool.py +64 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.1.dist-info}/METADATA +3 -2
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.1.dist-info}/RECORD +144 -55
- tooluniverse/data/genomics_tools.json +0 -174
- tooluniverse/tools/ToolDescriptionOptimizer.py +0 -67
- tooluniverse/tools/ToolImplementationGenerator.py +0 -67
- tooluniverse/tools/ToolOptimizer.py +0 -59
- tooluniverse/tools/ToolSpecificationGenerator.py +0 -67
- tooluniverse/tools/ToolSpecificationOptimizer.py +0 -63
- tooluniverse/ucsc_tool.py +0 -60
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.1.dist-info}/WHEEL +0 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.1.dist-info}/entry_points.txt +0 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.1.dist-info}/licenses/LICENSE +0 -0
- {tooluniverse-1.0.10.dist-info → tooluniverse-1.0.11.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File download tool - A curl-like tool for downloading files from URLs.
|
|
3
|
+
Supports Windows, Mac, and Linux platforms.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
import os
|
|
8
|
+
import tempfile
|
|
9
|
+
from urllib.parse import urlparse
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
from .base_tool import BaseTool
|
|
12
|
+
from .tool_registry import register_tool
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@register_tool("FileDownloadTool")
|
|
16
|
+
class FileDownloadTool(BaseTool):
|
|
17
|
+
"""
|
|
18
|
+
Download files from HTTP/HTTPS URLs - similar to curl.
|
|
19
|
+
|
|
20
|
+
Supports:
|
|
21
|
+
- Direct file downloads to specified or temporary locations
|
|
22
|
+
- Binary and text file handling
|
|
23
|
+
- Progress tracking (optional)
|
|
24
|
+
- Cross-platform (Windows, Mac, Linux)
|
|
25
|
+
|
|
26
|
+
Expects: {"url": "https://...", "output_path": "/path/to/save"}
|
|
27
|
+
Optional: {"timeout": seconds, "return_content": bool}
|
|
28
|
+
Returns: {"file_path": "...", "file_size": bytes} or {"error": "..."}
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, tool_config):
|
|
32
|
+
super().__init__(tool_config)
|
|
33
|
+
fields = tool_config.get("fields", {})
|
|
34
|
+
self.return_key = fields.get("return_key", "file_path")
|
|
35
|
+
|
|
36
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
37
|
+
"""
|
|
38
|
+
Download a file from a URL.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
arguments: Dictionary containing:
|
|
42
|
+
- url (str): URL to download from
|
|
43
|
+
- output_path (str, optional): Path to save the file
|
|
44
|
+
- timeout (int, optional): Request timeout (default: 30)
|
|
45
|
+
- return_content (bool): Return as text (default: False)
|
|
46
|
+
- chunk_size (int, optional): Chunk size (default: 8192)
|
|
47
|
+
- follow_redirects (bool): Follow redirects (default: True)
|
|
48
|
+
Returns:
|
|
49
|
+
Dict with file_path and file_size, or content, or error
|
|
50
|
+
"""
|
|
51
|
+
url = arguments.get("url")
|
|
52
|
+
if not url:
|
|
53
|
+
return {"error": "Parameter 'url' is required."}
|
|
54
|
+
|
|
55
|
+
if not (url.startswith("http://") or url.startswith("https://")):
|
|
56
|
+
return {"error": "URL must start with http:// or https://"}
|
|
57
|
+
|
|
58
|
+
# Parse parameters
|
|
59
|
+
output_path = arguments.get("output_path")
|
|
60
|
+
timeout = arguments.get("timeout", 30)
|
|
61
|
+
return_content = arguments.get("return_content", False)
|
|
62
|
+
chunk_size = arguments.get("chunk_size", 8192)
|
|
63
|
+
follow_redirects = arguments.get("follow_redirects", True)
|
|
64
|
+
|
|
65
|
+
# Determine output path
|
|
66
|
+
if output_path:
|
|
67
|
+
output_path = self._normalize_path(output_path)
|
|
68
|
+
output_dir = os.path.dirname(output_path)
|
|
69
|
+
if output_dir and not os.path.exists(output_dir):
|
|
70
|
+
try:
|
|
71
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
return {"error": f"Failed to create directory: {e}"}
|
|
74
|
+
else:
|
|
75
|
+
temp_dir = tempfile.gettempdir()
|
|
76
|
+
parsed_url = urlparse(url)
|
|
77
|
+
filename = os.path.basename(parsed_url.path) or "downloaded_file"
|
|
78
|
+
filename = filename.split("?")[0]
|
|
79
|
+
if not filename:
|
|
80
|
+
filename = "downloaded_file"
|
|
81
|
+
output_path = os.path.join(temp_dir, filename)
|
|
82
|
+
try:
|
|
83
|
+
response = requests.get(
|
|
84
|
+
url, timeout=timeout, allow_redirects=follow_redirects, stream=True
|
|
85
|
+
)
|
|
86
|
+
response.raise_for_status()
|
|
87
|
+
|
|
88
|
+
if return_content:
|
|
89
|
+
content = response.text
|
|
90
|
+
content_type = response.headers.get("Content-Type", "").lower()
|
|
91
|
+
return {
|
|
92
|
+
"content": content,
|
|
93
|
+
"content_type": content_type,
|
|
94
|
+
"size": len(content),
|
|
95
|
+
"url": url,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
file_size = 0
|
|
99
|
+
with open(output_path, "wb") as f:
|
|
100
|
+
for chunk in response.iter_content(chunk_size=chunk_size):
|
|
101
|
+
if chunk:
|
|
102
|
+
f.write(chunk)
|
|
103
|
+
file_size += len(chunk)
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"file_path": output_path,
|
|
107
|
+
"file_size": file_size,
|
|
108
|
+
"url": url,
|
|
109
|
+
"content_type": response.headers.get("Content-Type", ""),
|
|
110
|
+
"status_code": response.status_code,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
except requests.exceptions.Timeout:
|
|
114
|
+
return {"error": f"Request timed out after {timeout} seconds"}
|
|
115
|
+
except requests.exceptions.HTTPError as e:
|
|
116
|
+
return {"error": f"HTTP error: {e}"}
|
|
117
|
+
except requests.exceptions.ConnectionError as e:
|
|
118
|
+
return {"error": f"Connection error: {e}"}
|
|
119
|
+
except requests.exceptions.RequestException as e:
|
|
120
|
+
return {"error": f"Request failed: {e}"}
|
|
121
|
+
except IOError as e:
|
|
122
|
+
return {"error": f"Failed to write file: {e}"}
|
|
123
|
+
except Exception as e:
|
|
124
|
+
return {"error": f"Unexpected error: {e}"}
|
|
125
|
+
|
|
126
|
+
def _normalize_path(self, path: str) -> str:
|
|
127
|
+
"""
|
|
128
|
+
Normalize file path for cross-platform compatibility.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
path: File path to normalize
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Normalized path
|
|
135
|
+
"""
|
|
136
|
+
path = os.path.expanduser(path)
|
|
137
|
+
path = os.path.expandvars(path)
|
|
138
|
+
|
|
139
|
+
if not os.path.isabs(path):
|
|
140
|
+
path = os.path.abspath(path)
|
|
141
|
+
|
|
142
|
+
return path
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@register_tool("BinaryDownloadTool")
|
|
146
|
+
class BinaryDownloadTool(BaseTool):
|
|
147
|
+
"""
|
|
148
|
+
Download binary files with chunked streaming.
|
|
149
|
+
|
|
150
|
+
Optimized for large binary files like images, videos, executables.
|
|
151
|
+
Supports chunked downloads for better memory management.
|
|
152
|
+
|
|
153
|
+
Expects: {"url": "https://...", "output_path": "/path/to/save"}
|
|
154
|
+
Optional: {"chunk_size": bytes, "timeout": seconds}
|
|
155
|
+
Returns: {"file_path": "...", "size": bytes, "content_type": "..."}
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
def __init__(self, tool_config):
|
|
159
|
+
super().__init__(tool_config)
|
|
160
|
+
|
|
161
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
162
|
+
"""
|
|
163
|
+
Download binary file from URL.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
arguments: Dictionary containing url and optional parameters
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Dictionary with file_path and metadata, or error
|
|
170
|
+
"""
|
|
171
|
+
url = arguments.get("url")
|
|
172
|
+
if not url:
|
|
173
|
+
return {"error": "Parameter 'url' is required."}
|
|
174
|
+
|
|
175
|
+
output_path = arguments.get("output_path")
|
|
176
|
+
if not output_path:
|
|
177
|
+
msg = "Parameter 'output_path' is required for binary downloads."
|
|
178
|
+
return {"error": msg}
|
|
179
|
+
|
|
180
|
+
timeout = arguments.get("timeout", 30)
|
|
181
|
+
# 1MB chunks for binary files
|
|
182
|
+
chunk_size = arguments.get("chunk_size", 1024 * 1024)
|
|
183
|
+
|
|
184
|
+
output_path = os.path.expanduser(output_path)
|
|
185
|
+
output_path = os.path.expandvars(output_path)
|
|
186
|
+
|
|
187
|
+
output_dir = os.path.dirname(output_path)
|
|
188
|
+
if output_dir and not os.path.exists(output_dir):
|
|
189
|
+
try:
|
|
190
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
191
|
+
except Exception as e:
|
|
192
|
+
return {"error": f"Failed to create directory: {e}"}
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
response = requests.get(url, timeout=timeout, stream=True)
|
|
196
|
+
response.raise_for_status()
|
|
197
|
+
|
|
198
|
+
file_size = 0
|
|
199
|
+
with open(output_path, "wb") as f:
|
|
200
|
+
for chunk in response.iter_content(chunk_size=chunk_size):
|
|
201
|
+
if chunk:
|
|
202
|
+
f.write(chunk)
|
|
203
|
+
file_size += len(chunk)
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
"file_path": output_path,
|
|
207
|
+
"size": file_size,
|
|
208
|
+
"content_type": response.headers.get("Content-Type", ""),
|
|
209
|
+
"content_length": response.headers.get("Content-Length", ""),
|
|
210
|
+
"url": url,
|
|
211
|
+
"status_code": response.status_code,
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
except Exception as e:
|
|
215
|
+
return {"error": f"Failed to download binary file: {e}"}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@register_tool("TextDownloadTool")
|
|
219
|
+
class TextDownloadTool(BaseTool):
|
|
220
|
+
"""
|
|
221
|
+
Download and return text content from URLs.
|
|
222
|
+
|
|
223
|
+
Optimized for text files - returns content as string directly.
|
|
224
|
+
Supports encoding detection and normalization.
|
|
225
|
+
|
|
226
|
+
Expects: {"url": "https://..."}
|
|
227
|
+
Optional: {"encoding": "utf-8", "timeout": seconds}
|
|
228
|
+
Returns: {"content": "text content", "encoding": "utf-8"}
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def __init__(self, tool_config):
|
|
232
|
+
super().__init__(tool_config)
|
|
233
|
+
|
|
234
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
235
|
+
"""
|
|
236
|
+
Download text content from URL.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
arguments: Dictionary containing url and optional parameters
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Dictionary with content and encoding, or error
|
|
243
|
+
"""
|
|
244
|
+
url = arguments.get("url")
|
|
245
|
+
if not url:
|
|
246
|
+
return {"error": "Parameter 'url' is required."}
|
|
247
|
+
|
|
248
|
+
timeout = arguments.get("timeout", 30)
|
|
249
|
+
encoding = arguments.get("encoding", None) # Auto-detect if None
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
response = requests.get(url, timeout=timeout)
|
|
253
|
+
response.raise_for_status()
|
|
254
|
+
|
|
255
|
+
if encoding:
|
|
256
|
+
content = response.content.decode(encoding)
|
|
257
|
+
else:
|
|
258
|
+
content = response.text
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
"content": content,
|
|
262
|
+
"encoding": response.encoding,
|
|
263
|
+
"size": len(content),
|
|
264
|
+
"url": url,
|
|
265
|
+
"content_type": response.headers.get("Content-Type", ""),
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
return {"error": f"Failed to download text content: {e}"}
|
tooluniverse/geo_tool.py
CHANGED
|
@@ -7,18 +7,15 @@ next-generation sequencing, and other forms of high-throughput functional
|
|
|
7
7
|
genomics data.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
import requests
|
|
11
10
|
from typing import Dict, Any, List
|
|
12
|
-
from .
|
|
11
|
+
from .ncbi_eutils_tool import NCBIEUtilsTool
|
|
13
12
|
from .tool_registry import register_tool
|
|
14
13
|
|
|
15
|
-
GEO_BASE_URL = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
|
|
16
|
-
|
|
17
14
|
|
|
18
15
|
@register_tool("GEORESTTool")
|
|
19
|
-
class GEORESTTool(
|
|
16
|
+
class GEORESTTool(NCBIEUtilsTool):
|
|
20
17
|
"""
|
|
21
|
-
GEO Database REST API tool.
|
|
18
|
+
GEO Database REST API tool with rate limiting.
|
|
22
19
|
Generic wrapper for GEO API endpoints defined in expression_tools.json.
|
|
23
20
|
"""
|
|
24
21
|
|
|
@@ -34,7 +31,7 @@ class GEORESTTool(BaseTool):
|
|
|
34
31
|
def _build_url(self, arguments: Dict[str, Any]) -> str | Dict[str, Any]:
|
|
35
32
|
"""Build URL for GEO API request."""
|
|
36
33
|
url_path = self.endpoint_template
|
|
37
|
-
return
|
|
34
|
+
return self.base_url + url_path
|
|
38
35
|
|
|
39
36
|
def _build_params(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
40
37
|
"""Build parameters for GEO API request."""
|
|
@@ -85,22 +82,6 @@ class GEORESTTool(BaseTool):
|
|
|
85
82
|
|
|
86
83
|
return params
|
|
87
84
|
|
|
88
|
-
def _make_request(self, url: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
89
|
-
"""Perform a GET request and handle common errors."""
|
|
90
|
-
try:
|
|
91
|
-
response = requests.get(url, params=params, timeout=30)
|
|
92
|
-
response.raise_for_status()
|
|
93
|
-
|
|
94
|
-
if self.output_format == "JSON":
|
|
95
|
-
return response.json()
|
|
96
|
-
else:
|
|
97
|
-
return {"data": response.text}
|
|
98
|
-
|
|
99
|
-
except requests.exceptions.RequestException as e:
|
|
100
|
-
return {"error": f"Request failed: {str(e)}"}
|
|
101
|
-
except Exception as e:
|
|
102
|
-
return {"error": f"Unexpected error: {str(e)}"}
|
|
103
|
-
|
|
104
85
|
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
105
86
|
"""Execute the tool with given arguments."""
|
|
106
87
|
# Validate required parameters
|
|
@@ -108,9 +89,81 @@ class GEORESTTool(BaseTool):
|
|
|
108
89
|
if param not in arguments:
|
|
109
90
|
return {"error": f"Missing required parameter: {param}"}
|
|
110
91
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return url
|
|
114
|
-
|
|
92
|
+
# Set endpoint for the base class
|
|
93
|
+
self.endpoint = self.endpoint_template
|
|
115
94
|
params = self._build_params(arguments)
|
|
116
|
-
|
|
95
|
+
|
|
96
|
+
# Use the parent class's _make_request with rate limiting
|
|
97
|
+
return self._make_request(self.endpoint, params)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@register_tool("GEOSearchDatasets")
|
|
101
|
+
class GEOSearchDatasets(GEORESTTool):
|
|
102
|
+
"""Search GEO datasets by various criteria."""
|
|
103
|
+
|
|
104
|
+
def __init__(self, tool_config):
|
|
105
|
+
super().__init__(tool_config)
|
|
106
|
+
self.endpoint_template = "/esearch.fcgi"
|
|
107
|
+
|
|
108
|
+
def _build_params(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
109
|
+
"""Build parameters for GEO dataset search."""
|
|
110
|
+
params = {"db": "gds", "retmode": "json", "retmax": 50}
|
|
111
|
+
|
|
112
|
+
# Build search query
|
|
113
|
+
query_parts = []
|
|
114
|
+
if "query" in arguments:
|
|
115
|
+
query_parts.append(arguments["query"])
|
|
116
|
+
|
|
117
|
+
if "organism" in arguments:
|
|
118
|
+
organism = arguments["organism"]
|
|
119
|
+
query_parts.append(f'"{organism}"[organism]')
|
|
120
|
+
|
|
121
|
+
if "study_type" in arguments:
|
|
122
|
+
study_type = arguments["study_type"]
|
|
123
|
+
query_parts.append(f'"{study_type}"[study_type]')
|
|
124
|
+
|
|
125
|
+
if "platform" in arguments:
|
|
126
|
+
platform = arguments["platform"]
|
|
127
|
+
query_parts.append(f'"{platform}"[platform]')
|
|
128
|
+
|
|
129
|
+
if query_parts:
|
|
130
|
+
params["term"] = " AND ".join(query_parts)
|
|
131
|
+
|
|
132
|
+
if "limit" in arguments:
|
|
133
|
+
params["retmax"] = min(arguments["limit"], 500)
|
|
134
|
+
|
|
135
|
+
return params
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@register_tool("GEOGetDatasetInfo")
|
|
139
|
+
class GEOGetDatasetInfo(GEORESTTool):
|
|
140
|
+
"""Get detailed information about a specific GEO dataset."""
|
|
141
|
+
|
|
142
|
+
def __init__(self, tool_config):
|
|
143
|
+
super().__init__(tool_config)
|
|
144
|
+
self.endpoint_template = "/esummary.fcgi"
|
|
145
|
+
|
|
146
|
+
def _build_params(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
147
|
+
"""Build parameters for GEO dataset info retrieval."""
|
|
148
|
+
dataset_id = arguments.get("dataset_id", "")
|
|
149
|
+
if not dataset_id:
|
|
150
|
+
return {"error": "dataset_id is required"}
|
|
151
|
+
|
|
152
|
+
return {"db": "gds", "id": dataset_id, "retmode": "json"}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@register_tool("GEOGetSampleInfo")
|
|
156
|
+
class GEOGetSampleInfo(GEORESTTool):
|
|
157
|
+
"""Get sample information for a GEO dataset."""
|
|
158
|
+
|
|
159
|
+
def __init__(self, tool_config):
|
|
160
|
+
super().__init__(tool_config)
|
|
161
|
+
self.endpoint_template = "/esummary.fcgi"
|
|
162
|
+
|
|
163
|
+
def _build_params(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
164
|
+
"""Build parameters for GEO sample info retrieval."""
|
|
165
|
+
dataset_id = arguments.get("dataset_id", "")
|
|
166
|
+
if not dataset_id:
|
|
167
|
+
return {"error": "dataset_id is required"}
|
|
168
|
+
|
|
169
|
+
return {"db": "gds", "id": dataset_id, "retmode": "json"}
|
tooluniverse/gnomad_tool.py
CHANGED
|
@@ -1,63 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
gnomAD GraphQL API Tool
|
|
3
|
+
|
|
4
|
+
This tool provides access to the gnomAD (Genome Aggregation Database) for
|
|
5
|
+
population genetics data, variant frequencies, and gene constraint metrics using GraphQL.
|
|
6
|
+
"""
|
|
7
|
+
|
|
1
8
|
import requests
|
|
2
|
-
import
|
|
9
|
+
from typing import Dict, Any
|
|
3
10
|
from .base_tool import BaseTool
|
|
4
11
|
from .tool_registry import register_tool
|
|
12
|
+
from .graphql_tool import execute_query
|
|
5
13
|
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
class
|
|
9
|
-
"""
|
|
10
|
-
Local tool wrapper for gnomAD GraphQL API.
|
|
11
|
-
Queries variant information including allele frequencies.
|
|
12
|
-
"""
|
|
15
|
+
class gnomADGraphQLTool(BaseTool):
|
|
16
|
+
"""Base class for gnomAD GraphQL API tools."""
|
|
13
17
|
|
|
14
18
|
def __init__(self, tool_config):
|
|
15
19
|
super().__init__(tool_config)
|
|
16
|
-
self.
|
|
20
|
+
self.endpoint_url = "https://gnomad.broadinstitute.org/api"
|
|
21
|
+
self.query_schema = tool_config.get("query_schema", "")
|
|
17
22
|
self.session = requests.Session()
|
|
18
|
-
self.session.headers.update(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
query
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
self.session.headers.update(
|
|
24
|
+
{
|
|
25
|
+
"Accept": "application/json",
|
|
26
|
+
"Content-Type": "application/json",
|
|
27
|
+
"User-Agent": "ToolUniverse/1.0",
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
self.timeout = 30
|
|
31
|
+
|
|
32
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
33
|
+
"""Execute GraphQL query with given arguments."""
|
|
34
|
+
try:
|
|
35
|
+
result = execute_query(
|
|
36
|
+
endpoint_url=self.endpoint_url,
|
|
37
|
+
query=self.query_schema,
|
|
38
|
+
variables=arguments,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if result is None:
|
|
42
|
+
return {
|
|
43
|
+
"status": "error",
|
|
44
|
+
"error": "No data returned from gnomAD API",
|
|
45
|
+
"data": None,
|
|
36
46
|
}
|
|
47
|
+
|
|
48
|
+
return {"status": "success", "data": result, "url": self.endpoint_url}
|
|
49
|
+
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return {
|
|
52
|
+
"status": "error",
|
|
53
|
+
"error": f"gnomAD GraphQL request failed: {str(e)}",
|
|
54
|
+
"data": None,
|
|
37
55
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@register_tool("gnomADGetGeneConstraints")
|
|
59
|
+
class gnomADGetGeneConstraints(gnomADGraphQLTool):
|
|
60
|
+
"""Get gene constraint metrics from gnomAD."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, tool_config):
|
|
63
|
+
super().__init__(tool_config)
|
|
64
|
+
# Set default query schema if not provided in config
|
|
65
|
+
if not self.query_schema:
|
|
66
|
+
self.query_schema = """
|
|
67
|
+
query GeneConstraints($geneSymbol: String!) {
|
|
68
|
+
gene(gene_symbol: $geneSymbol, reference_genome: GRCh38) {
|
|
69
|
+
symbol
|
|
70
|
+
gene_id
|
|
71
|
+
exac_constraint {
|
|
72
|
+
exp_lof
|
|
73
|
+
obs_lof
|
|
74
|
+
pLI
|
|
75
|
+
exp_mis
|
|
76
|
+
obs_mis
|
|
77
|
+
exp_syn
|
|
78
|
+
obs_syn
|
|
79
|
+
}
|
|
80
|
+
gnomad_constraint {
|
|
81
|
+
exp_lof
|
|
82
|
+
obs_lof
|
|
83
|
+
oe_lof
|
|
84
|
+
pLI
|
|
85
|
+
exp_mis
|
|
86
|
+
obs_mis
|
|
87
|
+
oe_mis
|
|
88
|
+
exp_syn
|
|
89
|
+
obs_syn
|
|
90
|
+
oe_syn
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
97
|
+
"""Get gene constraints."""
|
|
98
|
+
gene_symbol = arguments.get("gene_symbol", "")
|
|
99
|
+
if not gene_symbol:
|
|
100
|
+
return {"status": "error", "error": "gene_symbol is required"}
|
|
101
|
+
|
|
102
|
+
# Convert gene_symbol to geneSymbol for GraphQL variable
|
|
103
|
+
graphql_args = {"geneSymbol": gene_symbol}
|
|
104
|
+
|
|
105
|
+
result = super().run(graphql_args)
|
|
106
|
+
|
|
107
|
+
# Add gene_symbol to result for reference
|
|
108
|
+
if result.get("status") == "success":
|
|
109
|
+
result["gene_symbol"] = gene_symbol
|
|
110
|
+
|
|
111
|
+
return result
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
from .base_tool import BaseTool
|
|
4
|
+
from .tool_registry import register_tool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@register_tool("GtoPdbRESTTool")
|
|
8
|
+
class GtoPdbRESTTool(BaseTool):
|
|
9
|
+
def __init__(self, tool_config: Dict):
|
|
10
|
+
super().__init__(tool_config)
|
|
11
|
+
self.base_url = "https://www.guidetopharmacology.org/services"
|
|
12
|
+
self.session = requests.Session()
|
|
13
|
+
self.session.headers.update({"Accept": "application/json"})
|
|
14
|
+
self.timeout = 30
|
|
15
|
+
|
|
16
|
+
def _build_url(self, args: Dict[str, Any]) -> str:
|
|
17
|
+
url = self.tool_config["fields"]["endpoint"]
|
|
18
|
+
for k, v in args.items():
|
|
19
|
+
url = url.replace(f"{{{k}}}", str(v))
|
|
20
|
+
return url
|
|
21
|
+
|
|
22
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
23
|
+
try:
|
|
24
|
+
url = self._build_url(arguments)
|
|
25
|
+
response = self.session.get(url, timeout=self.timeout)
|
|
26
|
+
response.raise_for_status()
|
|
27
|
+
data = response.json()
|
|
28
|
+
|
|
29
|
+
# Apply limit if specified
|
|
30
|
+
limit = arguments.get("limit", 20)
|
|
31
|
+
if isinstance(data, list) and len(data) > limit:
|
|
32
|
+
data = data[:limit]
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
"status": "success",
|
|
36
|
+
"data": data,
|
|
37
|
+
"url": url,
|
|
38
|
+
"count": len(data) if isinstance(data, list) else 1,
|
|
39
|
+
}
|
|
40
|
+
except Exception as e:
|
|
41
|
+
return {"status": "error", "error": f"GtoPdb API error: {str(e)}"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
from .base_tool import BaseTool
|
|
4
|
+
from .tool_registry import register_tool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@register_tool("InterProRESTTool")
|
|
8
|
+
class InterProRESTTool(BaseTool):
|
|
9
|
+
def __init__(self, tool_config: Dict):
|
|
10
|
+
super().__init__(tool_config)
|
|
11
|
+
self.base_url = "https://www.ebi.ac.uk/interpro/api"
|
|
12
|
+
self.session = requests.Session()
|
|
13
|
+
self.session.headers.update(
|
|
14
|
+
{"Accept": "application/json", "User-Agent": "ToolUniverse/1.0"}
|
|
15
|
+
)
|
|
16
|
+
self.timeout = 30
|
|
17
|
+
|
|
18
|
+
def _build_url(self, args: Dict[str, Any]) -> str:
|
|
19
|
+
"""Build URL from endpoint template and arguments"""
|
|
20
|
+
url = self.tool_config["fields"]["endpoint"]
|
|
21
|
+
for k, v in args.items():
|
|
22
|
+
url = url.replace(f"{{{k}}}", str(v))
|
|
23
|
+
return url
|
|
24
|
+
|
|
25
|
+
def _extract_data(self, data: Dict, extract_path: str = None) -> Any:
|
|
26
|
+
"""Extract specific data from API response"""
|
|
27
|
+
if not extract_path:
|
|
28
|
+
return data
|
|
29
|
+
|
|
30
|
+
# Handle specific InterPro extraction patterns
|
|
31
|
+
if extract_path == "results":
|
|
32
|
+
return data.get("results", [])
|
|
33
|
+
elif extract_path == "count":
|
|
34
|
+
return data.get("count", 0)
|
|
35
|
+
elif extract_path == "metadata":
|
|
36
|
+
return data.get("metadata", {})
|
|
37
|
+
|
|
38
|
+
return data
|
|
39
|
+
|
|
40
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
41
|
+
"""Execute the InterPro API call"""
|
|
42
|
+
try:
|
|
43
|
+
# Build URL from endpoint template
|
|
44
|
+
url = self._build_url(arguments)
|
|
45
|
+
|
|
46
|
+
# Make API request
|
|
47
|
+
response = self.session.get(url, timeout=self.timeout)
|
|
48
|
+
response.raise_for_status()
|
|
49
|
+
|
|
50
|
+
# Parse JSON response
|
|
51
|
+
data = response.json()
|
|
52
|
+
|
|
53
|
+
# Extract data if specified
|
|
54
|
+
extract_path = self.tool_config["fields"].get("extract_path")
|
|
55
|
+
if extract_path:
|
|
56
|
+
result = self._extract_data(data, extract_path)
|
|
57
|
+
else:
|
|
58
|
+
result = data
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
"status": "success",
|
|
62
|
+
"data": result,
|
|
63
|
+
"url": url,
|
|
64
|
+
"count": len(result) if isinstance(result, list) else 1,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
return {
|
|
69
|
+
"status": "error",
|
|
70
|
+
"error": f"InterPro API error: {str(e)}",
|
|
71
|
+
"url": url,
|
|
72
|
+
}
|