[Chore] Linted Files (#150)

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#150
This commit is contained in:
2025-10-09 07:25:13 +13:00
parent 22f0bbe10b
commit afeb56622c
50 changed files with 5616 additions and 4408 deletions

View File

@ -13,91 +13,80 @@ class CompoundTest(TestCase):
@classmethod
def setUpClass(cls):
super(CompoundTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
def test_smoke(self):
c = Compound.create(
self.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
name='Afoxolaner',
description='No Desc'
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
name="Afoxolaner",
description="No Desc",
)
self.assertEqual(c.default_structure.smiles,
'C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F')
self.assertEqual(c.name, 'Afoxolaner')
self.assertEqual(c.description, 'No Desc')
self.assertEqual(
c.default_structure.smiles,
"C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
)
self.assertEqual(c.name, "Afoxolaner")
self.assertEqual(c.description, "No Desc")
def test_missing_smiles(self):
with self.assertRaises(ValueError):
_ = Compound.create(
self.package,
smiles=None,
name='Afoxolaner',
description='No Desc'
)
_ = Compound.create(self.package, smiles=None, name="Afoxolaner", description="No Desc")
with self.assertRaises(ValueError):
_ = Compound.create(
self.package,
smiles='',
name='Afoxolaner',
description='No Desc'
)
_ = Compound.create(self.package, smiles="", name="Afoxolaner", description="No Desc")
with self.assertRaises(ValueError):
_ = Compound.create(
self.package,
smiles=' ',
name='Afoxolaner',
description='No Desc'
)
_ = Compound.create(self.package, smiles=" ", name="Afoxolaner", description="No Desc")
def test_smiles_are_trimmed(self):
c = Compound.create(
self.package,
smiles=' C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F ',
name='Afoxolaner',
description='No Desc'
smiles=" C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F ",
name="Afoxolaner",
description="No Desc",
)
self.assertEqual(c.default_structure.smiles,
'C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F')
self.assertEqual(
c.default_structure.smiles,
"C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
)
def test_name_and_description_optional(self):
c = Compound.create(
self.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
)
self.assertEqual(c.name, 'Compound 1')
self.assertEqual(c.description, 'no description')
self.assertEqual(c.name, "Compound 1")
self.assertEqual(c.description, "no description")
def test_empty_name_and_description_are_ignored(self):
c = Compound.create(
self.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
name='',
description='',
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
name="",
description="",
)
self.assertEqual(c.name, 'Compound 1')
self.assertEqual(c.description, 'no description')
self.assertEqual(c.name, "Compound 1")
self.assertEqual(c.description, "no description")
def test_deduplication(self):
c1 = Compound.create(
self.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
name='Afoxolaner',
description='No Desc'
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
name="Afoxolaner",
description="No Desc",
)
c2 = Compound.create(
self.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
name='Afoxolaner',
description='No Desc'
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
name="Afoxolaner",
description="No Desc",
)
# Check if create detects that this Compound already exist
@ -109,36 +98,36 @@ class CompoundTest(TestCase):
with self.assertRaises(ValueError):
_ = Compound.create(
self.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
name='Afoxolaner',
description='No Desc'
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
name="Afoxolaner",
description="No Desc",
)
def test_create_with_standardized_smiles(self):
c = Compound.create(
self.package,
smiles='O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name='Standardized SMILES',
description='No Desc'
smiles="O=C(O)C1=CC=C([N+](=O)[O-])C=C1",
name="Standardized SMILES",
description="No Desc",
)
self.assertEqual(len(c.structures.all()), 1)
cs = c.structures.all()[0]
self.assertEqual(cs.normalized_structure, True)
self.assertEqual(cs.smiles, 'O=C(O)C1=CC=C([N+](=O)[O-])C=C1')
self.assertEqual(cs.smiles, "O=C(O)C1=CC=C([N+](=O)[O-])C=C1")
def test_create_with_non_standardized_smiles(self):
c = Compound.create(
self.package,
smiles='[O-][N+](=O)c1ccc(C(=O)[O-])cc1',
name='Non Standardized SMILES',
description='No Desc'
smiles="[O-][N+](=O)c1ccc(C(=O)[O-])cc1",
name="Non Standardized SMILES",
description="No Desc",
)
self.assertEqual(len(c.structures.all()), 2)
for cs in c.structures.all():
if cs.normalized_structure:
self.assertEqual(cs.smiles, 'O=C(O)C1=CC=C([N+](=O)[O-])C=C1')
self.assertEqual(cs.smiles, "O=C(O)C1=CC=C([N+](=O)[O-])C=C1")
break
else:
# Loop finished without break, lets fail...
@ -147,51 +136,54 @@ class CompoundTest(TestCase):
def test_add_structure_smoke(self):
c = Compound.create(
self.package,
smiles='O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name='Standardized SMILES',
description='No Desc'
smiles="O=C(O)C1=CC=C([N+](=O)[O-])C=C1",
name="Standardized SMILES",
description="No Desc",
)
c.add_structure('[O-][N+](=O)c1ccc(C(=O)[O-])cc1', 'Non Standardized SMILES')
c.add_structure("[O-][N+](=O)c1ccc(C(=O)[O-])cc1", "Non Standardized SMILES")
self.assertEqual(len(c.structures.all()), 2)
def test_add_structure_with_different_normalized_smiles(self):
c = Compound.create(
self.package,
smiles='O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name='Standardized SMILES',
description='No Desc'
smiles="O=C(O)C1=CC=C([N+](=O)[O-])C=C1",
name="Standardized SMILES",
description="No Desc",
)
with self.assertRaises(ValueError):
c.add_structure(
'C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
'Different Standardized SMILES')
"C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
"Different Standardized SMILES",
)
def test_delete(self):
c = Compound.create(
self.package,
smiles='O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name='Standardization Test',
description='No Desc'
smiles="O=C(O)C1=CC=C([N+](=O)[O-])C=C1",
name="Standardization Test",
description="No Desc",
)
c.delete()
self.assertEqual(Compound.objects.filter(package=self.package).count(), 0)
self.assertEqual(CompoundStructure.objects.filter(compound__package=self.package).count(), 0)
self.assertEqual(
CompoundStructure.objects.filter(compound__package=self.package).count(), 0
)
def test_set_as_default_structure(self):
c1 = Compound.create(
self.package,
smiles='O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name='Standardized SMILES',
description='No Desc'
smiles="O=C(O)C1=CC=C([N+](=O)[O-])C=C1",
name="Standardized SMILES",
description="No Desc",
)
default_structure = c1.default_structure
c2 = c1.add_structure('[O-][N+](=O)c1ccc(C(=O)[O-])cc1', 'Non Standardized SMILES')
c2 = c1.add_structure("[O-][N+](=O)c1ccc(C(=O)[O-])cc1", "Non Standardized SMILES")
c1.set_default_structure(c2)
self.assertNotEqual(default_structure, c2)

View File

@ -1,6 +1,5 @@
from django.test import TestCase
from django.test import TestCase
from epdb.logic import PackageManager
from epdb.models import Compound, User, Reaction
@ -12,50 +11,47 @@ class CopyTest(TestCase):
@classmethod
def setUpClass(cls):
super(CopyTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Source Package', 'No Desc')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Source Package", "No Desc")
cls.AFOXOLANER = Compound.create(
cls.package,
smiles='C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F',
name='Afoxolaner',
description='Test compound for copying'
smiles="C1C(=NOC1(C2=CC(=CC(=C2)Cl)C(F)(F)F)C(F)(F)F)C3=CC=C(C4=CC=CC=C43)C(=O)NCC(=O)NCC(F)(F)F",
name="Afoxolaner",
description="Test compound for copying",
)
cls.FOUR_NITROBENZOIC_ACID = Compound.create(
cls.package,
smiles='[O-][N+](=O)c1ccc(C(=O)[O-])cc1', # Normalized: O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name='Test Compound',
description='Compound with multiple structures'
smiles="[O-][N+](=O)c1ccc(C(=O)[O-])cc1", # Normalized: O=C(O)C1=CC=C([N+](=O)[O-])C=C1',
name="Test Compound",
description="Compound with multiple structures",
)
cls.ETHANOL = Compound.create(
cls.package,
smiles='CCO',
name='Ethanol',
description='Simple alcohol'
cls.package, smiles="CCO", name="Ethanol", description="Simple alcohol"
)
cls.target_package = PackageManager.create_package(cls.user, 'Target Package', 'No Desc')
cls.target_package = PackageManager.create_package(cls.user, "Target Package", "No Desc")
cls.reaction_educt = Compound.create(
cls.package,
smiles='C(CCl)Cl',
name='1,2-Dichloroethane',
description='Eawag BBD compound c0001'
smiles="C(CCl)Cl",
name="1,2-Dichloroethane",
description="Eawag BBD compound c0001",
).default_structure
cls.reaction_product = Compound.create(
cls.package,
smiles='C(CO)Cl',
name='2-Chloroethanol',
description='Eawag BBD compound c0005'
smiles="C(CO)Cl",
name="2-Chloroethanol",
description="Eawag BBD compound c0005",
).default_structure
cls.REACTION = Reaction.create(
package=cls.package,
name='Eawag BBD reaction r0001',
name="Eawag BBD reaction r0001",
educts=[cls.reaction_educt],
products=[cls.reaction_product],
multi_step=False
multi_step=False,
)
def test_compound_copy_basic(self):
@ -68,7 +64,9 @@ class CopyTest(TestCase):
self.assertEqual(self.AFOXOLANER.description, copied_compound.description)
self.assertEqual(copied_compound.package, self.target_package)
self.assertEqual(self.AFOXOLANER.package, self.package)
self.assertEqual(self.AFOXOLANER.default_structure.smiles, copied_compound.default_structure.smiles)
self.assertEqual(
self.AFOXOLANER.default_structure.smiles, copied_compound.default_structure.smiles
)
def test_compound_copy_with_multiple_structures(self):
"""Test copying a compound with multiple structures"""
@ -86,7 +84,7 @@ class CopyTest(TestCase):
self.assertIsNotNone(copied_compound.default_structure)
self.assertEqual(
copied_compound.default_structure.smiles,
self.FOUR_NITROBENZOIC_ACID.default_structure.smiles
self.FOUR_NITROBENZOIC_ACID.default_structure.smiles,
)
def test_compound_copy_preserves_aliases(self):
@ -95,15 +93,15 @@ class CopyTest(TestCase):
original_compound = self.ETHANOL
# Add aliases if the method exists
if hasattr(original_compound, 'add_alias'):
original_compound.add_alias('Ethyl alcohol')
original_compound.add_alias('Grain alcohol')
if hasattr(original_compound, "add_alias"):
original_compound.add_alias("Ethyl alcohol")
original_compound.add_alias("Grain alcohol")
mapping = dict()
copied_compound = original_compound.copy(self.target_package, mapping)
# Verify aliases were copied if they exist
if hasattr(original_compound, 'aliases') and hasattr(copied_compound, 'aliases'):
if hasattr(original_compound, "aliases") and hasattr(copied_compound, "aliases"):
original_aliases = original_compound.aliases
copied_aliases = copied_compound.aliases
self.assertEqual(original_aliases, copied_aliases)
@ -113,10 +111,10 @@ class CopyTest(TestCase):
original_compound = self.ETHANOL
# Add external identifiers if the methods exist
if hasattr(original_compound, 'add_cas_number'):
original_compound.add_cas_number('64-17-5')
if hasattr(original_compound, 'add_pubchem_compound_id'):
original_compound.add_pubchem_compound_id('702')
if hasattr(original_compound, "add_cas_number"):
original_compound.add_cas_number("64-17-5")
if hasattr(original_compound, "add_pubchem_compound_id"):
original_compound.add_pubchem_compound_id("702")
mapping = dict()
copied_compound = original_compound.copy(self.target_package, mapping)
@ -146,7 +144,9 @@ class CopyTest(TestCase):
self.assertEqual(original_structure.smiles, copied_structure.smiles)
self.assertEqual(original_structure.canonical_smiles, copied_structure.canonical_smiles)
self.assertEqual(original_structure.inchikey, copied_structure.inchikey)
self.assertEqual(original_structure.normalized_structure, copied_structure.normalized_structure)
self.assertEqual(
original_structure.normalized_structure, copied_structure.normalized_structure
)
# Verify they are different objects
self.assertNotEqual(original_structure.uuid, copied_structure.uuid)
@ -177,7 +177,9 @@ class CopyTest(TestCase):
self.assertEqual(orig_educt.compound.package, self.package)
self.assertEqual(orig_educt.smiles, copy_educt.smiles)
for orig_product, copy_product in zip(self.REACTION.products.all(), copied_reaction.products.all()):
for orig_product, copy_product in zip(
self.REACTION.products.all(), copied_reaction.products.all()
):
self.assertNotEqual(orig_product.uuid, copy_product.uuid)
self.assertEqual(orig_product.name, copy_product.name)
self.assertEqual(orig_product.description, copy_product.description)

View File

@ -11,21 +11,21 @@ class DatasetTest(TestCase):
def setUp(self):
self.cs1 = Compound.create(
self.package,
name='2,6-Dibromohydroquinone',
description='http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1/compound/d6435251-1a54-4327-b4b1-fd6e9a8f4dc9/structure/d8a0225c-dbb5-4e6c-a642-730081c09c5b',
smiles='C1=C(C(=C(C=C1O)Br)O)Br',
name="2,6-Dibromohydroquinone",
description="http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1/compound/d6435251-1a54-4327-b4b1-fd6e9a8f4dc9/structure/d8a0225c-dbb5-4e6c-a642-730081c09c5b",
smiles="C1=C(C(=C(C=C1O)Br)O)Br",
).default_structure
self.cs2 = Compound.create(
self.package,
smiles='O=C(O)CC(=O)/C=C(/Br)C(=O)O',
smiles="O=C(O)CC(=O)/C=C(/Br)C(=O)O",
).default_structure
self.rule1 = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
smirks='[#8:8]([H])-[c:4]1[c:3]([H])[c:2](-[#1,#17,#35:9])[c:1](-[#8:7]([H]))[c:6](-[#1,#17,#35])[c:5]([H])1>>[#8-]-[#6:6](=O)-[#6:5]-[#6:4](=[O:8])\[#6:3]=[#6:2](\[#1,#17,#35:9])-[#6:1](-[#8-])=[O:7]',
description='http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1/simple-ambit-rule/f6a56c0f-a4a0-4ee3-b006-d765b4767cf6'
smirks="[#8:8]([H])-[c:4]1[c:3]([H])[c:2](-[#1,#17,#35:9])[c:1](-[#8:7]([H]))[c:6](-[#1,#17,#35])[c:5]([H])1>>[#8-]-[#6:6](=O)-[#6:5]-[#6:4](=[O:8])\\[#6:3]=[#6:2](\\[#1,#17,#35:9])-[#6:1](-[#8-])=[O:7]",
description="http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1/simple-ambit-rule/f6a56c0f-a4a0-4ee3-b006-d765b4767cf6",
)
self.reaction1 = Reaction.create(
@ -33,14 +33,14 @@ class DatasetTest(TestCase):
educts=[self.cs1],
products=[self.cs2],
rules=[self.rule1],
multi_step=False
multi_step=False,
)
@classmethod
def setUpClass(cls):
super(DatasetTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
def test_smoke(self):
reactions = [r for r in Reaction.objects.filter(package=self.package)]

View File

@ -1,18 +1,19 @@
from tempfile import TemporaryDirectory
from django.test import TestCase
from django.test import TestCase, tag
from epdb.logic import PackageManager
from epdb.models import User, EnviFormer, Package
@tag("slow")
class EnviFormerTest(TestCase):
fixtures = ["test_fixtures.jsonl.gz"]
@classmethod
def setUpClass(cls):
super(EnviFormerTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.BBD_SUBSET = Package.objects.get(name='Fixtures')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
cls.BBD_SUBSET = Package.objects.get(name="Fixtures")
def test_model_flow(self):
"""Test the full flow of EnviFormer, dataset build -> model finetune -> model evaluate -> model inference"""
@ -21,11 +22,14 @@ class EnviFormerTest(TestCase):
threshold = float(0.5)
data_package_objs = [self.BBD_SUBSET]
eval_packages_objs = [self.BBD_SUBSET]
mod = EnviFormer.create(self.package, data_package_objs, eval_packages_objs, threshold=threshold)
mod = EnviFormer.create(
self.package, data_package_objs, eval_packages_objs, threshold=threshold
)
mod.build_dataset()
mod.build_model()
mod.multigen_eval = True
mod.save()
mod.evaluate_model()
results = mod.predict('CCN(CC)C(=O)C1=CC(=CC=C1)C')
mod.predict("CCN(CC)C(=O)C1=CC(=CC=C1)C")

View File

@ -4,8 +4,7 @@ from utilities.chem import FormatConverter
class FormatConverterTestCase(TestCase):
def test_standardization(self):
smiles = 'C[n+]1c([N-](C))cccc1'
smiles = "C[n+]1c([N-](C))cccc1"
standardized_smiles = FormatConverter.standardize(smiles)
self.assertEqual(standardized_smiles, 'CN=C1C=CC=CN1C')
self.assertEqual(standardized_smiles, "CN=C1C=CC=CN1C")

View File

@ -4,7 +4,7 @@ import numpy as np
from django.test import TestCase
from epdb.logic import PackageManager
from epdb.models import User, MLRelativeReasoning, RuleBasedRelativeReasoning, Package
from epdb.models import User, MLRelativeReasoning, Package
class ModelTest(TestCase):
@ -13,9 +13,9 @@ class ModelTest(TestCase):
@classmethod
def setUpClass(cls):
super(ModelTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.BBD_SUBSET = Package.objects.get(name='Fixtures')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
cls.BBD_SUBSET = Package.objects.get(name="Fixtures")
def test_smoke(self):
with TemporaryDirectory() as tmpdir:
@ -32,8 +32,8 @@ class ModelTest(TestCase):
data_package_objs,
eval_packages_objs,
threshold=threshold,
name='ECC - BBD - 0.5',
description='Created MLRelativeReasoning in Testcase',
name="ECC - BBD - 0.5",
description="Created MLRelativeReasoning in Testcase",
)
# mod = RuleBasedRelativeReasoning.create(
@ -54,7 +54,7 @@ class ModelTest(TestCase):
mod.save()
mod.evaluate_model()
results = mod.predict('CCN(CC)C(=O)C1=CC(=CC=C1)C')
results = mod.predict("CCN(CC)C(=O)C1=CC(=CC=C1)C")
products = dict()
for r in results:
@ -62,8 +62,11 @@ class ModelTest(TestCase):
products[tuple(sorted(ps.product_set))] = (r.rule.name, r.probability)
expected = {
('CC=O', 'CCNC(=O)C1=CC(C)=CC=C1'): ('bt0243-4301', np.float64(0.33333333333333337)),
('CC1=CC=CC(C(=O)O)=C1', 'CCNCC'): ('bt0430-4011', np.float64(0.25)),
("CC=O", "CCNC(=O)C1=CC(C)=CC=C1"): (
"bt0243-4301",
np.float64(0.33333333333333337),
),
("CC1=CC=CC(C(=O)O)=C1", "CCNCC"): ("bt0430-4011", np.float64(0.25)),
}
self.assertEqual(products, expected)

View File

@ -1,4 +1,3 @@
import json
from django.test import TestCase
from networkx.utils.misc import graphs_equal
from epdb.logic import PackageManager, SPathway
@ -12,9 +11,11 @@ class MultiGenTest(TestCase):
@classmethod
def setUpClass(cls):
super(MultiGenTest, cls).setUpClass()
cls.user: 'User' = User.objects.get(username='anonymous')
cls.package: 'Package' = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.BBD_SUBSET: 'Package' = Package.objects.get(name='Fixtures')
cls.user: "User" = User.objects.get(username="anonymous")
cls.package: "Package" = PackageManager.create_package(
cls.user, "Anon Test Package", "No Desc"
)
cls.BBD_SUBSET: "Package" = Package.objects.get(name="Fixtures")
def test_equal_pathways(self):
"""Test that two identical pathways return a precision and recall of 1.0"""
@ -23,14 +24,23 @@ class MultiGenTest(TestCase):
if len(pathway.edge_set.all()) == 0: # Do not test pathways with no edges
continue
score, precision, recall = multigen_eval(pathway, pathway)
self.assertEqual(precision, 1.0, f"Precision should be one for identical pathways. "
f"Failed on pathway: {pathway.name}")
self.assertEqual(recall, 1.0, f"Recall should be one for identical pathways. "
f"Failed on pathway: {pathway.name}")
self.assertEqual(
precision,
1.0,
f"Precision should be one for identical pathways. "
f"Failed on pathway: {pathway.name}",
)
self.assertEqual(
recall,
1.0,
f"Recall should be one for identical pathways. Failed on pathway: {pathway.name}",
)
def test_intermediates(self):
"""Test that an intermediate can be correctly identified and the metrics are correctly adjusted"""
score, precision, recall, intermediates = multigen_eval(*self.intermediate_case(), return_intermediates=True)
score, precision, recall, intermediates = multigen_eval(
*self.intermediate_case(), return_intermediates=True
)
self.assertEqual(len(intermediates), 1, "There should be 1 found intermediate")
self.assertEqual(precision, 1, "Precision should be 1")
self.assertEqual(recall, 1, "Recall should be 1")
@ -49,7 +59,9 @@ class MultiGenTest(TestCase):
def test_all(self):
"""Test an intermediate, false-positive and false-negative together"""
score, precision, recall, intermediates = multigen_eval(*self.all_case(), return_intermediates=True)
score, precision, recall, intermediates = multigen_eval(
*self.all_case(), return_intermediates=True
)
self.assertEqual(len(intermediates), 1, "There should be 1 found intermediate")
self.assertAlmostEqual(precision, 0.6, 3, "Precision should be 0.6")
self.assertAlmostEqual(recall, 0.75, 3, "Recall should be 0.75")
@ -57,19 +69,22 @@ class MultiGenTest(TestCase):
def test_shallow_pathway(self):
pathways = self.BBD_SUBSET.pathways.all()
for pathway in pathways:
pathway_name = pathway.name
if len(pathway.edge_set.all()) == 0: # Do not test pathways with no edges
continue
shallow_pathway = graph_from_pathway(SPathway.from_pathway(pathway))
pathway = graph_from_pathway(pathway)
if not graphs_equal(shallow_pathway, pathway):
print('\n\nS', shallow_pathway.adj)
print('\n\nPW', pathway.adj)
print("\n\nS", shallow_pathway.adj)
print("\n\nPW", pathway.adj)
# print(shallow_pathway.nodes, pathway.nodes)
# print(shallow_pathway.graph, pathway.graph)
self.assertTrue(graphs_equal(shallow_pathway, pathway), f"Networkx graph from shallow pathway not "
f"equal to pathway for pathway {pathway.name}")
self.assertTrue(
graphs_equal(shallow_pathway, pathway),
f"Networkx graph from shallow pathway not "
f"equal to pathway for pathway {pathway.name}",
)
def test_graph_edit_eval(self):
"""Performs all the previous tests but with graph_edit_eval
@ -79,10 +94,16 @@ class MultiGenTest(TestCase):
if len(pathway.edge_set.all()) == 0: # Do not test pathways with no edges
continue
score = pathway_edit_eval(pathway, pathway)
self.assertEqual(score, 0.0, "Pathway edit distance should be zero for identical pathways. "
f"Failed on pathway: {pathway.name}")
self.assertEqual(
score,
0.0,
"Pathway edit distance should be zero for identical pathways. "
f"Failed on pathway: {pathway.name}",
)
inter_score = pathway_edit_eval(*self.intermediate_case())
self.assertAlmostEqual(inter_score, 1.75, 3, "Pathway edit distance failed on intermediate case")
self.assertAlmostEqual(
inter_score, 1.75, 3, "Pathway edit distance failed on intermediate case"
)
fp_score = pathway_edit_eval(*self.fp_case())
self.assertAlmostEqual(fp_score, 1.25, 3, "Pathway edit distance failed on fp case")
fn_score = pathway_edit_eval(*self.fn_case())
@ -93,22 +114,30 @@ class MultiGenTest(TestCase):
def intermediate_case(self):
"""Create an example with an intermediate in the predicted pathway"""
true_pathway = Pathway.create(self.package, "CCO")
true_pathway.add_edge([true_pathway.root_nodes.all()[0]], [true_pathway.add_node("CC(=O)O", depth=1)])
true_pathway.add_edge(
[true_pathway.root_nodes.all()[0]], [true_pathway.add_node("CC(=O)O", depth=1)]
)
pred_pathway = Pathway.create(self.package, "CCO")
pred_pathway.add_edge([pred_pathway.root_nodes.all()[0]],
[acetaldehyde := pred_pathway.add_node("CC=O", depth=1)])
pred_pathway.add_edge(
[pred_pathway.root_nodes.all()[0]],
[acetaldehyde := pred_pathway.add_node("CC=O", depth=1)],
)
pred_pathway.add_edge([acetaldehyde], [pred_pathway.add_node("CC(=O)O", depth=2)])
return true_pathway, pred_pathway
def fp_case(self):
"""Create an example with an extra compound in the predicted pathway"""
true_pathway = Pathway.create(self.package, "CCO")
true_pathway.add_edge([true_pathway.root_nodes.all()[0]],
[acetaldehyde := true_pathway.add_node("CC=O", depth=1)])
true_pathway.add_edge(
[true_pathway.root_nodes.all()[0]],
[acetaldehyde := true_pathway.add_node("CC=O", depth=1)],
)
true_pathway.add_edge([acetaldehyde], [true_pathway.add_node("CC(=O)O", depth=2)])
pred_pathway = Pathway.create(self.package, "CCO")
pred_pathway.add_edge([pred_pathway.root_nodes.all()[0]],
[acetaldehyde := pred_pathway.add_node("CC=O", depth=1)])
pred_pathway.add_edge(
[pred_pathway.root_nodes.all()[0]],
[acetaldehyde := pred_pathway.add_node("CC=O", depth=1)],
)
pred_pathway.add_edge([acetaldehyde], [pred_pathway.add_node("CC(=O)O", depth=2)])
pred_pathway.add_edge([acetaldehyde], [pred_pathway.add_node("C", depth=2)])
return true_pathway, pred_pathway
@ -116,22 +145,30 @@ class MultiGenTest(TestCase):
def fn_case(self):
"""Create an example with a missing compound in the predicted pathway"""
true_pathway = Pathway.create(self.package, "CCO")
true_pathway.add_edge([true_pathway.root_nodes.all()[0]],
[acetaldehyde := true_pathway.add_node("CC=O", depth=1)])
true_pathway.add_edge(
[true_pathway.root_nodes.all()[0]],
[acetaldehyde := true_pathway.add_node("CC=O", depth=1)],
)
true_pathway.add_edge([acetaldehyde], [true_pathway.add_node("CC(=O)O", depth=2)])
pred_pathway = Pathway.create(self.package, "CCO")
pred_pathway.add_edge([pred_pathway.root_nodes.all()[0]], [pred_pathway.add_node("CC=O", depth=1)])
pred_pathway.add_edge(
[pred_pathway.root_nodes.all()[0]], [pred_pathway.add_node("CC=O", depth=1)]
)
return true_pathway, pred_pathway
def all_case(self):
"""Create an example with an intermediate, extra compound and missing compound"""
true_pathway = Pathway.create(self.package, "CCO")
true_pathway.add_edge([true_pathway.root_nodes.all()[0]],
[acetaldehyde := true_pathway.add_node("CC=O", depth=1)])
true_pathway.add_edge(
[true_pathway.root_nodes.all()[0]],
[acetaldehyde := true_pathway.add_node("CC=O", depth=1)],
)
true_pathway.add_edge([acetaldehyde], [true_pathway.add_node("C", depth=2)])
true_pathway.add_edge([acetaldehyde], [true_pathway.add_node("CC(=O)O", depth=2)])
pred_pathway = Pathway.create(self.package, "CCO")
pred_pathway.add_edge([pred_pathway.root_nodes.all()[0]], [methane := pred_pathway.add_node("C", depth=1)])
pred_pathway.add_edge(
[pred_pathway.root_nodes.all()[0]], [methane := pred_pathway.add_node("C", depth=1)]
)
pred_pathway.add_edge([methane], [true_pathway.add_node("CC=O", depth=2)])
pred_pathway.add_edge([methane], [true_pathway.add_node("c1ccccc1", depth=2)])
return true_pathway, pred_pathway

View File

@ -10,127 +10,127 @@ class ReactionTest(TestCase):
@classmethod
def setUpClass(cls):
super(ReactionTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
def test_smoke(self):
educt = Compound.create(
self.package,
smiles='C(CCl)Cl',
name='1,2-Dichloroethane',
description='Eawag BBD compound c0001'
smiles="C(CCl)Cl",
name="1,2-Dichloroethane",
description="Eawag BBD compound c0001",
).default_structure
product = Compound.create(
self.package,
smiles='C(CO)Cl',
name='2-Chloroethanol',
description='Eawag BBD compound c0005'
smiles="C(CO)Cl",
name="2-Chloroethanol",
description="Eawag BBD compound c0005",
).default_structure
r = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
name="Eawag BBD reaction r0001",
educts=[educt],
products=[product],
multi_step=False
multi_step=False,
)
self.assertEqual(r.smirks(), 'C(CCl)Cl>>C(CO)Cl')
self.assertEqual(r.name, 'Eawag BBD reaction r0001')
self.assertEqual(r.description, 'no description')
self.assertEqual(r.smirks(), "C(CCl)Cl>>C(CO)Cl")
self.assertEqual(r.name, "Eawag BBD reaction r0001")
self.assertEqual(r.description, "no description")
def test_string_educts_and_products(self):
r = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
multi_step=False
name="Eawag BBD reaction r0001",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
multi_step=False,
)
self.assertEqual(r.smirks(), 'C(CCl)Cl>>C(CO)Cl')
self.assertEqual(r.smirks(), "C(CCl)Cl>>C(CO)Cl")
def test_missing_smiles(self):
educt = Compound.create(
self.package,
smiles='C(CCl)Cl',
name='1,2-Dichloroethane',
description='Eawag BBD compound c0001'
smiles="C(CCl)Cl",
name="1,2-Dichloroethane",
description="Eawag BBD compound c0001",
).default_structure
product = Compound.create(
self.package,
smiles='C(CO)Cl',
name='2-Chloroethanol',
description='Eawag BBD compound c0005'
smiles="C(CO)Cl",
name="2-Chloroethanol",
description="Eawag BBD compound c0005",
).default_structure
with self.assertRaises(ValueError):
_ = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
name="Eawag BBD reaction r0001",
educts=[educt],
products=[],
multi_step=False
multi_step=False,
)
with self.assertRaises(ValueError):
_ = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
name="Eawag BBD reaction r0001",
educts=[],
products=[product],
multi_step=False
multi_step=False,
)
with self.assertRaises(ValueError):
_ = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
name="Eawag BBD reaction r0001",
educts=[],
products=[],
multi_step=False
multi_step=False,
)
def test_empty_name_and_description_are_ignored(self):
r = Reaction.create(
package=self.package,
name='',
description='',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
name="",
description="",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
multi_step=False,
)
self.assertEqual(r.name, 'no name')
self.assertEqual(r.description, 'no description')
self.assertEqual(r.name, "no name")
self.assertEqual(r.description, "no description")
def test_deduplication(self):
rule = Rule.create(
package=self.package,
rule_type='SimpleAmbitRule',
name='bt0022-2833',
description='Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative',
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
rule_type="SimpleAmbitRule",
name="bt0022-2833",
description="Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative",
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
)
r1 = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
name="Eawag BBD reaction r0001",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
rules=[rule],
multi_step=False
multi_step=False,
)
r2 = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
name="Eawag BBD reaction r0001",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
rules=[rule],
multi_step=False
multi_step=False,
)
# Check if create detects that this Compound already exist
@ -141,18 +141,18 @@ class ReactionTest(TestCase):
def test_deduplication_without_rules(self):
r1 = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
multi_step=False
name="Eawag BBD reaction r0001",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
multi_step=False,
)
r2 = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
multi_step=False
name="Eawag BBD reaction r0001",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
multi_step=False,
)
# Check if create detects that this Compound already exist
@ -164,19 +164,19 @@ class ReactionTest(TestCase):
with self.assertRaises(ValueError):
_ = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['ASDF'],
products=['C(CO)Cl'],
multi_step=False
name="Eawag BBD reaction r0001",
educts=["ASDF"],
products=["C(CO)Cl"],
multi_step=False,
)
def test_delete(self):
r = Reaction.create(
package=self.package,
name='Eawag BBD reaction r0001',
educts=['C(CCl)Cl'],
products=['C(CO)Cl'],
multi_step=False
name="Eawag BBD reaction r0001",
educts=["C(CCl)Cl"],
products=["C(CO)Cl"],
multi_step=False,
)
r.delete()

View File

@ -10,73 +10,79 @@ class RuleTest(TestCase):
@classmethod
def setUpClass(cls):
super(RuleTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
def test_smoke(self):
r = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
name='bt0022-2833',
description='Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative',
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
name="bt0022-2833",
description="Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative",
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
)
self.assertEqual(r.smirks,
'[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]')
self.assertEqual(r.name, 'bt0022-2833')
self.assertEqual(r.description,
'Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative')
self.assertEqual(
r.smirks,
"[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
)
self.assertEqual(r.name, "bt0022-2833")
self.assertEqual(
r.description,
"Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative",
)
def test_smirks_are_trimmed(self):
r = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
name='bt0022-2833',
description='Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative',
smirks=' [H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4] ',
name="bt0022-2833",
description="Dihalomethyl derivative + Halomethyl derivative > 1-Halo-1-methylalcohol derivative + 1-Methylalcohol derivative",
smirks=" [H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4] ",
)
self.assertEqual(r.smirks,
'[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]')
self.assertEqual(
r.smirks,
"[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
)
def test_name_and_description_optional(self):
r = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
)
self.assertRegex(r.name, 'Rule \\d+')
self.assertEqual(r.description, 'no description')
self.assertRegex(r.name, "Rule \\d+")
self.assertEqual(r.description, "no description")
def test_empty_name_and_description_are_ignored(self):
r = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
name='',
description='',
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
name="",
description="",
)
self.assertRegex(r.name, 'Rule \\d+')
self.assertEqual(r.description, 'no description')
self.assertRegex(r.name, "Rule \\d+")
self.assertEqual(r.description, "no description")
def test_deduplication(self):
r1 = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
name='',
description='',
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
name="",
description="",
)
r2 = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
name='',
description='',
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
name="",
description="",
)
self.assertEqual(r1.pk, r2.pk)
@ -84,21 +90,21 @@ class RuleTest(TestCase):
def test_valid_smirks(self):
with self.assertRaises(ValueError):
r = Rule.create(
rule_type='SimpleAmbitRule',
Rule.create(
rule_type="SimpleAmbitRule",
package=self.package,
smirks='This is not a valid SMIRKS',
name='',
description='',
smirks="This is not a valid SMIRKS",
name="",
description="",
)
def test_delete(self):
r = Rule.create(
rule_type='SimpleAmbitRule',
rule_type="SimpleAmbitRule",
package=self.package,
smirks='[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]',
name='',
description='',
smirks="[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
name="",
description="",
)
r.delete()

File diff suppressed because it is too large Load Diff

View File

@ -12,34 +12,32 @@ class SimpleAmbitRuleTest(TestCase):
@classmethod
def setUpClass(cls):
super(SimpleAmbitRuleTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Simple Ambit Rule Test Package',
'Test Package for SimpleAmbitRule')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(
cls.user, "Simple Ambit Rule Test Package", "Test Package for SimpleAmbitRule"
)
def test_create_basic_rule(self):
"""Test creating a basic SimpleAmbitRule with minimal parameters."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
rule = SimpleAmbitRule.create(
package=self.package,
smirks=smirks
)
rule = SimpleAmbitRule.create(package=self.package, smirks=smirks)
self.assertIsInstance(rule, SimpleAmbitRule)
self.assertEqual(rule.smirks, smirks)
self.assertEqual(rule.package, self.package)
self.assertRegex(rule.name, r'Rule \d+')
self.assertEqual(rule.description, 'no description')
self.assertRegex(rule.name, r"Rule \d+")
self.assertEqual(rule.description, "no description")
self.assertIsNone(rule.reactant_filter_smarts)
self.assertIsNone(rule.product_filter_smarts)
def test_create_with_all_parameters(self):
"""Test creating SimpleAmbitRule with all parameters."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
name = 'Test Rule'
description = 'A test biotransformation rule'
reactant_filter = '[CH2X4]'
product_filter = '[OH]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
name = "Test Rule"
description = "A test biotransformation rule"
reactant_filter = "[CH2X4]"
product_filter = "[OH]"
rule = SimpleAmbitRule.create(
package=self.package,
@ -47,7 +45,7 @@ class SimpleAmbitRuleTest(TestCase):
description=description,
smirks=smirks,
reactant_filter_smarts=reactant_filter,
product_filter_smarts=product_filter
product_filter_smarts=product_filter,
)
self.assertEqual(rule.name, name)
@ -60,127 +58,114 @@ class SimpleAmbitRuleTest(TestCase):
"""Test that SMIRKS is required for rule creation."""
with self.assertRaises(ValueError) as cm:
SimpleAmbitRule.create(package=self.package, smirks=None)
self.assertIn('SMIRKS is required', str(cm.exception))
self.assertIn("SMIRKS is required", str(cm.exception))
with self.assertRaises(ValueError) as cm:
SimpleAmbitRule.create(package=self.package, smirks='')
self.assertIn('SMIRKS is required', str(cm.exception))
SimpleAmbitRule.create(package=self.package, smirks="")
self.assertIn("SMIRKS is required", str(cm.exception))
with self.assertRaises(ValueError) as cm:
SimpleAmbitRule.create(package=self.package, smirks=' ')
self.assertIn('SMIRKS is required', str(cm.exception))
SimpleAmbitRule.create(package=self.package, smirks=" ")
self.assertIn("SMIRKS is required", str(cm.exception))
@patch('epdb.models.FormatConverter.is_valid_smirks')
@patch("epdb.models.FormatConverter.is_valid_smirks")
def test_invalid_smirks_validation(self, mock_is_valid):
"""Test validation of SMIRKS format."""
mock_is_valid.return_value = False
invalid_smirks = 'invalid_smirks_string'
invalid_smirks = "invalid_smirks_string"
with self.assertRaises(ValueError) as cm:
SimpleAmbitRule.create(
package=self.package,
smirks=invalid_smirks
)
SimpleAmbitRule.create(package=self.package, smirks=invalid_smirks)
self.assertIn(f'SMIRKS "{invalid_smirks}" is invalid', str(cm.exception))
mock_is_valid.assert_called_once_with(invalid_smirks)
def test_smirks_trimming(self):
"""Test that SMIRKS strings are trimmed during creation."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks_with_whitespace = f' {smirks} '
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
smirks_with_whitespace = f" {smirks} "
rule = SimpleAmbitRule.create(
package=self.package,
smirks=smirks_with_whitespace
)
rule = SimpleAmbitRule.create(package=self.package, smirks=smirks_with_whitespace)
self.assertEqual(rule.smirks, smirks)
def test_empty_name_and_description_handling(self):
"""Test that empty name and description are handled appropriately."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
rule = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
name='',
description=' '
package=self.package, smirks=smirks, name="", description=" "
)
self.assertRegex(rule.name, r'Rule \d+')
self.assertEqual(rule.description, 'no description')
self.assertRegex(rule.name, r"Rule \d+")
self.assertEqual(rule.description, "no description")
def test_deduplication_basic(self):
"""Test that identical rules are deduplicated."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
rule1 = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
name='Rule 1'
)
rule1 = SimpleAmbitRule.create(package=self.package, smirks=smirks, name="Rule 1")
rule2 = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
name='Rule 2' # Different name, but same SMIRKS
name="Rule 2", # Different name, but same SMIRKS
)
self.assertEqual(rule1.pk, rule2.pk)
self.assertEqual(SimpleAmbitRule.objects.filter(package=self.package, smirks=smirks).count(), 1)
self.assertEqual(
SimpleAmbitRule.objects.filter(package=self.package, smirks=smirks).count(), 1
)
def test_deduplication_with_filters(self):
"""Test deduplication with filter SMARTS."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
reactant_filter = '[CH2X4]'
product_filter = '[OH]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
reactant_filter = "[CH2X4]"
product_filter = "[OH]"
rule1 = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
reactant_filter_smarts=reactant_filter,
product_filter_smarts=product_filter
product_filter_smarts=product_filter,
)
rule2 = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
reactant_filter_smarts=reactant_filter,
product_filter_smarts=product_filter
product_filter_smarts=product_filter,
)
self.assertEqual(rule1.pk, rule2.pk)
def test_no_deduplication_different_filters(self):
"""Test that rules with different filters are not deduplicated."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
rule1 = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
reactant_filter_smarts='[CH2X4]'
package=self.package, smirks=smirks, reactant_filter_smarts="[CH2X4]"
)
rule2 = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
reactant_filter_smarts='[CH3X4]'
package=self.package, smirks=smirks, reactant_filter_smarts="[CH3X4]"
)
self.assertNotEqual(rule1.pk, rule2.pk)
self.assertEqual(SimpleAmbitRule.objects.filter(package=self.package, smirks=smirks).count(), 2)
self.assertEqual(
SimpleAmbitRule.objects.filter(package=self.package, smirks=smirks).count(), 2
)
def test_filter_smarts_trimming(self):
"""Test that filter SMARTS are trimmed and handled correctly."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
# Test with whitespace-only filters (should be treated as None)
rule = SimpleAmbitRule.create(
package=self.package,
smirks=smirks,
reactant_filter_smarts=' ',
product_filter_smarts=' '
reactant_filter_smarts=" ",
product_filter_smarts=" ",
)
self.assertIsNone(rule.reactant_filter_smarts)
@ -188,94 +173,85 @@ class SimpleAmbitRuleTest(TestCase):
def test_url_property(self):
"""Test the URL property generation."""
rule = SimpleAmbitRule.create(
package=self.package,
smirks='[H:1][C:2]>>[H:1][O:2]'
)
rule = SimpleAmbitRule.create(package=self.package, smirks="[H:1][C:2]>>[H:1][O:2]")
expected_url = f'{self.package.url}/simple-ambit-rule/{rule.uuid}'
expected_url = f"{self.package.url}/simple-ambit-rule/{rule.uuid}"
self.assertEqual(rule.url, expected_url)
@patch('epdb.models.FormatConverter.apply')
@patch("epdb.models.FormatConverter.apply")
def test_apply_method(self, mock_apply):
"""Test the apply method delegates to FormatConverter."""
mock_apply.return_value = ['product1', 'product2']
mock_apply.return_value = ["product1", "product2"]
rule = SimpleAmbitRule.create(
package=self.package,
smirks='[H:1][C:2]>>[H:1][O:2]'
)
rule = SimpleAmbitRule.create(package=self.package, smirks="[H:1][C:2]>>[H:1][O:2]")
test_smiles = 'CCO'
test_smiles = "CCO"
result = rule.apply(test_smiles)
mock_apply.assert_called_once_with(test_smiles, rule.smirks)
self.assertEqual(result, ['product1', 'product2'])
self.assertEqual(result, ["product1", "product2"])
def test_reactants_smarts_property(self):
"""Test reactants_smarts property extracts correct part of SMIRKS."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
expected_reactants = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
expected_reactants = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]"
rule = SimpleAmbitRule.create(
package=self.package,
smirks=smirks
)
rule = SimpleAmbitRule.create(package=self.package, smirks=smirks)
self.assertEqual(rule.reactants_smarts, expected_reactants)
def test_products_smarts_property(self):
"""Test products_smarts property extracts correct part of SMIRKS."""
smirks = '[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
expected_products = '[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]'
smirks = "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
expected_products = "[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]"
rule = SimpleAmbitRule.create(
package=self.package,
smirks=smirks
)
rule = SimpleAmbitRule.create(package=self.package, smirks=smirks)
self.assertEqual(rule.products_smarts, expected_products)
@patch('epdb.models.Package.objects')
@patch("epdb.models.Package.objects")
def test_related_reactions_property(self, mock_package_objects):
"""Test related_reactions property returns correct queryset."""
mock_qs = MagicMock()
mock_package_objects.filter.return_value = mock_qs
rule = SimpleAmbitRule.create(
package=self.package,
smirks='[H:1][C:2]>>[H:1][O:2]'
)
rule = SimpleAmbitRule.create(package=self.package, smirks="[H:1][C:2]>>[H:1][O:2]")
# Instead of directly assigning, patch the property or use with patch.object
with patch.object(type(rule), 'reaction_rule', new_callable=PropertyMock) as mock_reaction_rule:
mock_reaction_rule.return_value.filter.return_value.order_by.return_value = ['reaction1', 'reaction2']
with patch.object(
type(rule), "reaction_rule", new_callable=PropertyMock
) as mock_reaction_rule:
mock_reaction_rule.return_value.filter.return_value.order_by.return_value = [
"reaction1",
"reaction2",
]
result = rule.related_reactions
mock_package_objects.filter.assert_called_once_with(reviewed=True)
mock_reaction_rule.return_value.filter.assert_called_once_with(package__in=mock_qs)
mock_reaction_rule.return_value.filter.return_value.order_by.assert_called_once_with('name')
self.assertEqual(result, ['reaction1', 'reaction2'])
mock_reaction_rule.return_value.filter.return_value.order_by.assert_called_once_with(
"name"
)
self.assertEqual(result, ["reaction1", "reaction2"])
@patch('epdb.models.Pathway.objects')
@patch('epdb.models.Edge.objects')
@patch("epdb.models.Pathway.objects")
@patch("epdb.models.Edge.objects")
def test_related_pathways_property(self, mock_edge_objects, mock_pathway_objects):
"""Test related_pathways property returns correct queryset."""
mock_related_reactions = ['reaction1', 'reaction2']
mock_related_reactions = ["reaction1", "reaction2"]
with patch.object(SimpleAmbitRule, "related_reactions", new_callable=PropertyMock) as mock_prop:
with patch.object(
SimpleAmbitRule, "related_reactions", new_callable=PropertyMock
) as mock_prop:
mock_prop.return_value = mock_related_reactions
rule = SimpleAmbitRule.create(
package=self.package,
smirks='[H:1][C:2]>>[H:1][O:2]'
)
rule = SimpleAmbitRule.create(package=self.package, smirks="[H:1][C:2]>>[H:1][O:2]")
# Mock Edge objects query
mock_edge_values = MagicMock()
mock_edge_values.values.return_value = ['pathway_id1', 'pathway_id2']
mock_edge_values.values.return_value = ["pathway_id1", "pathway_id2"]
mock_edge_objects.filter.return_value = mock_edge_values
# Mock Pathway objects query
@ -285,52 +261,49 @@ class SimpleAmbitRuleTest(TestCase):
result = rule.related_pathways
mock_edge_objects.filter.assert_called_once_with(edge_label__in=mock_related_reactions)
mock_edge_values.values.assert_called_once_with('pathway_id')
mock_edge_values.values.assert_called_once_with("pathway_id")
mock_pathway_objects.filter.assert_called_once()
self.assertEqual(result, mock_pathway_qs)
@patch('epdb.models.IndigoUtils.smirks_to_svg')
@patch("epdb.models.IndigoUtils.smirks_to_svg")
def test_as_svg_property(self, mock_smirks_to_svg):
"""Test as_svg property calls IndigoUtils correctly."""
mock_smirks_to_svg.return_value = '<svg>test_svg</svg>'
mock_smirks_to_svg.return_value = "<svg>test_svg</svg>"
rule = SimpleAmbitRule.create(
package=self.package,
smirks='[H:1][C:2]>>[H:1][O:2]'
)
rule = SimpleAmbitRule.create(package=self.package, smirks="[H:1][C:2]>>[H:1][O:2]")
result = rule.as_svg
mock_smirks_to_svg.assert_called_once_with(rule.smirks, True, width=800, height=400)
self.assertEqual(result, '<svg>test_svg</svg>')
self.assertEqual(result, "<svg>test_svg</svg>")
def test_atomic_transaction(self):
"""Test that rule creation is atomic."""
smirks = '[H:1][C:2]>>[H:1][O:2]'
smirks = "[H:1][C:2]>>[H:1][O:2]"
# This should work normally
rule = SimpleAmbitRule.create(package=self.package, smirks=smirks)
self.assertIsInstance(rule, SimpleAmbitRule)
# Test transaction rollback on error
with patch('epdb.models.SimpleAmbitRule.save', side_effect=Exception('Database error')):
with patch("epdb.models.SimpleAmbitRule.save", side_effect=Exception("Database error")):
with self.assertRaises(Exception):
SimpleAmbitRule.create(package=self.package, smirks='[H:3][C:4]>>[H:3][O:4]')
SimpleAmbitRule.create(package=self.package, smirks="[H:3][C:4]>>[H:3][O:4]")
# Verify no partial data was saved
self.assertEqual(SimpleAmbitRule.objects.filter(package=self.package).count(), 1)
def test_multiple_duplicate_warning(self):
"""Test logging when multiple duplicates are found."""
smirks = '[H:1][C:2]>>[H:1][O:2]'
smirks = "[H:1][C:2]>>[H:1][O:2]"
# Create first rule
rule1 = SimpleAmbitRule.create(package=self.package, smirks=smirks)
# Manually create a duplicate to simulate the error condition
rule2 = SimpleAmbitRule(package=self.package, smirks=smirks, name='Manual Rule')
rule2 = SimpleAmbitRule(package=self.package, smirks=smirks, name="Manual Rule")
rule2.save()
with patch('epdb.models.logger') as mock_logger:
with patch("epdb.models.logger") as mock_logger:
# This should find the existing rule and log an error about multiple matches
result = SimpleAmbitRule.create(package=self.package, smirks=smirks)
@ -339,24 +312,28 @@ class SimpleAmbitRuleTest(TestCase):
# Should log an error about multiple matches
mock_logger.error.assert_called()
self.assertIn('More than one rule matched', mock_logger.error.call_args[0][0])
self.assertIn("More than one rule matched", mock_logger.error.call_args[0][0])
def test_model_fields(self):
"""Test model field properties."""
rule = SimpleAmbitRule.create(
package=self.package,
smirks='[H:1][C:2]>>[H:1][O:2]',
reactant_filter_smarts='[CH3]',
product_filter_smarts='[OH]'
smirks="[H:1][C:2]>>[H:1][O:2]",
reactant_filter_smarts="[CH3]",
product_filter_smarts="[OH]",
)
# Test field properties
self.assertFalse(rule._meta.get_field('smirks').blank)
self.assertFalse(rule._meta.get_field('smirks').null)
self.assertTrue(rule._meta.get_field('reactant_filter_smarts').null)
self.assertTrue(rule._meta.get_field('product_filter_smarts').null)
self.assertFalse(rule._meta.get_field("smirks").blank)
self.assertFalse(rule._meta.get_field("smirks").null)
self.assertTrue(rule._meta.get_field("reactant_filter_smarts").null)
self.assertTrue(rule._meta.get_field("product_filter_smarts").null)
# Test verbose names
self.assertEqual(rule._meta.get_field('smirks').verbose_name, 'SMIRKS')
self.assertEqual(rule._meta.get_field('reactant_filter_smarts').verbose_name, 'Reactant Filter SMARTS')
self.assertEqual(rule._meta.get_field('product_filter_smarts').verbose_name, 'Product Filter SMARTS')
self.assertEqual(rule._meta.get_field("smirks").verbose_name, "SMIRKS")
self.assertEqual(
rule._meta.get_field("reactant_filter_smarts").verbose_name, "Reactant Filter SMARTS"
)
self.assertEqual(
rule._meta.get_field("product_filter_smarts").verbose_name, "Product Filter SMARTS"
)

View File

@ -1,32 +1,29 @@
from django.test import TestCase
from epdb.logic import SNode, SEdge, SPathway
from epdb.logic import SNode, SEdge
class SObjectTest(TestCase):
def setUp(self):
pass
def test_snode_eq(self):
snode1 = SNode('CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O', 0)
snode2 = SNode('CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O', 0)
snode1 = SNode("CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O", 0)
snode2 = SNode("CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O", 0)
assert snode1 == snode2
def test_snode_hash(self):
pass
def test_sedge_eq(self):
sedge1 = SEdge([SNode('CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O', 0)],
[SNode('CN1C(=O)NC2=C(C1=O)N(C)C=N2', 1), SNode('C=O', 1)],
rule=None)
sedge2 = SEdge([SNode('CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O', 0)],
[SNode('CN1C(=O)NC2=C(C1=O)N(C)C=N2', 1), SNode('C=O', 1)],
rule=None)
sedge1 = SEdge(
[SNode("CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O", 0)],
[SNode("CN1C(=O)NC2=C(C1=O)N(C)C=N2", 1), SNode("C=O", 1)],
rule=None,
)
sedge2 = SEdge(
[SNode("CN1C2C(N(C(N(C)C=2N=C1)=O)C)=O", 0)],
[SNode("CN1C(=O)NC2=C(C1=O)N(C)C=N2", 1), SNode("C=O", 1)],
rule=None,
)
assert sedge1 == sedge2
def test_sedge_hash(self):
pass
def test_spathway(self):
pw = SPathway()

