forked from enviPath/enviPy
[Chore] Leftovers (#426)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#426
This commit is contained in:
@ -1620,7 +1620,7 @@ class PathwayNode(Schema):
|
|||||||
image: str = Field(None, alias="image")
|
image: str = Field(None, alias="image")
|
||||||
imageSize: int = Field(None, alias="image_size")
|
imageSize: int = Field(None, alias="image_size")
|
||||||
name: str = Field(None, alias="name")
|
name: str = Field(None, alias="name")
|
||||||
proposed: List[Dict[str, str]] = Field([], alias="proposed_intermediate")
|
proposed: List[Dict[str, str]] = []
|
||||||
smiles: str = Field(None, alias="smiles")
|
smiles: str = Field(None, alias="smiles")
|
||||||
pseudo: bool = Field(False, alias="pseudo")
|
pseudo: bool = Field(False, alias="pseudo")
|
||||||
|
|
||||||
@ -1910,7 +1910,7 @@ def add_pathway_node(request, package_uuid, pathway_uuid, n: Form[CreateNode]):
|
|||||||
else:
|
else:
|
||||||
node_depth = -1
|
node_depth = -1
|
||||||
|
|
||||||
n = Node.create(
|
node = Node.create(
|
||||||
pw,
|
pw,
|
||||||
n.nodeAsSmiles,
|
n.nodeAsSmiles,
|
||||||
node_depth,
|
node_depth,
|
||||||
@ -1919,7 +1919,7 @@ def add_pathway_node(request, package_uuid, pathway_uuid, n: Form[CreateNode]):
|
|||||||
description=n.nodeReason,
|
description=n.nodeReason,
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(n.url)
|
return redirect(node.url)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 403, {"message": "Adding node failed!"}
|
return 403, {"message": "Adding node failed!"}
|
||||||
|
|
||||||
|
|||||||
@ -1008,8 +1008,6 @@ class PackageManager(object):
|
|||||||
data: Dict[str, Any],
|
data: Dict[str, Any],
|
||||||
owner: User,
|
owner: User,
|
||||||
preserve_uuids=False,
|
preserve_uuids=False,
|
||||||
add_import_timestamp=True,
|
|
||||||
trust_reviewed=False,
|
|
||||||
) -> Package:
|
) -> Package:
|
||||||
importer = PackageImporter(data, preserve_uuids)
|
importer = PackageImporter(data, preserve_uuids)
|
||||||
imported_package = importer.do_import()
|
imported_package = importer.do_import()
|
||||||
@ -1830,6 +1828,7 @@ class SPathway(object):
|
|||||||
|
|
||||||
if edge.rule:
|
if edge.rule:
|
||||||
e["rule"] = edge.rule.simple_json()
|
e["rule"] = edge.rule.simple_json()
|
||||||
|
|
||||||
if edge.probability:
|
if edge.probability:
|
||||||
e["probability"] = edge.probability
|
e["probability"] = edge.probability
|
||||||
|
|
||||||
|
|||||||
115
epdb/models.py
115
epdb/models.py
@ -894,34 +894,46 @@ class Compound(
|
|||||||
if parsed is None:
|
if parsed is None:
|
||||||
raise InvalidSMILESException("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)
|
standardized_smiles = FormatConverter.standardize(smiles, remove_stereo=True)
|
||||||
|
|
||||||
|
qs = CompoundStructure.objects.filter(smiles=smiles, compound__package=package)
|
||||||
|
|
||||||
# Check if we find a direct match for a given SMILES
|
# Check if we find a direct match for a given SMILES
|
||||||
if CompoundStructure.objects.filter(smiles=smiles, compound__package=package).exists():
|
if qs.exists():
|
||||||
return CompoundStructure.objects.get(smiles=smiles, compound__package=package).compound
|
found_structure = qs.first()
|
||||||
|
found_compound = found_structure.compound
|
||||||
|
|
||||||
|
if name:
|
||||||
|
found_structure.add_alias(name)
|
||||||
|
found_compound.add_alias(name)
|
||||||
|
|
||||||
|
return found_compound
|
||||||
|
|
||||||
|
qs = CompoundStructure.objects.filter(smiles=standardized_smiles, compound__package=package)
|
||||||
|
|
||||||
# Check if we can find the standardized one
|
# Check if we can find the standardized one
|
||||||
if CompoundStructure.objects.filter(
|
if qs.exists():
|
||||||
smiles=standardized_smiles, compound__package=package
|
found_structure = qs.first()
|
||||||
).exists():
|
found_compound = found_structure.compound
|
||||||
found_c = CompoundStructure.objects.get(
|
|
||||||
smiles=standardized_smiles, compound__package=package
|
|
||||||
).compound
|
|
||||||
|
|
||||||
# As a direct match wasn't found add a new structure
|
# We've only found the standardized one, create the very structure
|
||||||
# TODO return newly created structure
|
_ = found_compound.add_structure(
|
||||||
_ = found_c.add_structure(smiles, molfile=molfile, name=name, description=description)
|
smiles, molfile=molfile, name=name, description=description
|
||||||
|
)
|
||||||
|
|
||||||
return found_c
|
if name:
|
||||||
|
found_compound.add_alias(name)
|
||||||
|
|
||||||
|
return found_compound
|
||||||
|
|
||||||
# Generate Compound
|
# Generate Compound
|
||||||
c = Compound()
|
c = Compound()
|
||||||
c.package = package
|
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 == "":
|
if name is None or name == "":
|
||||||
name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
|
name = f"Compound {Compound.objects.filter(package=package).count() + 1}"
|
||||||
|
|
||||||
@ -1218,8 +1230,15 @@ class CompoundStructure(
|
|||||||
# Overwrite SMILES from molfile
|
# Overwrite SMILES from molfile
|
||||||
smiles = FormatConverter.to_smiles(mol)
|
smiles = FormatConverter.to_smiles(mol)
|
||||||
|
|
||||||
|
# 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():
|
if CompoundStructure.objects.filter(compound=compound, smiles=smiles).exists():
|
||||||
found_cs = CompoundStructure.objects.get(smiles=smiles, compound=compound)
|
found_cs = CompoundStructure.objects.get(compound=compound, smiles=smiles)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
found_cs.add_alias(name)
|
||||||
|
|
||||||
if found_cs.molfile is None and (molfile is not None and molfile.strip() != ""):
|
if found_cs.molfile is None and (molfile is not None and molfile.strip() != ""):
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -1236,16 +1255,17 @@ class CompoundStructure(
|
|||||||
cs = CompoundStructure()
|
cs = CompoundStructure()
|
||||||
# Clean for potential XSS
|
# Clean for potential XSS
|
||||||
if name is not None:
|
if name is not None:
|
||||||
cs.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
cs.name = name
|
||||||
|
|
||||||
if description is not None:
|
# We have a default here only set the value if it carries some payload
|
||||||
|
if description is not None and description.strip() != "":
|
||||||
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
cs.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
cs.compound = compound
|
cs.compound = compound
|
||||||
cs.smiles = smiles
|
cs.smiles = smiles
|
||||||
|
|
||||||
# Check if molfile is present and valid
|
# If molfile is not None, it hase to be a valid Molfile as we've survived the parsing check
|
||||||
if molfile is not None and molfile.strip() != "":
|
if molfile is not None:
|
||||||
cs.molfile = molfile
|
cs.molfile = molfile
|
||||||
|
|
||||||
if "normalized_structure" in kwargs:
|
if "normalized_structure" in kwargs:
|
||||||
@ -1464,6 +1484,9 @@ class SimpleAmbitRule(SimpleRule):
|
|||||||
if not FormatConverter.is_valid_smirks(smirks):
|
if not FormatConverter.is_valid_smirks(smirks):
|
||||||
raise ValueError(f'SMIRKS "{smirks}" is invalid!')
|
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)
|
query = SimpleAmbitRule.objects.filter(package=package, smirks=smirks)
|
||||||
|
|
||||||
if reactant_filter_smarts is not None and reactant_filter_smarts.strip() != "":
|
if reactant_filter_smarts is not None and reactant_filter_smarts.strip() != "":
|
||||||
@ -1475,14 +1498,17 @@ class SimpleAmbitRule(SimpleRule):
|
|||||||
if query.exists():
|
if query.exists():
|
||||||
if query.count() > 1:
|
if query.count() > 1:
|
||||||
logger.error(f"More than one rule matched this one! {query}")
|
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 = SimpleAmbitRule()
|
||||||
r.package = package
|
r.package = package
|
||||||
|
|
||||||
if name is not None:
|
|
||||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
|
||||||
|
|
||||||
if name is None or name == "":
|
if name is None or name == "":
|
||||||
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
|
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
|
||||||
|
|
||||||
@ -1615,6 +1641,9 @@ class ParallelRule(Rule):
|
|||||||
f"Simple rule {sr.uuid} does not belong to package {package.uuid}!"
|
f"Simple rule {sr.uuid} does not belong to package {package.uuid}!"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if name is not None:
|
||||||
|
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
|
|
||||||
# Deduplication check
|
# Deduplication check
|
||||||
query = ParallelRule.objects.annotate(
|
query = ParallelRule.objects.annotate(
|
||||||
srs_count=Count("simple_rules", filter=Q(simple_rules__in=simple_rules), distinct=True)
|
srs_count=Count("simple_rules", filter=Q(simple_rules__in=simple_rules), distinct=True)
|
||||||
@ -1626,15 +1655,19 @@ class ParallelRule(Rule):
|
|||||||
|
|
||||||
if existing_rule_qs.exists():
|
if existing_rule_qs.exists():
|
||||||
if existing_rule_qs.count() > 1:
|
if existing_rule_qs.count() > 1:
|
||||||
logger.error(f"Found more than one reaction for given input! {existing_rule_qs}")
|
logger.error(
|
||||||
return existing_rule_qs.first()
|
f"Found more than one ParallelRule for given input! {existing_rule_qs}"
|
||||||
|
)
|
||||||
|
|
||||||
|
found_rule = existing_rule_qs.first()
|
||||||
|
if name:
|
||||||
|
found_rule.add_alias(name)
|
||||||
|
|
||||||
|
return found_rule
|
||||||
|
|
||||||
r = ParallelRule()
|
r = ParallelRule()
|
||||||
r.package = package
|
r.package = package
|
||||||
|
|
||||||
if name is not None:
|
|
||||||
name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
|
||||||
|
|
||||||
if name is None or name == "":
|
if name is None or name == "":
|
||||||
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
|
name = f"Rule {Rule.objects.filter(package=package).count() + 1}"
|
||||||
|
|
||||||
@ -1730,6 +1763,10 @@ class Reaction(
|
|||||||
rules: Union[Rule | List[Rule]] = None,
|
rules: Union[Rule | List[Rule]] = None,
|
||||||
multi_step: bool = False,
|
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 = []
|
_educts = []
|
||||||
_products = []
|
_products = []
|
||||||
|
|
||||||
@ -1784,14 +1821,21 @@ class Reaction(
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"Found more than one reaction for given input! {existing_reaction_qs}"
|
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 = Reaction()
|
||||||
r.package = package
|
r.package = package
|
||||||
|
|
||||||
# Clean for potential XSS
|
if name is None or name == "":
|
||||||
if name is not None and name.strip() != "":
|
name = f"Reaction {Reaction.objects.filter(package=package).count() + 1}"
|
||||||
r.name = nh3.clean(name, tags=s.ALLOWED_HTML_TAGS).strip()
|
|
||||||
|
r.name = name
|
||||||
|
|
||||||
if description is not None and description.strip() != "":
|
if description is not None and description.strip() != "":
|
||||||
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
r.description = nh3.clean(description, tags=s.ALLOWED_HTML_TAGS).strip()
|
||||||
@ -2420,6 +2464,7 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
|
|||||||
},
|
},
|
||||||
"predicted_properties": predicted_properties,
|
"predicted_properties": predicted_properties,
|
||||||
"is_engineered_intermediate": self.kv.get("is_engineered_intermediate", False),
|
"is_engineered_intermediate": self.kv.get("is_engineered_intermediate", False),
|
||||||
|
"proposed": self.get_proposed_info(),
|
||||||
"timeseries": self.get_timeseries_data(),
|
"timeseries": self.get_timeseries_data(),
|
||||||
**structure_data,
|
**structure_data,
|
||||||
}
|
}
|
||||||
@ -2516,7 +2561,7 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMixin)
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def is_proposed_intermediate(self):
|
def get_proposed_info(self):
|
||||||
collected = defaultdict(dict)
|
collected = defaultdict(dict)
|
||||||
for ai in self.additional_information.filter(
|
for ai in self.additional_information.filter(
|
||||||
type__in=["ProposedIntermediate", "TransformationProductImportance", "Confidence"],
|
type__in=["ProposedIntermediate", "TransformationProductImportance", "Confidence"],
|
||||||
|
|||||||
@ -134,7 +134,7 @@
|
|||||||
<!-- Reactions -->
|
<!-- Reactions -->
|
||||||
{% if compound.related_reactions %}
|
{% if compound.related_reactions %}
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" />
|
||||||
<div class="collapse-title text-xl font-medium">Reactions</div>
|
<div class="collapse-title text-xl font-medium">Reactions</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<ul class="menu bg-base-100 rounded-box">
|
<ul class="menu bg-base-100 rounded-box">
|
||||||
@ -153,7 +153,7 @@
|
|||||||
<!-- Pathways -->
|
<!-- Pathways -->
|
||||||
{% if compound.related_pathways %}
|
{% if compound.related_pathways %}
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" />
|
||||||
<div class="collapse-title text-xl font-medium">Pathways</div>
|
<div class="collapse-title text-xl font-medium">Pathways</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<ul class="menu bg-base-100 rounded-box">
|
<ul class="menu bg-base-100 rounded-box">
|
||||||
@ -172,7 +172,7 @@
|
|||||||
<!-- Scenarios -->
|
<!-- Scenarios -->
|
||||||
{% if compound.scenarios.all %}
|
{% if compound.scenarios.all %}
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" />
|
||||||
<div class="collapse-title text-xl font-medium">Scenarios</div>
|
<div class="collapse-title text-xl font-medium">Scenarios</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<ul class="menu bg-base-100 rounded-box">
|
<ul class="menu bg-base-100 rounded-box">
|
||||||
@ -240,7 +240,7 @@
|
|||||||
<!-- External Identifiers -->
|
<!-- External Identifiers -->
|
||||||
{% if compound.get_external_identifiers %}
|
{% if compound.get_external_identifiers %}
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" />
|
||||||
<div class="collapse-title text-xl font-medium">
|
<div class="collapse-title text-xl font-medium">
|
||||||
External Identifier
|
External Identifier
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -92,6 +92,25 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Pathways -->
|
||||||
|
{% if compound.related_pathways %}
|
||||||
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
|
<input type="checkbox" />
|
||||||
|
<div class="collapse-title text-xl font-medium">Pathways</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<ul class="menu bg-base-100 rounded-box">
|
||||||
|
{% for r in compound.related_pathways %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ r.url }}" class="hover:bg-base-200"
|
||||||
|
>{{ r.name }} <i>({{ r.package.name }})</i></a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if compound_structure.half_lifes %}
|
{% if compound_structure.half_lifes %}
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" />
|
<input type="checkbox" />
|
||||||
@ -144,7 +163,7 @@
|
|||||||
{% if compound_structure.scenarios.all %}
|
{% if compound_structure.scenarios.all %}
|
||||||
<!-- Scenarios -->
|
<!-- Scenarios -->
|
||||||
<div class="collapse-arrow bg-base-200 collapse">
|
<div class="collapse-arrow bg-base-200 collapse">
|
||||||
<input type="checkbox" checked />
|
<input type="checkbox" />
|
||||||
<div class="collapse-title text-xl font-medium">Scenarios</div>
|
<div class="collapse-title text-xl font-medium">Scenarios</div>
|
||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<ul class="menu bg-base-100 rounded-box">
|
<ul class="menu bg-base-100 rounded-box">
|
||||||
|
|||||||
@ -106,7 +106,7 @@ class ReactionTest(TestCase):
|
|||||||
multi_step=False,
|
multi_step=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(r.name, "no name")
|
self.assertEqual(r.name, "Reaction 1")
|
||||||
self.assertEqual(r.description, "no description")
|
self.assertEqual(r.description, "no description")
|
||||||
|
|
||||||
def test_deduplication(self):
|
def test_deduplication(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user