@@ -79,14 +79,12 @@ def convert2to3(sbol2_doc: Union[str, sbol2.Document], namespaces=None) -> sbol3
7979 namespaces = []
8080 if isinstance (sbol2_doc , sbol2 .Document ):
8181 sbol2_path = tempfile .mkstemp (suffix = '.xml' )[1 ]
82- # Turn off automatic validation on write to avoid requiring transmitting data to the validator webservice
83- # If you want validation, you should validate the document explicitly beforehand
84- was_using_validator = sbol2 .Config .getOption (sbol2 .ConfigOptions .VALIDATE )
82+ validate_online = sbol2 .Config .getOption (sbol2 .ConfigOptions .VALIDATE_ONLINE )
8583 try :
86- sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE , False )
84+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , False )
8785 sbol2_doc .write (sbol2_path )
8886 finally :
89- sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE , was_using_validator )
87+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , validate_online )
9088 else :
9189 sbol2_path = sbol2_doc
9290
@@ -159,6 +157,11 @@ def change_orientation(o):
159157 o .orientation = orientation_remapping [o .orientation ]
160158 doc .traverse (change_orientation )
161159
160+ report = doc .validate ()
161+ if len (report ):
162+ report_string = "\n " .join (str (e ) for e in doc .validate ())
163+ raise ValueError (f'Conversion from SBOL2 to SBOL3 produced an invalid document: { report_string } ' )
164+
162165 return doc
163166
164167
@@ -196,8 +199,8 @@ def convert3to2(doc3: sbol3.Document) -> sbol2.Document:
196199 }
197200
198201 def change_orientation (o ):
199- if isinstance (o , sbol3 .Location ):
200- if hasattr ( o , 'orientation' ) and o .orientation in orientation_remapping :
202+ if isinstance (o , sbol3 .Location ) or isinstance ( o , sbol3 . Feature ) :
203+ if o .orientation in orientation_remapping :
201204 o .orientation = orientation_remapping [o .orientation ]
202205 doc3 .traverse (change_orientation )
203206
@@ -215,7 +218,7 @@ def change_orientation(o):
215218 # Extract the rdf_xml output from the sbol converter
216219 rdf_xml = proc .stdout .decode ('utf-8' )
217220 except subprocess .CalledProcessError :
218- raise ValueError ('Embedded SBOL 3-to-2 converter failed opaquely, indicating a likely invalid SBOL file.' )
221+ raise ValueError ('Embedded SBOL 3-to-2 converter failed opaquely, possibly indicating an invalid SBOL file.' )
219222
220223 doc2 = sbol2 .Document ()
221224 doc2 .readString (rdf_xml )
@@ -224,8 +227,17 @@ def change_orientation(o):
224227 for sa in c .sequenceAnnotations :
225228 for loc in sa .locations :
226229 loc .sequence = None # remove optional sequences, per https://github.com/SynBioDex/libSBOLj/issues/621
227- # We explicitly do NOT validate here in order to avoid requiring transmitting data to the validator webservice
228- # If you want validation, you should run it on the document that is returned
230+
231+ # Validate document offline
232+ validate_online = sbol2 .Config .getOption (sbol2 .ConfigOptions .VALIDATE_ONLINE )
233+ try :
234+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , False )
235+ result = doc2 .validate ()
236+ if not result == "Valid." :
237+ raise ValueError (f'Conversion from SBOL3 to SBOL2 produced an invalid document: { result } ' )
238+ finally :
239+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , validate_online )
240+
229241 return doc2
230242
231243
@@ -285,15 +297,19 @@ def convert_from_genbank(path: str, namespace: str, allow_genbank_online: bool =
285297
286298 :param path: path to read GenBank file from
287299 :param namespace: URIs of Components will be set to {namespace}/{genbank_id}
288- :param allow_genbank_online: Allow use of the online converter (currently required)
300+ :param allow_genbank_online: Use the online converter, rather than the local converter
289301 :return: SBOL3 document containing converted materials
290302 """
291- if not allow_genbank_online :
292- raise NotImplementedError ('GenBank conversion currently requires use of the online SBOL validator/converter' )
293-
294303 doc2 = sbol2 .Document ()
295304 sbol2 .setHomespace (namespace )
296- doc2 .importFromFormat (path )
305+ # Convert document offline
306+ validate_online = sbol2 .Config .getOption (sbol2 .ConfigOptions .VALIDATE_ONLINE )
307+ try :
308+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , allow_genbank_online )
309+ doc2 .importFromFormat (path )
310+ finally :
311+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , validate_online )
312+
297313 doc = convert2to3 (doc2 , [namespace ])
298314 return doc
299315
@@ -305,13 +321,10 @@ def convert_to_genbank(doc3: sbol3.Document, path: str, allow_genbank_online: bo
305321 then a fixed bogus datestamp of January 1, 2000 is given
306322
307323 :param doc3: SBOL3 document to convert
308- :param path: path to write FASTA file to
309- :param allow_genbank_online: Allow use of the online converter (currently required)
324+ :param path: path to write GenBank file to
325+ :param allow_genbank_online: use the online converter rather than the local converter
310326 :return: BioPython SeqRecord of the GenBank that was written
311327 """
312- if not allow_genbank_online :
313- raise NotImplementedError ('GenBank conversion currently requires use of the online SBOL validator/converter' )
314-
315328 # first convert to SBOL2, then export to a temp GenBank file
316329 doc2 = convert3to2 (doc3 )
317330
@@ -322,7 +335,13 @@ def convert_to_genbank(doc3: sbol3.Document, path: str, allow_genbank_online: bo
322335 c .properties = {p : v for p , v in c .properties .items () if any (k for k in keepers if p .startswith (k ))}
323336
324337 gb_tmp = tempfile .mkstemp (suffix = '.gb' )[1 ]
325- doc2 .exportToFormat ('GenBank' , gb_tmp )
338+ # Convert document offline
339+ validate_online = sbol2 .Config .getOption (sbol2 .ConfigOptions .VALIDATE_ONLINE )
340+ try :
341+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , allow_genbank_online )
342+ doc2 .exportToFormat ('GenBank' , gb_tmp )
343+ finally :
344+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , validate_online )
326345
327346 # Read and re-write in order to sort and to purge invalid date information and standardize GenBank formatting
328347 with open (gb_tmp , 'r' ) as tmp :
@@ -393,7 +412,12 @@ def command_line_converter(args_dict: Dict[str, Any]):
393412 convert_to_genbank (doc3 , output_file , args_dict ['allow_genbank_online' ])
394413 elif output_file_type == 'SBOL2' :
395414 doc2 = convert3to2 (doc3 )
396- doc2 .write (output_file )
415+ validate_online = sbol2 .Config .getOption (sbol2 .ConfigOptions .VALIDATE_ONLINE )
416+ try :
417+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , False )
418+ doc2 .write (output_file )
419+ finally :
420+ sbol2 .Config .setOption (sbol2 .ConfigOptions .VALIDATE_ONLINE , validate_online )
397421 elif output_file_type == 'SBOL3' :
398422 doc3 .write (output_file , sbol3 .SORTED_NTRIPLES )
399423 else :
@@ -413,8 +437,7 @@ def main():
413437 parser .add_argument ('--verbose' , '-v' , dest = 'verbose' , action = 'count' , default = 0 ,
414438 help = "Print running explanation of conversion process" )
415439 parser .add_argument ('--allow-genbank-online' , dest = 'allow_genbank_online' , action = 'store_true' , default = False ,
416- help = 'Allow GenBank conversion to send material to online converter; '
417- 'currently required to be True' )
440+ help = 'Perform GenBank conversion using online converter' )
418441 args_dict = vars (parser .parse_args ())
419442 # Call the shared command-line conversion routine
420443 command_line_converter (args_dict )
@@ -448,8 +471,7 @@ def genbank2sbol():
448471 parser .add_argument ('--verbose' , '-v' , dest = 'verbose' , action = 'count' , default = 0 ,
449472 help = 'Print running explanation of conversion process' )
450473 parser .add_argument ('--allow-genbank-online' , dest = 'allow_genbank_online' , action = 'store_true' , default = False ,
451- help = 'Allow GenBank conversion to send material to online converter; '
452- 'currently required to be True' )
474+ help = 'Perform GenBank conversion using online converter' )
453475 args_dict = vars (parser .parse_args ())
454476 args_dict ['input_file_type' ] = 'GenBank'
455477 args_dict ['output_file_type' ] = 'SBOL3'
@@ -499,8 +521,7 @@ def sbol2genbank():
499521 parser .add_argument ('--verbose' , '-v' , dest = 'verbose' , action = 'count' , default = 0 ,
500522 help = "Print running explanation of conversion process" )
501523 parser .add_argument ('--allow-genbank-online' , dest = 'allow_genbank_online' , action = 'store_true' , default = False ,
502- help = 'Allow GenBank conversion to send material to online converter; '
503- 'currently required to be True' )
524+ help = 'Perform GenBank conversion using online converter' )
504525 args_dict = vars (parser .parse_args ())
505526 args_dict ['input_file_type' ] = 'SBOL3'
506527 args_dict ['output_file_type' ] = 'GenBank'
0 commit comments