View File

@ -3,7 +3,7 @@ from django.urls import reverse
from envipy_additional_information import Temperature, Interval
from epdb.logic import UserManager, PackageManager
from epdb.models import Compound, Scenario, ExternalIdentifier, ExternalDatabase
from epdb.models import Compound, Scenario, ExternalDatabase
class CompoundViewTest(TestCase):
@ -12,21 +12,28 @@ class CompoundViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(CompoundViewTest, cls).setUpClass()
cls.user1 = UserManager.create_user("user1", "user1@envipath.com", "SuperSafe",
set_setting=False, add_to_group=True, is_active=True)
cls.user1 = UserManager.create_user(
"user1",
"user1@envipath.com",
"SuperSafe",
set_setting=False,
add_to_group=True,
is_active=True,
)
cls.user1_default_package = cls.user1.default_package
cls.package = PackageManager.create_package(cls.user1, 'Test', 'Test Pack')
cls.package = PackageManager.create_package(cls.user1, "Test", "Test Pack")
def setUp(self):
self.client.force_login(self.user1)
def test_create_compound(self):
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -38,17 +45,18 @@ class CompoundViewTest(TestCase):
self.assertEqual(c.name, "1,2-Dichloroethane")
self.assertEqual(c.description, "Eawag BBD compound c0001")
self.assertEqual(c.default_structure.smiles, "C(CCl)Cl")
self.assertEqual(c.default_structure.canonical_smiles, 'ClCCCl')
self.assertEqual(c.default_structure.canonical_smiles, "ClCCCl")
self.assertEqual(c.structures.all().count(), 2)
self.assertEqual(self.user1_default_package.compounds.count(), 1)
# Adding the same rule again should return the existing one, hence not increasing the number of rules
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.url, compound_url)
@ -57,11 +65,12 @@ class CompoundViewTest(TestCase):
# Adding the same rule in a different package should create a new rule
response = self.client.post(
reverse("package compound list", kwargs={'package_uuid': self.package.uuid}), {
reverse("package compound list", kwargs={"package_uuid": self.package.uuid}),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -69,11 +78,12 @@ class CompoundViewTest(TestCase):
# adding another reaction should increase count
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "2-Chloroethanol",
"compound-description": "Eawag BBD compound c0005",
"compound-smiles": "C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -82,11 +92,12 @@ class CompoundViewTest(TestCase):
# Edit
def test_edit_rule(self):
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -95,13 +106,17 @@ class CompoundViewTest(TestCase):
c = Compound.objects.get(url=compound_url)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(self.user1_default_package.uuid),
'compound_uuid': str(c.uuid)
}), {
reverse(
"package compound detail",
kwargs={
"package_uuid": str(self.user1_default_package.uuid),
"compound_uuid": str(c.uuid),
},
),
{
"compound-name": "Test Compound Adjusted",
"compound-description": "New Description",
}
},
)
self.assertEqual(response.status_code, 302)
@ -121,7 +136,7 @@ class CompoundViewTest(TestCase):
"Test Desc",
"2025-10",
"soil",
[Temperature(interval=Interval(start=20, end=30))]
[Temperature(interval=Interval(start=20, end=30))],
)
s2 = Scenario.create(
@ -130,15 +145,16 @@ class CompoundViewTest(TestCase):
"Test Desc2",
"2025-10",
"soil",
[Temperature(interval=Interval(start=10, end=20))]
[Temperature(interval=Interval(start=10, end=20))],
)
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -147,36 +163,35 @@ class CompoundViewTest(TestCase):
c = Compound.objects.get(url=compound_url)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(c.package.uuid),
'compound_uuid': str(c.uuid)
}), {
"selected-scenarios": [s1.url, s2.url]
}
reverse(
"package compound detail",
kwargs={"package_uuid": str(c.package.uuid), "compound_uuid": str(c.uuid)},
),
{"selected-scenarios": [s1.url, s2.url]},
)
self.assertEqual(len(c.scenarios.all()), 2)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(c.package.uuid),
'compound_uuid': str(c.uuid)
}), {
"selected-scenarios": [s1.url]
}
reverse(
"package compound detail",
kwargs={"package_uuid": str(c.package.uuid), "compound_uuid": str(c.uuid)},
),
{"selected-scenarios": [s1.url]},
)
self.assertEqual(len(c.scenarios.all()), 1)
self.assertEqual(c.scenarios.first().url, s1.url)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(c.package.uuid),
'compound_uuid': str(c.uuid)
}), {
reverse(
"package compound detail",
kwargs={"package_uuid": str(c.package.uuid), "compound_uuid": str(c.uuid)},
),
{
# We have to set an empty string to avoid that the parameter is removed
"selected-scenarios": ""
}
},
)
self.assertEqual(len(c.scenarios.all()), 0)
@ -184,11 +199,12 @@ class CompoundViewTest(TestCase):
#
def test_copy(self):
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -196,12 +212,13 @@ class CompoundViewTest(TestCase):
c = Compound.objects.get(url=compound_url)
response = self.client.post(
reverse("package detail", kwargs={
'package_uuid': str(self.package.uuid),
}), {
"hidden": "copy",
"object_to_copy": c.url
}
reverse(
"package detail",
kwargs={
"package_uuid": str(self.package.uuid),
},
),
{"hidden": "copy", "object_to_copy": c.url},
)
self.assertEqual(response.status_code, 200)
@ -215,44 +232,48 @@ class CompoundViewTest(TestCase):
# Copy to the same package should fail
response = self.client.post(
reverse("package detail", kwargs={
'package_uuid': str(c.package.uuid),
}), {
"hidden": "copy",
"object_to_copy": c.url
}
reverse(
"package detail",
kwargs={
"package_uuid": str(c.package.uuid),
},
),
{"hidden": "copy", "object_to_copy": c.url},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['error'], f"Can't copy object {compound_url} to the same package!")
self.assertEqual(
response.json()["error"], f"Can't copy object {compound_url} to the same package!"
)
def test_references(self):
ext_db, _ = ExternalDatabase.objects.get_or_create(
name='PubChem Compound',
name="PubChem Compound",
defaults={
'full_name': 'PubChem Compound Database',
'description': 'Chemical database of small organic molecules',
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/compound/{id}'
}
"full_name": "PubChem Compound Database",
"description": "Chemical database of small organic molecules",
"base_url": "https://pubchem.ncbi.nlm.nih.gov",
"url_pattern": "https://pubchem.ncbi.nlm.nih.gov/compound/{id}",
},
)
ext_db2, _ = ExternalDatabase.objects.get_or_create(
name='PubChem Substance',
name="PubChem Substance",
defaults={
'full_name': 'PubChem Substance Database',
'description': 'Database of chemical substances',
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/substance/{id}'
}
"full_name": "PubChem Substance Database",
"description": "Database of chemical substances",
"base_url": "https://pubchem.ncbi.nlm.nih.gov",
"url_pattern": "https://pubchem.ncbi.nlm.nih.gov/substance/{id}",
},
)
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -260,42 +281,49 @@ class CompoundViewTest(TestCase):
c = Compound.objects.get(url=compound_url)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(c.package.uuid),
'compound_uuid': str(c.uuid),
}), {
'selected-database': ext_db.pk,
'identifier': '25154249'
}
reverse(
"package compound detail",
kwargs={
"package_uuid": str(c.package.uuid),
"compound_uuid": str(c.uuid),
},
),
{"selected-database": ext_db.pk, "identifier": "25154249"},
)
self.assertEqual(c.external_identifiers.count(), 1)
self.assertEqual(c.external_identifiers.first().database, ext_db)
self.assertEqual(c.external_identifiers.first().identifier_value, '25154249')
self.assertEqual(c.external_identifiers.first().url, 'https://pubchem.ncbi.nlm.nih.gov/compound/25154249')
self.assertEqual(c.external_identifiers.first().identifier_value, "25154249")
self.assertEqual(
c.external_identifiers.first().url, "https://pubchem.ncbi.nlm.nih.gov/compound/25154249"
)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(c.package.uuid),
'compound_uuid': str(c.uuid),
}), {
'selected-database': ext_db2.pk,
'identifier': '25154249'
}
reverse(
"package compound detail",
kwargs={
"package_uuid": str(c.package.uuid),
"compound_uuid": str(c.uuid),
},
),
{"selected-database": ext_db2.pk, "identifier": "25154249"},
)
self.assertEqual(c.external_identifiers.count(), 2)
self.assertEqual(c.external_identifiers.last().database, ext_db2)
self.assertEqual(c.external_identifiers.last().identifier_value, '25154249')
self.assertEqual(c.external_identifiers.last().url, 'https://pubchem.ncbi.nlm.nih.gov/substance/25154249')
self.assertEqual(c.external_identifiers.last().identifier_value, "25154249")
self.assertEqual(
c.external_identifiers.last().url, "https://pubchem.ncbi.nlm.nih.gov/substance/25154249"
)
def test_delete(self):
response = self.client.post(
reverse("compounds"), {
reverse("compounds"),
{
"compound-name": "1,2-Dichloroethane",
"compound-description": "Eawag BBD compound c0001",
"compound-smiles": "C(CCl)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -304,12 +332,11 @@ class CompoundViewTest(TestCase):
c = Compound.objects.get(url=compound_url)
response = self.client.post(
reverse("package compound detail", kwargs={
'package_uuid': str(c.package.uuid),
'compound_uuid': str(c.uuid)
}), {
"hidden": "delete"
}
reverse(
"package compound detail",
kwargs={"package_uuid": str(c.package.uuid), "compound_uuid": str(c.uuid)},
),
{"hidden": "delete"},
)
self.assertEqual(self.user1_default_package.compounds.count(), 0)

View File

@ -2,8 +2,8 @@ from django.test import TestCase, override_settings
from django.urls import reverse
from django.conf import settings as s
from epdb.logic import UserManager, PackageManager
from epdb.models import Pathway, Edge, Package, User
from epdb.logic import UserManager
from epdb.models import Package, User
@override_settings(MODEL_DIR=s.FIXTURE_DIRS[0] / "models")
@ -13,10 +13,16 @@ class PathwayViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(PathwayViewTest, cls).setUpClass()
cls.user1 = UserManager.create_user("user1", "user1@envipath.com", "SuperSafe",
set_setting=True, add_to_group=True, is_active=True)
cls.user1 = UserManager.create_user(
"user1",
"user1@envipath.com",
"SuperSafe",
set_setting=True,
add_to_group=True,
is_active=True,
)
cls.user1_default_package = cls.user1.default_package
cls.model_package = Package.objects.get(name='Fixtures')
cls.model_package = Package.objects.get(name="Fixtures")
def setUp(self):
self.client.force_login(self.user1)
@ -24,90 +30,96 @@ class PathwayViewTest(TestCase):
def test_predict(self):
self.client.force_login(User.objects.get(username="admin"))
response = self.client.get(
reverse("package model detail", kwargs={
'package_uuid': str(self.model_package.uuid),
'model_uuid': str(self.model_package.models.first().uuid)
}), {
'classify': 'ILikeCats!',
'smiles': 'CCN(CC)C(=O)C1=CC(=CC=C1)CO',
}
reverse(
"package model detail",
kwargs={
"package_uuid": str(self.model_package.uuid),
"model_uuid": str(self.model_package.models.first().uuid),
},
),
{
"classify": "ILikeCats!",
"smiles": "CCN(CC)C(=O)C1=CC(=CC=C1)CO",
},
)
expected = [
{
'products': [
[
'O=C(O)C1=CC(CO)=CC=C1',
'CCNCC'
]
],
'probability': 0.25,
'btrule': {
'url': 'http://localhost:8000/package/1869d3f0-60bb-41fd-b6f8-afa75ffb09d3/simple-ambit-rule/0e6e9290-b658-4450-b291-3ec19fa19206',
'name': 'bt0430-4011'
}
}, {
'products': [
[
'CCNC(=O)C1=CC(CO)=CC=C1',
'CC=O'
]
], 'probability': 0.0,
'btrule': {
'url': 'http://localhost:8000/package/1869d3f0-60bb-41fd-b6f8-afa75ffb09d3/simple-ambit-rule/27a3a353-0b66-4228-bd16-e407949e90df',
'name': 'bt0243-4301'
}
}, {
'products': [
[
'CCN(CC)C(=O)C1=CC(C=O)=CC=C1'
]
], 'probability': 0.75,
'btrule': {
'url': 'http://localhost:8000/package/1869d3f0-60bb-41fd-b6f8-afa75ffb09d3/simple-ambit-rule/2f2e0c39-e109-4836-959f-2bda2524f022',
'name': 'bt0001-3568'
}
}
"products": [["O=C(O)C1=CC(CO)=CC=C1", "CCNCC"]],
"probability": 0.25,
"btrule": {
"url": "http://localhost:8000/package/1869d3f0-60bb-41fd-b6f8-afa75ffb09d3/simple-ambit-rule/0e6e9290-b658-4450-b291-3ec19fa19206",
"name": "bt0430-4011",
},
},
{
"products": [["CCNC(=O)C1=CC(CO)=CC=C1", "CC=O"]],
"probability": 0.0,
"btrule": {
"url": "http://localhost:8000/package/1869d3f0-60bb-41fd-b6f8-afa75ffb09d3/simple-ambit-rule/27a3a353-0b66-4228-bd16-e407949e90df",
"name": "bt0243-4301",
},
},
{
"products": [["CCN(CC)C(=O)C1=CC(C=O)=CC=C1"]],
"probability": 0.75,
"btrule": {
"url": "http://localhost:8000/package/1869d3f0-60bb-41fd-b6f8-afa75ffb09d3/simple-ambit-rule/2f2e0c39-e109-4836-959f-2bda2524f022",
"name": "bt0001-3568",
},
},
]
actual = response.json()
self.assertEqual(actual, expected)
response = self.client.get(
reverse("package model detail", kwargs={
'package_uuid': str(self.model_package.uuid),
'model_uuid': str(self.model_package.models.first().uuid)
}), {
'classify': 'ILikeCats!',
'smiles': '',
}
reverse(
"package model detail",
kwargs={
"package_uuid": str(self.model_package.uuid),
"model_uuid": str(self.model_package.models.first().uuid),
},
),
{
"classify": "ILikeCats!",
"smiles": "",
},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['error'], 'Received empty SMILES')
self.assertEqual(response.json()["error"], "Received empty SMILES")
response = self.client.get(
reverse("package model detail", kwargs={
'package_uuid': str(self.model_package.uuid),
'model_uuid': str(self.model_package.models.first().uuid)
}), {
'classify': 'ILikeCats!',
'smiles': ' ', # Input should be stripped
}
reverse(
"package model detail",
kwargs={
"package_uuid": str(self.model_package.uuid),
"model_uuid": str(self.model_package.models.first().uuid),
},
),
{
"classify": "ILikeCats!",
"smiles": " ", # Input should be stripped
},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['error'], 'Received empty SMILES')
self.assertEqual(response.json()["error"], "Received empty SMILES")
response = self.client.get(
reverse("package model detail", kwargs={
'package_uuid': str(self.model_package.uuid),
'model_uuid': str(self.model_package.models.first().uuid)
}), {
'classify': 'ILikeCats!',
'smiles': 'RandomInput',
}
reverse(
"package model detail",
kwargs={
"package_uuid": str(self.model_package.uuid),
"model_uuid": str(self.model_package.models.first().uuid),
},
),
{
"classify": "ILikeCats!",
"smiles": "RandomInput",
},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['error'], '"RandomInput" is not a valid SMILES')
self.assertEqual(response.json()["error"], '"RandomInput" is not a valid SMILES')

View File

@ -13,19 +13,34 @@ class PackageViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(PackageViewTest, cls).setUpClass()
cls.user1 = UserManager.create_user("user1", "user1@envipath.com", "SuperSafe",
set_setting=False, add_to_group=True, is_active=True)
cls.user2 = UserManager.create_user("user2", "user2@envipath.com", "SuperSafe",
set_setting=False, add_to_group=True, is_active=True)
cls.user1 = UserManager.create_user(
"user1",
"user1@envipath.com",
"SuperSafe",
set_setting=False,
add_to_group=True,
is_active=True,
)
cls.user2 = UserManager.create_user(
"user2",
"user2@envipath.com",
"SuperSafe",
set_setting=False,
add_to_group=True,
is_active=True,
)
def setUp(self):
self.client.force_login(self.user1)
def test_create_package(self):
response = self.client.post(reverse("packages"), {
"package-name": "Test Package",
"package-description": "Just a Description",
})
response = self.client.post(
reverse("packages"),
{
"package-name": "Test Package",
"package-description": "Just a Description",
},
)
self.assertEqual(response.status_code, 302)
package_url = response.url
@ -41,13 +56,12 @@ class PackageViewTest(TestCase):
file = SimpleUploadedFile(
"Fixture_Package.json",
open(s.FIXTURE_DIRS[0] / "Fixture_Package.json", "rb").read(),
content_type="application/json"
content_type="application/json",
)
response = self.client.post(reverse("packages"), {
"file": file,
"hidden": "import-package-json"
})
response = self.client.post(
reverse("packages"), {"file": file, "hidden": "import-package-json"}
)
self.assertEqual(response.status_code, 302)
package_url = response.url
@ -67,13 +81,12 @@ class PackageViewTest(TestCase):
file = SimpleUploadedFile(
"EAWAG-BBD.json",
open(s.FIXTURE_DIRS[0] / "packages" / "2025-07-18" / "EAWAG-BBD.json", "rb").read(),
content_type="application/json"
content_type="application/json",
)
response = self.client.post(reverse("packages"), {
"file": file,
"hidden": "import-legacy-package-json"
})
response = self.client.post(
reverse("packages"), {"file": file, "hidden": "import-legacy-package-json"}
)
self.assertEqual(response.status_code, 302)
package_url = response.url
@ -90,17 +103,23 @@ class PackageViewTest(TestCase):
self.assertEqual(upp.permission, Permission.ALL[0])
def test_edit_package(self):
response = self.client.post(reverse("packages"), {
"package-name": "Test Package",
"package-description": "Just a Description",
})
response = self.client.post(
reverse("packages"),
{
"package-name": "Test Package",
"package-description": "Just a Description",
},
)
self.assertEqual(response.status_code, 302)
package_url = response.url
self.client.post(package_url, {
"package-name": "New Name",
"package-description": "New Description",
})
self.client.post(
package_url,
{
"package-name": "New Name",
"package-description": "New Description",
},
)
p = Package.objects.get(url=package_url)
@ -108,10 +127,13 @@ class PackageViewTest(TestCase):
self.assertEqual(p.description, "New Description")
def test_edit_package_permissions(self):
response = self.client.post(reverse("packages"), {
"package-name": "Test Package",
"package-description": "Just a Description",
})
response = self.client.post(
reverse("packages"),
{
"package-name": "Test Package",
"package-description": "Just a Description",
},
)
self.assertEqual(response.status_code, 302)
package_url = response.url
p = Package.objects.get(url=package_url)
@ -119,57 +141,63 @@ class PackageViewTest(TestCase):
with self.assertRaises(UserPackagePermission.DoesNotExist):
UserPackagePermission.objects.get(package=p, user=self.user2)
self.client.post(package_url, {
"grantee": self.user2.url,
"read": "on",
"write": "on",
})
self.client.post(
package_url,
{
"grantee": self.user2.url,
"read": "on",
"write": "on",
},
)
upp = UserPackagePermission.objects.get(package=p, user=self.user2)
self.assertEqual(upp.permission, Permission.WRITE[0])
def test_publish_package(self):
response = self.client.post(reverse("packages"), {
"package-name": "Test Package",
"package-description": "Just a Description",
})
response = self.client.post(
reverse("packages"),
{
"package-name": "Test Package",
"package-description": "Just a Description",
},
)
self.assertEqual(response.status_code, 302)
package_url = response.url
p = Package.objects.get(url=package_url)
self.client.post(package_url, {
"hidden": "publish-package"
})
self.client.post(package_url, {"hidden": "publish-package"})
self.assertEqual(Group.objects.filter(public=True).count(), 1)
g = Group.objects.get(public=True)
gpp = GroupPackagePermission.objects.get(package=p, group=g)
self.assertEqual(gpp.permission, Permission.READ[0])
def test_set_package_license(self):
response = self.client.post(reverse("packages"), {
"package-name": "Test Package",
"package-description": "Just a Description",
})
response = self.client.post(
reverse("packages"),
{
"package-name": "Test Package",
"package-description": "Just a Description",
},
)
package_url = response.url
p = Package.objects.get(url=package_url)
self.client.post(package_url, {
"license": "no-license"
})
self.client.post(package_url, {"license": "no-license"})
self.assertIsNone(p.license)
# TODO test others
def test_delete_package(self):
response = self.client.post(reverse("packages"), {
"package-name": "Test Package",
"package-description": "Just a Description",
})
response = self.client.post(
reverse("packages"),
{
"package-name": "Test Package",
"package-description": "Just a Description",
},
)
package_url = response.url
p = Package.objects.get(url=package_url)
@ -182,11 +210,11 @@ class PackageViewTest(TestCase):
def test_delete_default_package(self):
self.client.force_login(self.user1)
# Try to delete the default package
response = self.client.post(self.user1.default_package.url, {
"hidden": "delete"
})
response = self.client.post(self.user1.default_package.url, {"hidden": "delete"})
self.assertEqual(response.status_code, 400)
self.assertTrue(f'You cannot delete the default package. '
f'If you want to delete this package you have to '
f'set another default package first' in response.content.decode())
self.assertTrue(
"You cannot delete the default package. "
"If you want to delete this package you have to "
"set another default package first" in response.content.decode()
)

View File

@ -5,6 +5,7 @@ from django.conf import settings as s
from epdb.logic import UserManager, PackageManager
from epdb.models import Pathway, Edge
@override_settings(MODEL_DIR=s.FIXTURE_DIRS[0] / "models")
class PathwayViewTest(TestCase):
fixtures = ["test_fixtures_incl_model.jsonl.gz"]
@ -12,41 +13,52 @@ class PathwayViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(PathwayViewTest, cls).setUpClass()
cls.user1 = UserManager.create_user("user1", "user1@envipath.com", "SuperSafe",
set_setting=True, add_to_group=True, is_active=True)
cls.user1 = UserManager.create_user(
"user1",
"user1@envipath.com",
"SuperSafe",
set_setting=True,
add_to_group=True,
is_active=True,
)
cls.user1_default_package = cls.user1.default_package
cls.package = PackageManager.create_package(cls.user1, 'Test', 'Test Pack')
cls.package = PackageManager.create_package(cls.user1, "Test", "Test Pack")
def setUp(self):
self.client.force_login(self.user1)
def test_predict_pathway(self):
response = self.client.post(reverse("pathways"), {
'name': 'Test Pathway',
'description': 'Just a Description',
'predict': 'predict',
'smiles': 'CCN(CC)C(=O)C1=CC(=CC=C1)CO',
})
response = self.client.post(
reverse("pathways"),
{
"name": "Test Pathway",
"description": "Just a Description",
"predict": "predict",
"smiles": "CCN(CC)C(=O)C1=CC(=CC=C1)CO",
},
)
self.assertEqual(response.status_code, 302)
pathway_url = response.url
pw = Pathway.objects.get(url=pathway_url)
self.assertEqual(self.user1_default_package, pw.package)
self.assertEqual(pw.name, 'Test Pathway')
self.assertEqual(pw.description, 'Just a Description')
self.assertEqual(pw.name, "Test Pathway")
self.assertEqual(pw.description, "Just a Description")
self.assertEqual(len(pw.root_nodes), 1)
self.assertEqual(pw.root_nodes.first().default_node_label.smiles, 'CCN(CC)C(=O)C1=CC(CO)=CC=C1')
self.assertEqual(
pw.root_nodes.first().default_node_label.smiles, "CCN(CC)C(=O)C1=CC(CO)=CC=C1"
)
first_level_nodes = {
# Edge 1
'CCN(CC)C(=O)C1=CC(C=O)=CC=C1',
"CCN(CC)C(=O)C1=CC(C=O)=CC=C1",
# Edge 2
'CCNC(=O)C1=CC(CO)=CC=C1',
'CC=O',
"CCNC(=O)C1=CC(CO)=CC=C1",
"CC=O",
# Edge 3
'CCNCC',
'O=C(O)C1=CC(CO)=CC=C1',
"CCNCC",
"O=C(O)C1=CC(CO)=CC=C1",
}
predicted_nodes = set()
@ -60,32 +72,36 @@ class PathwayViewTest(TestCase):
def test_predict_package_pathway(self):
response = self.client.post(
reverse("package pathway list", kwargs={'package_uuid': str(self.package.uuid)}), {
'name': 'Test Pathway',
'description': 'Just a Description',
'predict': 'predict',
'smiles': 'CCN(CC)C(=O)C1=CC(=CC=C1)CO',
})
reverse("package pathway list", kwargs={"package_uuid": str(self.package.uuid)}),
{
"name": "Test Pathway",
"description": "Just a Description",
"predict": "predict",
"smiles": "CCN(CC)C(=O)C1=CC(=CC=C1)CO",
},
)
self.assertEqual(response.status_code, 302)
pathway_url = response.url
pw = Pathway.objects.get(url=pathway_url)
self.assertEqual(self.package, pw.package)
self.assertEqual(pw.name, 'Test Pathway')
self.assertEqual(pw.description, 'Just a Description')
self.assertEqual(pw.name, "Test Pathway")
self.assertEqual(pw.description, "Just a Description")
self.assertEqual(len(pw.root_nodes), 1)
self.assertEqual(pw.root_nodes.first().default_node_label.smiles, 'CCN(CC)C(=O)C1=CC(CO)=CC=C1')
self.assertEqual(
pw.root_nodes.first().default_node_label.smiles, "CCN(CC)C(=O)C1=CC(CO)=CC=C1"
)
first_level_nodes = {
# Edge 1
'CCN(CC)C(=O)C1=CC(C=O)=CC=C1',
"CCN(CC)C(=O)C1=CC(C=O)=CC=C1",
# Edge 2
'CCNC(=O)C1=CC(CO)=CC=C1',
'CC=O',
"CCNC(=O)C1=CC(CO)=CC=C1",
"CC=O",
# Edge 3
'CCNCC',
'O=C(O)C1=CC(CO)=CC=C1',
"CCNCC",
"O=C(O)C1=CC(CO)=CC=C1",
}
predicted_nodes = set()

View File

@ -3,7 +3,7 @@ from django.urls import reverse
from envipy_additional_information import Temperature, Interval
from epdb.logic import UserManager, PackageManager
from epdb.models import Reaction, Scenario, ExternalIdentifier, ExternalDatabase
from epdb.models import Reaction, Scenario, ExternalDatabase
class ReactionViewTest(TestCase):
@ -12,21 +12,28 @@ class ReactionViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(ReactionViewTest, cls).setUpClass()
cls.user1 = UserManager.create_user("user1", "user1@envipath.com", "SuperSafe",
set_setting=False, add_to_group=True, is_active=True)
cls.user1 = UserManager.create_user(
"user1",
"user1@envipath.com",
"SuperSafe",
set_setting=False,
add_to_group=True,
is_active=True,
)
cls.user1_default_package = cls.user1.default_package
cls.package = PackageManager.create_package(cls.user1, 'Test', 'Test Pack')
cls.package = PackageManager.create_package(cls.user1, "Test", "Test Pack")
def setUp(self):
self.client.force_login(self.user1)
def test_create_reaction(self):
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -42,11 +49,12 @@ class ReactionViewTest(TestCase):
# Adding the same rule again should return the existing one, hence not increasing the number of rules
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.url, reaction_url)
@ -55,11 +63,12 @@ class ReactionViewTest(TestCase):
# Adding the same rule in a different package should create a new rule
response = self.client.post(
reverse("package reaction list", kwargs={'package_uuid': self.package.uuid}), {
reverse("package reaction list", kwargs={"package_uuid": self.package.uuid}),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -67,11 +76,12 @@ class ReactionViewTest(TestCase):
# adding another reaction should increase count
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0002",
"reaction-description": "Description for Eawag BBD reaction r0002",
"reaction-smirks": "C(CO)Cl>>C(C=O)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -80,11 +90,12 @@ class ReactionViewTest(TestCase):
# Edit
def test_edit_rule(self):
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -93,13 +104,17 @@ class ReactionViewTest(TestCase):
r = Reaction.objects.get(url=reaction_url)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(self.user1_default_package.uuid),
'reaction_uuid': str(r.uuid)
}), {
reverse(
"package reaction detail",
kwargs={
"package_uuid": str(self.user1_default_package.uuid),
"reaction_uuid": str(r.uuid),
},
),
{
"reaction-name": "Test Reaction Adjusted",
"reaction-description": "New Description",
}
},
)
self.assertEqual(response.status_code, 302)
@ -119,7 +134,7 @@ class ReactionViewTest(TestCase):
"Test Desc",
"2025-10",
"soil",
[Temperature(interval=Interval(start=20, end=30))]
[Temperature(interval=Interval(start=20, end=30))],
)
s2 = Scenario.create(
@ -128,15 +143,16 @@ class ReactionViewTest(TestCase):
"Test Desc2",
"2025-10",
"soil",
[Temperature(interval=Interval(start=10, end=20))]
[Temperature(interval=Interval(start=10, end=20))],
)
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -144,47 +160,47 @@ class ReactionViewTest(TestCase):
r = Reaction.objects.get(url=reaction_url)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(r.package.uuid),
'reaction_uuid': str(r.uuid)
}), {
"selected-scenarios": [s1.url, s2.url]
}
reverse(
"package reaction detail",
kwargs={"package_uuid": str(r.package.uuid), "reaction_uuid": str(r.uuid)},
),
{"selected-scenarios": [s1.url, s2.url]},
)
self.assertEqual(len(r.scenarios.all()), 2)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(r.package.uuid),
'reaction_uuid': str(r.uuid)
}), {
"selected-scenarios": [s1.url]
}
reverse(
"package reaction detail",
kwargs={"package_uuid": str(r.package.uuid), "reaction_uuid": str(r.uuid)},
),
{"selected-scenarios": [s1.url]},
)
self.assertEqual(len(r.scenarios.all()), 1)
self.assertEqual(r.scenarios.first().url, s1.url)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(r.package.uuid),
'reaction_uuid': str(r.uuid)
}), {
reverse(
"package reaction detail",
kwargs={"package_uuid": str(r.package.uuid), "reaction_uuid": str(r.uuid)},
),
{
# We have to set an empty string to avoid that the parameter is removed
"selected-scenarios": ""
}
},
)
self.assertEqual(len(r.scenarios.all()), 0)
def test_copy(self):
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -192,12 +208,13 @@ class ReactionViewTest(TestCase):
r = Reaction.objects.get(url=reaction_url)
response = self.client.post(
reverse("package detail", kwargs={
'package_uuid': str(self.package.uuid),
}), {
"hidden": "copy",
"object_to_copy": r.url
}
reverse(
"package detail",
kwargs={
"package_uuid": str(self.package.uuid),
},
),
{"hidden": "copy", "object_to_copy": r.url},
)
self.assertEqual(response.status_code, 200)
@ -211,44 +228,48 @@ class ReactionViewTest(TestCase):
# Copy to the same package should fail
response = self.client.post(
reverse("package detail", kwargs={
'package_uuid': str(r.package.uuid),
}), {
"hidden": "copy",
"object_to_copy": r.url
}
reverse(
"package detail",
kwargs={
"package_uuid": str(r.package.uuid),
},
),
{"hidden": "copy", "object_to_copy": r.url},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['error'], f"Can't copy object {reaction_url} to the same package!")
self.assertEqual(
response.json()["error"], f"Can't copy object {reaction_url} to the same package!"
)
def test_references(self):
ext_db, _ = ExternalDatabase.objects.get_or_create(
name='KEGG Reaction',
name="KEGG Reaction",
defaults={
'full_name': 'KEGG Reaction Database',
'description': 'Database of biochemical reactions',
'base_url': 'https://www.genome.jp',
'url_pattern': 'https://www.genome.jp/entry/{id}'
}
"full_name": "KEGG Reaction Database",
"description": "Database of biochemical reactions",
"base_url": "https://www.genome.jp",
"url_pattern": "https://www.genome.jp/entry/{id}",
},
)
ext_db2, _ = ExternalDatabase.objects.get_or_create(
name='RHEA',
name="RHEA",
defaults={
'full_name': 'RHEA Reaction Database',
'description': 'Comprehensive resource of biochemical reactions',
'base_url': 'https://www.rhea-db.org',
'url_pattern': 'https://www.rhea-db.org/rhea/{id}'
"full_name": "RHEA Reaction Database",
"description": "Comprehensive resource of biochemical reactions",
"base_url": "https://www.rhea-db.org",
"url_pattern": "https://www.rhea-db.org/rhea/{id}",
},
)
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -256,45 +277,49 @@ class ReactionViewTest(TestCase):
r = Reaction.objects.get(url=reaction_url)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(r.package.uuid),
'reaction_uuid': str(r.uuid),
}), {
'selected-database': ext_db.pk,
'identifier': 'C12345'
}
reverse(
"package reaction detail",
kwargs={
"package_uuid": str(r.package.uuid),
"reaction_uuid": str(r.uuid),
},
),
{"selected-database": ext_db.pk, "identifier": "C12345"},
)
self.assertEqual(r.external_identifiers.count(), 1)
self.assertEqual(r.external_identifiers.first().database, ext_db)
self.assertEqual(r.external_identifiers.first().identifier_value, 'C12345')
self.assertEqual(r.external_identifiers.first().identifier_value, "C12345")
# TODO Fixture contains old url template there the real test fails, use old value instead
# self.assertEqual(r.external_identifiers.first().url, 'https://www.genome.jp/entry/C12345')
self.assertEqual(r.external_identifiers.first().url, 'https://www.genome.jp/entry/reaction+C12345')
self.assertEqual(
r.external_identifiers.first().url, "https://www.genome.jp/entry/reaction+C12345"
)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(r.package.uuid),
'reaction_uuid': str(r.uuid),
}), {
'selected-database': ext_db2.pk,
'identifier': '60116'
}
reverse(
"package reaction detail",
kwargs={
"package_uuid": str(r.package.uuid),
"reaction_uuid": str(r.uuid),
},
),
{"selected-database": ext_db2.pk, "identifier": "60116"},
)
self.assertEqual(r.external_identifiers.count(), 2)
self.assertEqual(r.external_identifiers.last().database, ext_db2)
self.assertEqual(r.external_identifiers.last().identifier_value, '60116')
self.assertEqual(r.external_identifiers.last().url, 'https://www.rhea-db.org/rhea/60116')
self.assertEqual(r.external_identifiers.last().identifier_value, "60116")
self.assertEqual(r.external_identifiers.last().url, "https://www.rhea-db.org/rhea/60116")
def test_delete(self):
response = self.client.post(
reverse("reactions"), {
reverse("reactions"),
{
"reaction-name": "Eawag BBD reaction r0001",
"reaction-description": "Description for Eawag BBD reaction r0001",
"reaction-smirks": "C(CCl)Cl>>C(CO)Cl",
}
},
)
self.assertEqual(response.status_code, 302)
@ -302,12 +327,11 @@ class ReactionViewTest(TestCase):
r = Reaction.objects.get(url=reaction_url)
response = self.client.post(
reverse("package reaction detail", kwargs={
'package_uuid': str(r.package.uuid),
'reaction_uuid': str(r.uuid)
}), {
"hidden": "delete"
}
reverse(
"package reaction detail",
kwargs={"package_uuid": str(r.package.uuid), "reaction_uuid": str(r.uuid)},
),
{"hidden": "delete"},
)
self.assertEqual(self.user1_default_package.reactions.count(), 0)

View File

@ -12,22 +12,29 @@ class RuleViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(RuleViewTest, cls).setUpClass()
cls.user1 = UserManager.create_user("user1", "user1@envipath.com", "SuperSafe",
set_setting=False, add_to_group=True, is_active=True)
cls.user1 = UserManager.create_user(
"user1",
"user1@envipath.com",
"SuperSafe",
set_setting=False,
add_to_group=True,
is_active=True,
)
cls.user1_default_package = cls.user1.default_package
cls.package = PackageManager.create_package(cls.user1, 'Test', 'Test Pack')
cls.package = PackageManager.create_package(cls.user1, "Test", "Test Pack")
def setUp(self):
self.client.force_login(self.user1)
def test_create_rule(self):
response = self.client.post(
reverse("rules"), {
reverse("rules"),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.status_code, 302)
@ -38,18 +45,21 @@ class RuleViewTest(TestCase):
self.assertEqual(r.package, self.user1_default_package)
self.assertEqual(r.name, "Test Rule")
self.assertEqual(r.description, "Just a Description")
self.assertEqual(r.smirks,
"[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]")
self.assertEqual(
r.smirks,
"[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
)
self.assertEqual(self.user1_default_package.rules.count(), 1)
# Adding the same rule again should return the existing one, hence not increasing the number of rules
response = self.client.post(
reverse("rules"), {
reverse("rules"),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.url, rule_url)
@ -58,12 +68,13 @@ class RuleViewTest(TestCase):
# Adding the same rule in a different package should create a new rule
response = self.client.post(
reverse("package rule list", kwargs={'package_uuid': self.package.uuid}), {
reverse("package rule list", kwargs={"package_uuid": self.package.uuid}),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.status_code, 302)
@ -72,12 +83,13 @@ class RuleViewTest(TestCase):
# Edit
def test_edit_rule(self):
response = self.client.post(
reverse("rules"), {
reverse("rules"),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.status_code, 302)
@ -86,13 +98,17 @@ class RuleViewTest(TestCase):
r = Rule.objects.get(url=rule_url)
response = self.client.post(
reverse("package rule detail", kwargs={
'package_uuid': str(self.user1_default_package.uuid),
'rule_uuid': str(r.uuid)
}), {
reverse(
"package rule detail",
kwargs={
"package_uuid": str(self.user1_default_package.uuid),
"rule_uuid": str(r.uuid),
},
),
{
"rule-name": "Test Rule Adjusted",
"rule-description": "New Description",
}
},
)
self.assertEqual(response.status_code, 302)
@ -108,7 +124,7 @@ class RuleViewTest(TestCase):
"Test Desc",
"2025-10",
"soil",
[Temperature(interval=Interval(start=20, end=30))]
[Temperature(interval=Interval(start=20, end=30))],
)
s2 = Scenario.create(
@ -117,16 +133,17 @@ class RuleViewTest(TestCase):
"Test Desc2",
"2025-10",
"soil",
[Temperature(interval=Interval(start=10, end=20))]
[Temperature(interval=Interval(start=10, end=20))],
)
response = self.client.post(
reverse("rules"), {
reverse("rules"),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.status_code, 302)
@ -134,48 +151,48 @@ class RuleViewTest(TestCase):
r = Rule.objects.get(url=rule_url)
response = self.client.post(
reverse("package rule detail", kwargs={
'package_uuid': str(r.package.uuid),
'rule_uuid': str(r.uuid)
}), {
"selected-scenarios": [s1.url, s2.url]
}
reverse(
"package rule detail",
kwargs={"package_uuid": str(r.package.uuid), "rule_uuid": str(r.uuid)},
),
{"selected-scenarios": [s1.url, s2.url]},
)
self.assertEqual(len(r.scenarios.all()), 2)
response = self.client.post(
reverse("package rule detail", kwargs={
'package_uuid': str(r.package.uuid),
'rule_uuid': str(r.uuid)
}), {
"selected-scenarios": [s1.url]
}
reverse(
"package rule detail",
kwargs={"package_uuid": str(r.package.uuid), "rule_uuid": str(r.uuid)},
),
{"selected-scenarios": [s1.url]},
)
self.assertEqual(len(r.scenarios.all()), 1)
self.assertEqual(r.scenarios.first().url, s1.url)
response = self.client.post(
reverse("package rule detail", kwargs={
'package_uuid': str(r.package.uuid),
'rule_uuid': str(r.uuid)
}), {
reverse(
"package rule detail",
kwargs={"package_uuid": str(r.package.uuid), "rule_uuid": str(r.uuid)},
),
{
# We have to set an empty string to avoid that the parameter is removed
"selected-scenarios": ""
}
},
)
self.assertEqual(len(r.scenarios.all()), 0)
def test_copy(self):
response = self.client.post(
reverse("rules"), {
reverse("rules"),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.status_code, 302)
@ -183,12 +200,13 @@ class RuleViewTest(TestCase):
r = Rule.objects.get(url=rule_url)
response = self.client.post(
reverse("package detail", kwargs={
'package_uuid': str(self.package.uuid),
}), {
"hidden": "copy",
"object_to_copy": r.url
}
reverse(
"package detail",
kwargs={
"package_uuid": str(self.package.uuid),
},
),
{"hidden": "copy", "object_to_copy": r.url},
)
self.assertEqual(response.status_code, 200)
@ -202,26 +220,29 @@ class RuleViewTest(TestCase):
# Copy to the same package should fail
response = self.client.post(
reverse("package detail", kwargs={
'package_uuid': str(r.package.uuid),
}), {
"hidden": "copy",
"object_to_copy": r.url
}
reverse(
"package detail",
kwargs={
"package_uuid": str(r.package.uuid),
},
),
{"hidden": "copy", "object_to_copy": r.url},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()['error'], f"Can't copy object {rule_url} to the same package!")
self.assertEqual(
response.json()["error"], f"Can't copy object {rule_url} to the same package!"
)
def test_delete(self):
response = self.client.post(
reverse("rules"), {
reverse("rules"),
{
"rule-name": "Test Rule",
"rule-description": "Just a Description",
"rule-smirks": "[H:5][C:1]([#6:6])([#1,#9,#17,#35,#53:4])[#9,#17,#35,#53]>>[H:5][C:1]([#6:6])([#8])[#1,#9,#17,#35,#53:4]",
"rule-type": "SimpleAmbitRule",
}
},
)
self.assertEqual(response.status_code, 302)
@ -229,12 +250,11 @@ class RuleViewTest(TestCase):
r = Rule.objects.get(url=rule_url)
response = self.client.post(
reverse("package rule detail", kwargs={
'package_uuid': str(r.package.uuid),
'rule_uuid': str(r.uuid)
}), {
"hidden": "delete"
}
reverse(
"package rule detail",
kwargs={"package_uuid": str(r.package.uuid), "rule_uuid": str(r.uuid)},
),
{"hidden": "delete"},
)
self.assertEqual(self.user1_default_package.rules.count(), 0)

View File

@ -11,70 +11,81 @@ class UserViewTest(TestCase):
@classmethod
def setUpClass(cls):
super(UserViewTest, cls).setUpClass()
cls.user = User.objects.get(username='anonymous')
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
cls.BBD_SUBSET = Package.objects.get(name='Fixtures')
cls.user = User.objects.get(username="anonymous")
cls.package = PackageManager.create_package(cls.user, "Anon Test Package", "No Desc")
cls.BBD_SUBSET = Package.objects.get(name="Fixtures")
def test_login_with_valid_credentials(self):
response = self.client.post(reverse("login"), {
"username": "user0",
"password": 'SuperSafe',
})
response = self.client.post(
reverse("login"),
{
"username": "user0",
"password": "SuperSafe",
},
)
self.assertRedirects(response, reverse("index"))
self.assertTrue(response.wsgi_request.user.is_authenticated)
def test_login_with_invalid_credentials(self):
response = self.client.post(reverse("login"), {
"username": "user0",
"password": "wrongpassword",
})
response = self.client.post(
reverse("login"),
{
"username": "user0",
"password": "wrongpassword",
},
)
self.assertEqual(response.status_code, 200)
self.assertFalse(response.wsgi_request.user.is_authenticated)
def test_register(self):
response = self.client.post(reverse("register"), {
"username": "user1",
"email": "user1@envipath.com",
"password": "SuperSafe",
"rpassword": "SuperSafe",
})
response = self.client.post(
reverse("register"),
{
"username": "user1",
"email": "user1@envipath.com",
"password": "SuperSafe",
"rpassword": "SuperSafe",
},
)
self.assertEqual(response.status_code, 200)
# TODO currently fails as the fixture does not provide a global setting...
self.assertContains(response, "Registration failed!")
def test_register_password_mismatch(self):
response = self.client.post(reverse("register"), {
"username": "user1",
"email": "user1@envipath.com",
"password": "SuperSafe",
"rpassword": "SuperSaf3",
})
response = self.client.post(
reverse("register"),
{
"username": "user1",
"email": "user1@envipath.com",
"password": "SuperSafe",
"rpassword": "SuperSaf3",
},
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Registration failed, provided passwords differ")
def test_logout(self):
response = self.client.post(reverse("login"), {
"username": "user0",
"password": 'SuperSafe',
"login": "true"
})
response = self.client.post(
reverse("login"), {"username": "user0", "password": "SuperSafe", "login": "true"}
)
self.assertTrue(response.wsgi_request.user.is_authenticated)
response = self.client.post(reverse('logout'), {
"logout": "true",
})
response = self.client.post(
reverse("logout"),
{
"logout": "true",
},
)
self.assertFalse(response.wsgi_request.user.is_authenticated)
def test_next_param_properly_handled(self):
response = self.client.get(reverse('packages'))
response = self.client.get(reverse("packages"))
self.assertRedirects(response, f"{reverse('login')}/?next=/package")
response = self.client.post(reverse('login'), {
"username": "user0",
"password": 'SuperSafe',
"login": "true",
"next": "/package"
})
response = self.client.post(
reverse("login"),
{"username": "user0", "password": "SuperSafe", "login": "true", "next": "/package"},
)
self.assertRedirects(response, reverse('packages'))
self.assertRedirects(response, reverse("packages"))