Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7b50bb6
Used Optional[] as type hint for Python 3.9 compatibility
tieneupin Oct 2, 2024
e796663
Raise Exception if no TransportManager instance is found when running…
tieneupin Oct 2, 2024
0167f96
Corrected database call in 'validate_and_sanitise' function; simplifi…
tieneupin Oct 2, 2024
6dac704
Added functions to post requests to the server to register LIF and TI…
tieneupin Oct 2, 2024
bbd3e29
Used Path object to resolve file path in 'validate_and_sanitise'; add…
tieneupin Oct 3, 2024
b6a4297
Corrected returned booleans at the end of different workflow branches
tieneupin Oct 9, 2024
9d03fa2
Corrected inconsistent returns and raises in functions
tieneupin Oct 9, 2024
dadb02d
Simplified CLEM BaseModels and updated CLEMContext file handling logi…
tieneupin Oct 9, 2024
c69a22f
Allow forward slashes in series name when validating input
tieneupin Oct 9, 2024
276ee54
Added folder to store module feedback callback workflows in
tieneupin Oct 10, 2024
f6fd56d
Added feedback callback elif-blocks for CLEM workflows
tieneupin Oct 10, 2024
5ef7218
Updated 'lif_to_stack' API endpoint to load and pass on more information
tieneupin Oct 10, 2024
d29b8ed
Updated 'lif_to_stack' workflow to handle additional zocalo wrapper p…
tieneupin Oct 10, 2024
398b09e
Notes on how 'feedback_callback' works
tieneupin Oct 30, 2024
7820501
Constructed parameters from file path; updated parameter names
tieneupin Oct 30, 2024
51c528c
Fixed comments
tieneupin Oct 30, 2024
2d6d367
Removed 'instrument_name' parameter from murfey.server.murfey_db
tieneupin Oct 31, 2024
e8447e0
Refactored CLEM Murfey workflows
tieneupin Nov 1, 2024
c4bdfc7
Missed deleting the old file
tieneupin Nov 1, 2024
a01a786
Updated TIFF Pydantic model
tieneupin Nov 1, 2024
185158f
Added Pydantic models to validate LIF and TIFF preprocessing result m…
tieneupin Nov 1, 2024
ad9a489
Changed 'color' to the more generic 'channel'
tieneupin Nov 1, 2024
c9ffa31
Refactored functions to parse CLEM preprocessing results and started …
tieneupin Nov 1, 2024
c3c78a0
Completed draft of function to register LIF preprocessing results
tieneupin Nov 4, 2024
f9858ee
Added 'number_of_members' as a parameter to register for a series
tieneupin Nov 4, 2024
ecf6d38
Added 'return None' to CLEM results registration code blocks
tieneupin Nov 4, 2024
a132b86
Merged recent changes from 'main' branch
tieneupin Nov 4, 2024
f7681c9
Rewrote 'tiff_to_stack' function to work with Zocalo wrapper
tieneupin Nov 4, 2024
480a7e4
Modified URLs for CLEM preprocesisng API endpoints
tieneupin Nov 4, 2024
09e85cc
Stringified TIFF list when submitting to cluster
tieneupin Nov 4, 2024
3cd3344
Ensured file paths in recipes are represented canonically
tieneupin Nov 4, 2024
816d434
Adjusted order of parameters
tieneupin Nov 4, 2024
8576eb1
Canonicalisation of strings appears to not be needed when submitting …
tieneupin Nov 4, 2024
4e5b202
Fixed outdated parameters to pass over to 'tiff_to_stack' workflow
tieneupin Nov 5, 2024
fbc9fe5
Fixed broken database refreshes and updated logged messages
tieneupin Nov 6, 2024
8bcd8c0
Updated 'TIFFPreprocessingResult' Pydantic model to parse stringified…
tieneupin Nov 6, 2024
2cc5624
Completed function to register TIFF preprocessing results
tieneupin Nov 6, 2024
0811cba
Missed a return statement in 'except' block
tieneupin Nov 6, 2024
3fd77b4
Rewrote CLEM preprocessing results registration workflows to make use…
tieneupin Nov 6, 2024
93c08ea
Adjusted naming convention for LIF and TIFF processing functions and …
tieneupin Nov 6, 2024
9cd58ff
Replaced 'row' with 'session_row' to make variable more explicit
tieneupin Nov 7, 2024
befd420
Rewrote function to iterate over entry point names and run the match
tieneupin Nov 7, 2024
5397c0e
Missed a print statement
tieneupin Nov 7, 2024
fa6c5c8
Reverted entry point group name to 'murfey.workflows' to facilitate g…
tieneupin Nov 7, 2024
1a0057b
Optimised code logic for LIF and TIFF processing API endpoints
tieneupin Nov 7, 2024
feade10
Added 'requeue=False' argument when nacking message
tieneupin Nov 7, 2024
36efb6f
Fixed logic when reading rsync base path from machine config
tieneupin Nov 7, 2024
aafc518
Used 'entry_points' from 'backports.entry_points_selectable' instead
tieneupin Nov 8, 2024
cb1a570
Used 'entry_points' instance from 'backports.entry_points_selectable'…
tieneupin Nov 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,10 @@ murfey = "murfey.client:run"
[project.entry-points."murfey.config.extraction"]
"murfey_machine" = "murfey.util.config:get_extended_machine_config"
[project.entry-points."murfey.workflows"]
"lif_to_stack" = "murfey.workflows.lif_to_stack:zocalo_cluster_request"
"tiff_to_stack" = "murfey.workflows.tiff_to_stack:zocalo_cluster_request"
"process_raw_lifs" = "murfey.workflows.clem.process_raw_lifs:zocalo_cluster_request"
"process_raw_tiffs" = "murfey.workflows.clem.process_raw_tiffs:zocalo_cluster_request"
"register_lif_preprocessing_result" = "murfey.workflows.clem.register_preprocessing_results:register_lif_preprocessing_result"
"register_tiff_preprocessing_result" = "murfey.workflows.clem.register_preprocessing_results:register_tiff_preprocessing_result"

