44from boldigger .boldblast_coi import slices
55from bs4 import BeautifulSoup as BSoup
66
7+
78## funtion to scan the BOLDresutls file and return a list
89## of all unique Process ID's found, will also return the workbook
910## ato later use it when saving the data
@@ -14,18 +15,29 @@ def retrieve_process_ids(xlsx_path):
1415 sheet = wb .active
1516
1617 ## get type (coi or its/rbcl) and extract process ids
17- if sheet .cell (row = 1 , column = 11 ).value == 'Process ID' :
18- type = 'coi'
19- process_ids = [sheet .cell (row = row , column = 11 ).value for row in range (2 , sheet .max_row + 1 ) if sheet .cell (row = row , column = 11 ).value != None and sheet .cell (row = row , column = 11 ).value != '' ]
20- elif sheet .cell (row = 1 , column = 11 ).value == 'Similarity' :
21- type = 'its_rbcl'
22- process_ids = [sheet .cell (row = row , column = 14 ).value for row in range (2 , sheet .max_row + 1 ) if sheet .cell (row = row , column = 14 ).value != None and sheet .cell (row = row , column = 14 ).value != '' ]
18+ if sheet .cell (row = 1 , column = 11 ).value == "Process ID" :
19+ type = "coi"
20+ process_ids = [
21+ sheet .cell (row = row , column = 11 ).value
22+ for row in range (2 , sheet .max_row + 1 )
23+ if sheet .cell (row = row , column = 11 ).value != None
24+ and sheet .cell (row = row , column = 11 ).value != ""
25+ ]
26+ elif sheet .cell (row = 1 , column = 11 ).value == "Similarity" :
27+ type = "its_rbcl"
28+ process_ids = [
29+ sheet .cell (row = row , column = 14 ).value
30+ for row in range (2 , sheet .max_row + 1 )
31+ if sheet .cell (row = row , column = 14 ).value != None
32+ and sheet .cell (row = row , column = 14 ).value != ""
33+ ]
2334 else :
2435 raise ValueError
2536
2637 ## remove duplicates and return
2738 return wb , list (unique_everseen (process_ids )), type
2839
40+
2941## function to loop through the process IDs and call the BOLD API for additional data
3042## will return a dict in form of {Process ID: [BOLD Record ID, BIN, Sex, Life stage, Country, Identifier, Identification method, Institution storing]}
3143def get_data (process_ids , processbar ):
@@ -34,114 +46,159 @@ def get_data(process_ids, processbar):
3446
3547 ## open a new html session
3648 with requests_html .HTMLSession () as session :
37-
3849 ## initialize the final dict output
3950 process_id_dict = {}
4051
4152 for id_pack in process_ids :
42-
4353 ## request the data, retry if the request failes
4454 while True :
4555 try :
46- resp = session .get ('http://www.boldsystems.org/index.php/API_Public/specimen?ids=' + '|' .join (id_pack ))
56+ resp = session .get (
57+ "http://www.boldsystems.org/index.php/API_Public/specimen?ids="
58+ + "|" .join (id_pack )
59+ )
4760 except :
4861 continue
4962 break
5063
5164 ## use beautifulsoup to find all records in the response
52- soup = BSoup (resp .text , 'html.parser' )
53- records = soup .find_all (' record' )
65+ soup = BSoup (resp .text , "xml" )
66+ records = soup .find_all (" record" )
5467
5568 ## loop through records to extract interesting data
5669 for count in range (len (records )):
57-
58- tags = ['processid' , 'record_id' , 'bin_uri' , 'sex' , 'lifestage' , 'country' , 'identification_provided_by' , 'identification_method' , 'institution_storing' ]
70+ tags = [
71+ "processid" ,
72+ "record_id" ,
73+ "bin_uri" ,
74+ "sex" ,
75+ "lifestage" ,
76+ "country" ,
77+ "identification_provided_by" ,
78+ "identification_method" ,
79+ "institution_storing" ,
80+ ]
5981
6082 ## search the data encapsuled by each tag
61- specimen_data = [records [count ].find (tag ) if records [count ].find (tag ) != None else '' for tag in tags ]
83+ specimen_data = [
84+ records [count ].find (tag ) if records [count ].find (tag ) != None else ""
85+ for tag in tags
86+ ]
6287
6388 ## extract the texts from these tags
64- specimen_data = [datapoint .text if datapoint != '' else '' for datapoint in specimen_data ]
89+ specimen_data = [
90+ datapoint .text if datapoint != "" else ""
91+ for datapoint in specimen_data
92+ ]
6593
6694 ## append a link to the specimen page to the results if user is interested in looking up even more data
67- specimen_data .append ('http://www.boldsystems.org/index.php/MAS_DataRetrieval_OpenSpecimen?selectedrecordid=' + specimen_data [1 ])
95+ specimen_data .append (
96+ "http://www.boldsystems.org/index.php/MAS_DataRetrieval_OpenSpecimen?selectedrecordid="
97+ + specimen_data [1 ]
98+ )
6899
69100 ## put the data in a dictionary in form of processID: [listofinformation]
70101 process_dict = {specimen_data [0 ]: specimen_data [1 :]}
71102
72103 ## update the final output
73104 process_id_dict .update (process_dict )
74105
75- processbar .UpdateBar (round (100 / len (process_ids ) * (process_ids .index (id_pack ) + 1 )))
106+ processbar .UpdateBar (
107+ round (100 / len (process_ids ) * (process_ids .index (id_pack ) + 1 ))
108+ )
76109
77110 return process_id_dict
78111
112+
79113## function to save the additional data to the input file
80114def save_results (workbook , additional_data , xlsx_path , type ):
81-
82115 sheet = workbook .active
83116
84117 ## headers to add to the resultfile
85- headers = ['Record ID' , 'BOLD BIN' , 'Sex' , 'Life stage' , 'Country' , 'Identifier' , 'Identification Method' , 'Institution storing' , 'Specimen page url' ]
118+ headers = [
119+ "Record ID" ,
120+ "BOLD BIN" ,
121+ "Sex" ,
122+ "Life stage" ,
123+ "Country" ,
124+ "Identifier" ,
125+ "Identification Method" ,
126+ "Institution storing" ,
127+ "Specimen page url" ,
128+ ]
86129
87130 ## first empty column depends on the type either 12 oder 15
88- start = 12 if type == ' coi' else 15
131+ start = 12 if type == " coi" else 15
89132
90133 ## write the header row
91134 for i in range (start , start + len (headers )):
92- sheet .cell (row = 1 , column = i ).value = headers [i - start ]
135+ sheet .cell (row = 1 , column = i ).value = headers [i - start ]
93136
94137 ## add the additional data to the resultfile
95138 for row in range (2 , sheet .max_row + 1 ):
96139 for column in range (start , start + len (headers )):
97- if sheet .cell (row = row , column = start - 1 ).value in additional_data .keys ():
98- sheet .cell (row = row , column = column ).value = additional_data [sheet .cell (row = row , column = start - 1 ).value ][column - start ]
140+ if sheet .cell (row = row , column = start - 1 ).value in additional_data .keys ():
141+ sheet .cell (row = row , column = column ).value = additional_data [
142+ sheet .cell (row = row , column = start - 1 ).value
143+ ][column - start ]
99144
100145 workbook .save (xlsx_path )
101146
147+
102148## main function to controll the flow
103149def main (xlsx_path ):
104-
105150 ## define a layout for the new window
106151 layout = [
107- [sg .Text ('Download status' , size = (15 , 1 ), key = 'bar_des' ), sg .ProgressBar (100 , orientation = 'h' , size = (20 , 20 ), key = 'bar' )],
108- [sg .Multiline (size = (50 , 10 ), key = 'out' , autoscroll = True )]
152+ [
153+ sg .Text ("Download status" , size = (15 , 1 ), key = "bar_des" ),
154+ sg .ProgressBar (100 , orientation = "h" , size = (20 , 20 ), key = "bar" ),
155+ ],
156+ [sg .Multiline (size = (50 , 10 ), key = "out" , autoscroll = True )],
109157 ]
110158
111159 ## run the download loop only once. After that only run event loop
112- window = sg .Window (' Additional data download' , layout )
113- bar = window [' bar' ]
160+ window = sg .Window (" Additional data download" , layout )
161+ bar = window [" bar" ]
114162 ran = False
115163
116164 while True :
117-
118- event , values = window .read (timeout = 10 )
165+ event , values = window .read (timeout = 10 )
119166 ## start inner loop only once
120- window ['out' ].print ("%s: Extracting process ID's." % datetime .datetime .now ().strftime ("%H:%M:%S" ))
167+ window ["out" ].print (
168+ "%s: Extracting process ID's."
169+ % datetime .datetime .now ().strftime ("%H:%M:%S" )
170+ )
121171 window .Refresh ()
122172
123173 if not ran :
124-
125174 ## catch any wrong file formats here to avoid crash
126175 try :
127176 wb , process_ids , type = retrieve_process_ids (xlsx_path )
128177 except ValueError :
129- window [' out' ].print (' Wrong file format. Close to continue.' )
178+ window [" out" ].print (" Wrong file format. Close to continue." )
130179
131180 ## collect the data from BOLD
132- window ['out' ].print ('%s: Downloading additional data.' % datetime .datetime .now ().strftime ("%H:%M:%S" ))
181+ window ["out" ].print (
182+ "%s: Downloading additional data."
183+ % datetime .datetime .now ().strftime ("%H:%M:%S" )
184+ )
133185 window .Refresh ()
134186 additional_data = get_data (process_ids , bar )
135187
136188 ## saving the data according to type
137- window ['out' ].print ('%s: Saving the results.' % datetime .datetime .now ().strftime ("%H:%M:%S" ))
189+ window ["out" ].print (
190+ "%s: Saving the results." % datetime .datetime .now ().strftime ("%H:%M:%S" )
191+ )
138192 window .Refresh ()
139193 save_results (wb , additional_data , xlsx_path , type )
140194
141195 ran = True
142196
143197 ## get events (just closing) and values
144- window ['out' ].print ('%s: Done. Close to continue.' % datetime .datetime .now ().strftime ("%H:%M:%S" ))
198+ window ["out" ].print (
199+ "%s: Done. Close to continue."
200+ % datetime .datetime .now ().strftime ("%H:%M:%S" )
201+ )
145202 window .Refresh ()
146203 event , values = window .read ()
147204
0 commit comments