bacdive 0.3.1__py3-none-any.whl → 2.0.0__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.
- .DS_Store +0 -0
- bacdive/client.py +267 -232
- {bacdive-0.3.1.dist-info → bacdive-2.0.0.dist-info}/METADATA +146 -108
- bacdive-2.0.0.dist-info/RECORD +8 -0
- {bacdive-0.3.1.dist-info → bacdive-2.0.0.dist-info}/WHEEL +1 -1
- bacdive-0.3.1.dist-info/RECORD +0 -7
- {bacdive-0.3.1.dist-info → bacdive-2.0.0.dist-info/licenses}/LICENSE +0 -0
- {bacdive-0.3.1.dist-info → bacdive-2.0.0.dist-info}/top_level.txt +0 -0
.DS_Store
ADDED
|
Binary file
|
bacdive/client.py
CHANGED
|
@@ -1,232 +1,267 @@
|
|
|
1
|
-
'''
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
self.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return json.loads(resp.content)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def
|
|
141
|
-
''' Initialize search by
|
|
142
|
-
item =
|
|
143
|
-
result = self.do_api_call('
|
|
144
|
-
return result
|
|
145
|
-
|
|
146
|
-
def
|
|
147
|
-
''' Initialize search by
|
|
148
|
-
item =
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
elif querytype == '
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
1
|
+
'''
|
|
2
|
+
This package is for using the BacDive API V2 (2026-02).
|
|
3
|
+
Registration is not required anymore.
|
|
4
|
+
'''
|
|
5
|
+
|
|
6
|
+
from requests.adapters import HTTPAdapter
|
|
7
|
+
from urllib3.util.retry import Retry
|
|
8
|
+
import requests
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ReportRetry(Retry):
|
|
14
|
+
''' Wrapper for retry strategy to report retries'''
|
|
15
|
+
def __init__(self, url=None, *args, **kwargs):
|
|
16
|
+
self.url = url
|
|
17
|
+
self.retry_count = 0
|
|
18
|
+
super().__init__(*args, **kwargs)
|
|
19
|
+
|
|
20
|
+
def increment(self, *args, **kwargs):
|
|
21
|
+
self.retry_count += 1
|
|
22
|
+
print(f"Retrying API request for {self.url}. Attempt number {self.retry_count}.")
|
|
23
|
+
return super().increment(*args, **kwargs)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BacdiveClient():
|
|
27
|
+
def __init__(self, user=None, password=None, public=True, max_retries=10, retry_delay=50, request_timeout=300):
|
|
28
|
+
''' Initialize client and authenticate on the server '''
|
|
29
|
+
self.result = {}
|
|
30
|
+
self.public = public
|
|
31
|
+
self.max_retries = max_retries
|
|
32
|
+
self.retry_delay = retry_delay # in seconds
|
|
33
|
+
self.request_timeout = request_timeout # in seconds
|
|
34
|
+
|
|
35
|
+
self.predictions = False
|
|
36
|
+
self.search_type = False
|
|
37
|
+
|
|
38
|
+
client_id = "api.bacdive.public"
|
|
39
|
+
if self.public:
|
|
40
|
+
server_url = "https://sso.dsmz.de/auth/"
|
|
41
|
+
else:
|
|
42
|
+
server_url = "https://sso.dmz.dsmz.de/auth/"
|
|
43
|
+
|
|
44
|
+
def includePredictions(self):
|
|
45
|
+
self.predictions = True
|
|
46
|
+
|
|
47
|
+
def excludePredictions(self):
|
|
48
|
+
self.predictions = False
|
|
49
|
+
|
|
50
|
+
def setSearchType(self, search_type):
|
|
51
|
+
if search_type:
|
|
52
|
+
allowed = ['exact', 'contains', 'startswith', 'endswith']
|
|
53
|
+
if search_type not in allowed:
|
|
54
|
+
print("WARNING - Search Type is not allowed.")
|
|
55
|
+
self.search_type = "exact"
|
|
56
|
+
else:
|
|
57
|
+
self.search_type = search_type
|
|
58
|
+
else:
|
|
59
|
+
self.search_type = False
|
|
60
|
+
|
|
61
|
+
def do_api_call(self, url):
|
|
62
|
+
''' Initialize API call on given URL and returns result as json '''
|
|
63
|
+
if self.public:
|
|
64
|
+
baseurl = "https://api.bacdive.dsmz.de/v2/"
|
|
65
|
+
else:
|
|
66
|
+
baseurl = "http://api.bacdive-dev.dsmz.local/v2/"
|
|
67
|
+
|
|
68
|
+
if not url.startswith("http"):
|
|
69
|
+
# if base is missing add default:
|
|
70
|
+
url = baseurl + url
|
|
71
|
+
resp = self.do_request(url)
|
|
72
|
+
|
|
73
|
+
if resp.status_code == 500 or resp.status_code == 400 or resp.status_code == 503:
|
|
74
|
+
print(f"Error {resp.status_code}: {resp.content}")
|
|
75
|
+
return json.loads(resp.content)
|
|
76
|
+
elif (resp.status_code == 401):
|
|
77
|
+
msg = json.loads(resp.content)
|
|
78
|
+
|
|
79
|
+
return msg
|
|
80
|
+
else:
|
|
81
|
+
return json.loads(resp.content)
|
|
82
|
+
|
|
83
|
+
def do_request(self, url):
|
|
84
|
+
''' Perform request'''
|
|
85
|
+
headers = {
|
|
86
|
+
"Accept": "application/json",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if self.predictions:
|
|
90
|
+
if "?" in url:
|
|
91
|
+
url += "&predictions=1"
|
|
92
|
+
else:
|
|
93
|
+
url += "?predictions=1"
|
|
94
|
+
# session with retry strategy
|
|
95
|
+
retry_strategy = ReportRetry(
|
|
96
|
+
url=url,
|
|
97
|
+
total=self.max_retries,
|
|
98
|
+
backoff_factor=1, # how much to increase delay between each try
|
|
99
|
+
status_forcelist=[429, 500, 502, 503, 504] # retry on
|
|
100
|
+
)
|
|
101
|
+
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
102
|
+
http = requests.Session()
|
|
103
|
+
http.mount("https://", adapter)
|
|
104
|
+
http.mount("http://", adapter)
|
|
105
|
+
|
|
106
|
+
resp = http.get(url, headers=headers, timeout=self.request_timeout) # timeout in seconds
|
|
107
|
+
return resp
|
|
108
|
+
|
|
109
|
+
def filterResult(self, d, keys):
|
|
110
|
+
''' Helper function to filter nested dict by keys '''
|
|
111
|
+
if not isinstance(d, dict):
|
|
112
|
+
yield None
|
|
113
|
+
for k, v in d.items():
|
|
114
|
+
if k in keys:
|
|
115
|
+
yield {k: v}
|
|
116
|
+
if isinstance(v, dict):
|
|
117
|
+
yield from self.filterResult(v, keys)
|
|
118
|
+
elif isinstance(v, list):
|
|
119
|
+
for i in v:
|
|
120
|
+
if isinstance(i, dict):
|
|
121
|
+
yield from self.filterResult(i, keys)
|
|
122
|
+
|
|
123
|
+
def retrieve(self, filter=None):
|
|
124
|
+
''' Yields all the received entries and does next call if result is incomplete '''
|
|
125
|
+
ids = ";".join([str(i) for i in self.result['results']])
|
|
126
|
+
entries = self.do_api_call('fetch/'+ids)['results'] if ids else []
|
|
127
|
+
for el in entries:
|
|
128
|
+
if isinstance(el, dict):
|
|
129
|
+
entry = el
|
|
130
|
+
el = entry.get("id")
|
|
131
|
+
else:
|
|
132
|
+
entry = entries[el]
|
|
133
|
+
if filter:
|
|
134
|
+
entry = {el: [i for i in self.filterResult(entry, filter)]}
|
|
135
|
+
yield entry
|
|
136
|
+
if self.result['next']:
|
|
137
|
+
self.result = self.do_api_call(self.result['next'])
|
|
138
|
+
yield from self.retrieve(filter)
|
|
139
|
+
|
|
140
|
+
def getIDByCultureno(self, culturecolnumber):
|
|
141
|
+
''' Initialize search by culture collection number '''
|
|
142
|
+
item = culturecolnumber.strip()
|
|
143
|
+
result = self.do_api_call('culturecollectionno/'+str(item))
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
def getIDsByTaxonomy(self, genus, species_epithet=None, subspecies_epithet=None):
|
|
147
|
+
''' Initialize search by taxonomic names '''
|
|
148
|
+
item = genus.strip()
|
|
149
|
+
if species_epithet:
|
|
150
|
+
item += "/" + species_epithet
|
|
151
|
+
if subspecies_epithet:
|
|
152
|
+
item += "/" + subspecies_epithet
|
|
153
|
+
result = self.do_api_call("taxon/"+item)
|
|
154
|
+
return result
|
|
155
|
+
|
|
156
|
+
def getIDsBy16S(self, seq_acc_num):
|
|
157
|
+
''' Initialize search by 16S sequence accession '''
|
|
158
|
+
item = seq_acc_num.strip()
|
|
159
|
+
result = self.do_api_call('sequence_16s/'+str(item))
|
|
160
|
+
return result
|
|
161
|
+
|
|
162
|
+
def getIDsByGenome(self, seq_acc_num):
|
|
163
|
+
''' Initialize search by genome sequence accession '''
|
|
164
|
+
item = seq_acc_num.strip()
|
|
165
|
+
result = self.do_api_call('sequence_genome/'+str(item))
|
|
166
|
+
return result
|
|
167
|
+
|
|
168
|
+
def search(self, **params):
|
|
169
|
+
''' Initialize search with *one* of the following parameters:
|
|
170
|
+
|
|
171
|
+
id -- BacDive-IDs either as a semicolon seperated string or list
|
|
172
|
+
taxonomy -- Taxonomic names either as string or list
|
|
173
|
+
sequence -- Sequence accession number of unknown type
|
|
174
|
+
genome -- Genome sequence accession number
|
|
175
|
+
16s -- 16S sequence accession number
|
|
176
|
+
culturecolno -- Culture collection number (mind the space!)
|
|
177
|
+
'''
|
|
178
|
+
params = list(params.items())
|
|
179
|
+
allowed = ['id', 'taxonomy', 'sequence',
|
|
180
|
+
'genome', '16s', 'culturecolno']
|
|
181
|
+
if len(params) != 1:
|
|
182
|
+
print(
|
|
183
|
+
"ERROR: Exacly one parameter is required. Please choose one of the following:")
|
|
184
|
+
print(", ".join(allowed))
|
|
185
|
+
return 0
|
|
186
|
+
querytype, query = params[0]
|
|
187
|
+
querytype = querytype.lower()
|
|
188
|
+
if querytype not in allowed:
|
|
189
|
+
print(
|
|
190
|
+
"ERROR: The given query type is not allowed. Please choose one of the following:")
|
|
191
|
+
print(", ".join(allowed))
|
|
192
|
+
return 0
|
|
193
|
+
if querytype == 'id':
|
|
194
|
+
if type(query) == type(1):
|
|
195
|
+
query = str(query)
|
|
196
|
+
if type(query) == type(""):
|
|
197
|
+
query = query.split(';')
|
|
198
|
+
self.result = {'count': len(query), 'next': None,
|
|
199
|
+
'previous': None, 'results': query}
|
|
200
|
+
elif querytype == 'taxonomy':
|
|
201
|
+
if type(query) == type(""):
|
|
202
|
+
query = [i for i in query.split(" ") if i != "subsp."]
|
|
203
|
+
if len(query) > 3:
|
|
204
|
+
print("Your query contains more than three taxonomical units.")
|
|
205
|
+
print(
|
|
206
|
+
"This query supports only genus, species epithet (optional), and subspecies (optional).")
|
|
207
|
+
print("They can be defined as list, tuple or string (space separated).")
|
|
208
|
+
return 0
|
|
209
|
+
self.result = self.getIDsByTaxonomy(*query)
|
|
210
|
+
elif querytype == 'sequence':
|
|
211
|
+
query = self.parseSearchTypeQuery(query)
|
|
212
|
+
self.result = self.getIDsByGenome(query)
|
|
213
|
+
if self.result['count'] == 0:
|
|
214
|
+
self.result = self.getIDsBy16S(query)
|
|
215
|
+
elif querytype == 'genome':
|
|
216
|
+
query = self.parseSearchTypeQuery(query)
|
|
217
|
+
self.result = self.getIDsByGenome(query)
|
|
218
|
+
elif querytype == '16s':
|
|
219
|
+
query = self.parseSearchTypeQuery(query)
|
|
220
|
+
self.result = self.getIDsBy16S(query)
|
|
221
|
+
elif querytype == 'culturecolno':
|
|
222
|
+
query = self.parseSearchTypeQuery(query)
|
|
223
|
+
self.result = self.getIDByCultureno(query)
|
|
224
|
+
|
|
225
|
+
if not self.result:
|
|
226
|
+
print("ERROR: Something went wrong. Please check your query and try again")
|
|
227
|
+
return 0
|
|
228
|
+
if not 'count' in self.result:
|
|
229
|
+
print("ERROR:", self.result.get("title"))
|
|
230
|
+
print(self.result.get("message"))
|
|
231
|
+
return 0
|
|
232
|
+
if self.result['count'] == 0:
|
|
233
|
+
print("Your search did not receive any results.")
|
|
234
|
+
return 0
|
|
235
|
+
return self.result['count']
|
|
236
|
+
|
|
237
|
+
def parseSearchTypeQuery(self, query):
|
|
238
|
+
if type(query) == type(1):
|
|
239
|
+
query = str(query)
|
|
240
|
+
if type(query) == type(""):
|
|
241
|
+
query = query.split(';')
|
|
242
|
+
|
|
243
|
+
item = ";".join([ str(i).strip() for i in query ])
|
|
244
|
+
|
|
245
|
+
if self.search_type:
|
|
246
|
+
if "?" in item:
|
|
247
|
+
item += "&search_type=" + self.search_type
|
|
248
|
+
else:
|
|
249
|
+
item += "?search_type=" + self.search_type
|
|
250
|
+
|
|
251
|
+
return item
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
if __name__ == "__main__":
|
|
256
|
+
client = BacdiveClient('mail.address@server.example', 'password')
|
|
257
|
+
|
|
258
|
+
# the prepare method fetches all BacDive-IDs matching your query
|
|
259
|
+
# and returns the number of IDs found
|
|
260
|
+
count = client.search(taxonomy='Bacillus subtilis subtilis')
|
|
261
|
+
print(count, 'entries found.')
|
|
262
|
+
|
|
263
|
+
# The retrieve method lets you iterate over all entries
|
|
264
|
+
# and returns the full entry as dict
|
|
265
|
+
# Entries can be further filtered using a list of keys (e.g. ['keywords'])
|
|
266
|
+
for entry in client.retrieve():
|
|
267
|
+
print(entry)
|
|
@@ -1,108 +1,146 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name: bacdive
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: BacDive-API - Programmatic Access to the BacDive Database
|
|
5
|
-
Home-page: https://bacdive.dsmz.de/
|
|
6
|
-
Author: Julia Koblitz
|
|
7
|
-
Author-email: julia.koblitz@dsmz.de
|
|
8
|
-
Keywords: microbiology bacteria strains phenotypes
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Intended Audience :: Science/Research
|
|
12
|
-
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
13
|
-
Requires-Python: >=3.6
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# the
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
query = {"
|
|
60
|
-
query = {"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
query = {"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bacdive
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: BacDive-API - Programmatic Access to the BacDive Database
|
|
5
|
+
Home-page: https://bacdive.dsmz.de/
|
|
6
|
+
Author: Julia Koblitz
|
|
7
|
+
Author-email: julia.koblitz@dsmz.de
|
|
8
|
+
Keywords: microbiology bacteria strains phenotypes
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
13
|
+
Requires-Python: >=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: requests>=2.25.1
|
|
17
|
+
Requires-Dist: urllib3>=1.26.5
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: keywords
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: requires-python
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# BacDive API v2
|
|
31
|
+
|
|
32
|
+
Using the BacDive API does not require registration anymore, but the usage of BacDive data is only permitted when in compliance with the BacDive terms of use. See [About BacDive](https://bacdive.dsmz.de/about) for details.
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import bacdive
|
|
36
|
+
|
|
37
|
+
client = bacdive.BacdiveClient()
|
|
38
|
+
|
|
39
|
+
# [optional] You may define the search type as one of the following:
|
|
40
|
+
# 'exact' (default), 'contains', 'startswith', 'endswith'
|
|
41
|
+
client.setSearchType('exact')
|
|
42
|
+
|
|
43
|
+
# The search method fetches all BacDive-IDs matching your query
|
|
44
|
+
# and returns the number of IDs found
|
|
45
|
+
count = client.search(taxonomy='Bacillus subtilis subtilis')
|
|
46
|
+
print(count, 'strains found.')
|
|
47
|
+
|
|
48
|
+
# the retrieve method lets you iterate over all strains
|
|
49
|
+
# and returns the full entry as dict
|
|
50
|
+
# Entries can be further filtered using a list of keys (e.g. ['keywords'])
|
|
51
|
+
for strain in client.retrieve():
|
|
52
|
+
print(strain)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Example queries:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# Search by BacDive-IDs (either semicolon separated or as list):
|
|
59
|
+
query = {"id": 24493}
|
|
60
|
+
query = {"id": "24493;12;132485"}
|
|
61
|
+
query = {"id": [24493, 12, 132485]}
|
|
62
|
+
|
|
63
|
+
# Search by culture collection number
|
|
64
|
+
query = {"culturecolno": "DSM 26640"}
|
|
65
|
+
# New in v1.0: Search by culture collection number with multiple numbers:
|
|
66
|
+
query = {"culturecolno": ["DSM 26640", "DSM 26646"]}
|
|
67
|
+
query = {"culturecolno": "DSM 26640;DSM 26646"} # semicolon may be used as separator
|
|
68
|
+
|
|
69
|
+
# Search by culture collection number with search type 'startswith':
|
|
70
|
+
client.setSearchType('startswith')
|
|
71
|
+
query = {"culturecolno": "DSM"}
|
|
72
|
+
|
|
73
|
+
# Search by taxonomy (either as full name or as list):
|
|
74
|
+
# With genus name, species epithet (optional), and subspecies (optional).
|
|
75
|
+
query = {"taxonomy": "Bacillus subtilis subsp. subtilis"}
|
|
76
|
+
query = {"taxonomy": ("Escherichia", "coli")}
|
|
77
|
+
|
|
78
|
+
# Search by 16S sequence accession numbers:
|
|
79
|
+
query = {"16s": "AF000162"}
|
|
80
|
+
# New in v1.0: Search by 16S sequence with multiple sequence accession numbers:
|
|
81
|
+
query = {"16s": ["AB681963", "JN566021", "AY027686"]}
|
|
82
|
+
# New in v1.0: Search by 16S sequence with search type 'startswith':
|
|
83
|
+
client.setSearchType('startswith')
|
|
84
|
+
query = {"16s": "AB"}
|
|
85
|
+
|
|
86
|
+
# Search by genome sequence accession numbers:
|
|
87
|
+
query = {"genome": "GCA_006094295"}
|
|
88
|
+
# New in v1.0: Search by genome sequence with multiple sequence accession numbers:
|
|
89
|
+
query = {"genome": ["GCA_003332855", "GCA_024623325", "GCA_017377855"]}
|
|
90
|
+
# New in v1.0: Search by genome sequence with search type 'startswith':
|
|
91
|
+
client.setSearchType('startswith')
|
|
92
|
+
query = {"genome": "DSM"}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# run query
|
|
96
|
+
client.search(**query)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Filtering
|
|
100
|
+
|
|
101
|
+
Results from the `retrieve` Method of both clients can be further filtered. The result contains a list of matched keyword dicts:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
filter=['keywords', 'culture collection no.']
|
|
105
|
+
result = client.retrieve(filter)
|
|
106
|
+
print({k:v for x in result for k,v in x.items()})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The printed result will look like this:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
{'1161': [{'keywords': ['human pathogen', 'Bacteria']},
|
|
113
|
+
{'culture collection no.': 'DSM 4393, pC194, SB202'}],
|
|
114
|
+
'1162': [{'keywords': ['human pathogen', 'Bacteria']},
|
|
115
|
+
{'culture collection no.': 'DSM 4514, ATCC 37015, BD170, NCIB 11624, '
|
|
116
|
+
'pUB110'}],
|
|
117
|
+
'1163': [{'keywords': ['human pathogen', 'Bacteria']},
|
|
118
|
+
{'culture collection no.': 'DSM 4554, ATCC 37128, BGSC 1E18, pE194'}],
|
|
119
|
+
'1164': [{'keywords': 'Bacteria'},
|
|
120
|
+
{'culture collection no.': 'DSM 4750, 1E7, BGSC 1E7, pE194-cop6'}],
|
|
121
|
+
...
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Hints for more advanced queries
|
|
125
|
+
If you have more advanced queries that are currently not covered by the API, we recommend you to use the [Bac*Dive* Advanced Search](https://bacdive.dsmz.de/advsearch), which is very flexible and powerful. You can then download the resulting table as CSV (button at the top right), import the CSV into your Python script, and use the BacDive-IDs to download all relevant information via the API.
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## New in v0.3
|
|
129
|
+
|
|
130
|
+
We added AI-based predictions to the Bac*Dive* database. Predicted traits are excluded by default. To include them, you have to call the method `includePredictions()`:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
client.includePredictions()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
You can exclude predictions again by calling:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
client.excludePredictions()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## New in v1.0
|
|
143
|
+
|
|
144
|
+
Thanks to [phenolophthaleinum](https://github.com/phenolophthaleinum) for improving the error handling and Joaquim Sardá for improving the BacDive-API and adding new search possibilities.
|
|
145
|
+
|
|
146
|
+
Examples for search type definitions and array requests are included in the examples above.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
.DS_Store,sha256=6kR8yA9s9_CWzDhydpvo0tm6-DKqdlejyWlPP6LyccY,8196
|
|
2
|
+
bacdive/__init__.py,sha256=m_PQ86KbAxoaj6q4ZhZghe4k4clRTHj6jgtBuQxl5Gs,33
|
|
3
|
+
bacdive/client.py,sha256=L0k98YF6xtEcAPEEQmE6gP_wk_c1UMfvCws7UPh9jZY,9957
|
|
4
|
+
bacdive-2.0.0.dist-info/licenses/LICENSE,sha256=5wPFG6uBYvOHGR5R3n3AI3SpYOY1ODbY8lHGOXM6Mt8,1142
|
|
5
|
+
bacdive-2.0.0.dist-info/METADATA,sha256=qDEIOcDG6jmsEHyUHQMSdMmEIMFTZYrIdFIFectggYw,5292
|
|
6
|
+
bacdive-2.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
7
|
+
bacdive-2.0.0.dist-info/top_level.txt,sha256=_lfFGIEO4Y9K0ky5sUVKRn_iijFQfdHzR7L-jSqkW8U,8
|
|
8
|
+
bacdive-2.0.0.dist-info/RECORD,,
|
bacdive-0.3.1.dist-info/RECORD
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
bacdive/__init__.py,sha256=m_PQ86KbAxoaj6q4ZhZghe4k4clRTHj6jgtBuQxl5Gs,33
|
|
2
|
-
bacdive/client.py,sha256=YRxP-qh7Q6kYc9hCRaomD6mdzVT_Qy5cas1wcNVBBKA,9060
|
|
3
|
-
bacdive-0.3.1.dist-info/LICENSE,sha256=5wPFG6uBYvOHGR5R3n3AI3SpYOY1ODbY8lHGOXM6Mt8,1142
|
|
4
|
-
bacdive-0.3.1.dist-info/METADATA,sha256=a7MOhs9w-l8UUh4qpP4t_c5HAedaAIcu0jLNp5WuprU,3552
|
|
5
|
-
bacdive-0.3.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
6
|
-
bacdive-0.3.1.dist-info/top_level.txt,sha256=_lfFGIEO4Y9K0ky5sUVKRn_iijFQfdHzR7L-jSqkW8U,8
|
|
7
|
-
bacdive-0.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|