Skip to content

Commit a27765d

Browse files
authored
Added URL posts to register CLEM workflow files (#357)
1 parent c905b86 commit a27765d

File tree

6 files changed

+211
-101
lines changed

6 files changed

+211
-101
lines changed

src/murfey/client/contexts/clem.py

Lines changed: 168 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from datetime import datetime
88
from pathlib import Path
99
from typing import Dict, Generator, List, Optional
10+
from urllib.parse import quote
1011
from xml.etree import ElementTree as ET
1112

1213
from defusedxml.ElementTree import parse
@@ -92,11 +93,7 @@ def __init__(self, acquisition_software: str, basepath: Path):
9293
self._basepath = basepath
9394
# CLEM contexts for "auto-save" acquisition mode
9495
self._tiff_series: Dict[str, List[str]] = {} # {Series name : TIFF path list}
95-
self._tiff_timestamps: Dict[str, List[float]] = {} # {Series name : Timestamps}
96-
self._tiff_sizes: Dict[str, List[int]] = {} # {Series name : File sizes}
9796
self._series_metadata: Dict[str, str] = {} # {Series name : Metadata file path}
98-
self._metadata_timestamp: Dict[str, float] = {} # {Series name : Timestamp}
99-
self._metadata_size: Dict[str, int] = {} # {Series name : File size}
10097
self._files_in_series: Dict[str, int] = {} # {Series name : Total TIFFs}
10198

10299
def post_transfer(
@@ -128,13 +125,13 @@ def post_transfer(
128125
logger.warning(f"No source found for file {transferred_file}")
129126
return False
130127

131-
# Get the Path on the DLS file system
132-
file_path = _file_transferred_to(
128+
# Get the file Path at the destination
129+
destination_file = _file_transferred_to(
133130
environment=environment,
134131
source=source,
135132
file_path=transferred_file,
136133
)
137-
if not file_path:
134+
if not destination_file:
138135
logger.warning(
139136
f"File {transferred_file.name!r} not found on the storage system"
140137
)
@@ -167,16 +164,22 @@ def post_transfer(
167164
if len(transferred_file.stem.split("--")) == 3:
168165
series_name = "/".join(
169166
[
170-
*file_path.parent.parts[-2:], # Upper 2 parent directories
171-
file_path.stem.split("--")[0],
167+
*destination_file.parent.parts[
168+
-2:
169+
], # Upper 2 parent directories
170+
destination_file.stem.split("--")[0],
172171
]
173172
)
174173
# When this a repeated position
175174
elif len(transferred_file.stem.split("--")) == 4:
176175
series_name = "/".join(
177176
[
178-
*file_path.parent.parts[-2:], # Upper 2 parent directories
179-
"--".join(file_path.stem.split("--")[i] for i in [0, -1]),
177+
*destination_file.parent.parts[
178+
-2:
179+
], # Upper 2 parent directories
180+
"--".join(
181+
destination_file.stem.split("--")[i] for i in [0, -1]
182+
),
180183
]
181184
)
182185
else:
@@ -191,20 +194,17 @@ def post_transfer(
191194
# Create key-value pairs containing empty list if not already present
192195
if series_name not in self._tiff_series.keys():
193196
self._tiff_series[series_name] = []
194-
if series_name not in self._tiff_sizes.keys():
195-
self._tiff_sizes[series_name] = []
196-
if series_name not in self._tiff_timestamps.keys():
197-
self._tiff_timestamps[series_name] = []
198197
# Append information to list
199-
self._tiff_series[series_name].append(str(file_path))
200-
self._tiff_sizes[series_name].append(transferred_file.stat().st_size)
201-
self._tiff_timestamps[series_name].append(
202-
transferred_file.stat().st_ctime
203-
)
198+
self._tiff_series[series_name].append(str(destination_file))
204199
logger.debug(
205200
f"Created TIFF file dictionary entries for {series_name!r}"
206201
)
207202

203+
# Register the TIFF file in the database
204+
post_result = self.register_tiff_file(destination_file, environment)
205+
if post_result is False:
206+
return False
207+
208208
# Process XLIF files
209209
if transferred_file.suffix == ".xlif":
210210

@@ -230,7 +230,7 @@ def post_transfer(
230230
# XLIF files don't have the "--ZXX--CXX" additions in the file name
231231
# But they have "/Metadata/" as the immediate parent
232232
series_name = "/".join(
233-
[*file_path.parent.parent.parts[-2:], file_path.stem]
233+
[*destination_file.parent.parent.parts[-2:], destination_file.stem]
234234
) # The previous 2 parent directories should be unique enough
235235
logger.debug(
236236
f"File {transferred_file.name!r} given the series name {series_name!r}"
@@ -262,11 +262,12 @@ def post_transfer(
262262

263263
# Update dictionary entries
264264
self._files_in_series[series_name] = num_files
265-
self._series_metadata[series_name] = str(file_path)
266-
self._metadata_size[series_name] = transferred_file.stat().st_size
267-
self._metadata_timestamp[series_name] = transferred_file.stat().st_ctime
265+
self._series_metadata[series_name] = str(destination_file)
268266
logger.debug(f"Created dictionary entries for {series_name!r} metadata")
269267

268+
# A new copy of the metadata file is created in 'processed', so no need
269+
# to register this instance of it
270+
270271
# Post message if all files for the associated series have been collected
271272
# .get(series_name, 0) returns 0 if no associated key is found
272273
if not len(self._tiff_series.get(series_name, [])):
@@ -284,27 +285,16 @@ def post_transfer(
284285
f"Collected expected number of TIFF files for series {series_name!r}; posting job to server"
285286
)
286287

287-
# Construct URL for Murfey server to communicate with
288-
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/tiff_to_stack"
289-
if not url:
290-
logger.warning("No URL found for the environment")
291-
return True
292-
293288
# Post the message and log any errors that arise
294-
capture_post(
295-
url,
296-
json={
297-
"series_name": series_name,
298-
"tiff_files": self._tiff_series[series_name],
299-
"tiff_sizes": self._tiff_sizes[series_name],
300-
"tiff_timestamps": self._tiff_timestamps[series_name],
301-
"series_metadata": self._series_metadata[series_name],
302-
"metadata_size": self._metadata_size[series_name],
303-
"metadata_timestamp": self._metadata_timestamp[series_name],
304-
"description": "",
305-
},
306-
)
307-
return True
289+
tiff_dataset = {
290+
"series_name": series_name,
291+
"tiff_files": self._tiff_series[series_name],
292+
"series_metadata": self._series_metadata[series_name],
293+
}
294+
post_result = self.process_tiff_series(tiff_dataset, environment)
295+
if post_result is False:
296+
return False
297+
308298
else:
309299
logger.debug(f"TIFF series {series_name!r} is still being processed")
310300

@@ -313,42 +303,154 @@ def post_transfer(
313303
# Type checking to satisfy MyPy
314304
if not environment:
315305
logger.warning("No environment passed in")
316-
return True
306+
return False
317307

318308
# Location of the file on the client PC
319309
source = _get_source(transferred_file, environment)
320310
# Type checking to satisfy MyPy
321311
if not source:
322312
logger.warning(f"No source found for file {transferred_file}")
323-
return True
313+
return False
324314

325315
logger.debug(
326-
f"File {transferred_file.name!r} is a valid LIF file; posting job to server"
316+
f"File {transferred_file.name!r} is a valid LIF file; starting processing"
327317
)
328318

329-
# Construct the URL for the Murfey server to communicate with
330-
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/lif_to_stack"
331-
# Type checking to satisfy MyPy
332-
if not url:
333-
logger.warning("No URL found for the environment")
334-
return True
335-
336-
# Get the Path on the DLS file system
337-
file_path = _file_transferred_to(
319+
# Get the Path at the destination
320+
destination_file = _file_transferred_to(
338321
environment=environment,
339322
source=source,
340323
file_path=transferred_file,
341324
)
325+
if not destination_file:
326+
logger.warning(
327+
f"File {transferred_file.name!r} not found on the storage system"
328+
)
329+
return False
330+
331+
# Post URL to register LIF file in database
332+
post_result = self.register_lif_file(destination_file, environment)
333+
if post_result is False:
334+
return False
335+
logger.info(f"Registered {destination_file.name!r} in the database")
336+
337+
# Post URL to trigger job and convert LIF file into image stacks
338+
post_result = self.process_lif_file(destination_file, environment)
339+
if post_result is False:
340+
return False
341+
logger.info(f"Started preprocessing of {destination_file.name!r}")
342+
343+
# Function has completed as expected
344+
return True
345+
346+
def register_lif_file(
347+
self,
348+
lif_file: Path,
349+
environment: MurfeyInstanceEnvironment,
350+
):
351+
"""
352+
Constructs the URL and dictionary to be posted to the server, which will then
353+
register the LIF file in the database correctly as part of the CLEM workflow.
354+
"""
355+
try:
356+
# Construct URL to post to post the request to
357+
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/clem/lif_files?lif_file={quote(str(lif_file), safe='')}"
358+
# Validate
359+
if not url:
360+
logger.error(
361+
"URL could not be constructed from the environment and file path"
362+
)
363+
return False
364+
365+
# Send the message
366+
capture_post(url)
367+
return True
368+
369+
except Exception as e:
370+
logger.error(
371+
f"Error encountered when registering the LIF file in the database: {e}"
372+
)
373+
return False
374+
375+
def process_lif_file(
376+
self,
377+
lif_file: Path,
378+
environment: MurfeyInstanceEnvironment,
379+
):
380+
"""
381+
Constructs the URL and dictionary to be posted to the server, which will then
382+
trigger the preprocessing of the LIF file.
383+
"""
384+
385+
try:
386+
# Construct the URL to post the request to
387+
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/lif_to_stack?lif_file={quote(str(lif_file), safe='')}"
388+
# Validate
389+
if not url:
390+
logger.error(
391+
"URL could not be constructed from the environment and file path"
392+
)
393+
return False
394+
395+
# Send the message
396+
capture_post(url)
397+
return True
398+
399+
except Exception as e:
400+
logger.error(f"Error encountered processing LIF file: {e}")
401+
return False
342402

343-
# Post the message and logs it if there's an error
344-
capture_post(
345-
url,
346-
json={
347-
"name": str(file_path),
348-
"size": transferred_file.stat().st_size, # File size, in bytes
349-
"timestamp": transferred_file.stat().st_ctime, # For Unix systems, shows last metadata change
350-
"description": "",
351-
},
403+
def register_tiff_file(
404+
self,
405+
tiff_file: Path,
406+
environment: MurfeyInstanceEnvironment,
407+
):
408+
"""
409+
Constructs the URL and dictionary to be posted to the server, which will then
410+
register the TIFF file in the database correctly as part of the CLEM workflow.
411+
"""
412+
413+
try:
414+
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/clem/tiff_files?tiff_file={quote(str(tiff_file), safe='')}"
415+
if not url:
416+
logger.error(
417+
"URL could not be constructed from the environment and file path"
418+
)
419+
return False
420+
421+
# Send the message
422+
capture_post(url)
423+
return True
424+
425+
except Exception as e:
426+
logger.error(
427+
f"Error encountered when registering the TIFF file in the database: {e}"
352428
)
429+
return False
430+
431+
def process_tiff_series(
432+
self,
433+
tiff_dataset: dict,
434+
environment: MurfeyInstanceEnvironment,
435+
):
436+
"""
437+
Constructs the URL and dictionary to be posted to the server, which will then
438+
trigger the preprocessing of this instance of a TIFF series.
439+
"""
440+
441+
try:
442+
# Construct URL for Murfey server to communicate with
443+
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/tiff_to_stack"
444+
if not url:
445+
logger.error(
446+
"URL could not be constructed from the environment and file path"
447+
)
448+
return False
449+
450+
# Send the message
451+
capture_post(url, json=tiff_dataset)
353452
return True
354-
return True
453+
454+
except Exception as e:
455+
logger.error(f"Error encountered processing the TIFF series: {e}")
456+
return False

0 commit comments

Comments
 (0)