[tool.setuptools]
package-dir = {"" = "src"}
Expand Down
4 changes: 2 additions & 2 deletions src/murfey/client/contexts/clem.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@

try:
# Construct the URL to post the request to
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/lif_to_stack?lif_file={quote(str(lif_file), safe='')}"
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/clem/preprocessing/process_raw_lifs?lif_file={quote(str(lif_file), safe='')}"

Check warning on line 389 in src/murfey/client/contexts/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/client/contexts/clem.py#L389

Added line #L389 was not covered by tests
# Validate
if not url:
logger.error(
Expand Down Expand Up @@ -442,7 +442,7 @@

try:
# Construct URL for Murfey server to communicate with
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/tiff_to_stack"
url = f"{str(environment.url.geturl())}/sessions/{environment.murfey_session}/clem/preprocessing/process_raw_tiffs"

Check warning on line 445 in src/murfey/client/contexts/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/client/contexts/clem.py#L445

Added line #L445 was not covered by tests
if not url:
logger.error(
"URL could not be constructed from the environment and file path"
Expand Down
23 changes: 23 additions & 0 deletions src/murfey/server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
from murfey.server.ispyb import TransportManager # Session
except AttributeError:
pass
from backports.entry_points_selectable import entry_points
from importlib_metadata import EntryPoint # For type hinting only

import murfey.util.db as db
from murfey.util import LogFilter
from murfey.util.spa_params import default_spa_parameters
Expand Down Expand Up @@ -2964,6 +2967,26 @@
if _transport_object:
_transport_object.transport.ack(header)
return None
elif (
message["register"] in entry_points().select(group="murfey.workflows").names
):
# Run the workflow if a match is found
workflow: EntryPoint = list( # Returns a list of either 1 or 0

Check warning on line 2974 in src/murfey/server/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/__init__.py#L2974

Added line #L2974 was not covered by tests
entry_points().select(
group="murfey.workflows", name=message["register"]
)
)[0]
result = workflow.load()(

Check warning on line 2979 in src/murfey/server/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/__init__.py#L2979

Added line #L2979 was not covered by tests
message=message,
db=murfey_db,
)
if _transport_object:
if result:
_transport_object.transport.ack(header)

Check warning on line 2985 in src/murfey/server/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/__init__.py#L2985

Added line #L2985 was not covered by tests
else:
# Send it directly to DLQ without trying to rerun it
_transport_object.transport.nack(header, requeue=False)
return None

Check warning on line 2989 in src/murfey/server/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/__init__.py#L2988-L2989

Added lines #L2988 - L2989 were not covered by tests
if _transport_object:
_transport_object.transport.nack(header, requeue=False)
return None
Expand Down
128 changes: 66 additions & 62 deletions src/murfey/server/api/clem.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from __future__ import annotations

import re
import sys
import traceback
from importlib.metadata import EntryPoint # type hinting only
from logging import getLogger
from pathlib import Path
from typing import Optional, Type, Union

from backports.entry_points_selectable import entry_points
from fastapi import APIRouter
from sqlalchemy.exc import NoResultFound
from sqlmodel import Session, select
Expand All @@ -22,13 +23,7 @@
CLEMTIFFFile,
)
from murfey.util.db import Session as MurfeySession
from murfey.util.models import TiffSeriesInfo

# Use backport from importlib_metadata for Python <3.10
if sys.version_info.major == 3 and sys.version_info.minor < 10:
from importlib_metadata import EntryPoint, entry_points
else:
from importlib.metadata import EntryPoint, entry_points
from murfey.util.models import TIFFSeriesInfo

# Set up logger
logger = getLogger("murfey.server.api.clem")
Expand Down Expand Up @@ -81,23 +76,15 @@
machine_config = get_machine_config(instrument_name=instrument_name)[
instrument_name
]
rsync_basepath = machine_config.rsync_basepath
try:
base_path = list(rsync_basepath.parents)[-2].as_posix()
except IndexError:
# Print to troubleshoot
logger.warning(f"Base path {rsync_basepath!r} is too short")
base_path = rsync_basepath.as_posix()
except Exception:
raise Exception("Unexpected exception occurred when loading the file base path")
base_path = machine_config.rsync_basepath.as_posix()

Check warning on line 79 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L79

Added line #L79 was not covered by tests

# Check that full file path doesn't contain unallowed characters
# Currently allows only:
# - words (alphanumerics and "_"; \w),
# - spaces (\s),
# - periods,
# - dashes,
# - forward slashes ("/")
# Currently allows only:
# - words (alphanumerics and "_"; \w),
# - spaces (\s),
# - periods,
# - dashes,
# - forward slashes ("/")
if bool(re.fullmatch(r"^[\w\s\.\-/]+$", str(full_path))) is False:
raise ValueError(f"Unallowed characters present in {file}")

Expand Down Expand Up @@ -631,51 +618,68 @@
"""


@router.post("/sessions/{session_id}/lif_to_stack") # API posts to this URL
def lif_to_stack(
@router.post(
"/sessions/{session_id}/clem/preprocessing/process_raw_lifs"
) # API posts to this URL
def process_raw_lifs(
session_id: int, # Used by the decorator
lif_file: Path,
db: Session = murfey_db,
):
# Get command line entry point
murfey_workflows = entry_points().select(
group="murfey.workflows", name="lif_to_stack"
)

# Use entry point if found
if len(murfey_workflows) == 1:
workflow: EntryPoint = list(murfey_workflows)[0]
workflow.load()(
# Match the arguments found in murfey.workflows.lif_to_stack
file=lif_file,
root_folder="images",
messenger=_transport_object,
)
return True
# Raise error if Murfey workflow not found
else:
try:

Check warning on line 629 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L629

Added line #L629 was not covered by tests
# Try and load relevant Murfey workflow
workflow: EntryPoint = list(

Check warning on line 631 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L631

Added line #L631 was not covered by tests
entry_points().select(group="murfey.workflows", name="process_raw_lifs")
)[0]
except IndexError:

Check warning on line 634 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L634

Added line #L634 was not covered by tests
raise RuntimeError("The relevant Murfey workflow was not found")

# Get instrument name from the database to load the correct config file
session_row: MurfeySession = db.exec(

Check warning on line 638 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L638

Added line #L638 was not covered by tests
select(MurfeySession).where(MurfeySession.id == session_id)
).one()
instrument_name = session_row.instrument_name

Check warning on line 641 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L641

Added line #L641 was not covered by tests

# Pass arguments along to the correct workflow
workflow.load()(

Check warning on line 644 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L644

Added line #L644 was not covered by tests
# Match the arguments found in murfey.workflows.clem.process_raw_lifs
file=lif_file,
root_folder="images",
session_id=session_id,
instrument_name=instrument_name,
messenger=_transport_object,
)
return True

Check warning on line 652 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L652

Added line #L652 was not covered by tests


@router.post("/sessions/{session_id}/tiff_to_stack")
def tiff_to_stack(
@router.post("/sessions/{session_id}/clem/preprocessing/process_raw_tiffs")
def process_raw_tiffs(
session_id: int, # Used by the decorator
tiff_info: TiffSeriesInfo,
tiff_info: TIFFSeriesInfo,
db: Session = murfey_db,
):
# Get command line entry point
murfey_workflows = entry_points().select(
group="murfey.workflows", name="tiff_to_stack"
)

# Use entry point if found
if murfey_workflows:
workflow: EntryPoint = list(murfey_workflows)[0]
workflow.load()(
# Match the arguments found in murfey.workflows.tiff_to_stack
file=tiff_info.tiff_files[0], # Pass it only one file from the list
root_folder="images",
metadata=tiff_info.series_metadata,
messenger=_transport_object,
)
# Raise error if Murfey workflow not found
else:
try:

Check warning on line 661 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L661

Added line #L661 was not covered by tests
# Try and load relevant Murfey workflow
workflow: EntryPoint = list(

Check warning on line 663 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L663

Added line #L663 was not covered by tests
entry_points().select(group="murfey.workflows", name="process_raw_tiffs")
)[0]
except IndexError:

Check warning on line 666 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L666

Added line #L666 was not covered by tests
raise RuntimeError("The relevant Murfey workflow was not found")

# Get instrument name from the database to load the correct config file
session_row: MurfeySession = db.exec(

Check warning on line 670 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L670

Added line #L670 was not covered by tests
select(MurfeySession).where(MurfeySession.id == session_id)
).one()
instrument_name = session_row.instrument_name

Check warning on line 673 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L673

Added line #L673 was not covered by tests

# Pass arguments to correct workflow
workflow.load()(

Check warning on line 676 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L676

Added line #L676 was not covered by tests
# Match the arguments found in murfey.workflows.clem.process_raw_tiffs
tiff_list=tiff_info.tiff_files,
root_folder="images",
session_id=session_id,
instrument_name=instrument_name,
metadata=tiff_info.series_metadata,
messenger=_transport_object,
)
return True

Check warning on line 685 in src/murfey/server/api/clem.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/server/api/clem.py#L685

Added line #L685 was not covered by tests
3 changes: 0 additions & 3 deletions src/murfey/server/murfey_db.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import os
from functools import partial

import yaml
Expand All @@ -11,8 +10,6 @@

from murfey.util.config import Security, get_security_config

instrument_name = os.getenv("BEAMLINE", "")


def url(security_config: Security | None = None) -> str:
security_config = security_config or get_security_config()
Expand Down
9 changes: 6 additions & 3 deletions src/murfey/util/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,12 @@ class CLEMImageSeries(SQLModel, table=True): # type: ignore
) # One to many

# Process checklist for series
images_aligned: bool = False # Image stacks aligned to reference image
rgbs_created: bool = False # Image stacks all colorised
composite_created: bool = False # Composite flattened image created
number_of_members: int = (
0 # Expected number of image stacks belonging to this series
)
images_aligned: bool = False # Have all members been aligned?
rgbs_created: bool = False # Have all members been colourised?
composite_created: bool = False # Has a composite image been created?
composite_image: Optional[str] = None # Full path to composite image


Expand Down
39 changes: 37 additions & 2 deletions src/murfey/util/models.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import annotations

from ast import literal_eval
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

from pydantic import BaseModel
from pydantic import BaseModel, validator

"""
General Models
Expand Down Expand Up @@ -154,12 +155,46 @@
"""


class TiffSeriesInfo(BaseModel):
class TIFFSeriesInfo(BaseModel):
series_name: str
tiff_files: List[Path]
series_metadata: Path


class LIFPreprocessingResult(BaseModel):
image_stack: Path
metadata: Path
series_name: str
channel: str
number_of_members: int
parent_lif: Path


class TIFFPreprocessingResult(BaseModel):
image_stack: Path
metadata: Path
series_name: str
channel: str
number_of_members: int
parent_tiffs: list[Path]

@validator(
"parent_tiffs",
pre=True,
)
def parse_stringified_list(cls, value):
if isinstance(value, str):
try:
eval_result = literal_eval(value)

Check warning on line 188 in src/murfey/util/models.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/util/models.py#L187-L188

Added lines #L187 - L188 were not covered by tests
if isinstance(eval_result, list):
parent_tiffs = [Path(p) for p in eval_result]
return parent_tiffs
except (SyntaxError, ValueError):
raise ValueError("Unable to parse input")

Check warning on line 193 in src/murfey/util/models.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/util/models.py#L190-L193

Added lines #L190 - L193 were not covered by tests
# Return value as-is; if it fails, it fails
return value

Check warning on line 195 in src/murfey/util/models.py

View check run for this annotation

Codecov / codecov/patch

src/murfey/util/models.py#L195

Added line #L195 was not covered by tests


"""
FIB
===
Expand Down
Empty file.
Loading