Skip to content

Commit

Permalink
merge v0.13.4 release
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed May 15, 2023
2 parents d30fd18 + df3d4ef commit 1f89c32
Show file tree
Hide file tree
Showing 19 changed files with 177 additions and 89 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ Changelog for the SODAR project. Loosely follows the
`Keep a Changelog <http://keepachangelog.com/en/1.0.0/>`_ guidelines.


v0.13.4 (2023-05-15)
====================

Changed
-------

- **Samplesheets**
- Update ISA-Tab template dependency to ``cubi-isa-templates`` (#1667)
- Allow assay tables with no materials after sample (#1676)

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)


v0.13.3 (2023-05-10)
====================

Expand Down
3 changes: 2 additions & 1 deletion config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion docs_manual/source/api_examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::

Expand Down
2 changes: 1 addition & 1 deletion docs_manual/source/api_landingzones.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion docs_manual/source/api_samplesheets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions docs_manual/source/app_samplesheets_create.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------------

Expand Down
2 changes: 1 addition & 1 deletion docs_manual/source/app_samplesheets_edit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand Down
2 changes: 1 addition & 1 deletion docs_manual/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'


# -- General configuration ---------------------------------------------------
Expand Down
11 changes: 11 additions & 0 deletions docs_manual/source/sodar_release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ list of changes in current and previous releases, see the
:ref:`full changelog<sodar_changelog>`.


v0.13.4 (2023-05-15)
====================

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


v0.13.3 (2023-05-10)
====================

Expand Down
9 changes: 7 additions & 2 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -102,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
Expand Down
81 changes: 48 additions & 33 deletions samplesheets/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@
# 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 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):
Expand All @@ -40,12 +59,9 @@ class SheetImportForm(forms.Form):
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:
Expand All @@ -68,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(
Expand All @@ -100,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'
Expand Down Expand Up @@ -145,6 +156,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
):
Expand All @@ -157,18 +176,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)
Expand All @@ -189,18 +211,15 @@ 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):
# 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['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:
Expand All @@ -212,14 +231,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'
Expand All @@ -232,12 +247,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)
Expand Down

0 comments on commit 1f89c32

Please sign in to comment.