Skip to content

Commit e45675f

Browse files
alanbchristiekaliifWaztomAlan Christiedependabot[bot]
authored
Merge staging changes down to production (#543)
* Some changes to cset_upload.py to allow site observation short codes (#527) * stashing * fix: cset_upload.py updated to allow new-style site observation codes NB! this probably still won't work! I suspect the file I was given is broken and I cannot test it further * stashing * stashing * Short code prefix and tooltip to backend Target loader now reads short code prefix and tooltip from meta_aligner.yaml. Tooltip is saved to Experiment model. TODO: make tooltip available via API * Prefix tooltip now serverd by api/site_observation * stashing * Site observation groups for shortcodes now by experiment * feat: download structure fixed TODO: add all the yamls * All yaml files added to download * New format to download zip (issue 1326) (#530) * stashing * stashing * feat: download structure fixed TODO: add all the yamls * All yaml files added to download * cset_upload.py: lhs_pdb renamed to ref_pdb * Renamed canon- and conf site tags * Adds support for key-based SSH connections (#534) * Centralised environment variables (#529) * refactor: Restructured settings.py * docs: Minor tweaks * refactor: Move security and infection config to settings * refactor: b/e & f/e/ tags now in settings (also fixed f/e tag value) * refactor: Move Neo4j config to settings * refactor: More variables into settings * refactor: Moved remaining config * docs: Adds configuration guide as comments * docs: Variable prefix now 'stack_' not 'stack_env_' --------- Co-authored-by: Alan Christie <alan.christie@matildapeak.com> * feat: Adds support for private keys on SSH tunnel * fix: Fixes key-based logic --------- Co-authored-by: Alan Christie <alan.christie@matildapeak.com> * build(deps): bump cryptography from 42.0.0 to 42.0.2 (#533) Bumps [cryptography](https://github.com/pyca/cryptography) from 42.0.0 to 42.0.2. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](pyca/cryptography@42.0.0...42.0.2) --- updated-dependencies: - dependency-name: cryptography dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: Updates documentation (#536) Co-authored-by: Alan Christie <alan.christie@matildapeak.com> * build(deps): bump django from 3.2.20 to 3.2.24 (#535) Bumps [django](https://github.com/django/django) from 3.2.20 to 3.2.24. - [Commits](django/django@3.2.20...3.2.24) --- updated-dependencies: - dependency-name: django dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: reverting wrong changes * fix: reverting wrong changes (#538) * stashing * add site observation's ligand sdf to aligned_files * fix: custom pdb now downloadable * fix: increased loglevel to error on unexpected exceptions block * fix: Discourse service check now checks API key before creating a service (#544) Co-authored-by: Alan Christie <alan.christie@matildapeak.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Kalev Takkis <ktakkis@informaticsmatters.com> Co-authored-by: Warren Thompson <waztom@gmail.com> Co-authored-by: Alan Christie <alan.christie@matildapeak.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 0e3a9d6 commit e45675f

10 files changed

+222
-190
lines changed

media_serve/urls.py

+3
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@
1111
re_path(
1212
r"^target_loader_data/(?P<file_path>.+)", views.tld_download, name="get_tld"
1313
),
14+
re_path(
15+
r"^computed_set_data/(?P<file_path>.+)", views.cspdb_download, name="get_cspdb"
16+
),
1417
re_path(r"^pdbs/(?P<file_path>.+)", views.file_download, name="get_file"),
1518
]

media_serve/views.py

+22-4
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,35 @@ def tld_download(request, file_path):
7373
ispy_b_static.permission_string = (
7474
"experiment__experiment_upload__target__project_id"
7575
)
76-
# ispy_b_static.field_name = "pdb_info"
7776
ispy_b_static.field_name = "apo_file"
7877
ispy_b_static.content_type = "application/x-pilot"
79-
# ispy_b_static.prefix = "target_loader_data/48225dbf-204a-48e1-8ae7-f1632f4dba89/Mpro-v2/Mpro/upload_2/aligned_files/Mpro_Nterm-x0029/"
80-
# ispy_b_static.prefix = "target_loader_data"
81-
# ispy_b_static.prefix = "/target_loader_data/"
8278
ispy_b_static.prefix = "/target_loader_data/"
8379
ispy_b_static.input_string = file_path
8480
return ispy_b_static.get_response()
8581

8682

83+
def cspdb_download(request, file_path):
84+
"""
85+
Download a protein by nginx redirect
86+
:param request: the initial request
87+
:param file_path: the file path we're getting from the static
88+
:return: the response (a redirect to nginx internal)
89+
"""
90+
logger.info("+ Received cspdb_download file path: %s", file_path)
91+
ispy_b_static = ISpyBSafeStaticFiles2()
92+
ispy_b_static.model = SiteObservation
93+
ispy_b_static.request = request
94+
# the following 2 aren't used atm
95+
ispy_b_static.permission_string = (
96+
"experiment__experiment_upload__target__project_id"
97+
)
98+
ispy_b_static.field_name = "apo_file"
99+
ispy_b_static.content_type = "application/x-pilot"
100+
ispy_b_static.prefix = "/computed_set_data/"
101+
ispy_b_static.input_string = file_path
102+
return ispy_b_static.get_response()
103+
104+
87105
def bound_download(request, file_path):
88106
"""
89107
Download a protein by nginx redirect

viewer/cset_upload.py

+86-102
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
import datetime
33
import logging
44
import os
5-
import shutil
65
import uuid
76
import zipfile
7+
from pathlib import Path
88
from typing import Any, Dict, List, Optional, Tuple
99

1010
from openpyxl.utils import get_column_letter
@@ -142,37 +142,31 @@ def __init__(
142142
self.zfile = zfile
143143
self.zfile_hashvals = zfile_hashvals
144144

145-
def process_pdb(self, pdb_code, target, zfile, zfile_hashvals) -> SiteObservation:
145+
def process_pdb(self, pdb_code, zfile, zfile_hashvals) -> str | None:
146146
for key in zfile_hashvals.keys():
147147
if key == pdb_code:
148148
pdb_code = f'{pdb_code}#{zfile_hashvals[pdb_code]}'
149149

150-
pdb_fp = zfile[pdb_code]
151-
pdb_fn = zfile[pdb_code].split('/')[-1]
150+
try:
151+
pdb_fp = zfile[pdb_code]
152+
except KeyError:
153+
return None
152154

153-
new_filename = f'{settings.MEDIA_ROOT}pdbs/{pdb_fn}'
154-
old_filename = settings.MEDIA_ROOT + pdb_fp
155-
shutil.copy(old_filename, new_filename)
155+
# ensure filename uniqueness
156+
pdb_fn = '_'.join([zfile[pdb_code].split('/')[-1], uuid.uuid4().hex])
157+
pdb_field = Path(settings.COMPUTED_SET_MEDIA_DIRECTORY).joinpath(pdb_fn)
156158

157-
# Create Protein object
158-
target_obj = Target.objects.get(title=target)
159-
# prot.target_id = target_obj
160-
site_obvs, created = SiteObservation.objects.get_or_create(
161-
code=pdb_code, target_id=target_obj
162-
)
163-
# prot.code = pdb_code
164-
if created:
165-
target_obj = Target.objects.get(title=target)
166-
site_obvs.target_id = target_obj
167-
site_obvs.pdb_info = f'pdbs/{pdb_fn}'
168-
site_obvs.save()
159+
new_filename = Path(settings.MEDIA_ROOT).joinpath(pdb_field)
160+
old_filename = Path(settings.MEDIA_ROOT).joinpath(pdb_fp)
161+
old_filename.rename(new_filename)
162+
os.chmod(new_filename, 0o755)
169163

170-
return site_obvs
164+
return str(pdb_field)
171165

172166
# use zfile object for pdb files uploaded in zip
173167
def get_site_observation(
174168
self, property_name, mol, target, compound_set, zfile, zfile_hashvals
175-
) -> Optional[SiteObservation]:
169+
) -> SiteObservation | str | None:
176170
# Get a SiteObservation from the molecule using
177171
# a named property (i.e. lhs_pdb or ref_pdb for example)
178172

@@ -187,61 +181,69 @@ def get_site_observation(
187181
return None
188182

189183
pdb_fn = mol.GetProp(property_name).split('/')[-1]
190-
site_obvs = None
191184

192185
if zfile:
186+
# pdb archive uploaded. referenced pdb file may or may not be included
193187
pdb_code = pdb_fn.replace('.pdb', '')
194-
site_obvs = self.process_pdb(
188+
pdb_file = self.process_pdb(
195189
pdb_code=pdb_code,
196-
target=target,
197190
zfile=zfile,
198191
zfile_hashvals=zfile_hashvals,
199192
)
200-
else:
201-
name = pdb_fn
202-
try:
203-
site_obvs = SiteObservation.objects.get(
204-
code__contains=name,
205-
experiment__experiment_upload__target__title=target,
193+
if pdb_file:
194+
return pdb_file
195+
else:
196+
logger.info(
197+
'No protein pdb (%s) found in zipfile',
198+
pdb_fn,
206199
)
207-
except SiteObservation.DoesNotExist:
208-
# Initial SiteObservation lookup failed.
209-
logger.warning(
210-
'Failed to get SiteObservation object (target=%s name=%s)',
211-
compound_set.target.title,
200+
201+
# pdb was not included, try to find the matching site observation
202+
name = pdb_fn
203+
site_obvs = None
204+
try:
205+
site_obvs = SiteObservation.objects.get(
206+
code__contains=name,
207+
experiment__experiment_upload__target__title=target,
208+
)
209+
except SiteObservation.DoesNotExist:
210+
# Initial SiteObservation lookup failed.
211+
logger.warning(
212+
'Failed to get SiteObservation object (target=%s name=%s)',
213+
compound_set.target.title,
214+
name,
215+
)
216+
# Try alternatives.
217+
# If all else fails then the site_obvs will be 'None'
218+
qs = SiteObservation.objects.filter(
219+
code__contains=name,
220+
experiment__experiment_upload__target__title=target,
221+
)
222+
if qs.exists():
223+
logger.info(
224+
'Found SiteObservation containing name=%s qs=%s',
212225
name,
226+
qs,
213227
)
214-
# Try alternatives.
215-
# If all else fails then the site_obvs will be 'None'
228+
else:
229+
alt_name = name.split(':')[0].split('_')[0]
216230
qs = SiteObservation.objects.filter(
217-
code__contains=name,
231+
code__contains=alt_name,
218232
experiment__experiment_upload__target__title=target,
219233
)
220234
if qs.exists():
221235
logger.info(
222-
'Found SiteObservation containing name=%s qs=%s',
223-
name,
236+
'Found SiteObservation containing alternative name=%s qs=%s',
237+
alt_name,
224238
qs,
225239
)
226-
else:
227-
alt_name = name.split(':')[0].split('_')[0]
228-
qs = SiteObservation.objects.filter(
229-
code__contains=alt_name,
230-
experiment__experiment_upload__target__title=target,
231-
)
232-
if qs.exists():
233-
logger.info(
234-
'Found SiteObservation containing alternative name=%s qs=%s',
235-
alt_name,
236-
qs,
237-
)
238-
if qs.count() > 0:
239-
logger.debug(
240-
'Found alternative (target=%s name=%s)',
241-
compound_set.target.title,
242-
name,
243-
)
244-
site_obvs = qs[0]
240+
if qs.count() > 0:
241+
logger.debug(
242+
'Found alternative (target=%s name=%s)',
243+
compound_set.target.title,
244+
name,
245+
)
246+
site_obvs = qs[0]
245247

246248
if not site_obvs:
247249
logger.warning(
@@ -360,31 +362,10 @@ def set_mol(
360362

361363
insp_frags.append(ref)
362364

363-
# Try to get the LHS SiteObservation,
364-
# This will be used to set the ComputedMolecule.site_observation_code.
365-
# This may fail.
366-
lhs_property = 'ref_pdb'
367-
lhs_so = self.get_site_observation(
368-
lhs_property,
369-
mol,
370-
target,
371-
compound_set,
372-
zfile,
373-
zfile_hashvals=zfile_hashvals,
374-
)
375-
if not lhs_so:
376-
logger.warning(
377-
'Failed to get a LHS SiteObservation (%s) for %s, %s, %s',
378-
lhs_property,
379-
mol,
380-
target,
381-
compound_set,
382-
)
383-
384-
# Try to get the reference SiteObservation,
385-
# This will be used to set the ComputedMolecule.reference_code.
386-
# This may fail.
387365
ref_property = 'ref_pdb'
366+
# data in ref ref_pdb field may be one of 2 things:
367+
# - siteobservation's short code (code field)
368+
# - pdb file in uploaded zipfile
388369
ref_so = self.get_site_observation(
389370
ref_property,
390371
mol,
@@ -402,15 +383,6 @@ def set_mol(
402383
compound_set,
403384
)
404385

405-
# A LHS or Reference protein must be provided.
406-
# (Part of "Fix behaviour of RHS [P] button - also RHS upload change", issue #1249)
407-
if not lhs_so and not ref_so:
408-
logger.error(
409-
'ComputedMolecule has no LHS (%s) or Reference (%s) property',
410-
lhs_property,
411-
ref_property,
412-
)
413-
414386
# Need a ComputedMolecule before saving.
415387
# Check if anything exists already...
416388
existing_computed_molecules = ComputedMolecule.objects.filter(
@@ -433,15 +405,27 @@ def set_mol(
433405
logger.info('Creating new ComputedMolecule')
434406
computed_molecule = ComputedMolecule()
435407

408+
if isinstance(ref_so, SiteObservation):
409+
code = ref_so.code
410+
pdb_info = ref_so.experiment.pdb_info
411+
lhs_so = ref_so
412+
else:
413+
code = None
414+
pdb_info = ref_so
415+
lhs_so = None
416+
436417
assert computed_molecule
437418
computed_molecule.compound = compound
438419
computed_molecule.computed_set = compound_set
439420
computed_molecule.sdf_info = Chem.MolToMolBlock(mol)
440-
computed_molecule.site_observation_code = lhs_so.code if lhs_so else None
441-
computed_molecule.reference_code = ref_so.code if ref_so else None
421+
computed_molecule.site_observation_code = code
422+
computed_molecule.reference_code = code
442423
computed_molecule.molecule_name = molecule_name
443424
computed_molecule.name = f"{target}-{computed_molecule.identifier}"
444425
computed_molecule.smiles = smiles
426+
computed_molecule.pdb = lhs_so
427+
# TODO: this is wrong
428+
computed_molecule.pdb_info = pdb_info
445429
# Extract possible reference URL and Rationale
446430
# URLs have to be valid URLs and rationals must contain more than one word
447431
ref_url: Optional[str] = (
@@ -591,6 +575,14 @@ def task(self) -> ComputedSet:
591575
assert settings.AUTHENTICATE_UPLOAD is False
592576
computed_set.save()
593577

578+
# check compound set folder exists.
579+
cmp_set_folder = os.path.join(
580+
settings.MEDIA_ROOT, settings.COMPUTED_SET_MEDIA_DIRECTORY
581+
)
582+
if not os.path.isdir(cmp_set_folder):
583+
logger.info('Making ComputedSet folder (%s)', cmp_set_folder)
584+
os.mkdir(cmp_set_folder)
585+
594586
# Set descriptions in return for the Molecules.
595587
# This also sets the submitter and method URL properties of the computed set
596588
# while also saving it.
@@ -611,14 +603,6 @@ def task(self) -> ComputedSet:
611603
self.zfile_hashvals,
612604
)
613605

614-
# check compound set folder exists.
615-
cmp_set_folder = os.path.join(
616-
settings.MEDIA_ROOT, settings.COMPUTED_SET_MEDIA_DIRECTORY
617-
)
618-
if not os.path.isdir(cmp_set_folder):
619-
logger.info('Making ComputedSet folder (%s)', cmp_set_folder)
620-
os.mkdir(cmp_set_folder)
621-
622606
# move and save the compound set
623607
new_filename = f'{settings.MEDIA_ROOT}{settings.COMPUTED_SET_MEDIA_DIRECTORY}/{computed_set.name}.sdf'
624608
os.rename(sdf_filename, new_filename)

0 commit comments

Comments
 (0)