Experimental App Domain (#43)

Backend App Domain done, Frontend missing

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#43
This commit is contained in:
2025-08-08 20:52:21 +12:00
parent 280ddc7205
commit 579cd519d0
14 changed files with 1094 additions and 574 deletions

52
tests/test_dataset.py Normal file
View File

@ -0,0 +1,52 @@
from django.test import TestCase
from epdb.logic import PackageManager
from epdb.models import Reaction, Compound, User, Rule
from utilities.ml import Dataset
class DatasetTest(TestCase):
fixtures = ["test_fixture.cleaned.json"]
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',
).default_structure
self.cs2 = Compound.create(
self.package,
smiles='O=C(O)CC(=O)/C=C(/Br)C(=O)O',
).default_structure
self.rule1 = Rule.create(
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'
)
self.reaction1 = Reaction.create(
package=self.package,
educts=[self.cs1],
products=[self.cs2],
rules=[self.rule1],
multi_step=False
)
@classmethod
def setUpClass(cls):
super(DatasetGeneratorTest, cls).setUpClass()
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)]
applicable_rules = [self.rule1]
ds = Dataset.generate_dataset(reactions, applicable_rules)
self.assertEqual(len(ds.y()), 1)
self.assertEqual(sum(ds.y()[0]), 1)

View File

@ -1,111 +0,0 @@
from django.test import TestCase
from epdb.models import ParallelRule
from utilities.ml import Compound, Reaction, DatasetGenerator
class CompoundTest(TestCase):
def setUp(self):
self.c1 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C", uuid='c1')
self.c2 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C", uuid='c2')
def test_compound_eq_ignores_uuid(self):
self.assertEqual(self.c1, self.c2)
class ReactionTest(TestCase):
def setUp(self):
self.c1 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C")
self.c2 = Compound(smiles="CCN(CCO)C(=O)C1=CC(C)=CC=C1")
# self.r1 = Rule(uuid="bt0334")
# c1 --r1--> c2
self.c3_1 = Compound(smiles="CCNC(=O)C1=CC(C)=CC=C1")
self.c3_2 = Compound(smiles="CC=O")
# self.r2 = Rule(uuid="bt0243")
# c1 --r2--> c3_1, c3_2
def test_reaction_equality_ignores_uuid(self):
r1 = Reaction([self.c1], [self.c2], self.r1, uuid="abc")
r2 = Reaction([self.c1], [self.c2], self.r1, uuid="xyz")
self.assertEqual(r1, r2)
def test_reaction_inequality_on_data_change(self):
r1 = Reaction([self.c1], [self.c2], self.r1)
r2 = Reaction([self.c1], [self.c3_1], self.r1)
self.assertNotEqual(r1, r2)
def test_reaction_is_hashable(self):
r = Reaction([self.c1], [self.c2], self.r1)
reactions = {r}
self.assertIn(Reaction([self.c1], [self.c2], self.r1), reactions)
def test_rule_is_optional(self):
r = Reaction([self.c1], [self.c2])
self.assertIsNone(r.rule)
def test_uuid_is_optional(self):
r = Reaction([self.c1], [self.c2], self.r1)
self.assertIsNone(r.uuid)
def test_repr_includes_uuid(self):
r = Reaction([self.c1], [self.c2], self.r1, uuid="abc")
self.assertIn("abc", repr(r))
def test_reaction_equality_with_multiple_compounds_different_ordering(self):
r1 = Reaction([self.c1], [self.c3_1, self.c3_2], self.r2)
r2 = Reaction([self.c1], [self.c3_2, self.c3_1], self.r2)
self.assertEqual(r1, r2, "Reaction equality should not rely on list order")
class RuleTest(TestCase):
def setUp(self):
pass
# self.r1 = Rule(uuid="bt0334")
# self.r2 = Rule(uuid="bt0243")
class DatasetGeneratorTest(TestCase):
fixtures = ['bootstrap.json']
def setUp(self):
self.c1 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C")
self.c2 = Compound(smiles="CCN(CCO)C(=O)C1=CC(C)=CC=C1")
self.c3_1 = Compound(smiles="CCNC(=O)C1=CC(C)=CC=C1")
self.c3_2 = Compound(smiles="CC=O")
# self.r1 = Rule(uuid="bt0334") # trig
# self.r2 = Rule(uuid="bt0243") # trig
# self.r3 = Rule(uuid="bt0003") # no trig
self.reaction1 = Reaction([self.c1], [self.c2], self.r3)
self.reaction2 = Reaction([self.c1], [self.c3_1, self.c3_2], self.r2)
def test_test(self):
compounds = [
self.c1,
self.c2,
self.c3_1,
self.c3_2,
]
reactions = [
self.reaction1,
self.reaction2,
]
applicable_rules = [
# Rule('bt0334', ParallelRule.objects.get(name='bt0334')),
# Rule('bt0243', ParallelRule.objects.get(name='bt0243')),
# Rule('bt0003', ParallelRule.objects.get(name='bt0003')),
]
ds = DatasetGenerator.generate_dataset(compounds, reactions, applicable_rules)
self.assertIsNotNone(ds)

55
tests/test_model.py Normal file
View File

@ -0,0 +1,55 @@
import json
from django.test import TestCase
from epdb.logic import PackageManager
from epdb.models import Compound, User, CompoundStructure, Reaction, Rule, MLRelativeReasoning
class ModelTest(TestCase):
fixtures = ["test_fixture.cleaned.json"]
def setUp(self):
pass
@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')
bbd_data = json.load(open('fixtures/packages/2025-07-18/EAWAG-BBD.json'))
cls.BBD = PackageManager.import_package(bbd_data, cls.user)
@classmethod
def tearDownClass(cls):
pass
def tearDown(self):
pass
def test_smoke(self):
threshold = float(0.5)
# get Package objects from urls
rule_package_objs = [self.BBD]
data_package_objs = [self.BBD]
eval_packages_objs = []
mod = MLRelativeReasoning.create(
self.package,
'ECC - BBD - 0.5',
'Created MLRelativeReasoning in Testcase',
rule_package_objs,
data_package_objs,
eval_packages_objs,
threshold
)
ds = mod.load_dataset()
mod.build_model()
print("Model built!")
mod.evaluate_model()
print("Model Evaluated")
results = mod.predict('CCN(CC)C(=O)C1=CC(=CC=C1)C')
print(results)