agr-curation-api-client 0.1.0__tar.gz
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.
- agr_curation_api_client-0.1.0/LICENSE +21 -0
- agr_curation_api_client-0.1.0/PKG-INFO +321 -0
- agr_curation_api_client-0.1.0/README.md +279 -0
- agr_curation_api_client-0.1.0/pyproject.toml +78 -0
- agr_curation_api_client-0.1.0/setup.cfg +62 -0
- agr_curation_api_client-0.1.0/setup.py +11 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api/__init__.py +39 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api/client.py +347 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api/exceptions.py +43 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api/models.py +132 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api/py.typed +0 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api_client.egg-info/PKG-INFO +321 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api_client.egg-info/SOURCES.txt +16 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api_client.egg-info/dependency_links.txt +1 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api_client.egg-info/requires.txt +16 -0
- agr_curation_api_client-0.1.0/src/agr_curation_api_client.egg-info/top_level.txt +1 -0
- agr_curation_api_client-0.1.0/tests/test_okta_authentication.py +77 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alliance of Genome Resources
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agr-curation-api-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unified Python client for Alliance of Genome Resources (AGR) curation APIs
|
|
5
|
+
Author-email: Alliance of Genome Resources <valearna@caltech.edu>
|
|
6
|
+
Maintainer-email: Alliance Blue Team <valearna@caltech.edu>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/alliance-genome/agr_curation_api_client
|
|
9
|
+
Project-URL: Bug Reports, https://github.com/alliance-genome/agr_curation_api_client/issues
|
|
10
|
+
Project-URL: Source, https://github.com/alliance-genome/agr_curation_api_client
|
|
11
|
+
Project-URL: Documentation, https://github.com/alliance-genome/agr_curation_api_client#readme
|
|
12
|
+
Keywords: agr,alliance,genome,curation,api,client
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: requests>=2.28.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0.0
|
|
28
|
+
Requires-Dist: httpx>=0.24.0
|
|
29
|
+
Requires-Dist: tenacity>=8.0.0
|
|
30
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
31
|
+
Requires-Dist: fastapi_okta>=1.3.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
36
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: types-requests; extra == "dev"
|
|
40
|
+
Requires-Dist: types-python-dateutil; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# AGR Curation API Client
|
|
44
|
+
|
|
45
|
+
A unified Python client for Alliance of Genome Resources (AGR) curation APIs.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- **Unified Interface**: Single client for all AGR curation API endpoints
|
|
50
|
+
- **Type Safety**: Full type hints and Pydantic models for request/response validation
|
|
51
|
+
- **Retry Logic**: Automatic retry with exponential backoff for transient failures
|
|
52
|
+
- **Authentication**: Support for API key and Okta token authentication
|
|
53
|
+
- **Async Support**: Built on httpx for both sync and async operations
|
|
54
|
+
- **Comprehensive Error Handling**: Detailed exceptions for different error scenarios
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install agr-curation-api-client
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For development:
|
|
63
|
+
```bash
|
|
64
|
+
git clone https://github.com/alliance-genome/agr_curation_api_client.git
|
|
65
|
+
cd agr_curation_api_client
|
|
66
|
+
make install-dev
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Authentication
|
|
70
|
+
|
|
71
|
+
The client supports automatic Okta token generation using the same environment variables as other AGR services:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
export OKTA_DOMAIN="your-okta-domain"
|
|
75
|
+
export OKTA_API_AUDIENCE="your-api-audience"
|
|
76
|
+
export OKTA_CLIENT_ID="your-client-id"
|
|
77
|
+
export OKTA_CLIENT_SECRET="your-client-secret"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
With these environment variables set, the client will automatically obtain an authentication token when initialized.
|
|
81
|
+
|
|
82
|
+
## Quick Start
|
|
83
|
+
|
|
84
|
+
### Basic Usage
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from agr_curation_api import AGRCurationAPIClient, APIConfig
|
|
88
|
+
|
|
89
|
+
# Option 1: Automatic authentication (requires OKTA env vars)
|
|
90
|
+
client = AGRCurationAPIClient()
|
|
91
|
+
|
|
92
|
+
# Option 2: Manual token configuration
|
|
93
|
+
config = APIConfig(
|
|
94
|
+
base_url="https://curation.alliancegenome.org/api",
|
|
95
|
+
okta_token="your-okta-token" # Optional - will auto-retrieve if not provided
|
|
96
|
+
)
|
|
97
|
+
client = AGRCurationAPIClient(config)
|
|
98
|
+
|
|
99
|
+
# Use the client
|
|
100
|
+
with client:
|
|
101
|
+
# Get genes from WormBase
|
|
102
|
+
genes = client.get_genes(data_provider="WB", limit=10)
|
|
103
|
+
|
|
104
|
+
for gene in genes:
|
|
105
|
+
symbol = gene.gene_symbol.get("displayText", "") if gene.gene_symbol else ""
|
|
106
|
+
print(f"{gene.curie}: {symbol}")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Working with Genes
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from agr_curation_api import AGRCurationAPIClient, Gene
|
|
113
|
+
|
|
114
|
+
# Use default configuration
|
|
115
|
+
client = AGRCurationAPIClient()
|
|
116
|
+
|
|
117
|
+
# Get genes from a specific data provider
|
|
118
|
+
wb_genes = client.get_genes(data_provider="WB", limit=100)
|
|
119
|
+
print(f"Found {len(wb_genes)} WormBase genes")
|
|
120
|
+
|
|
121
|
+
# Get a specific gene by ID
|
|
122
|
+
gene = client.get_gene("WB:WBGene00001234")
|
|
123
|
+
if gene:
|
|
124
|
+
print(f"Gene: {gene.gene_symbol}")
|
|
125
|
+
print(f"Full name: {gene.gene_full_name}")
|
|
126
|
+
print(f"Species: {gene.taxon}")
|
|
127
|
+
|
|
128
|
+
# Get all genes (paginated)
|
|
129
|
+
all_genes = client.get_genes(limit=5000, page=0)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Working with Species
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
# Get all species
|
|
136
|
+
species_list = client.get_species()
|
|
137
|
+
|
|
138
|
+
for species in species_list:
|
|
139
|
+
print(f"{species.abbreviation}: {species.display_name}")
|
|
140
|
+
|
|
141
|
+
# Find a specific species
|
|
142
|
+
wb_species = [s for s in species_list if s.abbreviation == "WB"]
|
|
143
|
+
if wb_species:
|
|
144
|
+
print(f"WormBase: {wb_species[0].full_name}")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Working with Ontology Terms
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
# Get GO term root nodes
|
|
151
|
+
go_roots = client.get_ontology_root_nodes("goterm")
|
|
152
|
+
print(f"Found {len(go_roots)} GO root terms")
|
|
153
|
+
|
|
154
|
+
# Get children of a specific GO term
|
|
155
|
+
children = client.get_ontology_node_children("GO:0008150", "goterm") # biological_process
|
|
156
|
+
for child in children:
|
|
157
|
+
print(f"{child.curie}: {child.name}")
|
|
158
|
+
|
|
159
|
+
# Get disease ontology terms
|
|
160
|
+
disease_roots = client.get_ontology_root_nodes("doterm")
|
|
161
|
+
|
|
162
|
+
# Get anatomical terms
|
|
163
|
+
anatomy_roots = client.get_ontology_root_nodes("anatomicalterm")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Working with Expression Annotations
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# Get expression annotations for WormBase
|
|
170
|
+
wb_expressions = client.get_expression_annotations(
|
|
171
|
+
data_provider="WB",
|
|
172
|
+
limit=100
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
for expr in wb_expressions:
|
|
176
|
+
if expr.expression_annotation_subject:
|
|
177
|
+
gene_id = expr.expression_annotation_subject.get("primaryExternalId")
|
|
178
|
+
gene_symbol = expr.expression_annotation_subject.get("geneSymbol", {}).get("displayText")
|
|
179
|
+
print(f"Gene: {gene_id} ({gene_symbol})")
|
|
180
|
+
|
|
181
|
+
if expr.expression_pattern:
|
|
182
|
+
anatomy = expr.expression_pattern.get("whereExpressed", {}).get("anatomicalStructure", {}).get("curie")
|
|
183
|
+
print(f" Expressed in: {anatomy}")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Working with Alleles
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# Get alleles from a specific data provider
|
|
190
|
+
wb_alleles = client.get_alleles(data_provider="WB", limit=50)
|
|
191
|
+
|
|
192
|
+
for allele in wb_alleles:
|
|
193
|
+
symbol = allele.allele_symbol.get("displayText", "") if allele.allele_symbol else ""
|
|
194
|
+
print(f"{allele.curie}: {symbol}")
|
|
195
|
+
|
|
196
|
+
# Get a specific allele
|
|
197
|
+
allele = client.get_allele("WB:WBVar00001234")
|
|
198
|
+
if allele:
|
|
199
|
+
print(f"Allele: {allele.allele_symbol}")
|
|
200
|
+
print(f"Full name: {allele.allele_full_name}")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Generic Search
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
# Generic entity search
|
|
207
|
+
search_filters = {
|
|
208
|
+
"dataProvider.abbreviation": "WB",
|
|
209
|
+
"geneSymbol.displayText": "daf-16"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
results = client.search_entities(
|
|
213
|
+
entity_type="gene",
|
|
214
|
+
search_filters=search_filters,
|
|
215
|
+
limit=10
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
print(f"Total results: {results.total_results}")
|
|
219
|
+
print(f"Returned: {results.returned_records}")
|
|
220
|
+
|
|
221
|
+
for gene_data in results.results:
|
|
222
|
+
print(f"Found gene: {gene_data}")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Error Handling
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from agr_curation_api import (
|
|
229
|
+
AGRAPIError,
|
|
230
|
+
AGRAuthenticationError,
|
|
231
|
+
AGRConnectionError,
|
|
232
|
+
AGRTimeoutError,
|
|
233
|
+
AGRValidationError
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
try:
|
|
237
|
+
reference = client.get_reference("invalid-id")
|
|
238
|
+
except AGRAuthenticationError:
|
|
239
|
+
print("Authentication failed - check your credentials")
|
|
240
|
+
except AGRValidationError as e:
|
|
241
|
+
print(f"Invalid data: {e}")
|
|
242
|
+
except AGRTimeoutError:
|
|
243
|
+
print("Request timed out - try again later")
|
|
244
|
+
except AGRConnectionError:
|
|
245
|
+
print("Connection failed - check network")
|
|
246
|
+
except AGRAPIError as e:
|
|
247
|
+
print(f"API error: {e}")
|
|
248
|
+
if e.status_code:
|
|
249
|
+
print(f"Status code: {e.status_code}")
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Configuration Options
|
|
253
|
+
|
|
254
|
+
The `APIConfig` class supports the following options:
|
|
255
|
+
|
|
256
|
+
- `base_url`: Base URL for the A-Team Curation API (default: "https://curation.alliancegenome.org/api")
|
|
257
|
+
- `okta_token`: Okta bearer token for authentication (auto-retrieved if not provided)
|
|
258
|
+
- `timeout`: Request timeout in seconds (default: 30)
|
|
259
|
+
- `max_retries`: Maximum retry attempts (default: 3)
|
|
260
|
+
- `retry_delay`: Initial delay between retries in seconds (default: 1)
|
|
261
|
+
- `verify_ssl`: Whether to verify SSL certificates (default: True)
|
|
262
|
+
- `headers`: Additional headers to include in requests
|
|
263
|
+
|
|
264
|
+
### Environment Variables
|
|
265
|
+
|
|
266
|
+
The client uses the following environment variables for configuration:
|
|
267
|
+
|
|
268
|
+
- `ATEAM_API`: Override the default A-Team API URL (default: uses production curation API)
|
|
269
|
+
- `OKTA_DOMAIN`: Your Okta domain (required for automatic authentication)
|
|
270
|
+
- `OKTA_API_AUDIENCE`: Your API audience (required for automatic authentication)
|
|
271
|
+
- `OKTA_CLIENT_ID`: Your Okta client ID (required for automatic authentication)
|
|
272
|
+
- `OKTA_CLIENT_SECRET`: Your Okta client secret (required for automatic authentication)
|
|
273
|
+
|
|
274
|
+
## Development
|
|
275
|
+
|
|
276
|
+
### Running Tests
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
make test
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Code Quality
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# Run linting
|
|
286
|
+
make lint
|
|
287
|
+
|
|
288
|
+
# Run type checking
|
|
289
|
+
make type-check
|
|
290
|
+
|
|
291
|
+
# Format code
|
|
292
|
+
make format
|
|
293
|
+
|
|
294
|
+
# Run all checks
|
|
295
|
+
make check
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Building Documentation
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
cd docs
|
|
302
|
+
make html
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Contributing
|
|
306
|
+
|
|
307
|
+
1. Fork the repository
|
|
308
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
309
|
+
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
|
|
310
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
311
|
+
5. Open a Pull Request
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
316
|
+
|
|
317
|
+
## Support
|
|
318
|
+
|
|
319
|
+
- **Issues**: [GitHub Issues](https://github.com/alliance-genome/agr_curation_api_client/issues)
|
|
320
|
+
- **Documentation**: [API Documentation](https://alliancegenome.org/api-docs)
|
|
321
|
+
- **Contact**: software@alliancegenome.org
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# AGR Curation API Client
|
|
2
|
+
|
|
3
|
+
A unified Python client for Alliance of Genome Resources (AGR) curation APIs.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Unified Interface**: Single client for all AGR curation API endpoints
|
|
8
|
+
- **Type Safety**: Full type hints and Pydantic models for request/response validation
|
|
9
|
+
- **Retry Logic**: Automatic retry with exponential backoff for transient failures
|
|
10
|
+
- **Authentication**: Support for API key and Okta token authentication
|
|
11
|
+
- **Async Support**: Built on httpx for both sync and async operations
|
|
12
|
+
- **Comprehensive Error Handling**: Detailed exceptions for different error scenarios
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install agr-curation-api-client
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For development:
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/alliance-genome/agr_curation_api_client.git
|
|
23
|
+
cd agr_curation_api_client
|
|
24
|
+
make install-dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Authentication
|
|
28
|
+
|
|
29
|
+
The client supports automatic Okta token generation using the same environment variables as other AGR services:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
export OKTA_DOMAIN="your-okta-domain"
|
|
33
|
+
export OKTA_API_AUDIENCE="your-api-audience"
|
|
34
|
+
export OKTA_CLIENT_ID="your-client-id"
|
|
35
|
+
export OKTA_CLIENT_SECRET="your-client-secret"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
With these environment variables set, the client will automatically obtain an authentication token when initialized.
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
### Basic Usage
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from agr_curation_api import AGRCurationAPIClient, APIConfig
|
|
46
|
+
|
|
47
|
+
# Option 1: Automatic authentication (requires OKTA env vars)
|
|
48
|
+
client = AGRCurationAPIClient()
|
|
49
|
+
|
|
50
|
+
# Option 2: Manual token configuration
|
|
51
|
+
config = APIConfig(
|
|
52
|
+
base_url="https://curation.alliancegenome.org/api",
|
|
53
|
+
okta_token="your-okta-token" # Optional - will auto-retrieve if not provided
|
|
54
|
+
)
|
|
55
|
+
client = AGRCurationAPIClient(config)
|
|
56
|
+
|
|
57
|
+
# Use the client
|
|
58
|
+
with client:
|
|
59
|
+
# Get genes from WormBase
|
|
60
|
+
genes = client.get_genes(data_provider="WB", limit=10)
|
|
61
|
+
|
|
62
|
+
for gene in genes:
|
|
63
|
+
symbol = gene.gene_symbol.get("displayText", "") if gene.gene_symbol else ""
|
|
64
|
+
print(f"{gene.curie}: {symbol}")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Working with Genes
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from agr_curation_api import AGRCurationAPIClient, Gene
|
|
71
|
+
|
|
72
|
+
# Use default configuration
|
|
73
|
+
client = AGRCurationAPIClient()
|
|
74
|
+
|
|
75
|
+
# Get genes from a specific data provider
|
|
76
|
+
wb_genes = client.get_genes(data_provider="WB", limit=100)
|
|
77
|
+
print(f"Found {len(wb_genes)} WormBase genes")
|
|
78
|
+
|
|
79
|
+
# Get a specific gene by ID
|
|
80
|
+
gene = client.get_gene("WB:WBGene00001234")
|
|
81
|
+
if gene:
|
|
82
|
+
print(f"Gene: {gene.gene_symbol}")
|
|
83
|
+
print(f"Full name: {gene.gene_full_name}")
|
|
84
|
+
print(f"Species: {gene.taxon}")
|
|
85
|
+
|
|
86
|
+
# Get all genes (paginated)
|
|
87
|
+
all_genes = client.get_genes(limit=5000, page=0)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Working with Species
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
# Get all species
|
|
94
|
+
species_list = client.get_species()
|
|
95
|
+
|
|
96
|
+
for species in species_list:
|
|
97
|
+
print(f"{species.abbreviation}: {species.display_name}")
|
|
98
|
+
|
|
99
|
+
# Find a specific species
|
|
100
|
+
wb_species = [s for s in species_list if s.abbreviation == "WB"]
|
|
101
|
+
if wb_species:
|
|
102
|
+
print(f"WormBase: {wb_species[0].full_name}")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Working with Ontology Terms
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# Get GO term root nodes
|
|
109
|
+
go_roots = client.get_ontology_root_nodes("goterm")
|
|
110
|
+
print(f"Found {len(go_roots)} GO root terms")
|
|
111
|
+
|
|
112
|
+
# Get children of a specific GO term
|
|
113
|
+
children = client.get_ontology_node_children("GO:0008150", "goterm") # biological_process
|
|
114
|
+
for child in children:
|
|
115
|
+
print(f"{child.curie}: {child.name}")
|
|
116
|
+
|
|
117
|
+
# Get disease ontology terms
|
|
118
|
+
disease_roots = client.get_ontology_root_nodes("doterm")
|
|
119
|
+
|
|
120
|
+
# Get anatomical terms
|
|
121
|
+
anatomy_roots = client.get_ontology_root_nodes("anatomicalterm")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Working with Expression Annotations
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# Get expression annotations for WormBase
|
|
128
|
+
wb_expressions = client.get_expression_annotations(
|
|
129
|
+
data_provider="WB",
|
|
130
|
+
limit=100
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
for expr in wb_expressions:
|
|
134
|
+
if expr.expression_annotation_subject:
|
|
135
|
+
gene_id = expr.expression_annotation_subject.get("primaryExternalId")
|
|
136
|
+
gene_symbol = expr.expression_annotation_subject.get("geneSymbol", {}).get("displayText")
|
|
137
|
+
print(f"Gene: {gene_id} ({gene_symbol})")
|
|
138
|
+
|
|
139
|
+
if expr.expression_pattern:
|
|
140
|
+
anatomy = expr.expression_pattern.get("whereExpressed", {}).get("anatomicalStructure", {}).get("curie")
|
|
141
|
+
print(f" Expressed in: {anatomy}")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Working with Alleles
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# Get alleles from a specific data provider
|
|
148
|
+
wb_alleles = client.get_alleles(data_provider="WB", limit=50)
|
|
149
|
+
|
|
150
|
+
for allele in wb_alleles:
|
|
151
|
+
symbol = allele.allele_symbol.get("displayText", "") if allele.allele_symbol else ""
|
|
152
|
+
print(f"{allele.curie}: {symbol}")
|
|
153
|
+
|
|
154
|
+
# Get a specific allele
|
|
155
|
+
allele = client.get_allele("WB:WBVar00001234")
|
|
156
|
+
if allele:
|
|
157
|
+
print(f"Allele: {allele.allele_symbol}")
|
|
158
|
+
print(f"Full name: {allele.allele_full_name}")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Generic Search
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Generic entity search
|
|
165
|
+
search_filters = {
|
|
166
|
+
"dataProvider.abbreviation": "WB",
|
|
167
|
+
"geneSymbol.displayText": "daf-16"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
results = client.search_entities(
|
|
171
|
+
entity_type="gene",
|
|
172
|
+
search_filters=search_filters,
|
|
173
|
+
limit=10
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
print(f"Total results: {results.total_results}")
|
|
177
|
+
print(f"Returned: {results.returned_records}")
|
|
178
|
+
|
|
179
|
+
for gene_data in results.results:
|
|
180
|
+
print(f"Found gene: {gene_data}")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Error Handling
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from agr_curation_api import (
|
|
187
|
+
AGRAPIError,
|
|
188
|
+
AGRAuthenticationError,
|
|
189
|
+
AGRConnectionError,
|
|
190
|
+
AGRTimeoutError,
|
|
191
|
+
AGRValidationError
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
reference = client.get_reference("invalid-id")
|
|
196
|
+
except AGRAuthenticationError:
|
|
197
|
+
print("Authentication failed - check your credentials")
|
|
198
|
+
except AGRValidationError as e:
|
|
199
|
+
print(f"Invalid data: {e}")
|
|
200
|
+
except AGRTimeoutError:
|
|
201
|
+
print("Request timed out - try again later")
|
|
202
|
+
except AGRConnectionError:
|
|
203
|
+
print("Connection failed - check network")
|
|
204
|
+
except AGRAPIError as e:
|
|
205
|
+
print(f"API error: {e}")
|
|
206
|
+
if e.status_code:
|
|
207
|
+
print(f"Status code: {e.status_code}")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Configuration Options
|
|
211
|
+
|
|
212
|
+
The `APIConfig` class supports the following options:
|
|
213
|
+
|
|
214
|
+
- `base_url`: Base URL for the A-Team Curation API (default: "https://curation.alliancegenome.org/api")
|
|
215
|
+
- `okta_token`: Okta bearer token for authentication (auto-retrieved if not provided)
|
|
216
|
+
- `timeout`: Request timeout in seconds (default: 30)
|
|
217
|
+
- `max_retries`: Maximum retry attempts (default: 3)
|
|
218
|
+
- `retry_delay`: Initial delay between retries in seconds (default: 1)
|
|
219
|
+
- `verify_ssl`: Whether to verify SSL certificates (default: True)
|
|
220
|
+
- `headers`: Additional headers to include in requests
|
|
221
|
+
|
|
222
|
+
### Environment Variables
|
|
223
|
+
|
|
224
|
+
The client uses the following environment variables for configuration:
|
|
225
|
+
|
|
226
|
+
- `ATEAM_API`: Override the default A-Team API URL (default: uses production curation API)
|
|
227
|
+
- `OKTA_DOMAIN`: Your Okta domain (required for automatic authentication)
|
|
228
|
+
- `OKTA_API_AUDIENCE`: Your API audience (required for automatic authentication)
|
|
229
|
+
- `OKTA_CLIENT_ID`: Your Okta client ID (required for automatic authentication)
|
|
230
|
+
- `OKTA_CLIENT_SECRET`: Your Okta client secret (required for automatic authentication)
|
|
231
|
+
|
|
232
|
+
## Development
|
|
233
|
+
|
|
234
|
+
### Running Tests
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
make test
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Code Quality
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Run linting
|
|
244
|
+
make lint
|
|
245
|
+
|
|
246
|
+
# Run type checking
|
|
247
|
+
make type-check
|
|
248
|
+
|
|
249
|
+
# Format code
|
|
250
|
+
make format
|
|
251
|
+
|
|
252
|
+
# Run all checks
|
|
253
|
+
make check
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Building Documentation
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
cd docs
|
|
260
|
+
make html
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Contributing
|
|
264
|
+
|
|
265
|
+
1. Fork the repository
|
|
266
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
267
|
+
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
|
|
268
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
269
|
+
5. Open a Pull Request
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
274
|
+
|
|
275
|
+
## Support
|
|
276
|
+
|
|
277
|
+
- **Issues**: [GitHub Issues](https://github.com/alliance-genome/agr_curation_api_client/issues)
|
|
278
|
+
- **Documentation**: [API Documentation](https://alliancegenome.org/api-docs)
|
|
279
|
+
- **Contact**: software@alliancegenome.org
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agr-curation-api-client"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Unified Python client for Alliance of Genome Resources (AGR) curation APIs"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Alliance of Genome Resources", email = "valearna@caltech.edu"},
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{name = "Alliance Blue Team", email = "valearna@caltech.edu"},
|
|
17
|
+
]
|
|
18
|
+
keywords = ["agr", "alliance", "genome", "curation", "api", "client"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"requests>=2.28.0",
|
|
33
|
+
"pydantic>=2.0.0",
|
|
34
|
+
"httpx>=0.24.0",
|
|
35
|
+
"tenacity>=8.0.0",
|
|
36
|
+
"python-dateutil>=2.8.0",
|
|
37
|
+
"fastapi_okta>=1.3.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
dev = [
|
|
42
|
+
"pytest>=7.0.0",
|
|
43
|
+
"pytest-cov>=4.0.0",
|
|
44
|
+
"pytest-asyncio>=0.21.0",
|
|
45
|
+
"black>=23.0.0",
|
|
46
|
+
"flake8>=6.0.0",
|
|
47
|
+
"mypy>=1.0.0",
|
|
48
|
+
"types-requests",
|
|
49
|
+
"types-python-dateutil",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
"Homepage" = "https://github.com/alliance-genome/agr_curation_api_client"
|
|
54
|
+
"Bug Reports" = "https://github.com/alliance-genome/agr_curation_api_client/issues"
|
|
55
|
+
"Source" = "https://github.com/alliance-genome/agr_curation_api_client"
|
|
56
|
+
"Documentation" = "https://github.com/alliance-genome/agr_curation_api_client#readme"
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.packages.find]
|
|
59
|
+
where = ["src"]
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.package-data]
|
|
62
|
+
agr_curation_api = ["py.typed"]
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.9"
|
|
66
|
+
warn_return_any = true
|
|
67
|
+
warn_unused_configs = true
|
|
68
|
+
disallow_untyped_defs = true
|
|
69
|
+
ignore_missing_imports = true
|
|
70
|
+
|
|
71
|
+
[tool.black]
|
|
72
|
+
line-length = 120
|
|
73
|
+
target-version = ['py39']
|
|
74
|
+
|
|
75
|
+
[tool.pytest.ini_options]
|
|
76
|
+
testpaths = ["tests"]
|
|
77
|
+
python_files = ["test_*.py", "*_test.py"]
|
|
78
|
+
addopts = "-ra -v --cov=agr_curation_api --cov-report=html --cov-report=term"
|