Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

0
epdb/__init__.py Normal file
View File

36
epdb/admin.py Normal file
View File

@ -0,0 +1,36 @@
from django.contrib import admin
from .models import User, Group, UserPackagePermission, GroupPackagePermission, Setting, SimpleAmbitRule
class UserAdmin(admin.ModelAdmin):
pass
class GroupAdmin(admin.ModelAdmin):
pass
class UserPackagePermissionAdmin(admin.ModelAdmin):
pass
class GroupPackagePermissionAdmin(admin.ModelAdmin):
pass
class SettingAdmin(admin.ModelAdmin):
pass
admin.site.register(User, UserAdmin)
admin.site.register(Group, GroupAdmin)
admin.site.register(UserPackagePermission, UserPackagePermissionAdmin)
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
admin.site.register(Setting, SettingAdmin)
class SimpleAmbitRuleAdmin(admin.ModelAdmin):
pass
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)

108
epdb/api.py Normal file
View File

@ -0,0 +1,108 @@
from typing import List
from django.contrib.auth import get_user_model
from ninja import Router, Schema, Field
from ninja.errors import HttpError
from ninja.pagination import paginate
from ninja.security import HttpBearer
from .logic import PackageManager
from .models import User, Compound, APIToken
class BearerTokenAuth(HttpBearer):
def authenticate(self, request, token):
for token_obj in APIToken.objects.select_related("user").all():
if token_obj.check_token(token) and token_obj.is_valid():
return token_obj.user
raise HttpError(401, "Invalid or expired token")
def _anonymous_or_real(request):
if request.user.is_authenticated and not request.user.is_anonymous:
return request.user
return get_user_model().objects.get(username='anonymous')
router = Router(auth=BearerTokenAuth())
class UserSchema(Schema):
email: str
username: str
id: str = Field(None, alias="url")
class PackageIn(Schema):
name: str
description: str
class PackageOut(Schema):
id: str = Field(None, alias="url")
name: str
reviewed: bool
compound_links: str = None
@staticmethod
def resolve_compound_links(obj):
return f"{obj.url}/compound"
class Error(Schema):
message: str
class CompoundSchema(Schema):
name: str = Field(None, alias="name")
id: str = Field(None, alias="url")
smiles: str = Field(None, alias="default_structure.smiles")
reviewed: bool = Field(None, alias="package.reviewed")
@router.get("/user", response={200: List[UserSchema], 403: Error})
def get_users(request):
return User.objects.all()
@router.get("/package", response={200: List[PackageOut], 403: Error})
def get_packages(request):
return PackageManager.get_all_readable_packages(request.user, include_reviewed=True)
@router.post("/package", response=PackageOut)
def create_package(request, package: PackageIn):
user = request.auth
name = package.name.strip()
description = package.description.strip()
p = PackageManager.create_package(user, name, description=description)
return p
@router.get("/package/{uuid:package_uuid}", response={200: PackageOut, 403: Error})
def get_package(request, package_uuid):
try:
return PackageManager.get_package_by_id(request.auth, package_id=package_uuid)
except ValueError:
return 403, {'message': f'Getting Package with id {package_uuid} failed due to insufficient rights!'}
@router.get("/compound", response={200: List[CompoundSchema], 403: Error})
@paginate
def get_compounds(request):
qs = Compound.objects.none()
for p in PackageManager.get_reviewed_packages():
qs |= Compound.objects.filter(package=p)
return qs
@router.get("/package/{uuid:package_uuid}/compound", response={200: List[CompoundSchema], 403: Error})
@paginate
def get_package_compounds(request, package_uuid):
try:
p = PackageManager.get_package_by_id(request.auth, package_uuid)
return Compound.objects.filter(package=p)
except ValueError:
return 403, {
'message': f'Getting Compounds for Package with id {package_uuid} failed due to insufficient rights!'}

6
epdb/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class EPDBConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'epdb'

5
epdb/forms.py Normal file
View File

@ -0,0 +1,5 @@
from django import forms
class EmailLoginForm(forms.Form):
email = forms.EmailField()

492
epdb/logic.py Normal file
View File

