@@ -88,7 +88,11 @@ def load(
88
88
structure's position (recommended).
89
89
"""
90
90
# First check if we are loading from an object
91
- if not isinstance (filename_or_object , str ):
91
+ if not (
92
+ isinstance (filename_or_object , str )
93
+ or isinstance (filename_or_object , list )
94
+ or isinstance (filename_or_object , tuple )
95
+ ):
92
96
return load_object (
93
97
obj = filename_or_object ,
94
98
compound = compound ,
@@ -97,19 +101,26 @@ def load(
97
101
** kwargs ,
98
102
)
99
103
# Second check if we are loading SMILES strings
100
- elif smiles :
104
+ elif smiles and ( backend is None or backend . lower () == "rdkit" ) :
101
105
# Ignore the box info for SMILES (its never there)
102
- ignore_box_warn = True
103
- return load_smiles (
106
+ seed = kwargs . get ( "seed" , 0 )
107
+ return load_rdkit_smiles (
104
108
smiles_or_filename = filename_or_object ,
105
109
compound = compound ,
106
110
infer_hierarchy = infer_hierarchy ,
107
- ignore_box_warn = ignore_box_warn ,
108
- backend = backend ,
109
- ** kwargs ,
111
+ ignore_box_warn = True ,
112
+ seed = seed ,
110
113
)
111
- # Last, if none of the above, load from file
114
+ elif smiles and isinstance (backend , str ) and backend .lower () == "pybel" :
115
+ return load_pybel_smiles (
116
+ smiles_or_filename = filename_or_object ,
117
+ compound = compound ,
118
+ infer_hierarchy = infer_hierarchy ,
119
+ ignore_box_warn = True ,
120
+ )
121
+
112
122
else :
123
+ # Last, if none of the above, load from file
113
124
return load_file (
114
125
filename = filename_or_object ,
115
126
relative_to_module = relative_to_module ,
@@ -191,14 +202,12 @@ def load_object(
191
202
raise ValueError (f"Object of type { type (obj ).__name__ } is not supported." )
192
203
193
204
194
- def load_smiles (
205
+ def load_pybel_smiles (
195
206
smiles_or_filename ,
196
207
compound = None ,
197
208
infer_hierarchy = True ,
198
209
ignore_box_warn = False ,
199
- backend = "rdkit" ,
200
210
coords_only = False ,
201
- ** kwargs ,
202
211
):
203
212
"""Load a SMILES string as an mBuild Compound.
204
213
@@ -216,88 +225,115 @@ def load_smiles(
216
225
If True, ignore warning if no box is present.
217
226
coords_only : bool, optional, default=False
218
227
Only load the coordinates into a provided compound.
219
- backend : str, optional, default='rdkit'
220
- The smiles loading backend, either 'rdkit' or 'pybel'
221
228
222
229
Returns
223
230
-------
224
231
compound : mb.Compound
225
232
"""
226
- # Initialize an mb.Compound if none is provided
227
- if not compound :
233
+ if compound is None :
228
234
compound = mb .Compound ()
229
235
230
- test_path = Path (smiles_or_filename )
236
+ pybel = import_ ("pybel" )
237
+ # First we try treating smiles_or_filename as a SMILES string
238
+ try :
239
+ mymol = pybel .readstring ("smi" , smiles_or_filename )
240
+ mymolGen = [mymol ]
241
+ # Now we treat it as a filename
242
+ except (OSError , IOError ):
243
+ mymolGen = pybel .readfile ("smi" , smiles_or_filename )
244
+
245
+ for mymol in mymolGen :
246
+ mymol .make3D ()
247
+ from_pybel (
248
+ pybel_mol = mymol ,
249
+ compound = compound ,
250
+ infer_hierarchy = infer_hierarchy ,
251
+ ignore_box_warn = ignore_box_warn ,
252
+ )
253
+
254
+ return compound
231
255
232
- # Will try to support list of smiles strings in the future
233
- if backend is None :
234
- backend = "rdkit"
235
256
236
- if backend == "rdkit" :
237
- rdkit = import_ ("rdkit" ) # noqa: F841
238
- from rdkit import Chem
257
+ def load_rdkit_smiles (
258
+ smiles_or_filename ,
259
+ compound = None ,
260
+ infer_hierarchy = True ,
261
+ ignore_box_warn = False ,
262
+ coords_only = False ,
263
+ seed = 0 ,
264
+ ):
265
+ """Load a SMILES string as an mBuild Compound.
239
266
240
- if test_path .exists ():
241
- # assuming this is a smi file now
242
- mymol = Chem .SmilesMolSupplier (smiles_or_filename )
243
- if not mymol :
244
- raise ValueError (
245
- "Provided smiles string or file was invalid. Refer to the "
246
- "above RDKit error messages for additional information."
247
- )
248
- mol_list = [mol for mol in mymol ]
249
- if len (mol_list ) == 1 :
250
- rdmol = mymol [0 ]
251
- else :
252
- rdmol = mymol [0 ]
253
- warn (
254
- "More than one SMILES string in file, more than one SMILES "
255
- f"string is not supported, using { Chem .MolToSmiles (rdmol )} "
256
- )
257
- else :
258
- rdmol = Chem .MolFromSmiles (smiles_or_filename )
267
+ Loading SMILES string from a string, a list, or a file using RDKit by
268
+ default. Must have rdkit or pybel packages installed.
269
+
270
+ Parameters
271
+ ----------
272
+ smiles_or_filename : str
273
+ SMILES string or file of SMILES string to load
274
+ compound : mb.Compound
275
+ The host mbuild Compound
276
+ infer_hierarchy : bool, optional, default=True
277
+ ignore_box_warn : bool, optional, default=False
278
+ If True, ignore warning if no box is present.
279
+ coords_only : bool, optional, default=False
280
+ Only load the coordinates into a provided compound.
259
281
260
- seed = kwargs .get ("smiles_seed" , 0 )
282
+ Returns
283
+ -------
284
+ compound : mb.Compound
285
+ """
286
+ # Initialize an mb.Compound if none is provided
287
+ if not compound :
288
+ compound = mb .Compound ()
289
+
290
+ if not seed : # default rdkit seed
291
+ seed = 0
292
+
293
+ rdkit = import_ ("rdkit" ) # noqa: F841
294
+ from rdkit import Chem
295
+
296
+ if isinstance (smiles_or_filename , (tuple , list )):
297
+ for mol in smiles_or_filename :
298
+ rdmol = Chem .MolFromSmiles (mol )
299
+ from_rdkit (
300
+ rdkit_mol = rdmol ,
301
+ compound = compound ,
302
+ coords_only = coords_only ,
303
+ smiles_seed = seed ,
304
+ )
305
+ return compound
261
306
307
+ rdmol = Chem .MolFromSmiles (smiles_or_filename )
308
+ if rdmol : # return right away if the smiles loads properly
262
309
return from_rdkit (
263
310
rdkit_mol = rdmol ,
264
311
compound = compound ,
265
312
coords_only = coords_only ,
266
313
smiles_seed = seed ,
267
314
)
268
- elif backend == "pybel" :
269
- pybel = import_ ("pybel" )
270
- # First we try treating filename_or_object as a SMILES string
271
- try :
272
- mymol = pybel .readstring ("smi" , smiles_or_filename )
273
- # Now we treat it as a filename
274
- except (OSError , IOError ):
275
- # For now, we only support reading in a single smiles molecule,
276
- # but pybel returns a generator, so we get the first molecule
277
- # and warn the user if there is more
278
-
279
- mymol_generator = pybel .readfile ("smi" , smiles_or_filename )
280
- mymol_list = list (mymol_generator )
281
- if len (mymol_list ) == 1 :
282
- mymol = mymol_list [0 ]
283
- else :
284
- mymol = mymol_list [0 ]
285
- warn (
286
- "More than one SMILES string in file, more than one SMILES "
287
- f"string is not supported, using { mymol .write ('smi' )} "
288
- )
289
- mymol .make3D ()
290
- return from_pybel (
291
- pybel_mol = mymol ,
315
+
316
+ # Try to assume it's a smiles file
317
+ mymol = Chem .SmilesMolSupplier (smiles_or_filename , titleLine = 0 )
318
+ if not mymol :
319
+ raise ValueError (
320
+ "Provided smiles string or file was invalid. Refer to the "
321
+ "above RDKit error messages for additional information."
322
+ )
323
+ molList = [mol for mol in mymol ]
324
+ for rdmol in molList :
325
+ from_rdkit (
326
+ rdkit_mol = rdmol ,
292
327
compound = compound ,
293
- infer_hierarchy = infer_hierarchy ,
294
- ignore_box_warn = ignore_box_warn ,
328
+ coords_only = coords_only ,
329
+ smiles_seed = seed ,
295
330
)
296
- else :
331
+ if not compound :
297
332
raise ValueError (
298
- "Expected SMILES loading backend 'rdkit' or 'pybel'. "
299
- f"Was provided: { backend } "
333
+ "Expected SMILES loading backend 'rdkit' failed to load any compouds. "
334
+ f"Check the SMILES string of .smi file passed to { smiles_or_filename = } "
300
335
)
336
+ return compound
301
337
302
338
303
339
def load_file (
@@ -409,7 +445,7 @@ def load_file(
409
445
elif extension == ".txt" :
410
446
warn (".txt file detected, loading as a SMILES string" )
411
447
# Fail-safe measure
412
- compound = load_smiles (filename , compound )
448
+ compound = load_pybel_smiles (filename , compound )
413
449
414
450
# Then mdtraj reader
415
451
elif backend == "mdtraj" :
0 commit comments