Skip to content

Commit

Permalink
Release v1.8.1
Browse files Browse the repository at this point in the history
  • Loading branch information
gfrn committed Sep 23, 2024
1 parent b374a2e commit 403784a
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 39 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
Changelog
==========

+++++++++
v1.8.1 (23/09/2024)
+++++++++

**Changed**

- Semgented/denoised tomogram images are now sourced from the `ProcessedTomogram` table

+++++++++
v1.8.0 (28/08/2024)
+++++++++
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# The devcontainer should use the build target and run as root with podman
# or docker with user namespaces.
#
FROM docker.io/library/python:3.12.4-slim-bookworm as build
FROM docker.io/library/python:3.12.5-slim-bookworm as build

# Add any system dependencies for the developer/build environment here
RUN apt-get update && apt-get upgrade -y && \
Expand All @@ -12,6 +12,7 @@ RUN apt-get update && apt-get upgrade -y && \
busybox \
git \
libmariadb-dev \
pkg-config \
net-tools \
&& rm -rf /var/lib/apt/lists/* \
&& busybox --install
Expand Down Expand Up @@ -39,7 +40,7 @@ RUN pip install --upgrade pip && \
# and replace with a comment to avoid a zero length asset upload later
sed -i '/file:/s/^/# Requirements for /' lockfiles/requirements.txt

FROM docker.io/library/python:3.12.1-slim-bullseye as runtime
FROM docker.io/library/python:3.12.5-slim-bookworm as runtime

# Add apt-get system dependecies for runtime here if needed
RUN apt-get update && apt-get install -y libmariadb-dev
Expand Down
11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ description = "PATO's backend"
dependencies = [
"python-multipart~=0.0.9",
"pika~=1.3.2",
"SQLAlchemy~=2.0.31",
"fastapi~=0.111.0",
"SQLAlchemy~=2.0.34",
"fastapi~=0.112.2",
"uvicorn[standard]~=0.30.1",
"requests~=2.32.3",
"mysqlclient~=2.1.1",
"mysqlclient~=2.2.4",
"mysql-connector-python~=8.2.0",
"pydantic~=2.5.3",
"pydantic~=2.8.2",
"types-requests",
"lims-utils~=0.2.2"
"lims-utils~=0.2.3"
]
dynamic = ["version"]
license.file = "LICENSE"
Expand Down Expand Up @@ -61,6 +61,7 @@ name = "Guilherme de Freitas"

[tool.setuptools_scm]
write_to = "src/pato/_version.py"
fallback_version = "1.9.0"

[tool.mypy]
ignore_missing_imports = true # Ignore missing stubs in imported modules
Expand Down
1 change: 0 additions & 1 deletion src/pato/crud/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def get_collection_groups(
search: Optional[str],
user: GenericUser,
) -> Paged[DataCollectionGroupSummaryResponse]:

query = (
select(
*unravel(DataCollectionGroup),
Expand Down
32 changes: 27 additions & 5 deletions src/pato/crud/tomograms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
CTF,
MotionCorrection,
Movie,
ProcessedTomogram,
TiltImageAlignment,
Tomogram,
)
Expand All @@ -31,7 +32,6 @@ def _get_generic_tomogram_file(tomogramId: int, column: Column) -> Optional[str]
)


@validate_path
def _prepend_denoise(
base_path: str, image_type: Literal["thumbnail", "movie"], movie_type: MovieType
):
Expand All @@ -50,6 +50,30 @@ def _prepend_denoise(
return split_file[0] + denoised_prefix + "".join(split_file[1:3])


@validate_path
def _get_movie(
tomogramId: int, movie_type: MovieType, image_type: Literal["thumbnail", "movie"]
):
if movie_type:
# If movie_Type is defined, this means that this is not the standard noisy tomogram we're looking for
base_path = db.session.scalar(
select(ProcessedTomogram.filePath).filter(
ProcessedTomogram.tomogramId == tomogramId,
ProcessedTomogram.processingType == movie_type.capitalize(),
)
)

if base_path:
suffix = "_movie.png" if image_type == "movie" else "_thumbnail.jpeg"
return base_path.replace(".mrc", suffix)

column = (
Tomogram.tomogramMovie if image_type == "movie" else Tomogram.centralSliceImage
)
base_path = _get_generic_tomogram_file(tomogramId, column)
return _prepend_denoise(base_path, image_type, movie_type)


@validate_path
def _get_shift_plot_path(tomogramId: int):
return _get_generic_tomogram_file(tomogramId, Tomogram.xyShiftPlot)
Expand Down Expand Up @@ -127,13 +151,11 @@ def get_ctf(tomogramId: int):


def get_slice_path(tomogramId: int, movie_type: MovieType):
base_path = _get_generic_tomogram_file(tomogramId, Tomogram.centralSliceImage)
return _prepend_denoise(base_path, "thumbnail", movie_type)
return _get_movie(tomogramId, movie_type, "thumbnail")


def get_movie_path(tomogramId: int, movie_type: MovieType):
base_path = _get_generic_tomogram_file(tomogramId, Tomogram.tomogramMovie)
return _prepend_denoise(base_path, "movie", movie_type)
return _get_movie(tomogramId, movie_type, "movie")


def get_projection_path(tomogramId: int, axis: Literal["xy", "xz"]):
Expand Down
27 changes: 15 additions & 12 deletions tests/tomograms/test_central_slice.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from unittest.mock import patch

import pytest

from ..conftest import mock_send


Expand All @@ -10,20 +12,13 @@ def test_get(mock_permissions, client):
assert resp.status_code == 200


def test_get_denoised(mock_permissions, exists_mock, client):
"""Get denoised central slice for tomogram"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
resp = client.get("/tomograms/1/centralSlice?movieType=denoised")
assert resp.status_code == 200
exists_mock.assert_called_with("/dls/test.denoised_thumbnail.png")


def test_get_segmented(mock_permissions, exists_mock, client):
"""Get segmented central slice for tomogram"""
@pytest.mark.parametrize("movie_type, expected", [("segmented", "denoised_segmented"), ("denoised", "denoised")])
def test_get_movie_type(mock_permissions, exists_mock, client, movie_type, expected):
"""Get central slice for tomogram by processing type"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
resp = client.get("/tomograms/1/centralSlice?movieType=segmented")
resp = client.get(f"/tomograms/1/centralSlice?movieType={movie_type}")
assert resp.status_code == 200
exists_mock.assert_called_with("/dls/test.denoised_segmented_thumbnail.png")
exists_mock.assert_called_with(f"/dls/test.{expected}_thumbnail.png")


def test_get_denoised_invalid_name(mock_permissions, exists_mock, client):
Expand All @@ -44,3 +39,11 @@ def test_inexistent_file(mock_permissions, client):
"""Try to get central slice for tomogram not in database"""
resp = client.get("/tomograms/221/centralSlice")
assert resp.status_code == 404

@pytest.mark.parametrize("movie_type, expected", [("segmented", "denoised_segmented"), ("denoised", "denoised")])
def test_get_movie_type_processed(mock_permissions, exists_mock, client, movie_type, expected):
"""Get central slice for tomogram by processing type from ProcessedTomogram table"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
resp = client.get(f"/tomograms/3/centralSlice?movieType={movie_type}")
assert resp.status_code == 200
exists_mock.assert_called_with(f"/dls/test.{expected}_thumbnail.jpeg")
29 changes: 15 additions & 14 deletions tests/tomograms/test_movie.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from unittest.mock import patch

import pytest

from tests.conftest import mock_send


Expand All @@ -9,23 +11,14 @@ def test_get_movie(mock_permissions, client):
resp = client.get("/tomograms/1/movie")
assert resp.status_code == 200


def test_get_denoised(mock_permissions, exists_mock, client):
"""Get denoised movie"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
resp = client.get("/tomograms/1/movie?movieType=denoised")
exists_mock.assert_called_with("/dls/test.denoised_movie.png")
assert resp.status_code == 200


def test_get_segmented(mock_permissions, exists_mock, client):
"""Get segmented movie"""
@pytest.mark.parametrize("movie_type, expected", [("segmented", "denoised_segmented"), ("denoised", "denoised")])
def test_get_movie_processing_type(mock_permissions, exists_mock, client, movie_type, expected):
"""Get movie by processing type"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
resp = client.get("/tomograms/1/movie?movieType=segmented")
exists_mock.assert_called_with("/dls/test.denoised_segmented_movie.png")
resp = client.get(f"/tomograms/1/movie?movieType={movie_type}")
exists_mock.assert_called_with(f"/dls/test.{expected}_movie.png")
assert resp.status_code == 200


def test_get_denoised_invalid_name(mock_permissions, exists_mock, client):
"""Get denoised movie (with non-conforming filename)"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
Expand All @@ -44,3 +37,11 @@ def test_inexistent_db(mock_permissions, client):
"""Try to get movie image that does not exist in database"""
resp = client.get("/tomograms/999/movie")
assert resp.status_code == 404

@pytest.mark.parametrize("movie_type, expected", [("segmented", "denoised_segmented"), ("denoised", "denoised")])
def test_get_movie_type_processed(mock_permissions, exists_mock, client, movie_type, expected):
"""Get denoised movie from ProcessedTomogram table"""
with patch("pato.routes.tomograms.FileResponse.__call__", new=mock_send):
resp = client.get(f"/tomograms/3/movie?movieType={movie_type}")
exists_mock.assert_called_with(f"/dls/test.{expected}_movie.png")
assert resp.status_code == 200

0 comments on commit 403784a

Please sign in to comment.