forked from enviPath/enviPy
[Feature] Generate Compounds by Molfile (#423)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#423
This commit is contained in:
@ -11,6 +11,9 @@ from epdb.models import Compound, Scenario, ExternalDatabase
|
||||
class CompoundViewTest(TestCase):
|
||||
fixtures = ["test_fixtures_incl_model.jsonl.gz"]
|
||||
|
||||
# A valid V2000 molfile for 4-Nitrobenzoic acid (O=C(O)C1=CC=C([N+](=O)[O-])C=C1)
|
||||
VALID_MOLFILE = """\n Mrv2211 01012500002D\n\n 12 12 0 0 0 0 999 V2000\n 1.4289 -0.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 0.7145 -0.4125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 0.0000 -0.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 0.0000 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 0.7145 -2.0625 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 1.4289 -1.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 0.7145 0.4125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 0.7145 1.2375 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 1.4289 0.8250 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 0.7145 -2.8875 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0\n 0.0000 -3.3000 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0\n 1.4289 -3.3000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 1 2 2 0 0 0 0\n 2 3 1 0 0 0 0\n 3 4 2 0 0 0 0\n 4 5 1 0 0 0 0\n 5 6 2 0 0 0 0\n 6 1 1 0 0 0 0\n 2 7 1 0 0 0 0\n 7 8 2 0 0 0 0\n 7 9 1 0 0 0 0\n 5 10 1 0 0 0 0\n 10 11 1 0 0 0 0\n 10 12 2 0 0 0 0\nM CHG 2 10 1 11 -1\nM END\n"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(CompoundViewTest, cls).setUpClass()
|
||||
@ -396,3 +399,108 @@ class CompoundViewTest(TestCase):
|
||||
|
||||
c = Compound.objects.get(url=compound_url)
|
||||
self.assertEqual(len(c.aliases), 0)
|
||||
|
||||
def test_create_compound_via_molfile(self):
|
||||
"""POSTing a valid molfile without a SMILES should create a compound successfully."""
|
||||
response = self.client.post(
|
||||
reverse("compounds"),
|
||||
{
|
||||
"compound-name": "4-Nitrobenzoic acid",
|
||||
"compound-description": "Created from molfile",
|
||||
"compound-molfile": self.VALID_MOLFILE,
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
compound_url = response.url
|
||||
|
||||
c = Compound.objects.get(url=compound_url)
|
||||
|
||||
self.assertEqual(c.name, "4-Nitrobenzoic acid")
|
||||
self.assertEqual(c.description, "Created from molfile")
|
||||
# SMILES should have been extracted from molfile, so it must be non-empty
|
||||
self.assertIsNotNone(c.default_structure.smiles)
|
||||
self.assertNotEqual(c.default_structure.smiles.strip(), "")
|
||||
|
||||
def test_create_compound_molfile_takes_precedence_over_smiles(self):
|
||||
"""When both molfile and SMILES are submitted, the molfile should win."""
|
||||
response = self.client.post(
|
||||
reverse("compounds"),
|
||||
{
|
||||
"compound-name": "4-Nitrobenzoic acid",
|
||||
"compound-description": "Molfile precedence test",
|
||||
"compound-smiles": "C", # intentionally wrong/different
|
||||
"compound-molfile": self.VALID_MOLFILE,
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
compound_url = response.url
|
||||
|
||||
c = Compound.objects.get(url=compound_url)
|
||||
|
||||
# The resulting SMILES must NOT be the dummy "C" supplied via compound-smiles
|
||||
self.assertNotEqual(c.default_structure.smiles, "C")
|
||||
|
||||
def test_create_compound_via_invalid_molfile_returns_error(self):
|
||||
"""POSTing an invalid molfile should not create a compound and should return an error response."""
|
||||
initial_count = self.user1_default_package.compounds.count()
|
||||
|
||||
response = self.client.post(
|
||||
reverse("compounds"),
|
||||
{
|
||||
"compound-name": "Bad Molfile Compound",
|
||||
"compound-description": "Should fail",
|
||||
"compound-molfile": "this is not a molfile at all",
|
||||
},
|
||||
)
|
||||
|
||||
# The view should signal an error (non-2xx or a redirect to an error page, not 302 to a new compound)
|
||||
self.assertNotEqual(response.status_code, 302)
|
||||
# No new compound should have been created
|
||||
self.assertEqual(self.user1_default_package.compounds.count(), initial_count)
|
||||
|
||||
def test_create_compound_via_empty_molfile_falls_back_to_smiles(self):
|
||||
"""Submitting an empty molfile with a valid SMILES should fall back to SMILES."""
|
||||
response = self.client.post(
|
||||
reverse("compounds"),
|
||||
{
|
||||
"compound-name": "Fallback SMILES Compound",
|
||||
"compound-description": "Empty molfile fallback",
|
||||
"compound-smiles": "C(CCl)Cl",
|
||||
"compound-molfile": " ", # whitespace only
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 302)
|
||||
compound_url = response.url
|
||||
|
||||
c = Compound.objects.get(url=compound_url)
|
||||
self.assertEqual(c.default_structure.smiles, "C(CCl)Cl")
|
||||
|
||||
def test_create_compound_via_molfile_deduplication(self):
|
||||
"""Submitting the same molfile twice should return the existing compound."""
|
||||
response1 = self.client.post(
|
||||
reverse("compounds"),
|
||||
{
|
||||
"compound-name": "4-Nitrobenzoic acid",
|
||||
"compound-description": "Molfile dedup test",
|
||||
"compound-molfile": self.VALID_MOLFILE,
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response1.status_code, 302)
|
||||
compound_url_1 = response1.url
|
||||
|
||||
response2 = self.client.post(
|
||||
reverse("compounds"),
|
||||
{
|
||||
"compound-name": "4-Nitrobenzoic acid",
|
||||
"compound-description": "Molfile dedup test",
|
||||
"compound-molfile": self.VALID_MOLFILE,
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response2.status_code, 302)
|
||||
self.assertEqual(response2.url, compound_url_1)
|
||||
self.assertEqual(self.user1_default_package.compounds.count(), 1)
|
||||
|
||||
Reference in New Issue
Block a user