@ -0,0 +1,492 @@
import re
import logging
from typing import Union, List, Optional, Set, Dict
from django.contrib.auth import get_user_model
from django.db import transaction
from epdb.models import User, Package, UserPackagePermission, GroupPackagePermission, Permission, Group, Setting, \
EPModel, UserSettingPermission, Rule, Pathway, Node, Edge
logger = logging.getLogger(__name__)
class UserManager(object):
@staticmethod
def create_user(username, email, password):
# avoid circular import :S
from .tasks import send_registration_mail
# TODO flip to False
u = get_user_model().objects.create_user(username, email, password, is_active=True)
# Create package
package_name = f"{u.username}{'' if u.username[-1] in 'sxzß' else 's'} Package"
package_description = f"This package was generated during registration."
p = PackageManager.create_package(u, package_name, package_description)
u.default_package = p
u.save()
if not u.is_active:
# send email for verification
send_registration_mail.delay(u.pk)
return u
@staticmethod
def get_user(user_url):
pass
@staticmethod
def get_users():
return []
class GroupManager(object):
@staticmethod
def create_group(owner):
g = Group()
g.name = 'enviPath Users'
g.description = 'All enviPath Users'
g.owner = owner
g.save()
return g
@staticmethod
def get_group_by_url(user, group_url):
return GroupManager.get_group_by_id(user, group_url.split('/')[-1])
@staticmethod
def get_group_by_id(user, group_id):
g = Group.objects.get(uuid=group_id)
if user in g.user_member.all():
return g
return None
@staticmethod
def get_groups(user):
return Group.objects.filter(user_member=user)
class PackageManager(object):
package_pattern = re.compile(r".*/package/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
@staticmethod
def get_reviewed_packages():
return Package.objects.filter(reviewed=True)
@staticmethod
def readable(user, package):
# TODO Owner!
if UserPackagePermission.objects.filter(package=package, user=user).exists() or \
GroupPackagePermission.objects.filter(package=package, group__in=user.groups.all()) or \
package.reviewed is True or \
user.is_superuser:
return True
return False
@staticmethod
def writable(user, package):
# TODO Owner!
if UserPackagePermission.objects.filter(package=package, user=user, permission=Permission.WRITE).exists() or \
GroupPackagePermission.objects.filter(package=package, group__in=user.groups.all(),
permission=Permission.WRITE) or \
user.is_superuser:
return True
return False
@staticmethod
def get_package_by_url(user, package_url):
match = re.findall(PackageManager.package_pattern, package_url)
if match:
package_id = match[0].split('/')[-1]
return PackageManager.get_package_by_id(user, package_id)
else:
raise ValueError("Requested URL {} does not contain a valid package identifier!".format(package_url))
@staticmethod
def get_package_by_id(user, package_id):
try:
p = Package.objects.get(uuid=package_id)
if PackageManager.readable(user, p):
return p
else:
raise ValueError(
"Insufficient permissions to access Package with ID {}".format(package_id))
except Package.DoesNotExist:
raise ValueError("Package with ID {} does not exist!".format(package_id))
@staticmethod
def get_all_readable_packages(user, include_reviewed=False):
# UserPermission only exists if at least read is granted...
if user.is_superuser:
qs = Package.objects.all()
else:
up = UserPackagePermission.objects.filter(user=user).values('package').distinct()
qs = Package.objects.filter(id__in=up)
if include_reviewed:
qs |= Package.objects.filter(reviewed=True)
else:
# remove package if user is owner and package is reviewed e.g. admin
qs = qs.filter(reviewed=False)
return qs.distinct()
@staticmethod
def get_all_writeable_packages(user):
# UserPermission only exists if at least read is granted...
if user.is_superuser:
qs = Package.objects.all()
else:
up = UserPackagePermission.objects.filter(user=user, permission=Permission.WRITE).values(
'package').distinct()
qs = Package.objects.filter(id__in=up)
qs = qs.filter(reviewed=False)
return qs.distinct()
@staticmethod
def get_packages():
return Package.objects.all()
@staticmethod
@transaction.atomic
def create_package(current_user, name: str, description: str = None):
p = Package()
p.name = name
p.description = description
p.save()
up = UserPackagePermission()
up.user = current_user
up.package = p
up.permission = UserPackagePermission.ALL[0]
up.save()
return p
class SettingManager(object):
setting_pattern = re.compile(r".*/setting/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
@staticmethod
def get_setting_by_url(user, setting_url):
match = re.findall(SettingManager.setting_pattern, setting_url)
if match:
setting_id = match[0].split('/')[-1]
return SettingManager.get_setting_by_id(user, setting_id)
else:
raise ValueError("Requested URL {} does not contain a valid setting identifier!".format(setting_url))
@staticmethod
def get_setting_by_id(user, setting_id):
s = Setting.objects.get(uuid=setting_id)
if s.global_default or s.public or s.owner == user or user.is_superuser:
return s
raise ValueError(
"Insufficient permissions to access Setting with ID {}".format(setting_id))
@staticmethod
def get_all_settings(user):
sp = UserSettingPermission.objects.filter(user=user).values('setting').distinct()
return Setting.objects.filter(id__in=sp)
@staticmethod
@transaction.atomic
def create_setting(user: User, name: str = None, description: str = None, max_nodes: int = None,
max_depth: int = None, rule_packages: List[Package] = None, model: EPModel = None,
model_threshold: float = None):
s = Setting()
s.name = name
s.description = description
s.max_nodes = max_nodes
s.max_depth = max_depth
s.model = model
s.model_threshold = model_threshold
s.save()
if rule_packages is not None:
for r in rule_packages:
s.rule_packages.add(r)
s.save()
usp = UserSettingPermission()
usp.user = user
usp.setting = s
usp.permission = Permission.ALL[0]
usp.save()
return s
@staticmethod
def get_default_setting(user: User):
pass
@staticmethod
@transaction.atomic
def set_default_setting(user: User, setting: Setting):
pass
class SNode(object):
def __init__(self, smiles: str, depth: int):
self.smiles = smiles
self.depth = depth
def __hash__(self):
return hash(self.smiles)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.smiles == other.smiles
return False
def __repr__(self):
return f"SNode('{self.smiles}', {self.depth})"
class SEdge(object):
def __init__(self, educts: Union[SNode, List[SNode]], products: Union[SNode | List[SNode]],
rule: Optional['Rule'] = None):
if not isinstance(educts, list):
educts = [educts]
self.educts = educts
self.products = products
self.rule = rule
def __hash__(self):
full_hash = 0
for n in sorted(self.educts, key=lambda x: x.smiles):
full_hash += hash(n)
for n in sorted(self.products, key=lambda x: x.smiles):
full_hash += hash(n)
if self.rule is not None:
full_hash += hash(self.rule)
return full_hash
def __eq__(self, other):
if not isinstance(other, SEdge):
return False
if self.rule is not None and other.rule is None or \
self.rule is None and other.rule is not None or \
self.rule != other.rule:
return False
if not (len(self.educts) == len(other.educts)):
return False
for n1, n2 in zip(sorted(self.educts, key=lambda x: x.smiles), sorted(other.educts, key=lambda x: x.smiles)):
if n1.smiles != n2.smiles:
return False
if not (len(self.products) == len(other.products)):
return False
for n1, n2 in zip(sorted(self.products, key=lambda x: x.smiles),
sorted(other.products, key=lambda x: x.smiles)):
if n1.smiles != n2.smiles:
return False
return True
def __repr__(self):
return f"SEdge({self.educts}, {self.products}, {self.rule})"
class SPathway(object):
def __init__(self, root_nodes: Optional[Union[str, SNode, List[str | SNode]]] = None,
persist: Optional['Pathway'] = None, prediction_setting: Optional[Setting] = None
):
self.root_nodes = []
self.persist = persist
self.snode_persist_lookup: Dict[SNode, Node] = dict()
self.sedge_persist_lookup: Dict[SEdge, Edge] = dict()
self.prediction_setting = prediction_setting
if persist:
for n in persist.root_nodes:
snode = SNode(n.default_node_label.smiles, n.depth)
self.root_nodes.append(snode)
self.snode_persist_lookup[snode] = n
else:
if not isinstance(root_nodes, list):
root_nodes = [root_nodes]
for n in root_nodes:
if isinstance(n, str):
self.root_nodes.append(SNode(n, 0))
elif isinstance(n, SNode):
self.root_nodes.append(n)
self.queue = list()
self.smiles_to_node: Dict[str, SNode] = dict(**{n.smiles: n for n in self.root_nodes})
self.edges: Set['SEdge'] = set()
self.done = False
def num_nodes(self):
return len(self.smiles_to_node.keys())
def depth(self):
return max([v.depth for v in self.smiles_to_node.values()])
def _get_nodes_for_depth(self, depth: int):
if depth == 0:
return self.root_nodes
res = []
for n in self.smiles_to_node.values():
if n.depth == depth:
res.append(n)
return sorted(res, key=lambda x: x.smiles)
def _get_edges_for_depth(self, depth: int):
res = []
for e in self.edges:
for n in e.educts:
if n.depth == depth:
res.append(e)
return sorted(res, key=lambda x: hash(x))
def predict_step(self, from_depth: int = 0):
substrates = self._get_nodes_for_depth(from_depth)
new_tp = False
if substrates:
for sub in substrates:
candidates = self.prediction_setting.expand(self, sub)
for cand_set in candidates:
if cand_set:
new_tp = True
for cand in cand_set:
cand_nodes = []
for c in cand:
if c not in self.smiles_to_node:
self.smiles_to_node[c] = SNode(c, sub.depth + 1)
node = self.smiles_to_node[c]
cand_nodes.append(node)
edge = SEdge(sub, cand_nodes, cand_set.rule)
self.edges.add(edge)
else:
self.done = True
if new_tp and self.persist:
self._sync_to_pathway()
def _sync_to_pathway(self):
logger.info("Updating Pathway with SPathway")
for snode in self.smiles_to_node.values():
if snode not in self.snode_persist_lookup:
n = Node.create(self.persist, snode.smiles, snode.depth)
self.snode_persist_lookup[snode] = n
for sedge in self.edges:
if sedge not in self.sedge_persist_lookup:
educt_nodes = []
for snode in sedge.educts:
educt_nodes.append(self.snode_persist_lookup[snode])
product_nodes = []
for snode in sedge.products:
product_nodes.append(self.snode_persist_lookup[snode])
e = Edge.create(self.persist, educt_nodes, product_nodes, sedge.rule)
self.sedge_persist_lookup[sedge] = e
logger.info("Update done!")
pass
def to_json(self):
nodes = []
edges = []
idx_lookup = {}
for i, s in enumerate(self.smiles_to_node):
n = self.smiles_to_node[s]
idx_lookup[s] = i
nodes.append({'depth': n.depth, 'smiles': n.smiles, 'id': i})
for edge in self.edges:
from_idx = idx_lookup[edge.educts[0].smiles]
to_indices = [idx_lookup[p.smiles] for p in edge.products]
e = {
'from': from_idx,
'to': to_indices,
}
# if edge.rule:
# e['rule'] = {
# 'name': edge.rule.name,
# 'id': edge.rule.url,
# }
edges.append(e)
return {
'nodes': nodes,
'edges': edges,
}
def graph_to_tree_string(self):
graph_json = self.to_json()
nodes = {node['id']: node for node in graph_json['nodes']}
edges = graph_json['edges']
children_map = {}
for edge in edges:
src = edge['from']
for tgt in edge['to']:
children_map.setdefault(src, []).append(tgt)
visited = set()
def recurse(node_id, prefix=''):
if node_id in visited:
return prefix + nodes[node_id]['smiles'] + " [loop detected]\n"
visited.add(node_id)
line = prefix + nodes[node_id]['smiles'] + f" [{node_id}]\n"
kids = children_map.get(node_id, [])
for i, kid in enumerate(kids):
if i == len(kids) - 1:
branch = '└── '
child_prefix = prefix + ' '
else:
branch = '├── '
child_prefix = prefix + ''
line += recurse(kid, prefix=prefix + branch)
return line
root_nodes = [n['id'] for n in graph_json['nodes'] if n['depth'] == 0]
result = ''
for root in root_nodes:
visited.clear()
result += recurse(root)
return result

View File

View File

View File

@ -0,0 +1,402 @@
import json
from collections import defaultdict
from datetime import datetime
from uuid import UUID
from django.core.management.base import BaseCommand
from django.conf import settings as s
from epdb.models import *
from epdb.logic import UserManager, GroupManager, PackageManager, SettingManager
class Command(BaseCommand):
def create_users(self):
if not User.objects.filter(email='anon@lorsba.ch').exists():
anon = UserManager.create_user("anonymous", "anon@lorsba.ch", "SuperSafe")
else:
anon = User.objects.get(email='anon@lorsba.ch')
if not User.objects.filter(email='admin@lorsba.ch').exists():
admin = UserManager.create_user("admin", "admin@lorsba.ch", "SuperSafe",)
admin.is_staff = True
admin.is_superuser = True
admin.save()
else:
admin = User.objects.get(email='admin@lorsba.ch')
g = GroupManager.create_group(admin)
g.user_member.add(anon)
g.save()
anon.default_group = g
anon.save()
admin.default_group = g
admin.save()
if not User.objects.filter(email='jebus@lorsba.ch').exists():
jebus = UserManager.create_user("jebus", "jebus@lorsba.ch", "SuperSafe",)
jebus.is_staff = True
jebus.is_superuser = True
jebus.save()
else:
jebus = User.objects.get(email='jebus@lorsba.ch')
g.user_member.add(jebus)
g.save()
jebus.default_group = g
jebus.save()
return anon, admin, g, jebus
def import_package(self, data, owner):
# Start import
pack = Package()
pack.uuid = UUID(data['id'].split('/')[-1])
pack.name = '{} - {}'.format(data['name'], datetime.now().strftime('%Y-%m-%d %H:%M'))
pack.reviewed = True if data['reviewStatus'] == 'reviewed' else False
pack.description = data['description']
pack.save()
up = UserPackagePermission()
up.user = owner
up.package = pack
up.permission = up.ALL
up.save()
# Stores old_id to new_id
mapping = {}
# Store compounds and its structures
for compound in data['compounds']:
comp = Compound()
comp.package = pack
comp.uuid = UUID(compound['id'].split('/')[-1])
comp.name = compound['name']
comp.description = compound['description']
comp.aliases = compound['aliases']
comp.save()
mapping[compound['id']] = comp.uuid
default_structure = None
for structure in compound['structures']:
struc = CompoundStructure()
# struc.object_url = Command.get_id(structure, keep_ids)
struc.compound = comp
struc.uuid = UUID(structure['id'].split('/')[-1])
struc.name = structure['name']
struc.description = structure['description']
struc.smiles = structure['smiles']
struc.save()
mapping[structure['id']] = struc.uuid
if structure['id'] == compound['defaultStructure']['id']:
default_structure = struc
struc.save()
if default_structure is None:
raise ValueError('No default structure set')
comp.default_structure = default_structure
comp.save()
print('Compounds imported...')
# Store simple and parallel-rules
par_rules = []
seq_rules = []
for rule in data['rules']:
if rule['identifier'] == 'parallel-rule':
par_rules.append(rule)
continue
if rule['identifier'] == 'sequential-rule':
seq_rules.append(rule)
continue
r = SimpleAmbitRule()
r.uuid = UUID(rule['id'].split('/')[-1])
r.package = pack
r.name = rule['name']
r.description = rule['description']
r.smirks = rule['smirks']
r.reactant_filter_smarts = rule.get('reactantFilterSmarts', None)
r.product_filter_smarts = rule.get('productFilterSmarts', None)
r.save()
mapping[rule['id']] = r.uuid
print("Par: ", len(par_rules))
print("Seq: ", len(seq_rules))
for par_rule in par_rules:
r = ParallelRule()
r.package = pack
r.uuid = UUID(par_rule['id'].split('/')[-1])
r.name = par_rule['name']
r.description = par_rule['description']
r.save()
mapping[par_rule['id']] = r.uuid
for simple_rule in par_rule['simpleRules']:
if simple_rule['id'] in mapping:
r.simple_rules.add(SimpleRule.objects.get(uuid=mapping[simple_rule['id']]))
r.save()
for seq_rule in seq_rules:
r = SequentialRule()
r.package = pack
r.uuid = UUID(seq_rule['id'].split('/')[-1])
r.name = seq_rule['name']
r.description = seq_rule['description']
r.save()
mapping[seq_rule['id']] = r.uuid
# m1 = Membership(
# ... person=ringo,
# ... group=beatles,
# ... date_joined=date(1962, 8, 16),
# ... invite_reason="Needed a new drummer.",
# ... )
# >>> m1.save()
for i, simple_rule in enumerate(seq_rule['simpleRules']):
sro = SequentialRuleOrdering()
sro.simple_rule = simple_rule
sro.sequential_rule = r
sro.order_index = i
sro.save()
# r.simple_rules.add(SimpleRule.objects.get(uuid=mapping[simple_rule['id']]))
r.save()
print('Rules imported...')
for reaction in data['reactions']:
r = Reaction()
r.package = pack
r.uuid = UUID(reaction['id'].split('/')[-1])
r.name = reaction['name']
r.description = reaction['description']
r.medlinereferences = reaction['medlinereferences'],
r.multi_step = True if reaction['multistep'] == 'true' else False
r.save()
mapping[reaction['id']] = r.uuid
for educt in reaction['educts']:
r.educts.add(CompoundStructure.objects.get(uuid=mapping[educt['id']]))
for product in reaction['products']:
r.products.add(CompoundStructure.objects.get(uuid=mapping[product['id']]))
if 'rules' in reaction:
for rule in reaction['rules']:
try:
r.rules.add(Rule.objects.get(uuid=mapping[rule['id']]))
except Exception as e:
print(f"Rule with id {rule['id']} not found!")
print(e)
r.save()
print('Reactions imported...')
for pathway in data['pathways']:
pw = Pathway()
pw.package = pack
pw.uuid = UUID(pathway['id'].split('/')[-1])
pw.name = pathway['name']
pw.description = pathway['description']
pw.save()
mapping[pathway['id']] = pw.uuid
out_nodes_mapping = defaultdict(set)
root_node = None
for node in pathway['nodes']:
n = Node()
n.uuid = UUID(node['id'].split('/')[-1])
n.name = node['name']
n.pathway = pw
n.depth = node['depth']
n.default_node_label = CompoundStructure.objects.get(uuid=mapping[node['defaultNodeLabel']['id']])
n.save()
mapping[node['id']] = n.uuid
for node_label in node['nodeLabels']:
n.node_labels.add(CompoundStructure.objects.get(uuid=mapping[node_label['id']]))
n.save()
for out_edge in node['outEdges']:
out_nodes_mapping[n.uuid].add(out_edge)
for edge in pathway['edges']:
e = Edge()
e.uuid = UUID(edge['id'].split('/')[-1])
e.name = edge['name']
e.pathway = pw
e.description = edge['description']
e.edge_label = Reaction.objects.get(uuid=mapping[edge['edgeLabel']['id']])
e.save()
mapping[edge['id']] = e.uuid
for start_node in edge['startNodes']:
e.start_nodes.add(Node.objects.get(uuid=mapping[start_node]))
for end_node in edge['endNodes']:
e.end_nodes.add(Node.objects.get(uuid=mapping[end_node]))
e.save()
for k, v in out_nodes_mapping.items():
n = Node.objects.get(uuid=k)
for v1 in v:
n.out_edges.add(Edge.objects.get(uuid=mapping[v1]))
n.save()
print('Pathways imported...')
print('Import statistics:')
print('Package {} stored'.format(pack.url))
print('Imported {} compounds'.format(Compound.objects.filter(package=pack).count()))
print('Imported {} rules'.format(Rule.objects.filter(package=pack).count()))
print('Imported {} reactions'.format(Reaction.objects.filter(package=pack).count()))
print('Imported {} pathways'.format(Pathway.objects.filter(package=pack).count()))
print("Fixing Node depths...")
total_pws = Pathway.objects.filter(package=pack).count()
for p, pw in enumerate(Pathway.objects.filter(package=pack)):
print(pw.url)
in_count = defaultdict(lambda: 0)
out_count = defaultdict(lambda: 0)
for e in pw.edges:
# TODO check if this will remain
for react in e.start_nodes.all():
out_count[str(react.uuid)] += 1
for prod in e.end_nodes.all():
in_count[str(prod.uuid)] += 1
root_nodes = []
for n in pw.nodes:
num_parents = in_count[str(n.uuid)]
if num_parents == 0:
# must be a root node or unconnected node
if n.depth != 0:
n.depth = 0
n.save()
# Only root node may have children
if out_count[str(n.uuid)] > 0:
root_nodes.append(n)
levels = [root_nodes]
seen = set()
# Do a bfs to determine depths starting with level 0 a.k.a. root nodes
for i, level_nodes in enumerate(levels):
new_level = []
for n in level_nodes:
for e in n.out_edges.all():
for prod in e.end_nodes.all():
if str(prod.uuid) not in seen:
old_depth = prod.depth
if old_depth != i + 1:
print(f'updating depth from {old_depth} to {i + 1}')
prod.depth = i + 1
prod.save()
new_level.append(prod)
seen.add(str(n.uuid))
if new_level:
levels.append(new_level)
print(f'{p + 1}/{total_pws} fixed.')
return pack
def create_default_setting(self, owner, packages):
s = SettingManager.create_setting(
owner,
name='Global Default Setting',
description='Global Default Setting containing BBD Rules and Max 30 Nodes and Max Depth of 8',
max_nodes=30,
max_depth=5,
rule_packages=packages,
model=None,
model_threshold=None
)
return s
@transaction.atomic
def handle(self, *args, **options):
# Create users
anon, admin, g, jebus = self.create_users()
# Import Packages
packages = [
'EAWAG-BBD.json',
'EAWAG-SOIL.json',
'EAWAG-SLUDGE.json',
]
mapping = {}
for p in packages:
print(f"Importing {p}...")
package_data = json.loads(open(s.BASE_DIR / 'fixtures' / p).read())
imported_package = self.import_package(package_data, admin)
mapping[p.replace('.json', '')] = imported_package
setting = self.create_default_setting(admin, [mapping['EAWAG-BBD']])
setting.public = True
setting.save()
setting.make_global_default()
for u in [anon, jebus]:
usp = UserSettingPermission()
usp.user = u
usp.setting = setting
usp.permission = Permission.READ[0]
usp.save()
# Create Model Package
pack = PackageManager.create_package(admin, "Public Prediction Models", "Package to make Prediction Models publicly available")
pack.reviewed = True
pack.save()
# Create RR
ml_model = MLRelativeReasoning.create(
pack,
'ECC - BBD - T0.5',
'ML Relative Reasoning',
[mapping['EAWAG-BBD']],
[mapping['EAWAG-BBD']],
[],
0.5
)
X, y = ml_model.build_dataset()
ml_model.build_model(X, y)
ml_model.evaluate_model()
# If available create EnviFormerModel
if s.ENVIFORMER_PRESENT:
enviFormer_model = EnviFormer.create(pack, 'EnviFormer - T0.5', 'EnviFormer Model with Threshold 0.5', 0.5)

View File

@ -0,0 +1,571 @@
# Generated by Django 5.2.1 on 2025-06-16 13:57
import datetime
import django.contrib.auth.models
import django.contrib.auth.validators
import django.contrib.postgres.fields
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='Compound',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
],
),
migrations.CreateModel(
name='EPModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
),
migrations.CreateModel(
name='Permission',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('permission', models.CharField(choices=[('read', 'Read'), ('write', 'Write'), ('all', 'All')], max_length=32)),
],
),
migrations.CreateModel(
name='Package',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('reviewed', models.BooleanField(default=False, verbose_name='Reviewstatus')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Rule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Package')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
),
migrations.CreateModel(
name='User',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('email', models.EmailField(max_length=254, unique=True)),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='APIToken',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hashed_key', models.CharField(max_length=128, unique=True)),
('created', models.DateTimeField(auto_now_add=True)),
('expires_at', models.DateTimeField(blank=True, default=datetime.datetime(2025, 9, 14, 13, 57, 57, 138459, tzinfo=datetime.timezone.utc), null=True)),
('name', models.CharField(blank=True, help_text='Optional name for the token', max_length=100)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='CompoundStructure',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
('smiles', models.TextField(verbose_name='SMILES')),
('normalized_structure', models.BooleanField(default=False)),
('compound', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.compound')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='compound',
name='default_structure',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='compound_default_structure', to='epdb.compoundstructure', verbose_name='Default Structure'),
),
migrations.CreateModel(
name='Edge',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
),
migrations.CreateModel(
name='EnviFormer',
fields=[
('epmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.epmodel')),
('threshold', models.FloatField(default=0.5)),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.epmodel',),
),
migrations.CreateModel(
name='PluginModel',
fields=[
('epmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.epmodel')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.epmodel',),
),
migrations.CreateModel(
name='RuleBaseRelativeReasoning',
fields=[
('epmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.epmodel')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.epmodel',),
),
migrations.CreateModel(
name='Group',
fields=[
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False, verbose_name='UUID of this object')),
('name', models.TextField(verbose_name='Group name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('group_member', models.ManyToManyField(related_name='groups_in_group', to='epdb.group', verbose_name='Group member')),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Group Owner')),
('user_member', models.ManyToManyField(related_name='users_in_group', to=settings.AUTH_USER_MODEL, verbose_name='User members')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='user',
name='default_group',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_group', to='epdb.group', verbose_name='Default Group'),
),
migrations.AddField(
model_name='user',
name='groups',
field=models.ManyToManyField(to='epdb.group', verbose_name='groups'),
),
migrations.CreateModel(
name='Node',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
('depth', models.IntegerField(verbose_name='Node depth')),
('default_node_label', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='default_node_structure', to='epdb.compoundstructure', verbose_name='Default Node Label')),
('node_labels', models.ManyToManyField(related_name='node_structures', to='epdb.compoundstructure', verbose_name='All Node Labels')),
('out_edges', models.ManyToManyField(to='epdb.edge', verbose_name='Outgoing Edges')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='edge',
name='end_nodes',
field=models.ManyToManyField(related_name='edge_products', to='epdb.node', verbose_name='End Nodes'),
),
migrations.AddField(
model_name='edge',
name='start_nodes',
field=models.ManyToManyField(related_name='edge_educts', to='epdb.node', verbose_name='Start Nodes'),
),
migrations.AddField(
model_name='epmodel',
name='package',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Package'),
),
migrations.AddField(
model_name='compound',
name='package',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Package'),
),
migrations.AddField(
model_name='user',
name='default_package',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='epdb.package', verbose_name='Default Package'),
),
migrations.CreateModel(
name='SequentialRule',
fields=[
('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.rule')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.rule',),
),
migrations.CreateModel(
name='SimpleRule',
fields=[
('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.rule')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.rule',),
),
migrations.CreateModel(
name='Pathway',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Package')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='node',
name='pathway',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.pathway', verbose_name='belongs to'),
),
migrations.AddField(
model_name='edge',
name='pathway',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.pathway', verbose_name='belongs to'),
),
migrations.CreateModel(
name='Reaction',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('aliases', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), default=list, size=None, verbose_name='Aliases')),
('multi_step', models.BooleanField(verbose_name='Multistep Reaction')),
('medline_references', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), null=True, size=None, verbose_name='Medline References')),
('educts', models.ManyToManyField(related_name='reaction_educts', to='epdb.compoundstructure', verbose_name='Educts')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Package')),
('products', models.ManyToManyField(related_name='reaction_products', to='epdb.compoundstructure', verbose_name='Products')),
('rules', models.ManyToManyField(related_name='reaction_rule', to='epdb.rule', verbose_name='Rule')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='edge',
name='edge_label',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='epdb.reaction', verbose_name='Edge label'),
),
migrations.CreateModel(
name='Scenario',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('date', models.DateField(null=True, verbose_name='Study date')),
('type', models.CharField(default='Not specified', max_length=256)),
('additional_information', models.JSONField(verbose_name='Additional Information')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Package')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='rule',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.AddField(
model_name='reaction',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.AddField(
model_name='pathway',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.AddField(
model_name='node',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.AddField(
model_name='edge',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.AddField(
model_name='compoundstructure',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.AddField(
model_name='compound',
name='scenarios',
field=models.ManyToManyField(to='epdb.scenario', verbose_name='Attached Scenarios'),
),
migrations.CreateModel(
name='Setting',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('public', models.BooleanField(default=False)),
('global_default', models.BooleanField(default=False)),
('max_depth', models.IntegerField(default=5, verbose_name='Setting Max Depth')),
('max_nodes', models.IntegerField(default=30, verbose_name='Setting Max Number of Nodes')),
('model_threshold', models.FloatField(blank=True, default=0.25, null=True, verbose_name='Setting Model Threshold')),
('model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='epdb.epmodel', verbose_name='Setting EPModel')),
('rule_packages', models.ManyToManyField(related_name='setting_rule_packages', to='epdb.package', verbose_name='Setting Rule Packages')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='user',
name='default_setting',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='epdb.setting', verbose_name='The users default settings'),
),
migrations.CreateModel(
name='MLRelativeReasoning',
fields=[
('epmodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.epmodel')),
('threshold', models.FloatField(default=0.5)),
('model_status', models.CharField(choices=[('INITIAL', 'Initial'), ('INITIALIZING', 'Model is initializing.'), ('BUILDING', 'Model is building.'), ('BUILT_NOT_EVALUATED', 'Model is built and can be used for predictions, Model is not evaluated yet.'), ('EVALUATING', 'Model is evaluating'), ('FINISHED', 'Model has finished building and evaluation.'), ('ERROR', 'Model has failed.')], default='INITIAL')),
('eval_results', models.JSONField(blank=True, default=dict, null=True)),
('data_packages', models.ManyToManyField(related_name='data_packages', to='epdb.package', verbose_name='Data Packages')),
('eval_packages', models.ManyToManyField(related_name='eval_packages', to='epdb.package', verbose_name='Evaluation Packages')),
('rule_packages', models.ManyToManyField(related_name='rule_packages', to='epdb.package', verbose_name='Rule Packages')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.epmodel',),
),
migrations.CreateModel(
name='ApplicabilityDomain',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('uuid', models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='UUID of this object')),
('name', models.TextField(default='no name', verbose_name='Name')),
('description', models.TextField(default='no description', verbose_name='Descriptions')),
('kv', models.JSONField(blank=True, default=dict, null=True)),
('num_neighbours', models.FloatField(default=5)),
('reliability_threshold', models.FloatField(default=0.5)),
('local_compatibilty_threshold', models.FloatField(default=0.5)),
('model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.mlrelativereasoning')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='SimpleAmbitRule',
fields=[
('simplerule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.simplerule')),
('smirks', models.TextField(verbose_name='SMIRKS')),
('reactant_filter_smarts', models.TextField(null=True, verbose_name='Reactant Filter SMARTS')),
('product_filter_smarts', models.TextField(null=True, verbose_name='Product Filter SMARTS')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.simplerule',),
),
migrations.CreateModel(
name='SimpleRDKitRule',
fields=[
('simplerule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.simplerule')),
('reaction_smarts', models.TextField(verbose_name='SMIRKS')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.simplerule',),
),
migrations.CreateModel(
name='SequentialRuleOrdering',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('order_index', models.IntegerField()),
('sequential_rule', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.sequentialrule')),
('simple_rule', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.simplerule')),
],
),
migrations.AddField(
model_name='sequentialrule',
name='simple_rules',
field=models.ManyToManyField(through='epdb.SequentialRuleOrdering', to='epdb.simplerule', verbose_name='Simple rules'),
),
migrations.CreateModel(
name='ParallelRule',
fields=[
('rule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='epdb.rule')),
('simple_rules', models.ManyToManyField(to='epdb.simplerule', verbose_name='Simple rules')),
],
options={
'abstract': False,
'base_manager_name': 'objects',
},
bases=('epdb.rule',),
),
migrations.AlterUniqueTogether(
name='compound',
unique_together={('uuid', 'package')},
),
migrations.CreateModel(
name='GroupPackagePermission',
fields=[
('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='epdb.permission')),
('uuid', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False, verbose_name='UUID of this object')),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.group', verbose_name='Permission to')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Permission on')),
],
options={
'unique_together': {('package', 'group')},
},
bases=('epdb.permission',),
),
migrations.CreateModel(
name='UserPackagePermission',
fields=[
('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='epdb.permission')),
('uuid', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False, verbose_name='UUID of this object')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.package', verbose_name='Permission on')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Permission to')),
],
options={
'unique_together': {('package', 'user')},
},
bases=('epdb.permission',),
),
migrations.CreateModel(
name='UserSettingPermission',
fields=[
('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='epdb.permission')),
('uuid', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False, verbose_name='UUID of this object')),
('setting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='epdb.setting', verbose_name='Permission on')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Permission to')),
],
options={
'unique_together': {('setting', 'user')},
},
bases=('epdb.permission',),
),
]

View File

1487
epdb/models.py Normal file

File diff suppressed because it is too large Load Diff

50
epdb/tasks.py Normal file
View File

@ -0,0 +1,50 @@
import logging
from celery.signals import worker_process_init
from celery import shared_task
from epdb.models import Pathway, Node, Edge, EPModel, Setting
from epdb.logic import SPathway
from utilities.chem import FormatConverter
logger = logging.getLogger(__name__)
@shared_task(queue='background')
def mul(a, b):
return a * b
@shared_task(queue='predict')
def predict_simple(model_pk: int, smiles: str):
mod = EPModel.objects.get(id=model_pk)
res = mod.predict(smiles)
return res
@shared_task(queue='background')
def send_registration_mail(user_pk: int):
pass
@shared_task(queue='model')
def build_model(model_pk: int):
mod = EPModel.objects.get(id=model_pk)
X, y = mod.build_dataset()
mod.build_model(X, y)
@shared_task(queue='model')
def evaluate_model(model_pk: int):
mod = EPModel.objects.get(id=model_pk)
mod.evaluate_model()
@shared_task(queue='predict')
def predict(pw_pk: int, pred_setting_pk: int):
pw = Pathway.objects.get(id=pw_pk)
setting = Setting.objects.get(id=pred_setting_pk)
spw = SPathway(prediction_setting=setting, persist=pw)
level = 0
while not spw.done:
spw.predict_step(from_depth=level)
level += 1

3
epdb/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

77
epdb/urls.py Normal file
View File

@ -0,0 +1,77 @@
from django.urls import path, re_path
from . import views as v
# from sesame.views import LoginView
UUID = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}'
urlpatterns = [
# Sesame
# path("login/", v.EmailLoginView.as_view(), name="email_login"),
# path("login/auth/", LoginView.as_view(), name="login"),
# Home
re_path(r'^$', v.index, name='index'),
# Top level urls
re_path(r'^package$', v.packages, name='packages'),
re_path(r'^compound$', v.compounds, name='compounds'),
re_path(r'^rule$', v.rules, name='rules'),
re_path(r'^reaction$', v.reactions, name='reactions'),
re_path(r'^pathway$', v.pathways, name='pathways'),
re_path(r'^scenario$', v.scenarios, name='scenarios'),
re_path(r'^model$', v.models, name='model'),
re_path(r'^user$', v.users, name='users'),
re_path(r'^group$', v.groups, name='groups'),
re_path(r'^search$', v.search, name='search'),
# User Detail
re_path(rf'^user/(?P<user_uuid>{UUID})', v.user, name='user'),
# Group Detail
re_path(rf'^group/(?P<group_uuid>{UUID})$', v.group, name='group_detail'),
# "in package" urls
re_path(rf'^package/(?P<package_uuid>{UUID})$', v.package, name='package_detail'),
# Compound
re_path(rf'^package/(?P<package_uuid>{UUID})/compound$', v.package_compounds, name='package compound list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})$', v.package_compound, name='package compound detail'),
# Compound Structure
re_path(rf'^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})/structure$', v.package_compound_structures, name='package compound structure list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/compound/(?P<compound_uuid>{UUID})/structure/(?P<structure_uuid>{UUID})$', v.package_compound_structure, name='package compound structure detail'),
# Rule
re_path(rf'^package/(?P<package_uuid>{UUID})/rule$', v.package_rules, name='package rule list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
re_path(rf'^package/(?P<package_uuid>{UUID})/simple-ambit-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
re_path(rf'^package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
re_path(rf'^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
re_path(rf'^package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$', v.package_rule, name='package rule detail'),
# Reaction
re_path(rf'^package/(?P<package_uuid>{UUID})/reaction$', v.package_reactions, name='package reaction list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/reaction/(?P<reaction_uuid>{UUID})$', v.package_reaction, name='package reaction detail'),
# # Pathway
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway$', v.package_pathways, name='package pathway list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})$', v.package_pathway, name='package pathway detail'),
# Pathway Nodes
# re_path(rf'^package/(?P<package_uuid>{UUID})/pathway(?P<pathway_uuid>{UUID})/node$', v.package_pathway_nodes, name='package pathway node list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/pathway/(?P<pathway_uuid>{UUID})/node/(?P<node_uuid>{UUID})$', v.package_pathway_node, name='package pathway node detail'),
# Pathway Edges
# re_path(rf'^package/(?P<package_uuid>{UUID})/pathway(?P<pathway_uuid>{UUID})/edge$', v.package_pathway_edges, name='package pathway edge list'),
# re_path(rf'^package/(?P<package_uuid>{UUID})/pathway(?P<pathway_uuid>{UUID})/edge/(?P<edge_uuid>{UUID})$', v.package_pathway_edge, name='package pathway edge detail'),
# Scenario
# re_path(rf'^package/(?P<package_uuid>{UUID})/scenario', v.package_scenarios, name='package scenario list'),
# re_path(rf'^package/(?P<package_uuid>{UUID})/scenario/(?P<scenario_uuid>{UUID})$', v.package_scenarios, name='package scenario detail'),
# Model
re_path(rf'^package/(?P<package_uuid>{UUID})/model$', v.package_models, name='package model list'),
re_path(rf'^package/(?P<package_uuid>{UUID})/model/(?P<model_uuid>{UUID})$', v.package_model,name='package model detail'),
re_path(r'^setting$', v.settings, name='settings'),
re_path(rf'^setting/(?P<setting_uuid>{UUID})', v.setting, name='setting'),
re_path(r'^indigo/info$', v.indigo, name='indigo_info'),
re_path(r'^indigo/aromatize$', v.aromatize, name='indigo_aromatize'),
re_path(r'^indigo/dearomatize$', v.dearomatize, name='indigo_dearomatize'),
re_path(r'^indigo/layout$', v.layout, name='indigo_layout'),
re_path(r'^depict$', v.depict, name='depict')
]

1356
epdb/views.py Normal file

File diff suppressed because it is too large Load Diff