1
2
3
4
5
6
7
8 """
9 silverwebel - A Cinfony module for Silverlight that runs on web services
10
11 Global variables:
12 informats - a dictionary of supported input formats
13 outformats - a dictionary of supported output formats
14 fps - a list of supported fingerprint types
15 """
16
17 import re
18 from time import sleep
19
20
21 from System.Net import WebClient
22 from System import Uri, UriKind
23 _webclient = WebClient()
24
25 tk = None
26
27 informats = {"smi":"SMILES", "inchikey":"InChIKey", "inchi":"InChI",
28 "name":"Common name"}
29 """A dictionary of supported input formats"""
30 outformats = {"smi":"SMILES", "cdxml":"ChemDraw XML", "inchi":"InChI",
31 "sdf":"Symyx SDF", "names":"Common names", "inchikey":"InChIKey",
32 "alc":"Alchemy", "cerius":"MSI Cerius II", "charmm":"CHARMM",
33 "cif":"Crystallographic Information File",
34 "cml":"Chemical Markup Language", "ctx":"Gasteiger Clear Text",
35 "gjf":"Gaussian job file", "gromacs":"GROMACS",
36 "hyperchem":"HyperChem", "jme":"Java Molecule Editor",
37 "maestro":"Schrodinger MacroModel",
38 "mol":"Symyx mol", "mol2":"Tripos Sybyl MOL2",
39 "mrv":"ChemAxon MRV", "pdb":"Protein Data Bank",
40 "sdf3000":"Symyx SDF3000", "sln":"Sybl line notation",
41 "xyz":"XYZ", "iupac":"IUPAC name"}
42 """A dictionary of supported output formats"""
43
44 fps = ["std", "maccs", "estate"]
45 """A list of supported fingerprint types"""
46
47
48 -def _quo(text, safe="/"):
49 always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
50 'abcdefghijklmnopqrstuvwxyz'
51 '0123456789' '_.-')
52 _safemaps = {}
53 cachekey = (safe, always_safe)
54 try:
55 safe_map = _safemaps[cachekey]
56 except KeyError:
57 safe += always_safe
58 safe_map = {}
59 for i in range(256):
60 c = chr(i)
61 safe_map[c] = (c in safe) and c or ('%%%02X' % i)
62 _safemaps[cachekey] = safe_map
63 res = map(safe_map.__getitem__, text)
64 return ''.join(res)
65
67 """Curry the name of the server"""
68 def server(*urlcomponents):
69 url = "/%s/" % serverurl + "/".join(urlcomponents)
70 result = [False, None, None]
71 def callback(s, e):
72 result[0] = True
73 result[1] = e.Error
74 if not result[1]:
75 result[2] = e.Result
76 webclient = WebClient()
77 webclient.DownloadStringCompleted += callback
78 webclient.DownloadStringAsync(Uri(url, UriKind.Relative))
79 while not result[0]:
80 sleep(0.5)
81 if result[1]:
82 raise IOError, "Problem accessing web server\n%s" % result[1]
83 return result[2]
84 return server
85
86 rajweb = _makeserver("rajweb")
87 nci = _makeserver("nci")
88
89 _descs = None
91 """Return a list of supported descriptor types"""
92 global _descs
93 if not _descs:
94 response = rajweb("descriptors").rstrip()
95 _descs = [x.split(".")[-1] for x in response.split("\n")]
96 return _descs
97
99 """Read in a molecule from a string.
100
101 Required parameters:
102 format - see the informats variable for a list of available
103 input formats
104 string
105
106 Note: For InChIKeys a list of molecules is returned.
107
108 Example:
109 >>> input = "C1=CC=CS1"
110 >>> mymol = readstring("smi", input)
111 """
112 format = format.lower()
113 if not format in informats:
114 raise ValueError("%s is not a recognised Webel format" % format)
115
116 if format != "smi":
117 smiles = nci(_quo(string), "smiles").rstrip()
118 else:
119 smiles = string
120 if format == "inchikey":
121 return [Molecule(smile) for smile in smiles.split("\n")]
122 else:
123 mol = Molecule(smiles)
124 if format == "name":
125 mol.title = string
126 return mol
127
129 """Represent a file to which *output* is to be sent.
130
131 Although it's possible to write a single molecule to a file by
132 calling the write() method of a molecule, if multiple molecules
133 are to be written to the same file you should use the Outputfile
134 class.
135
136 Required parameters:
137 format - see the outformats variable for a list of available
138 output formats
139 filename
140
141 Optional parameters:
142 overwrite -- if the output file already exists, should it
143 be overwritten? (default is False)
144
145 Methods:
146 write(molecule)
147 close()
148 """
149 - def __init__(self, format, filename, overwrite=False):
150 self.format = format.lower()
151 self.filename = filename
152 if not overwrite and os.path.isfile(self.filename):
153 raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % self.filename)
154 if not format in outformats:
155 raise ValueError("%s is not a recognised Webel format" % format)
156 self.file = open(filename, "w")
157
158 - def write(self, molecule):
159 """Write a molecule to the output file.
160
161 Required parameters:
162 molecule
163 """
164 if self.file.closed:
165 raise IOError("Outputfile instance is closed.")
166 output = molecule.write(self.format)
167 print >> self.file, output
168
170 """Close the Outputfile to further writing."""
171 self.file.close()
172
174 """Represent a Webel Molecule.
175
176 Required parameter:
177 smiles -- a SMILES string or any type of cinfony Molecule
178
179 Attributes:
180 formula, molwt, title
181
182 Methods:
183 calcfp(), calcdesc(), draw(), write()
184
185 The underlying SMILES string can be accessed using the attribute:
186 smiles
187 """
188 _cinfony = True
189
191
192 if hasattr(smiles, "_cinfony"):
193 a, b = smiles._exchange
194 if a == 0:
195 smiles = b
196 else:
197
198 smiles = smiles.write("smi").split()[0]
199
200 self.smiles = smiles
201 self.title = ""
202
203 @property
205 @property
206 - def molwt(self): return float(rajweb("mw", _quo(self.smiles)))
207 @property
209 return (0, self.smiles)
210
212 """Calculate descriptor values.
213
214 Optional parameter:
215 descnames -- a list of names of descriptors
216
217 If descnames is not specified, all available descriptors are
218 calculated. See the descs variable for a list of available
219 descriptors.
220 """
221 if not descnames:
222 descnames = getdescs()
223 else:
224 for descname in descnames:
225 if descname not in getdescs():
226 raise ValueError("%s is not a recognised Webel descriptor type" % descname)
227 ans = {}
228 p = re.compile("""Descriptor parent="(\w*)" name="([\w\-\+\d]*)" value="([\d\.]*)""")
229 for descname in descnames:
230 longname = "org.openscience.cdk.qsar.descriptors.molecular." + descname
231 response = rajweb("descriptor", longname, _quo(self.smiles))
232 for match in p.findall(response):
233 if match[2]:
234 ans["%s_%s" % (match[0], match[1])] = float(match[2])
235 return ans
236
237 - def calcfp(self, fptype="std"):
238 """Calculate a molecular fingerprint.
239
240 Optional parameters:
241 fptype -- the fingerprint type (default is "std"). See the
242 fps variable for a list of of available fingerprint
243 types.
244 """
245 fptype = fptype.lower()
246 if fptype not in fps:
247 raise ValueError("%s is not a recognised Webel Fingerprint type" % fptype)
248 fp = rajweb("fingerprint/%s/%s" % (fptype, _quo(self.smiles))).rstrip()
249 return Fingerprint(fp)
250
251 - def write(self, format="smi", filename=None, overwrite=False):
252 """Write the molecule to a file or return a string.
253
254 Optional parameters:
255 format -- see the informats variable for a list of available
256 output formats (default is "smi")
257 filename -- default is None
258 overwite -- if the output file already exists, should it
259 be overwritten? (default is False)
260
261 If a filename is specified, the result is written to a file.
262 Otherwise, a string is returned containing the result.
263
264 To write multiple molecules to the same file you should use
265 the Outputfile class.
266 """
267 format = format.lower()
268 if not format in outformats:
269 raise ValueError("%s is not a recognised Webel format" % format)
270 if format == "smi":
271 output = self.smiles
272 elif format == "names":
273 try:
274 output = nci(_quo(self.smiles), "%s" % format).rstrip().split("\n")
275 except urllib2.URLError, e:
276 if e.code == 404:
277 output = []
278 elif format in ['inchi', 'inchikey']:
279 format = "std" + format
280 output = nci(_quo(self.smiles), "%s" % format).rstrip()
281 elif format == 'iupac':
282 format = format + "_name"
283 try:
284 output = nci(_quo(self.smiles), "%s" % format).rstrip()
285 except urllib2.URLError, e:
286 if e.code == 404:
287 output = ""
288 else:
289 output = nci(_quo(self.smiles), "file?format=%s" % format).rstrip()
290
291 if filename:
292 if not overwrite and os.path.isfile(filename):
293 raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % filename)
294 outputfile = open(filename, "w")
295 print >> outputfile, output
296 outputfile.close()
297 else:
298 return output
299
302
304 """Create a 2D depiction of the molecule."""
305 global showimage
306 url = "http://cactus.nci.nih.gov/chemical/structure/%s/image" % _quo(self.smiles)
307 showimage(url)
308
310 """A Molecular Fingerprint.
311
312 Required parameters:
313 fingerprint -- a string of 0's and 1's representing a binary fingerprint
314
315 Attributes:
316 fp -- the underlying fingerprint object
317 bits -- a list of bits set in the Fingerprint
318
319 Methods:
320 The "|" operator can be used to calculate the Tanimoto coeff. For example,
321 given two Fingerprints 'a', and 'b', the Tanimoto coefficient is given by:
322 tanimoto = a | b
323 """
325 self.fp = fingerprint
327 mybits = set(self.bits)
328 otherbits = set(other.bits)
329 return len(mybits&otherbits) / float(len(mybits|otherbits))
330 @property
332 return [i for i,x in enumerate(self.fp) if x=="1"]
335
337 """A Smarts Pattern Matcher
338
339 Required parameters:
340 smartspattern
341
342 Methods:
343 match(molecule)
344
345 Example:
346 >>> mol = readstring("smi","CCN(CC)CC") # triethylamine
347 >>> smarts = Smarts("[#6][#6]") # Matches an ethyl group
348 >>> smarts.match(mol)
349 True
350 """
352 """Initialise with a SMARTS pattern."""
353 self.pat = smartspattern
354 - def match(self, molecule):
355 """Does a SMARTS pattern match a particular molecule?
356
357 Required parameters:
358 molecule
359 """
360 resp = rajweb("substruct", _quo(molecule.smiles), _quo(self.pat)).rstrip()
361 return resp == "true"
362
363 if __name__=="__main__":
364 import doctest
365 doctest.run_docstring_examples(rajweb, globals())
366