-
Notifications
You must be signed in to change notification settings - Fork 26
/
cirpy_test.py
190 lines (147 loc) · 7.56 KB
/
cirpy_test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
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
141
142
143
144
145
146
147
148
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
# -*- coding: utf-8 -*-
"""
Unit tests for cirpy.py
Python interface for the Chemical Identifier Resolver (CIR) by the CADD Group at the NCI/NIH.
https://github.com/mcs07/CIRpy
"""
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
import logging
import os
import time
import unittest
try:
from urllib.error import HTTPError
except ImportError:
from urllib2 import HTTPError
try:
from lxml import etree
except ImportError:
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
from cirpy import request, resolve, query, Molecule, Result, resolve_image
logging.basicConfig(level=logging.DEBUG)
class RateLimitTestCase(unittest.TestCase):
"""TestCase that delays before each test according to CIRPY_TEST_DELAY environment variable."""
def setUp(self):
time.sleep(float(os.environ.get('CIRPY_TEST_DELAY', 0)))
class TestRequest(RateLimitTestCase):
"""Test basic requests to CIR servers return the expected XML response."""
def test_requests(self):
"""Test a variety of basic requests to ensure they return the expected XML response."""
self.assertEqual(request('c1ccccc1', 'names').tag, 'request')
self.assertEqual(request('Aspirin', 'smiles').tag, 'request')
self.assertEqual(len(request('64-17-5', 'stdinchi')), 1)
def test_no_result_request(self):
"""Test that an empty XML response is returned when there are no results."""
response = request('arguergbaiurg', 'smiles')
self.assertEqual(response.tag, 'request')
self.assertEqual(len(response), 0)
def test_invalid_representation_request(self):
"""Test that HTTPError is raised when an invalid representation is specified."""
with self.assertRaises(HTTPError):
request('Morphine', 'ogiuewrgpw')
class TestQuery(RateLimitTestCase):
"""Test the query function returns expected results."""
def test_morphine_inchi(self):
"""Test morphine query for inchi returns expected result."""
results = query('morphine', 'inchi')
self.assertEqual(len(results), 2)
self.assertEqual(results[1].input, 'morphine')
self.assertEqual(results[1].representation, 'inchi')
self.assertEqual(results[1].resolver, 'name_by_cir')
self.assertEqual(results[1].input_format, 'chemical name (CIR)')
self.assertEqual(results[1].notation, 'Morphine')
self.assertEqual(results[1].value, 'InChI=1/C17H19NO3/c1-18-7-6-17-10-3-5-13(20)16(17)21-15-12(19)4-2-9(14(15)17)8-11(10)18/h2-5,10-11,13,16,19-20H,6-8H2,1H3/t10-,11+,13?,16-,17-/m0/s1')
def test_query_dict(self):
"""Test dict-style access to result attributes."""
results = query('Morphine', 'inchi')
self.assertEqual(len(results), 2)
self.assertEqual(results[1]['value'], 'InChI=1/C17H19NO3/c1-18-7-6-17-10-3-5-13(20)16(17)21-15-12(19)4-2-9(14(15)17)8-11(10)18/h2-5,10-11,13,16,19-20H,6-8H2,1H3/t10-,11+,13?,16-,17-/m0/s1')
self.assertEqual(results[1]['notation'], 'Morphine')
self.assertEqual(results[1]['resolver'], 'name_by_cir')
def test_no_result_query(self):
"""Test that an empty list is returned when there are no results."""
self.assertEqual(query('sjkvhaldfu', 'smiles'), [])
def test_invalid_representation_query(self):
"""Test that HTTPError is raised when an invalid representation is specified."""
with self.assertRaises(HTTPError):
query('Morphine', 'ogiuewrgpw')
def test_custom_resolvers(self):
"""Test expected results are returned when using custom name resolvers."""
results = query('2,4,6-trinitrotoluene', 'smiles')
self.assertEqual(len(results), 2)
self.assertEqual(results[0], Result(input='2,4,6-trinitrotoluene', representation='smiles', resolver='name_by_opsin', input_format='IUPAC name (OPSIN)', notation='2,4,6-trinitrotoluene', value='Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O'))
self.assertEqual(results[1], Result(input='2,4,6-trinitrotoluene', representation='smiles', resolver='name_by_cir', input_format='chemical name (CIR)', notation='2,4,6-Trinitrotoluene', value='Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O'))
def test_result_equality(self):
"""Test that identical result objects are considered equal."""
r1 = Result('input', 'notation', 'input_format', 'resolver', 'representation', 'value')
r2 = Result('input', 'notation', 'input_format', 'resolver', 'representation', 'value')
r3 = Result('input', 'notation', 'input_format', 'resolver', 'representation', 'another_value')
self.assertEqual(r1, r2)
self.assertNotEqual(r1, r3)
class TestResolve(RateLimitTestCase):
"""Test the resolve function."""
def test_alanine_smiles(self):
"""Test that alanine smiles resolves the expected result."""
self.assertEqual(resolve('Alanine', 'smiles'), 'C[C@H](N)C(O)=O')
def test_no_results_resolve(self):
"""Test that None is returned when there are no results."""
self.assertEqual(resolve('aruighaelirugaerg', 'inchi'), None)
def test_invalid_representation_resolve(self):
"""Test that HTTPError is raised when an invalid representation is specified."""
with self.assertRaises(HTTPError):
resolve('Morphine', 'ogiuewrgpw')
def test_tnt_smiles(self):
"""Test that TNT smiles resolves the expected result."""
self.assertEqual(
resolve('2,4,6-trinitrotoluene', 'smiles'),
'Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O'
)
def test_tnt_smiles_custom_resolvers(self):
"""Test custom resolvers return the expected result."""
self.assertEqual(
resolve('2,4,6-trinitrotoluene', 'smiles', ['name_by_opsin', 'name_by_cir']),
'Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O'
)
self.assertEqual(
resolve('2,4,6-trinitrotoluene', 'smiles', ['name_by_cir', 'name_by_opsin']),
'Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O'
)
class TestMolecule(RateLimitTestCase):
"""Test the Molecule class."""
def test_molecule_image(self):
"""Test Molecule image_url attribute."""
self.assertEqual(
Molecule('C#N', ['smiles']).image_url,
'https://cactus.nci.nih.gov/chemical/structure/C%23N/image?resolver=smiles'
)
class TestFiles(RateLimitTestCase):
"""Test resolving to file formats."""
def test_cml(self):
"""Test CML file format is resolved."""
cmlstring = resolve('Aspirin', 'cml')
cml = etree.fromstring(cmlstring)
self.assertEqual(cml.tag, '{http://www.xml-cml.org/schema/cml2/core}list')
self.assertEqual(len(cml.findall('.//{http://www.xml-cml.org/schema/cml2/core}molecule')), 1)
def test_pdb(self):
"""Test PDB file format is resolved."""
result = resolve('Aspirin', 'pdb')
self.assertIn('HEADER', result)
self.assertIn('ATOM', result)
self.assertIn('CONECT', result)
class TestImage(RateLimitTestCase):
"""Test resolving to image depiction."""
def test_png_format(self):
"""Test that response looks like valid PNG data."""
img = resolve_image('Glucose')
self.assertEqual(img[:8], b'\x89PNG\x0d\x0a\x1a\x0a')
def test_gif_format(self):
"""Test that response looks like valid GIF data."""
img = resolve_image('Glucose', fmt='gif')
self.assertEqual(img[:4], b'GIF8')
if __name__ == '__main__':
unittest.main()