Skip to content

Commit

Permalink
add assay plugin tests, fix and refactor (#1980, #2014, #2017)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Sep 27, 2024
1 parent 9f87f1c commit fb21ffb
Show file tree
Hide file tree
Showing 30 changed files with 915 additions and 116 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Added
- **Samplesheets**
- REST API list view pagination (#1994)
- ``notify_email_irods_request`` user app setting (#1939)
- Assay app unit tests (#1980)
- Missing assay plugin ``__init__.py`` files (#2014)

Changed
-------
Expand Down Expand Up @@ -53,6 +55,7 @@ Fixed

- **Samplesheets**
- Timeline event status not updated in ``SheetDeleteVieW`` with iRODS collections enabled (#1798)
- Assay plugin ``update_row()`` setting links for empty file names (#2017)

Removed
-------
Expand Down
Empty file.
Empty file.
2 changes: 2 additions & 0 deletions samplesheets/assayapps/cytof/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def update_row(self, row, table, assay, index):
and header['value'].lower() == 'name'
and top_header['value'].lower()
in ['raw data file', 'derived data file']
and row[i]['value']
and isinstance(row[i]['value'], str)
):
row[i]['link'] = (
base_url + '/' + mc_assay_name + '/' + row[i]['value']
Expand Down
Empty file.
140 changes: 140 additions & 0 deletions samplesheets/assayapps/cytof/tests/test_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""Plugin tests for the the cytof assay plugin"""

import os

from copy import deepcopy

from samplesheets.assayapps.tests.base import AssayPluginTestBase
from samplesheets.rendering import SIMPLE_LINK_TEMPLATE
from samplesheets.views import MISC_FILES_COLL


# Local constants
ASSAY_NAME = 'testassayname'
PANEL_NAME = 'testpanel'
REPORT_NAME = 'report.txt'
FILE_NAME = 'file1.txt'
FILE_NAME2 = 'file2.txt'
FILE_NAME3 = 'file3.txt'


class TestCytofAssayPlugin(AssayPluginTestBase):
"""Tests for cytof assay plugin"""

plugin_name = 'samplesheets_assay_cytof'
template_name = 'mass_cytometry'

def test_get_row_path_filled(self):
"""Test get_row_path() with filled out assay name"""
self.assay_table['table_data'][0][20]['value'] = ASSAY_NAME
row_path = self.plugin.get_row_path(
self.assay_table['table_data'][0],
self.assay_table,
self.assay,
self.assay_path,
)
expected = os.path.join(self.assay_path, ASSAY_NAME)
self.assertEqual(row_path, expected)

def test_get_row_path_default(self):
"""Test get_row_path() with default template values"""
# NOTE: Assay name is not filled by default, so we return None
row_path = self.plugin.get_row_path(
self.assay_table['table_data'][0],
self.assay_table,
self.assay,
self.assay_path,
)
self.assertEqual(row_path, None)

def test_update_row_panel(self):
"""Test update_row() with filled panel name"""
# Update unset values
self.assay_table['table_data'][0][15]['value'] = PANEL_NAME
self.assay_table['table_data'][0][20]['value'] = ASSAY_NAME
self.assay_table['table_data'][0][26]['value'] = FILE_NAME
self.assay_table['table_data'][0][31]['value'] = FILE_NAME2
self.assay_table['table_data'][0][36]['value'] = FILE_NAME3
# Set expected data
row_ex = deepcopy(self.assay_table['table_data'][0])
row_ex[15]['value'] = SIMPLE_LINK_TEMPLATE.format(
label=PANEL_NAME,
url=os.path.join(self.base_url, MISC_FILES_COLL, PANEL_NAME),
)
row_ex[26]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME)
row_ex[31]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME2)
row_ex[36]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME3)
row = self.plugin.update_row(
self.assay_table['table_data'][0], self.assay_table, self.assay, 0
)
self.assertEqual(row, row_ex)

def test_update_row_report(self):
"""Test update_row() with filled report file"""
self.assay_table['table_data'][0][16]['value'] = REPORT_NAME
self.assay_table['table_data'][0][20]['value'] = ASSAY_NAME
self.assay_table['table_data'][0][26]['value'] = FILE_NAME
self.assay_table['table_data'][0][31]['value'] = FILE_NAME2
self.assay_table['table_data'][0][36]['value'] = FILE_NAME3
row_ex = deepcopy(self.assay_table['table_data'][0])
row_ex[16]['value'] = SIMPLE_LINK_TEMPLATE.format(
label=REPORT_NAME,
url=os.path.join(self.base_url, ASSAY_NAME, REPORT_NAME),
)
row_ex[26]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME)
row_ex[31]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME2)
row_ex[36]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME3)
row = self.plugin.update_row(
self.assay_table['table_data'][0], self.assay_table, self.assay, 0
)
self.assertEqual(row, row_ex)

def test_update_row_barcode(self):
"""Test update_row() with filled barcode key"""
# Rename header
self.assay_table['field_header'][15]['value'] = 'Barcode Key'
self.assay_table['table_data'][0][15]['value'] = PANEL_NAME
self.assay_table['table_data'][0][20]['value'] = ASSAY_NAME
self.assay_table['table_data'][0][26]['value'] = FILE_NAME
self.assay_table['table_data'][0][31]['value'] = FILE_NAME2
self.assay_table['table_data'][0][36]['value'] = FILE_NAME3
row_ex = deepcopy(self.assay_table['table_data'][0])
row_ex[15]['value'] = SIMPLE_LINK_TEMPLATE.format(
label=PANEL_NAME,
url=os.path.join(self.base_url, MISC_FILES_COLL, PANEL_NAME),
)
row_ex[26]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME)
row_ex[31]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME2)
row_ex[36]['link'] = os.path.join(self.base_url, ASSAY_NAME, FILE_NAME3)
row = self.plugin.update_row(
self.assay_table['table_data'][0], self.assay_table, self.assay, 0
)
self.assertEqual(row, row_ex)

def test_update_row_barcode_empty_file_names(self):
"""Test update_row() with filled barcode key and empty file names"""
# Rename header
self.assay_table['field_header'][15]['value'] = 'Barcode Key'
self.assay_table['table_data'][0][15]['value'] = PANEL_NAME
self.assay_table['table_data'][0][20]['value'] = ASSAY_NAME
self.assertEqual(self.assay_table['table_data'][0][26]['value'], '')
self.assertEqual(self.assay_table['table_data'][0][31]['value'], '')
self.assertEqual(self.assay_table['table_data'][0][36]['value'], '')
row_ex = deepcopy(self.assay_table['table_data'][0])
row_ex[15]['value'] = SIMPLE_LINK_TEMPLATE.format(
label=PANEL_NAME,
url=os.path.join(self.base_url, MISC_FILES_COLL, PANEL_NAME),
)
# File names should not be updated
row = self.plugin.update_row(
self.assay_table['table_data'][0], self.assay_table, self.assay, 0
)
self.assertEqual(row, row_ex)

def test_update_row_default(self):
"""Test update_row() with default template values"""
row_ex = deepcopy(self.assay_table['table_data'][0])
row = self.plugin.update_row(
self.assay_table['table_data'][0], self.assay_table, self.assay, 0
)
self.assertEqual(row, row_ex)
Empty file.
50 changes: 50 additions & 0 deletions samplesheets/assayapps/dna_sequencing/tests/test_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Plugin tests for the the dna_sequencing assay plugin"""

import os

from copy import deepcopy

from samplesheets.assayapps.tests.base import AssayPluginTestBase


# Local constants
MATERIAL_NAME = 'alpha'
MATERIAL_NAME_UPDATE = 'alpha-material-update'


class TestDNASequencingAssayPlugin(AssayPluginTestBase):
"""Tests for dna_sequencing assay plugin"""

plugin_name = 'samplesheets_assay_dna_sequencing'
template_name = 'generic'

def test_get_row_path(self):
"""Test get_row_path()"""
row_path = self.plugin.get_row_path(
self.assay_table['table_data'][0],
self.assay_table,
self.assay,
self.assay_path,
)
expected = os.path.join(self.assay_path, MATERIAL_NAME)
self.assertEqual(row_path, expected)

def test_get_row_path_rename(self):
"""Test get_row_path() with renamed material name"""
self.assay_table['table_data'][0][-1]['value'] = MATERIAL_NAME_UPDATE
row_path = self.plugin.get_row_path(
self.assay_table['table_data'][0],
self.assay_table,
self.assay,
self.assay_path,
)
expected = os.path.join(self.assay_path, MATERIAL_NAME_UPDATE)
self.assertEqual(row_path, expected)

def test_update_row(self):
"""Test update_row()"""
row_ex = deepcopy(self.assay_table['table_data'][0])
row = self.plugin.update_row(
self.assay_table['table_data'][0], self.assay_table, self.assay, 0
)
self.assertEqual(row, row_ex)
Empty file.
72 changes: 35 additions & 37 deletions samplesheets/assayapps/generic/plugins.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Assay app plugin for samplesheets"""

import re
from django.conf import settings

from altamisa.constants import table_headers as th

from django.conf import settings

from samplesheets.plugins import SampleSheetAssayPluginPoint
from samplesheets.rendering import SIMPLE_LINK_TEMPLATE
from samplesheets.utils import get_top_header
Expand All @@ -16,6 +18,7 @@
MISC_FILES_COMMENT = 'SODAR Assay Link MiscFiles'
DATA_COMMENT_PREFIX = 'SODAR Assay Row Path'
DATA_LINK_COMMENT = 'SODAR Assay Link Row'
LINK_NAME_HEADERS = th.DATA_FILE_HEADERS + th.MATERIAL_NAME_HEADERS


class SampleSheetAssayPlugin(SampleSheetAssayPluginPoint):
Expand Down Expand Up @@ -58,19 +61,11 @@ def _link_from_comment(cell, header, top_header, target_cols, url):
:param target_cols: List of column names.
:param url: Base URL for link target.
"""
# Do nothing if not string or link
if not isinstance(cell['value'], str) or re.search(
'.+ <.*>', cell['value']
):
return True
# Special case for Material Names
# Special case for material names
if (
(
top_header['value']
in th.DATA_FILE_HEADERS + th.MATERIAL_NAME_HEADERS
)
top_header['value'] in LINK_NAME_HEADERS
and top_header['value'].lower() in target_cols
and (header['value'] == 'Name')
and (header['value'].lower() == 'name')
):
cell['link'] = f"{url}/{cell['value']}"
return True
Expand All @@ -81,6 +76,7 @@ def _link_from_comment(cell, header, top_header, target_cols, url):
url=f"{url}/{cell['value']}",
)
return True
return False

@classmethod
def _get_col_value(cls, target_col, row, table):
Expand Down Expand Up @@ -125,13 +121,11 @@ def get_row_path(self, row, table, assay, assay_path):
for name, value in sorted(assay.comments.items())
if name.startswith(DATA_COMMENT_PREFIX)
]

data_collections = []
for column_name in data_columns:
col_value = self._get_col_value(column_name, row, table)
if col_value:
data_collections.append(col_value)

# Build iRODS path from list and stop at first None value
if data_collections:
data_path = '/' + '/'.join(data_collections)
Expand Down Expand Up @@ -167,7 +161,7 @@ def update_row(self, row, table, assay, index):
data_cols = assay.comments.get(DATA_LINK_COMMENT)
if data_cols:
data_cols = data_cols.lower().split(';')
if table['irods_paths'][index]:
if 'irods_paths' in table and table['irods_paths'][index]:
row_path = table['irods_paths'][index]['path']
else:
row_path = self.get_row_path(row, table, assay, assay_path)
Expand All @@ -177,29 +171,33 @@ def update_row(self, row, table, assay, index):
if not top_header or i >= th_colspan:
top_header = get_top_header(table, i)
th_colspan += top_header['colspan']

# Skip if value is empty, not a string or already contains a link
if (
not row[i]['value']
or not isinstance(row[i]['value'], str)
or re.search('.+ <.*>', row[i]['value'])
):
continue
# TODO: Check if two comments reference the same column header?
# Create Results links
if results_cols:
if self._link_from_comment(
row[i],
header,
top_header,
results_cols,
f'{base_url}/{RESULTS_COLL}',
):
continue
# Create MiscFiles links
if misc_cols:
if self._link_from_comment(
row[i],
header,
top_header,
misc_cols,
f'{base_url}/{MISC_FILES_COLL}',
):
continue
# Create DataCollection links
# Create Results link
if results_cols and self._link_from_comment(
row[i],
header,
top_header,
results_cols,
f'{base_url}/{RESULTS_COLL}',
):
continue
# Create MiscFiles link
if misc_cols and self._link_from_comment(
row[i],
header,
top_header,
misc_cols,
f'{base_url}/{MISC_FILES_COLL}',
):
continue
# Create DataCollection link
if data_cols:
self._link_from_comment(
row[i],
Expand Down
Empty file.
Loading

0 comments on commit fb21ffb

Please sign in to comment.