From 78997eb6ca1e268f16143fbaf1381994a6ef6bbd Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Thu, 11 May 2023 15:45:25 +0200 Subject: [PATCH 1/8] fix django-autocomplete-light crash with whitenoise (#1666) --- CHANGELOG.rst | 10 ++++++++++ docs_manual/source/conf.py | 2 +- docs_manual/source/sodar_release_notes.rst | 8 ++++++++ requirements/base.txt | 4 ++++ samplesheets/vueapp/package-lock.json | 4 ++-- samplesheets/vueapp/package.json | 2 +- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c0fe4232..dab30666 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,16 @@ Changelog for the SODAR project. Loosely follows the `Keep a Changelog `_ guidelines. +Unreleased +========== + +Fixed +----- + +- **General** + - Docker build crash from ``django-autocomplete-light==3.9.5`` and ``whitenoise`` (#1666) + + v0.13.3 (2023-05-10) ==================== diff --git a/docs_manual/source/conf.py b/docs_manual/source/conf.py index 4bbe6919..25f6eabf 100644 --- a/docs_manual/source/conf.py +++ b/docs_manual/source/conf.py @@ -26,7 +26,7 @@ author = 'BIH Core Unit Bioinformatics' # The full version, including alpha/beta/rc tags -release = '0.13.3' +release = '0.13.4-WIP' # -- General configuration --------------------------------------------------- diff --git a/docs_manual/source/sodar_release_notes.rst b/docs_manual/source/sodar_release_notes.rst index 291f2e83..948bc3d5 100644 --- a/docs_manual/source/sodar_release_notes.rst +++ b/docs_manual/source/sodar_release_notes.rst @@ -8,6 +8,14 @@ list of changes in current and previous releases, see the :ref:`full changelog`. +v0.13.4 (WIP) +============= + +Release for minor updates, maintenance and bug fixes. + +- Fix django-autocomplete-light Docker build crash + + v0.13.3 (2023-05-10) ==================== diff --git a/requirements/base.txt b/requirements/base.txt index c755f321..e14019cb 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -71,6 +71,10 @@ mistune==2.0.4 # Django-plugins (with Django v3.0+ support) -e git+https://github.com/mikkonie/django-plugins.git@42e86e7904e5c09f1da32173862b26843eda5dd8#egg=django-plugins +# Pin to avoid issue with v3.9.5 +# See issue #166 and bihealth/sodar-core#1225 +django-autocomplete-light==3.9.4 + # SODAR Core django-sodar-core==0.12.0 # -e git+https://github.com/bihealth/sodar-core.git@55d46268e5da4ef8a26913ce3b2c584d794d275c#egg=django-sodar-core diff --git a/samplesheets/vueapp/package-lock.json b/samplesheets/vueapp/package-lock.json index 84c3334e..0441c135 100644 --- a/samplesheets/vueapp/package-lock.json +++ b/samplesheets/vueapp/package-lock.json @@ -1,12 +1,12 @@ { "name": "samplesheets", - "version": "0.13.3", + "version": "0.13.4-WIP", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "samplesheets", - "version": "0.13.3", + "version": "0.13.4-WIP", "dependencies": { "bootstrap-vue": "^2.22.0", "core-js": "^3.23.5", diff --git a/samplesheets/vueapp/package.json b/samplesheets/vueapp/package.json index e55b74de..d94f7ede 100644 --- a/samplesheets/vueapp/package.json +++ b/samplesheets/vueapp/package.json @@ -1,6 +1,6 @@ { "name": "samplesheets", - "version": "0.13.3", + "version": "0.13.4-WIP", "private": true, "scripts": { "serve": "vue-cli-service serve", From eadb40323d64dca7b5d614510442ecf0d04bb540 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Fri, 12 May 2023 11:28:39 +0200 Subject: [PATCH 2/8] update cubi-tk dependency to cubi-isa-templates (#1667) --- CHANGELOG.rst | 8 +++- docs_manual/source/sodar_release_notes.rst | 1 + requirements/base.txt | 5 ++- samplesheets/forms.py | 46 +++++++++++----------- samplesheets/tests/test_ui.py | 4 +- samplesheets/tests/test_views.py | 12 +++--- samplesheets/views.py | 6 +-- 7 files changed, 45 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dab30666..b473ff33 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,11 +8,17 @@ Changelog for the SODAR project. Loosely follows the Unreleased ========== +Changed +------- + +- **Samplesheets** + - Update ISA-Tab template dependency to ``cubi-isa-templates`` (#1667) + Fixed ----- - **General** - - Docker build crash from ``django-autocomplete-light==3.9.5`` and ``whitenoise`` (#1666) + - ``django-autocomplete-light`` Docker build crash with ``whitenoise`` (#1666) v0.13.3 (2023-05-10) diff --git a/docs_manual/source/sodar_release_notes.rst b/docs_manual/source/sodar_release_notes.rst index 948bc3d5..4ffe4d77 100644 --- a/docs_manual/source/sodar_release_notes.rst +++ b/docs_manual/source/sodar_release_notes.rst @@ -13,6 +13,7 @@ v0.13.4 (WIP) Release for minor updates, maintenance and bug fixes. +- Update ISA-Tab template dependency to ``cubi-isa-templates`` - Fix django-autocomplete-light Docker build crash diff --git a/requirements/base.txt b/requirements/base.txt index e14019cb..51fc5c95 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -106,8 +106,9 @@ django-webpack-loader==1.6.0 fastobo==0.12.2 pronto==2.5.0 # For OWL conversion -# CUBI-TK for sheet templates --e git+https://github.com/bihealth/cubi-tk.git@0c0250cdfd546eaac1e0364df62213ad3c97ef7c#egg=cubi-tk +# CUBI ISA-Tab templates +cookiecutter==2.1.1 +-e git+https://github.com/bihealth/cubi-isa-templates.git@13ec5a83c9f7871d64064bbae658a0009d4bf113#egg=cubi-isa-templates # Taskflow requirements tooz==3.0.0 diff --git a/samplesheets/forms.py b/samplesheets/forms.py index 62d5ef83..b1b5feba 100644 --- a/samplesheets/forms.py +++ b/samplesheets/forms.py @@ -32,6 +32,7 @@ # Local constants ERROR_MSG_INVALID_PATH = 'Not a valid iRODS path for this project' ERROR_MSG_EXISTING = 'An active request already exists for this path' +TPL_DIR_FIELD = '__output_dir' class SheetImportForm(forms.Form): @@ -145,6 +146,14 @@ def save(self, *args, **kwargs): class SheetTemplateCreateForm(forms.Form): """Form for creating sample sheets from an ISA-Tab template.""" + @classmethod + def _get_tsv_data(cls, path, file_names): + ret = {} + for n in file_names: + with open(os.path.join(path, n)) as f: + ret[n] = {'path': n, 'tsv': f.read()} + return ret + def __init__( self, project=None, sheet_tpl=None, current_user=None, *args, **kwargs ): @@ -157,18 +166,21 @@ def __init__( self.current_user = current_user self.sheet_tpl = sheet_tpl self.json_fields = [] - self.fields['i_dir_name'] = forms.CharField( - label='Directory Name', - help_text='Investigation directory name and assay prefix', - ) - self.initial['i_dir_name'] = clean_sheet_dir_name(project.title) for k, v in sheet_tpl.configuration.items(): # Skip fields generated by cookiecutter if isinstance(v, str) and ('{{' in v or '{%' in v): continue - field_kwargs = {'label': k} - if isinstance(v, str): + field_kwargs = { + 'label': k if k != TPL_DIR_FIELD else 'Output Directory' + } + if k == TPL_DIR_FIELD: + field_kwargs[ + 'help_text' + ] = 'Investigation directory and assay prefix' + self.fields[k] = forms.CharField(**field_kwargs) + self.initial[k] = clean_sheet_dir_name(project.title) + elif isinstance(v, str): if not v: # Allow empty value if default is not set field_kwargs = {'required': False} self.fields[k] = forms.CharField(**field_kwargs) @@ -189,18 +201,10 @@ def __init__( if k in HIDDEN_SHEET_TEMPLATE_FIELDS: self.fields[k].widget = forms.widgets.HiddenInput() - @classmethod - def _get_tsv_data(cls, path, file_names): - ret = {} - for n in file_names: - with open(os.path.join(path, n)) as f: - ret[n] = {'path': n, 'tsv': f.read()} - return ret - def clean(self): # Force regex for dir name - self.cleaned_data['i_dir_name'] = clean_sheet_dir_name( - self.cleaned_data['i_dir_name'] + self.cleaned_data[TPL_DIR_FIELD] = clean_sheet_dir_name( + self.cleaned_data[TPL_DIR_FIELD] ) # Validate JSON for k in self.json_fields: @@ -212,14 +216,10 @@ def clean(self): return self.cleaned_data def save(self): - extra_context = { - k: v for k, v in self.cleaned_data.items() if k != 'i_dir_name' - } + extra_context = {k: v for k, v in self.cleaned_data.items()} for k in self.json_fields: if not isinstance(extra_context[k], dict): extra_context[k] = json.loads(extra_context[k]) - tpl_dir_name = self.cleaned_data['i_dir_name'] - extra_context['i_dir_name'] = tpl_dir_name if 'is_triplet' in self.sheet_tpl.configuration: extra_context['is_triplet'] = self.sheet_tpl.configuration[ 'is_triplet' @@ -232,12 +232,12 @@ def save(self): output_dir=td, no_input=True, ) - isa_data = { 'investigation': {}, 'studies': {}, 'assays': {}, } + tpl_dir_name = self.cleaned_data[TPL_DIR_FIELD] path = os.path.join(td, tpl_dir_name) i_name = [n for n in os.listdir(path) if n.startswith('i_')][0] i_path = os.path.join(path, i_name) diff --git a/samplesheets/tests/test_ui.py b/samplesheets/tests/test_ui.py index f01bc0d8..8199297d 100644 --- a/samplesheets/tests/test_ui.py +++ b/samplesheets/tests/test_ui.py @@ -2,7 +2,7 @@ import json -from cubi_tk.isa_tpl import _TEMPLATES as TK_TEMPLATES +from cubi_isa_templates import _TEMPLATES as ISA_TEMPLATES from django.urls import reverse from django.utils.http import urlencode @@ -264,7 +264,7 @@ class TestSheetTemplateCreateFormView(TestProjectSheetsVueAppBase): def test_render_hidden_fields(self): """Test rendering hidden fields in the sheet template form""" - for t in TK_TEMPLATES: + for t in ISA_TEMPLATES: url = ( reverse( 'samplesheets:template_create', diff --git a/samplesheets/tests/test_views.py b/samplesheets/tests/test_views.py index e1ef50d0..70ed109e 100644 --- a/samplesheets/tests/test_views.py +++ b/samplesheets/tests/test_views.py @@ -3,7 +3,7 @@ import json import os -from cubi_tk.isa_tpl import _TEMPLATES as TK_TEMPLATES +from cubi_isa_templates import _TEMPLATES as ISA_TEMPLATES from urllib.parse import urlencode from zipfile import ZipFile @@ -30,6 +30,7 @@ from landingzones.models import LandingZone from landingzones.tests.test_models import LandingZoneMixin +from samplesheets.forms import TPL_DIR_FIELD from samplesheets.io import SampleSheetIO from samplesheets.models import Investigation, Assay, ISATab from samplesheets.rendering import ( @@ -753,15 +754,15 @@ def test_post_batch(self): """Test POST request with supported templates and default values""" templates = { t.name: t - for t in TK_TEMPLATES + for t in ISA_TEMPLATES if t.name in settings.SHEETS_ENABLED_TEMPLATES } - for t in settings.SHEETS_ENABLED_TEMPLATES: self.assertIsNone(self.project.investigations.first()) - sheet_tpl = templates[t] - post_data = {'i_dir_name': clean_sheet_dir_name(self.project.title)} + post_data = { + TPL_DIR_FIELD: clean_sheet_dir_name(self.project.title) + } for k, v in sheet_tpl.configuration.items(): if isinstance(v, str): if '{{' in v or '{%' in v: @@ -771,7 +772,6 @@ def test_post_batch(self): post_data[k] = v[0] elif isinstance(v, dict): post_data[k] = json.dumps(v) - with self.login(self.user): response = self.client.post( reverse( diff --git a/samplesheets/views.py b/samplesheets/views.py index 143651fa..b131c517 100644 --- a/samplesheets/views.py +++ b/samplesheets/views.py @@ -9,7 +9,7 @@ import requests import zipfile -from cubi_tk.isa_tpl import _TEMPLATES as TK_TEMPLATES +from cubi_isa_templates import _TEMPLATES as ISA_TEMPLATES from irods.exception import CollectionDoesNotExist from packaging import version @@ -1155,7 +1155,7 @@ def get_context_data(self, **kwargs): # HACK: Skip non-working templates in cubi-tk for t in [ t - for t in TK_TEMPLATES + for t in ISA_TEMPLATES if t.name in settings.SHEETS_ENABLED_TEMPLATES ]: templates.append( @@ -1204,7 +1204,7 @@ class SheetTemplateCreateView( def _get_sheet_template(self): t_name = self.request.GET.get('sheet_tpl') - return {t.name: t for t in TK_TEMPLATES}[t_name] + return {t.name: t for t in ISA_TEMPLATES}[t_name] def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) From cc6c74d69a45eb1553c8724a859acf93ac066780 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Fri, 12 May 2023 14:42:09 +0200 Subject: [PATCH 3/8] fix multi-file upload in sheet import (#1670) --- CHANGELOG.rst | 2 ++ samplesheets/forms.py | 30 ++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b473ff33..4f1c2f3d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,8 @@ Fixed - **General** - ``django-autocomplete-light`` Docker build crash with ``whitenoise`` (#1666) +- **Samplesheets** + - Multi-file upload not working (# v0.13.3 (2023-05-10) diff --git a/samplesheets/forms.py b/samplesheets/forms.py index b1b5feba..c1c903f9 100644 --- a/samplesheets/forms.py +++ b/samplesheets/forms.py @@ -35,18 +35,33 @@ TPL_DIR_FIELD = '__output_dir' +class MultipleFileInput(forms.ClearableFileInput): + allow_multiple_selected = True + + +class MultipleFileField(forms.FileField): + def __init__(self, *args, **kwargs): + kwargs.setdefault('widget', MultipleFileInput()) + super().__init__(*args, **kwargs) + + def clean(self, data, initial=None): + single_file_clean = super().clean + if isinstance(data, (list, tuple)): + result = [single_file_clean(d, initial) for d in data] + else: + result = single_file_clean(data, initial) + return result + + class SheetImportForm(forms.Form): """ Form for importing an ISA investigation from an ISA-Tab archive or directory. """ - file_upload = forms.FileField( + file_upload = MultipleFileField( allow_empty_file=False, help_text='Zip archive or ISA-Tab files for a single investigation', - widget=forms.ClearableFileInput( - attrs={'allow_multiple_selected': True} - ), ) class Meta: @@ -69,21 +84,18 @@ def __init__( def clean(self): files = self.files.getlist('file_upload') - # Zip archive upload if len(files) == 1: - file = self.cleaned_data.get('file_upload') + file = self.cleaned_data.get('file_upload')[0] try: self.isa_zip = self.sheet_io.get_zip_file(file) except OSError as ex: self.add_error('file_upload', str(ex)) return self.cleaned_data - # Multi-file checkup else: inv_found = False study_found = False - for file in files: if file.content_type in ARCHIVE_TYPES: self.add_error( @@ -101,14 +113,12 @@ def clean(self): inv_found = True elif file.name.startswith('s_'): study_found = True - if not inv_found: self.add_error( 'file_upload', 'Investigation file not found among uploaded files', ) return self.cleaned_data - if not study_found: self.add_error( 'file_upload', 'Study file not found among uploaded files' From 466d5c4a684d8f2610c865ba86064a25f0f0714b Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Fri, 12 May 2023 14:43:07 +0200 Subject: [PATCH 4/8] fix changelog --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4f1c2f3d..f6f0f8e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,7 +20,7 @@ Fixed - **General** - ``django-autocomplete-light`` Docker build crash with ``whitenoise`` (#1666) - **Samplesheets** - - Multi-file upload not working (# + - Multi-file upload not working (#1670) v0.13.3 (2023-05-10) From 6cb63785f00bf7bb0fb853e01a175df36d57ebd5 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Fri, 12 May 2023 15:16:00 +0200 Subject: [PATCH 5/8] fix template create view multiple request handling (#1672) --- CHANGELOG.rst | 1 + samplesheets/forms.py | 5 +++ samplesheets/tests/test_views.py | 62 ++++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f6f0f8e7..0ce80185 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,6 +21,7 @@ Fixed - ``django-autocomplete-light`` Docker build crash with ``whitenoise`` (#1666) - **Samplesheets** - Multi-file upload not working (#1670) + - Template create form allowing multiple ISA-Tabs per project (#1672) v0.13.3 (2023-05-10) diff --git a/samplesheets/forms.py b/samplesheets/forms.py index c1c903f9..5a12b81a 100644 --- a/samplesheets/forms.py +++ b/samplesheets/forms.py @@ -212,6 +212,11 @@ def __init__( self.fields[k].widget = forms.widgets.HiddenInput() def clean(self): + # Do not allow creating multiple investigations + inv = Investigation.objects.filter(project=self.project).first() + if inv: + self.add_error(None, 'Sample sheets already exist in project') + return self.cleaned_data # Force regex for dir name self.cleaned_data[TPL_DIR_FIELD] = clean_sheet_dir_name( self.cleaned_data[TPL_DIR_FIELD] diff --git a/samplesheets/tests/test_views.py b/samplesheets/tests/test_views.py index 70ed109e..7be500d0 100644 --- a/samplesheets/tests/test_views.py +++ b/samplesheets/tests/test_views.py @@ -699,6 +699,31 @@ def test_render_with_sheets(self): class TestSheetTemplateCreateFormView(TestViewsBase): """Tests for SheetTemplateCreateFormView""" + def _get_post_data(self, tpl_name): + """ + Return POST data for creation from template + + :param tpl_name: Template name (string) + :return: Dict + """ + templates = { + t.name: t + for t in ISA_TEMPLATES + if t.name in settings.SHEETS_ENABLED_TEMPLATES + } + sheet_tpl = templates[tpl_name] + ret = {TPL_DIR_FIELD: clean_sheet_dir_name(self.project.title)} + for k, v in sheet_tpl.configuration.items(): + if isinstance(v, str): + if '{{' in v or '{%' in v: + continue + ret[k] = v + elif isinstance(v, list): + ret[k] = v[0] + elif isinstance(v, dict): + ret[k] = json.dumps(v) + return ret + def test_render_batch(self): """Test rendering the view with supported templates""" for t in settings.SHEETS_ENABLED_TEMPLATES: @@ -752,26 +777,10 @@ def test_render_no_template(self): def test_post_batch(self): """Test POST request with supported templates and default values""" - templates = { - t.name: t - for t in ISA_TEMPLATES - if t.name in settings.SHEETS_ENABLED_TEMPLATES - } + for t in settings.SHEETS_ENABLED_TEMPLATES: self.assertIsNone(self.project.investigations.first()) - sheet_tpl = templates[t] - post_data = { - TPL_DIR_FIELD: clean_sheet_dir_name(self.project.title) - } - for k, v in sheet_tpl.configuration.items(): - if isinstance(v, str): - if '{{' in v or '{%' in v: - continue - post_data[k] = v - elif isinstance(v, list): - post_data[k] = v[0] - elif isinstance(v, dict): - post_data[k] = json.dumps(v) + post_data = self._get_post_data(t) with self.login(self.user): response = self.client.post( reverse( @@ -786,6 +795,23 @@ def test_post_batch(self): self.assertIsNotNone(self.project.investigations.first()) self.project.investigations.first().delete() + def test_post_multiple(self): + """Test multiple requests to add multiple sample sheets (should fail)""" + tpl_name = settings.SHEETS_ENABLED_TEMPLATES[0] + url = reverse( + 'samplesheets:template_create', + kwargs={'project': self.project.sodar_uuid}, + ) + url += '?sheet_tpl=' + tpl_name + post_data = self._get_post_data(tpl_name) + with self.login(self.user): + response = self.client.post(url, data=post_data) + self.assertEqual(response.status_code, 302) + self.assertEqual(self.project.investigations.count(), 1) + response = self.client.post(url, data=post_data) + self.assertEqual(response.status_code, 200) + self.assertEqual(self.project.investigations.count(), 1) + class TestSheetExcelExportView(TestViewsBase): """Tests for the sample sheet Excel export view""" From 6d508a90101f9a4ba104b9c6005e84b714f9cee3 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Mon, 15 May 2023 11:56:11 +0200 Subject: [PATCH 6/8] update sheet import to allow assay table without materials (#1676) --- CHANGELOG.rst | 1 + docs_manual/source/sodar_release_notes.rst | 4 ++- samplesheets/io.py | 42 ++++++++++++---------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0ce80185..e499b0b0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,7 @@ Changed - **Samplesheets** - Update ISA-Tab template dependency to ``cubi-isa-templates`` (#1667) + - Allow assay tables with no materials after sample (#1676) Fixed ----- diff --git a/docs_manual/source/sodar_release_notes.rst b/docs_manual/source/sodar_release_notes.rst index 4ffe4d77..5237a6be 100644 --- a/docs_manual/source/sodar_release_notes.rst +++ b/docs_manual/source/sodar_release_notes.rst @@ -11,9 +11,11 @@ list of changes in current and previous releases, see the v0.13.4 (WIP) ============= -Release for minor updates, maintenance and bug fixes. +Release for minor sample sheet updates, maintenance and bug fixes. - Update ISA-Tab template dependency to ``cubi-isa-templates`` +- Allow assay tables with no materials after sample +- Fix sample sheet creation form resubmit handling - Fix django-autocomplete-light Docker build crash diff --git a/samplesheets/io.py b/samplesheets/io.py index e543dffc..ec8f125d 100644 --- a/samplesheets/io.py +++ b/samplesheets/io.py @@ -51,7 +51,6 @@ ISATAB_TYPES = ['text/plain', 'text/tab-separated-values'] ALTAMISA_MATERIAL_TYPE_SAMPLE = 'Sample Name' - MATERIAL_TYPE_MAP = { 'Source Name': 'SOURCE', 'Sample Name': 'SAMPLE', @@ -74,12 +73,15 @@ 'Metabolite Assignment File': 'DATA', 'Array Data Matrix File': 'DATA', } - # For old ISA-Tabs where this field was not always filled out MATERIAL_TYPE_EXPORT_MAP = {'SOURCE': 'Source Name', 'SAMPLE': 'Sample Name'} SAMPLE_SEARCH_SUBSTR = '-sample-' PROTOCOL_UNKNOWN_NAME = 'Unknown' +EMPTY_TABLE_ERR_MSG = ( + 'No {items} in {class_name} "{file_name}": Importing sheets with empty ' + 'tables is currently not supported.' +) class SampleSheetIO: @@ -390,15 +392,6 @@ def _import_materials(cls, materials, db_parent, obj_lookup): material_vals = [] study = cls._get_study(db_parent) - # Fail if attempting to import an empty table - if len(materials.values()) == 0: - raise SampleSheetImportException( - 'No materials in {} "{}": Importing sheets with tables ' - 'containing zero lines is currently not supported.'.format( - db_parent.__class__.__name__.lower(), db_parent.file_name - ) - ) - for m in materials.values(): item_type = MATERIAL_TYPE_MAP[m.type] # Common values @@ -549,7 +542,6 @@ def import_isa( else '' ) ) - input_name = isa_data['investigation']['path'].split('/')[-1] input_file = io.StringIO(isa_data['investigation']['tsv']) @@ -689,20 +681,25 @@ def import_isa( ) ) + if len(s.materials.values()) == 0: + raise SampleSheetImportException( + EMPTY_TABLE_ERR_MSG.format( + items='materials', + class_name=db_study.__class__.__name__.lower(), + file_name=db_study.file_name, + ) + ) # Create study materials self._import_materials(s.materials, db_study, obj_lookup) - # Create study processes self._import_processes( s.processes, db_study, obj_lookup, protocol_lookup ) - # Create study arcs self._import_arcs(s.arcs, db_study) assay_count = 0 assay_paths = sorted([a.path for a in isa_study.assays]) - for assay_path in assay_paths: isa_assay = next( (a_i for a_i in isa_study.assays if a_i.path == assay_path), @@ -738,7 +735,6 @@ def import_isa( ) logger.error(ex_msg) raise Exception(ex_msg) - logger.debug('altamISA assay import OK') values = { @@ -770,17 +766,25 @@ def import_isa( if MATERIAL_TYPE_MAP[a.materials[k].type] not in ['SOURCE', 'SAMPLE'] } + if ( + len(assay_materials.values()) == 0 + and len(a.processes.values()) == 0 + ): + raise SampleSheetImportException( + EMPTY_TABLE_ERR_MSG.format( + items='materials or processes', + class_name=db_assay.__class__.__name__.lower(), + file_name=db_assay.file_name, + ) + ) self._import_materials(assay_materials, db_assay, obj_lookup) - # Create assay processes self._import_processes( a.processes, db_assay, obj_lookup, protocol_lookup ) - # Create assay arcs self._import_arcs(a.arcs, db_assay) assay_count += 1 - study_count += 1 # Raise exception if we got criticals and don't accept them From 3c239b584645193a7febf51eec76b5cdfc51c5bd Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Mon, 15 May 2023 12:45:19 +0200 Subject: [PATCH 7/8] fix chrome install script issues (#1677) --- CHANGELOG.rst | 1 + utility/install_chrome.sh | 2 +- utility/install_chromedriver.sh | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) mode change 100644 => 100755 utility/install_chromedriver.sh diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e499b0b0..f20c8cda 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,7 @@ Fixed - **General** - ``django-autocomplete-light`` Docker build crash with ``whitenoise`` (#1666) + - Chrome install script issues (#1677) - **Samplesheets** - Multi-file upload not working (#1670) - Template create form allowing multiple ISA-Tabs per project (#1672) diff --git a/utility/install_chrome.sh b/utility/install_chrome.sh index be44c8be..f919ca07 100755 --- a/utility/install_chrome.sh +++ b/utility/install_chrome.sh @@ -19,7 +19,7 @@ rm ~/google-chrome-stable_current_amd64.deb # Install ChromeDriver wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ -unzip ~/chromedriver_linux64.zip -d ~/ +unzip -o ~/chromedriver_linux64.zip -d ~/ rm ~/chromedriver_linux64.zip sudo mv -f ~/chromedriver /usr/local/bin/chromedriver sudo chown root:root /usr/local/bin/chromedriver diff --git a/utility/install_chromedriver.sh b/utility/install_chromedriver.sh old mode 100644 new mode 100755 index e19ade93..6df2f788 --- a/utility/install_chromedriver.sh +++ b/utility/install_chromedriver.sh @@ -11,7 +11,7 @@ sudo apt-get install -y unzip xvfb libxi6 libgconf-2-4 # Install ChromeDriver CHROME_DRIVER_VERSION=$(curl http://chromedriver.storage.googleapis.com/LATEST_RELEASE) wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ -unzip ~/chromedriver_linux64.zip -d ~/ +unzip -o ~/chromedriver_linux64.zip -d ~/ rm ~/chromedriver_linux64.zip sudo mv -f ~/chromedriver /usr/local/bin/chromedriver sudo chown root:root /usr/local/bin/chromedriver From df3d4ef13bc704aa40b3e9e78e0fbe27dac3767d Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Mon, 15 May 2023 14:01:35 +0200 Subject: [PATCH 8/8] cleanup and prepare v0.13.4 release (#1673) --- CHANGELOG.rst | 4 ++-- config/settings/base.py | 3 ++- docs_manual/source/api_examples.rst | 2 +- docs_manual/source/api_landingzones.rst | 2 +- docs_manual/source/api_samplesheets.rst | 2 +- docs_manual/source/app_samplesheets_create.rst | 5 +++++ docs_manual/source/app_samplesheets_edit.rst | 2 +- docs_manual/source/conf.py | 2 +- docs_manual/source/sodar_release_notes.rst | 4 ++-- samplesheets/vueapp/package-lock.json | 4 ++-- samplesheets/vueapp/package.json | 2 +- 11 files changed, 19 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f20c8cda..9a008de4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,8 +5,8 @@ Changelog for the SODAR project. Loosely follows the `Keep a Changelog `_ guidelines. -Unreleased -========== +v0.13.4 (2023-05-15) +==================== Changed ------- diff --git a/config/settings/base.py b/config/settings/base.py index e1e0629c..ebb1c0cb 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -586,7 +586,7 @@ def set_logging(level=None): # General API settings -SODAR_API_DEFAULT_VERSION = '0.13.3' +SODAR_API_DEFAULT_VERSION = '0.13.4' SODAR_API_ALLOWED_VERSIONS = [ '0.7.0', '0.7.1', @@ -604,6 +604,7 @@ def set_logging(level=None): '0.13.1', '0.13.2', '0.13.3', + '0.13.4', ] SODAR_API_MEDIA_TYPE = 'application/vnd.bihealth.sodar+json' SODAR_API_DEFAULT_HOST = env.url( diff --git a/docs_manual/source/api_examples.rst b/docs_manual/source/api_examples.rst index 2867eed0..6aa6e91e 100644 --- a/docs_manual/source/api_examples.rst +++ b/docs_manual/source/api_examples.rst @@ -43,7 +43,7 @@ the SODAR API: # Use core_headers for project management API endpoints core_headers = {**auth_header, 'Accept': 'application/vnd.bihealth.sodar-core+json; version=0.12.0'} # Use sodar_headers for sample sheet and landing zone API endpoints - sodar_headers = {**auth_header, 'Accept': 'application/vnd.bihealth.sodar+json; version=0.13.2'} + sodar_headers = {**auth_header, 'Accept': 'application/vnd.bihealth.sodar+json; version=0.13.4'} .. note:: diff --git a/docs_manual/source/api_landingzones.rst b/docs_manual/source/api_landingzones.rst index 294ef7e4..422f1916 100644 --- a/docs_manual/source/api_landingzones.rst +++ b/docs_manual/source/api_landingzones.rst @@ -30,4 +30,4 @@ SODAR version: .. code-block:: console - Accept: application/vnd.bihealth.sodar+json; version=0.13.3 + Accept: application/vnd.bihealth.sodar+json; version=0.13.4 diff --git a/docs_manual/source/api_samplesheets.rst b/docs_manual/source/api_samplesheets.rst index 47d6b921..ccc65a28 100644 --- a/docs_manual/source/api_samplesheets.rst +++ b/docs_manual/source/api_samplesheets.rst @@ -32,4 +32,4 @@ SODAR version: .. code-block:: console - Accept: application/vnd.bihealth.sodar+json; version=0.13.3 + Accept: application/vnd.bihealth.sodar+json; version=0.13.4 diff --git a/docs_manual/source/app_samplesheets_create.rst b/docs_manual/source/app_samplesheets_create.rst index 8dab231d..b6448009 100644 --- a/docs_manual/source/app_samplesheets_create.rst +++ b/docs_manual/source/app_samplesheets_create.rst @@ -47,6 +47,11 @@ In case of a successful import, you will be redirected to the main sample sheets view, where you should see the study and assay tables for your imported sample sheets. +.. note:: + + Importing ISA-Tab files with empty study or assay tables is not allowed. + Study tables must also contain source and sample materials. + Parser Warnings --------------- diff --git a/docs_manual/source/app_samplesheets_edit.rst b/docs_manual/source/app_samplesheets_edit.rst index 2cbbb35a..76419a10 100644 --- a/docs_manual/source/app_samplesheets_edit.rst +++ b/docs_manual/source/app_samplesheets_edit.rst @@ -222,7 +222,7 @@ Names of all nodes must be filled out before the row can be saved into the database. Exceptions for this include unnamed processes, which will be autofilled, as well as *File* type materials which can remain unnamed. Characteristics, factor values and other metadata fields can be filled or left -empty at tihs point. Their values can be edited freely just like any other cell +empty at this point. Their values can be edited freely just like any other cell after saving the row. .. hint:: diff --git a/docs_manual/source/conf.py b/docs_manual/source/conf.py index 25f6eabf..0ecbcf56 100644 --- a/docs_manual/source/conf.py +++ b/docs_manual/source/conf.py @@ -26,7 +26,7 @@ author = 'BIH Core Unit Bioinformatics' # The full version, including alpha/beta/rc tags -release = '0.13.4-WIP' +release = '0.13.4' # -- General configuration --------------------------------------------------- diff --git a/docs_manual/source/sodar_release_notes.rst b/docs_manual/source/sodar_release_notes.rst index 5237a6be..edf3c892 100644 --- a/docs_manual/source/sodar_release_notes.rst +++ b/docs_manual/source/sodar_release_notes.rst @@ -8,8 +8,8 @@ list of changes in current and previous releases, see the :ref:`full changelog`. -v0.13.4 (WIP) -============= +v0.13.4 (2023-05-15) +==================== Release for minor sample sheet updates, maintenance and bug fixes. diff --git a/samplesheets/vueapp/package-lock.json b/samplesheets/vueapp/package-lock.json index 0441c135..5c258c70 100644 --- a/samplesheets/vueapp/package-lock.json +++ b/samplesheets/vueapp/package-lock.json @@ -1,12 +1,12 @@ { "name": "samplesheets", - "version": "0.13.4-WIP", + "version": "0.13.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "samplesheets", - "version": "0.13.4-WIP", + "version": "0.13.4", "dependencies": { "bootstrap-vue": "^2.22.0", "core-js": "^3.23.5", diff --git a/samplesheets/vueapp/package.json b/samplesheets/vueapp/package.json index d94f7ede..4ea1a43d 100644 --- a/samplesheets/vueapp/package.json +++ b/samplesheets/vueapp/package.json @@ -1,6 +1,6 @@ { "name": "samplesheets", - "version": "0.13.4-WIP", + "version": "0.13.4", "private": true, "scripts": { "serve": "vue-cli-service serve",