Commit 2bd6a9b1 authored by Hervé  MENAGER's avatar Hervé MENAGER
Browse files

Merge branch 'master' into 'release'

Prepare for v1.0.3

See merge request !20
parents 24b5d5bf e231ff32
Pipeline #42116 canceled with stages
...@@ -54,7 +54,8 @@ extensions = [ ...@@ -54,7 +54,8 @@ extensions = [
'sphinx.ext.intersphinx', 'sphinx.ext.intersphinx',
'sphinx.ext.coverage', 'sphinx.ext.coverage',
'sphinx.ext.viewcode', 'sphinx.ext.viewcode',
'sphinx.ext.graphviz' 'sphinx.ext.graphviz',
'sphinxcontrib.bibtex'
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
......
...@@ -18,6 +18,7 @@ These pages contain the documentation for technical maintenance and development ...@@ -18,6 +18,7 @@ These pages contain the documentation for technical maintenance and development
install install
configuration configuration
database database
webservices
modules modules
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -8,6 +8,7 @@ import operator ...@@ -8,6 +8,7 @@ import operator
import re import re
import sys import sys
from boltons.iterutils import flatten, unique_iter
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
...@@ -985,6 +986,20 @@ class Compound(AutoFillableModel): ...@@ -985,6 +986,20 @@ class Compound(AutoFillableModel):
.count() .count()
) )
@property
def pk_tests_count(self):
"""
Return the number of associated pharmacokinetic tests
"""
return self.compoundpkresult_set.all().count()
@property
def cytotoxicity_tests_count(self):
"""
Return the number of associated cytotoxicity tests
"""
return self.compoundcytotoxicityresult_set.all().count()
@property @property
def sorted_similar_drugbank_compounds(self): def sorted_similar_drugbank_compounds(self):
""" """
...@@ -1183,6 +1198,60 @@ class Compound(AutoFillableModel): ...@@ -1183,6 +1198,60 @@ class Compound(AutoFillableModel):
CompoundTanimoto.objects.filter(compound=self).delete() CompoundTanimoto.objects.filter(compound=self).delete()
DrugbankCompoundTanimoto.objects.filter(compound=self).delete() DrugbankCompoundTanimoto.objects.filter(compound=self).delete()
def get_target_activities_table(self):
"""
Return test activity result data as a list of
items containing for each PPI family the compound
was tested against, the best activity, the linked diseases
and the modulation types
"""
ppi_families = [
item["test_activity_description__ppi__family"]
for item in self.compoundactivityresult_set.filter(
~Q(activity_type="KdRat")
)
.order_by()
.values("test_activity_description__ppi__family")
.distinct()
]
results = []
for ppi_family in ppi_families:
family_compound_activity_results = self.compoundactivityresult_set.filter(
~Q(activity_type="KdRat")
).filter(test_activity_description__ppi__family__id=ppi_family)
best_activity = (
family_compound_activity_results.order_by("-activity")
.values("activity")
.first()["activity"]
)
diseases = list(
unique_iter(
flatten(
[
list(fcar.test_activity_description.ppi.diseases.all())
for fcar in family_compound_activity_results
]
)
)
)
modulation_types = list(
set(
[
fcar.get_modulation_type_display()
for fcar in family_compound_activity_results
]
)
)
results.append(
{
"family": PpiFamily.objects.get(id=ppi_family),
"best_activity": best_activity,
"diseases": diseases,
"modulation_types": modulation_types,
}
)
return results
class CompoundTanimoto(models.Model): class CompoundTanimoto(models.Model):
canonical_smiles = models.TextField("Canonical Smile") canonical_smiles = models.TextField("Canonical Smile")
...@@ -1867,9 +1936,9 @@ def update_compound_cached_properties(compounds_queryset=None): ...@@ -1867,9 +1936,9 @@ def update_compound_cached_properties(compounds_queryset=None):
) )
.values("_bindtest_av")[:1] .values("_bindtest_av")[:1]
), ),
pktest_av=Exists(CompoundPKResult.objects.filter(id=OuterRef("id"))), pktest_av=Exists(CompoundPKResult.objects.filter(compound__id=OuterRef("id"))),
cytoxtest_av=Exists( cytoxtest_av=Exists(
CompoundCytotoxicityResult.objects.filter(id=OuterRef("id")) CompoundCytotoxicityResult.objects.filter(compound__id=OuterRef("id"))
), ),
insilico_av=Subquery( insilico_av=Subquery(
compounds_queryset.filter(id=OuterRef("id")) compounds_queryset.filter(id=OuterRef("id"))
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<div class="row" style="display: inline-block;height:auto; margin-right: 15px; margin-left: 15px;"> <div class="row" style="display: inline-block;height:auto; margin-right: 15px; margin-left: 15px;">
<div class="tab-content" id="tabContent"> <div class="tab-content" id="tabContent">
<div class="tab-pane fade show active" id="compound" role="tabpanel" aria-labelledby="compound-tab"> <div class="tab-pane fade show active" id="compound" role="tabpanel" aria-labelledby="compound-tab">
<div class="card"> <div class="card inner-wrap">
<div class="card-body"> <div class="card-body">
{% include "compound_l_item.html" with compound=compound show_detail=True %} {% include "compound_l_item.html" with compound=compound show_detail=True %}
</div> </div>
...@@ -382,20 +382,7 @@ ...@@ -382,20 +382,7 @@
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-sm-12 col-md-9" style="margin: 10px;"> <div class="col-sm-12 col-md-9" style="margin: 10px;">
<h5 class="card_title">Summary</h5> <h5 class="card_title">Summary</h5>
<div class="card_border row" style="text-align: center;"> {% include "compound_test_counts.html" with compound=compound show_bibrefs=True %}
<div class="col-md-4">
<h6 class="card_title">Bibliographic ressources</h6>
<p>{{ compound.biblio_refs.count }}</p>
</div>
<div class="col-md-4">
<h6 class="card_title">Biochemical tests</h6>
<p>{{ compound.bioch_tests_count }}</p>
</div>
<div class="col-md-4">
<h6 class="card_title">Cellular tests</h6>
<p>{{ compound.cell_tests_count }}</p>
</div>
</div>
</div> </div>
</div> </div>
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
......
{%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id or compound.ligand_id %} {%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id or compound.ligand_id %}
<table class="table mb-0"> <table class="table m-1 card_border">
<tbody> <tbody>
<tr class="row"> <tr class="table-row">
<td scope="col" class="col-2 text-center"> <td scope="col" class="col-2 text-center">
{% if compound.pubchem_id %} {% if compound.pubchem_id %}
<a href="{{ compound.pubchem_url }}" target="_blank"><img <a href="{{ compound.pubchem_url }}" target="_blank"><img
......
<table class="table mb-0"> <table class="table m-1 card_border">
<tbody> <tbody>
<tr class="row"> <tr class="table-row">
<td scope="col" class="col-2 text-center"> <td scope="col" class="col-2 text-center">
<a href="https://www.ncbi.nlm.nih.gov/pccompound?term={{ compound.inchikey }}" target="_blank"><img src="/static/images/Other/Pubchemlogo.png" style="height: 1.5em;" title="search INCHIKEY on PubChem" /></a> <a href="https://www.ncbi.nlm.nih.gov/pccompound?term={{ compound.inchikey }}" target="_blank"><img src="/static/images/Other/Pubchemlogo.png" style="height: 1.5em;" title="search INCHIKEY on PubChem" /></a>
</td> </td>
......
{% load customtags %}
<div class="row m-2 border border-info bg-light border_card" style="box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.2);"> <div class="row m-2 border border-info bg-light border_card" style="box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.2);">
{%if show_detail != True %} {%if show_detail != True %}
<div class="col-sm-3 border-info d-flex justify-content-center align-content-center {% if compound.replaced_with or compound.is_validated is False %}bg_warning{% endif %}"> <div class="col-sm-3 border-info justify-content-center align-content-center {% if compound.replaced_with or compound.is_validated is False %}bg_warning{% endif %}">
<a href="/compounds/{{ compound.id }}">{% include "compound_smiles_draw.html" with id=compound.id smile=compound.canonical_smile %}</a> <div class="row">
<h2 class="position-absolute" style="top:0.3em; left:0.3em;"><span class="badge badge-light"><a href="/compounds/{{ compound.id }}">{{ compound.id }}</a></span>{% if compound.replaced_with is not None %} <a style="overflow: hidden;" href="/compounds/{{ compound.id }}">{% include "compound_smiles_draw.html" with id=compound.id smile=compound.canonical_smile %}</a>
<span style="font-size: 26px; color:#fa8005; font-size: 75%;">replaced with <a href="/compounds/{{ compound.replaced_with.id }}">{{ compound.replaced_with.id }}</a></span>{% elif compound.is_validated is False %}<span <h2 class="position-absolute" style="top:0.3em; left:0.3em;"><span class="badge badge-light"><a href="/compounds/{{ compound.id }}">{{ compound.id }}</a></span>{% if compound.replaced_with is not None %}
style="font-size: 26px; color:#fa8005;">not validated</span>{% endif %}</h2> <span style="font-size: 26px; color:#fa8005; font-size: 75%;">replaced with <a href="/compounds/{{ compound.replaced_with.id }}">{{ compound.replaced_with.id }}</a></span>{% elif compound.is_validated is False %}<span
{% if compound.tanimoto != None %} style="font-size: 26px; color:#fa8005;">not validated</span>{% endif %}</h2>
<h2 class="position-absolute" style="top:0.3em; right:0.3em;" title="tanimoto similarity value"><span class="badge badge-light text-warning">{{ compound.tanimoto }}</span></h2> {% if compound.tanimoto != None %}
{% endif %} <h2 class="position-absolute" style="top:0.3em; right:0.3em;" title="tanimoto similarity value"><span class="badge badge-light text-warning">{{ compound.tanimoto }}</span></h2>
{% endif %}
</div>
<h4 class="pt-2 compound_list_title">Chemistry rules</h4>
<div class="row m-1">
<table class="table table-sm col-sm-12 col-md-6 card_border m-1" style="text-align: center;">
<thead>
<tr>
<th scope="col" class="card_title col_width">Lipinski's RO5</th>
<th scope="col" class="card_title col_width">Veber</th>
<th scope="col" class="card_title col_width">Pfizer's 3/75</th>
</tr>
</thead>
<tbody>
<tr>
<td>{% rule_status_icon compound.lipinsky "Lipinski's RO5" %}</td>
<td>{% rule_status_icon compound.veber "Veber" %}</td>
<td>{% rule_status_icon compound.pfizer "Pfizer" %}</td>
</tr>
</tbody>
</table>
</div>
</div> </div>
{% endif %} {% endif %}
<div class="{%if show_detail != True %}col-sm-9{% else %}col-sm-12{% endif %}"> <div class="{%if show_detail != True %}col-sm-9{% else %}col-sm-12{% endif %}">
...@@ -17,16 +40,16 @@ ...@@ -17,16 +40,16 @@
<li class="list-group-item">Common name: {{ compound.common_name }}</li> <li class="list-group-item">Common name: {{ compound.common_name }}</li>
{% endif %} {% endif %}
{% if compound.canonical_smile %} {% if compound.canonical_smile %}
<li class="list-group-item">Canonical SMILES: {{ compound.canonical_smile }}</li> <li class="list-group-item">Canonical SMILES: <pre style="overflow: scroll;">{{ compound.canonical_smile }}</pre></li>
{% endif %} {% endif %}
{% if compound.iupac_name %} {% if compound.iupac_name %}
<li class="list-group-item">IUPAC name: {{ compound.iupac_name }}</li> <li class="list-group-item">IUPAC name: <pre style="overflow: scroll;">{{ compound.iupac_name }}</pre></li>
{% endif %} {% endif %}
{% if compound.inchi %} {% if compound.inchi %}
<li class="list-group-item">InChi: {{ compound.inchi }}</li> <li class="list-group-item">InChi: <pre style="overflow: scroll;">{{ compound.inchi }}</pre></li>
{% endif %} {% endif %}
{% if compound.inchikey %} {% if compound.inchikey %}
<li class="list-group-item">InChiKey: {{ compound.inchikey }}</li> <li class="list-group-item">InChiKey: <pre style="overflow: scroll;">{{ compound.inchikey }}</pre></li>
{% endif %} {% endif %}
</ul> </ul>
{%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id or compound.ligand_id %} {%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id or compound.ligand_id %}
...@@ -38,24 +61,56 @@ ...@@ -38,24 +61,56 @@
{% include "compound_dbsearch_links.html" %} {% include "compound_dbsearch_links.html" %}
{% endif %} {% endif %}
{% if compound.biblio_refs %} {% if compound.biblio_refs %}
<h4 class="pt-2 compound_list_title">Bibliography</h4> <h4 class="pt-2 compound_list_title">Bibliography ({{compound.biblio_refs.count}})</h4>
<table class="table"> <table class="table m-1 card_border">
<thead> <thead>
<tr> <tr class="table-row">
<th scope="col">Publication</th> <th scope="col">Publication</th>
<th scope="col" title="Compound name in publication">Name</th> <th scope="col" title="Compound name in publication">Name</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for biblio_ref in compound.biblio_refs %} {% for biblio_ref in compound.biblio_refs %}
<tr> <tr class="table-row">
<td scope="col">{% include "biblio_citation.html" with bibliography=biblio_ref.bibliography%}</td> <td scope="col">{% include "biblio_citation.html" with bibliography=biblio_ref.bibliography%}</td>
<td scope="col">{{ biblio_ref.compound_name }}</td> <td scope="col">{{ biblio_ref.compound_name }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</ul> <h4 class="pt-2 compound_list_title">Pharmacological data</h4>
{% include "compound_test_counts.html" with compound=compound show_bibrefs=False %}
<h4 class="pt-2 compound_list_title">Targets</h4>
<table class="table m-1 card_border">
<thead>
<tr class="table-row">
<th scope="col">PPI family</th>
<th scope="col">Best activity</th>
<th scope="col">Diseases</th>
<th scope="col" title="Molecular Mechanism of Action">MMoA</th>
</tr>
</thead>
<tbody>
{% for row in compound.get_target_activities_table %}
<tr class="table-row">
<td scope="col">{{ row.family.name }}</td>
<td scope="col">{{ row.best_activity|floatformat:2 }}</td>
<td scope="col">
{% for disease in row.diseases %}
{{ disease.name }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
</td>
<td scope="col">
{% for modulation_type in row.modulation_types %}
{{ modulation_type }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %} {% endif %}
</div> </div>
</div> </div>
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
</div> </div>
<div class="inner-wrap container-fluid "> <div class="inner-wrap container-fluid ">
<div class="row flex-xl-nowrap"> <div class="row">
<main class="col-12" role="main"> <main class="col-12" role="main">
<h1 class="page-title">Query compounds</h1> <h1 class="page-title">Query compounds</h1>
......
<table class="table m-1 card_border">
<thead>
<tr class="table-row">
{% if show_bibrefs %}
<th scope="col">Bibliographic ressources</th>
{% endif %}
<th scope="col" title="Biochemical tests">Biochemical tests</th>
<th scope="col" title="Cellular tests">Cellular tests</th>
<th scope="col" title="Pharmacokinetic tests">PK tests</th>
<th scope="col" title="Cytotoxicity tests">Cytotoxicity tests</th>
</tr>
</thead>
<tbody>
<tr class="table-row">
{% if show_bibrefs %}
<td scope="col">{{ compound.biblio_refs.count }}</td>
{% endif %}
<th scope="col" title="Biochemical tests">{{ compound.bioch_tests_count }}</th>
<th scope="col" title="Cellular tests">{{ compound.cell_tests_count }}</th>
<th scope="col" title="Pharmacokinetic tests">{{ compound.pk_tests_count }}</th>
<th scope="col" title="Cytotoxicity tests">{{ compound.cytotoxicity_tests_count }}</th>
</tr>
</tbody>
</table>
\ No newline at end of file
...@@ -29,6 +29,22 @@ def status_class(value): ...@@ -29,6 +29,22 @@ def status_class(value):
return "table-secondary" return "table-secondary"
@register.simple_tag
def rule_status_icon(value, title):
if value is True:
class_suffix = "success"
icon_suffix = "check"
elif value is False:
class_suffix = "danger"
icon_suffix = "times"
else:
class_suffix = "secondary"
class_suffix = "question"
return mark_safe(
f'<i class="fas fa-{icon_suffix} text-{class_suffix}" title="{title}: failed"></i>'
)
@register.filter @register.filter
def bootstrap(object): def bootstrap(object):
return mark_safe("".join(bootstrap_core(object))) return mark_safe("".join(bootstrap_core(object)))
...@@ -88,7 +104,11 @@ def bootstrap_core(object): ...@@ -88,7 +104,11 @@ def bootstrap_core(object):
css_classes.add("formset-item-delete") css_classes.add("formset-item-delete")
# HACK: if the css_class is a bootstrap column layout, transfer it to container element # HACK: if the css_class is a bootstrap column layout, transfer it to container element
for css_class in css_classes: for css_class in css_classes:
if css_class.startswith("col") or css_class.startswith("order-") or css_class.startswith("mb-"): if (
css_class.startswith("col")
or css_class.startswith("order-")
or css_class.startswith("mb-")
):
wrapping_classes += f" {css_class}" wrapping_classes += f" {css_class}"
css_classes = set( css_classes = set(
[ [
......
...@@ -29,3 +29,4 @@ git+https://gitlab.pasteur.fr/hmenager/django-diu.git#egg=django_diu ...@@ -29,3 +29,4 @@ git+https://gitlab.pasteur.fr/hmenager/django-diu.git#egg=django_diu
django-crispy-forms django-crispy-forms
celery==4.4.7 celery==4.4.7
django-polymorphic django-polymorphic
boltons
...@@ -6,6 +6,7 @@ flake8-black ...@@ -6,6 +6,7 @@ flake8-black
# documentation generation # documentation generation
sphinx sphinx
sphinx_rtd_theme sphinx_rtd_theme
sphinxcontrib-bibtex
# coverage # coverage
coverage coverage
# tests # tests
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment