...
Some checks failed
CI / test (pull_request) Failing after 17s
API CI / api-tests (pull_request) Failing after 31s

This commit is contained in:
Tim Lorsbach
2026-06-23 21:20:02 +02:00
parent 687a90af0e
commit 0842f67560
4 changed files with 68 additions and 27 deletions

View File

@ -89,14 +89,13 @@ class BB4G(Classifier):
}
started = False
retries = 0
while not started and retries < 5:
while not started:
res = requests.post(f"{self.url}/start", headers=header, data={}, proxies=s.PROXIES or None)
logger.info(f"Starting BB4G: {res.status_code}")
if res.status_code == 200:
started = True
elif res.status_code in [500, 502]:
retries += 1
import time
time.sleep(5)
else:
@ -171,7 +170,7 @@ class BB4G(Classifier):
}
retries = 0
while retries < 5:
while retries < 100:
resp = requests.post(f"{self.url}/compute", headers=header, data=json.dumps(data),
proxies=s.PROXIES or None)
@ -179,7 +178,7 @@ class BB4G(Classifier):
retries += 1
logger.info(f"BB4G predict hit a 418, retrying in 60 seconds")
import time
time.sleep(60)
time.sleep(3)
continue
resp.raise_for_status()

2
epdb/exceptions.py Normal file
View File

@ -0,0 +1,2 @@
class InvalidSMILESException(Exception):
pass

View File

@ -31,6 +31,7 @@ from sklearn.model_selection import ShuffleSplit
from bridge.contracts import Property
from bridge.dto import RunResult, PropertyPrediction
from epdb.exceptions import InvalidSMILESException
from utilities.chem import FormatConverter, IndigoUtils, PredictionResult, ProductSet
from utilities.ml import (
ApplicabilityDomainPCA,
@ -785,7 +786,7 @@ class Compound(
"CompoundStructure",
verbose_name="Default Structure",
related_name="compound_default_structure",
on_delete=models.CASCADE,
on_delete=models.SET_NULL,
null=True,
)
@ -862,13 +863,17 @@ class Compound(
package: "Package", smiles: str, name: str = None, description: str = None, *args, **kwargs
) -> "Compound":
if smiles is None or smiles.strip() == "":
raise ValueError("SMILES is required")
raise InvalidSMILESException("SMILES is required")
smiles = smiles.strip()
parsed = FormatConverter.from_smiles(smiles)
if parsed is None:
raise ValueError("Given SMILES is invalid")
raise InvalidSMILESException("Given SMILES is invalid")
if name is not None:
# Clean for potential XSS
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
standardized_smiles = FormatConverter.standardize(smiles, remove_stereo=True)
@ -880,7 +885,12 @@ class Compound(
# Check if we find a direct match for a given SMILES
if qs.exists():
return qs.first().compound
found_compound = qs.first().compound
if name:
found_compound.add_alias(name)
return found_compound
qs = CompoundStructure.objects.filter(smiles=standardized_smiles, compound__package=package)
@ -890,16 +900,17 @@ class Compound(
# Check if we can find the standardized one
if qs.exists():
# TODO should we add a structure?
return qs.first().compound
found_compound = qs.first().compound
if name:
found_compound.add_alias(name)
return found_compound
# Generate Compound
c = Compound()
c.package = package
if name is not None:
# Clean for potential XSS
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if name is None or name == "":
name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
@ -1152,16 +1163,25 @@ class CompoundStructure(
def create(
compound: Compound, smiles: str, name: str = None, description: str = None, *args, **kwargs
):
# Clean for potential XSS
if name is not None:
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if CompoundStructure.objects.filter(compound=compound, smiles=smiles).exists():
return CompoundStructure.objects.get(compound=compound, smiles=smiles)
found_cs = CompoundStructure.objects.get(compound=compound, smiles=smiles)
if name:
found_cs.add_alias(name)
return found_cs
if compound.pk is None:
raise ValueError("Unpersisted Compound! Persist compound first!")
cs = CompoundStructure()
# Clean for potential XSS
if name is not None:
cs.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
cs.name = name
if description is not None:
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
@ -1383,6 +1403,9 @@ class SimpleAmbitRule(SimpleRule):
if not FormatConverter.is_valid_smirks(smirks):
raise ValueError(f'SMIRKS "{smirks}" is invalid!')
if name is not None:
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
query = SimpleAmbitRule.objects.filter(package=package, smirks=smirks)
if reactant_filter_smarts is not None and reactant_filter_smarts.strip() != "":
@ -1394,14 +1417,17 @@ class SimpleAmbitRule(SimpleRule):
if query.exists():
if query.count() > 1:
logger.error(f"More than one rule matched this one! {query}")
return query.first()
found_rule = query.first()
if name:
found_rule.add_alias(name)
return found_rule
r = SimpleAmbitRule()
r.package = package
if name is not None:
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if name is None or name == "":
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
@ -1642,8 +1668,13 @@ class Reaction(
educts: Union[List[str], List[CompoundStructure]] = None,
products: Union[List[str], List[CompoundStructure]] = None,
rules: Union[Rule | List[Rule]] = None,
multi_step: bool = True,
multi_step: bool = False,
):
# Clean for potential XSS
if name is not None and name.strip() != "":
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
_educts = []
_products = []
@ -1698,14 +1729,19 @@ class Reaction(
logger.error(
f"Found more than one reaction for given input! {existing_reaction_qs}"
)
return existing_reaction_qs.first()
found_reaction = existing_reaction_qs.first()
if name:
found_reaction.add_alias(name)
return found_reaction
r = Reaction()
r.package = package
# Clean for potential XSS
if name is not None and name.strip() != "":
r.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
if r is not None:
r.name = name
if description is not None and description.strip() != "":
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()

View File

@ -19,6 +19,7 @@ from sentry_sdk import capture_exception
from utilities.chem import FormatConverter, IndigoUtils
from utilities.decorators import package_permission_required
from .exceptions import InvalidSMILESException
from .logic import (
EPDBURLParser,
@ -2364,7 +2365,10 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
node_description = request.POST.get("node-description")
node_smiles = request.POST.get("node-smiles").strip()
try:
current_pathway.add_node(node_smiles, name=node_name, description=node_description)
except InvalidSMILESException as e:
return error(request, "Node creation failed!", f"Given SMILES ({node_smiles}) is invalid")
return redirect(current_pathway.url)