Skip to content

Commit

Permalink
feat: Add new command sodar landing-zone-validate (#219)
Browse files Browse the repository at this point in the history
Co-authored-by: your-highness <hiob@noisecore.org>
  • Loading branch information
sellth and your-highness authored Jan 25, 2024
1 parent 2184842 commit 98e21c1
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 1 deletion.
6 changes: 5 additions & 1 deletion cubi_tk/sodar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
``landing-zone-create``
Create a landing zone.
``landing-zone-validate`` (planned)
``landing-zone-validate``
Validate a landing zone.
``landing-zone-move``
Expand Down Expand Up @@ -61,6 +61,7 @@
from .lz_create import setup_argparse as setup_argparse_lz_create
from .lz_list import setup_argparse as setup_argparse_lz_list
from .lz_move import setup_argparse as setup_argparse_lz_move
from .lz_validate import setup_argparse as setup_argparse_lz_validate
from .pull_raw_data import setup_argparse as setup_argparse_pull_raw_data
from .upload_sheet import setup_argparse as setup_argparse_upload_sheet

Expand All @@ -86,6 +87,9 @@ def setup_argparse(parser: argparse.ArgumentParser) -> None:
setup_argparse_lz_move(
subparsers.add_parser("landing-zone-move", help="Submit landing zone for moving")
)
setup_argparse_lz_validate(
subparsers.add_parser("landing-zone-validate", help="Submit landing zone for validation")
)
setup_argparse_ingest_fastq(
subparsers.add_parser(
"ingest-fastq", help="Upload external files to SODAR (defaults for fastq)"
Expand Down
105 changes: 105 additions & 0 deletions cubi_tk/sodar/lz_validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""``cubi-tk sodar landing-zone-validate`` command line program
"""

import argparse
import json
import os
import typing

import cattr
import logzero
from logzero import logger
from sodar_cli import api

from ..common import load_toml_config

# no-frills logger
formatter = logzero.LogFormatter(fmt="%(message)s")
output_logger = logzero.setup_logger(formatter=formatter)

# for testing
output_logger.propagate = True


class ValidateLandingZoneCommand:
"""Implementation of the ``landing-zone-validate`` command."""

def __init__(self, args):
#: Command line arguments.
self.args = args

@classmethod
def setup_argparse(cls, parser: argparse.ArgumentParser) -> None:
"""Setup argument parser."""
parser.add_argument(
"--hidden-cmd", dest="sodar_cmd", default=cls.run, help=argparse.SUPPRESS
)

group_sodar = parser.add_argument_group("SODAR-related")
group_sodar.add_argument(
"--sodar-url",
default=os.environ.get("SODAR_URL", "https://sodar.bihealth.org/"),
help="URL to SODAR, defaults to SODAR_URL environment variable or fallback to https://sodar.bihealth.org/",
)
group_sodar.add_argument(
"--sodar-api-token",
default=os.environ.get("SODAR_API_TOKEN", None),
help="Authentication token when talking to SODAR. Defaults to SODAR_API_TOKEN environment variable.",
)

parser.add_argument(
"--format",
dest="format_string",
default=None,
help="Format string for printing, e.g. %%(uuid)s",
)

parser.add_argument("landing_zone_uuid", help="UUID of landing zone to validate.")

@classmethod
def run(
cls, args, _parser: argparse.ArgumentParser, _subparser: argparse.ArgumentParser
) -> typing.Optional[int]:
"""Entry point into the command."""
return cls(args).execute() # pragma: nocover

def check_args(self, args):
"""Called for checking arguments, override to change behaviour."""
res = 0

toml_config = load_toml_config(args)
args.sodar_url = args.sodar_url or toml_config.get("global", {}).get("sodar_server_url")
args.sodar_api_token = args.sodar_api_token or toml_config.get("global", {}).get(
"sodar_api_token"
)

return res

def execute(self) -> typing.Optional[int]:
"""Execute the landing zone validation."""
res = self.check_args(self.args)
if res: # pragma: nocover
return res

logger.info("Starting cubi-tk sodar landing-zone-validate.")
logger.debug("args: %s", self.args)

landing_zone = api.landingzone.submit_validate(
sodar_url=self.args.sodar_url,
sodar_api_token=self.args.sodar_api_token,
landingzone_uuid=self.args.landing_zone_uuid,
)
values = cattr.unstructure(landing_zone)
if self.args.format_string:
logger.info("Formatted server response:")
output_logger.info(self.args.format_string.replace(r"\t", "\t") % values)
else:
logger.info("Server response:")
output_logger.info(json.dumps(values))

return 0


def setup_argparse(parser: argparse.ArgumentParser) -> None: # pragma: nocover
"""Setup argument parser for ``cubi-tk sodar landing-zone-validate``."""
return ValidateLandingZoneCommand.setup_argparse(parser)
36 changes: 36 additions & 0 deletions tests/test_sodar_lz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""``Tests for sodar_lz functions``"""
from argparse import ArgumentParser
from unittest.mock import patch

from cubi_tk.sodar.lz_validate import ValidateLandingZoneCommand


@patch("cubi_tk.sodar.lz_validate.api.landingzone.submit_validate")
@patch("cubi_tk.sodar.lz_validate.load_toml_config")
def test_validate(mocktoml, mockapi, caplog):
mockapi.return_value = {"a": 1, "b": 2}
argv = [
"--sodar-url",
"sodar_url",
"--sodar-api-token",
"token",
"u-u-i-d",
]

parser = ArgumentParser()
ValidateLandingZoneCommand.setup_argparse(parser)

# No format string
args = parser.parse_args(argv)
ValidateLandingZoneCommand(args).execute()
mockapi.assert_called_with(
sodar_url="sodar_url", sodar_api_token="token", landingzone_uuid="u-u-i-d"
)
assert '{"a": 1, "b": 2}' in caplog.messages

# With format string
argv.insert(-1, "--format")
argv.insert(-1, "%(a)s")
args = parser.parse_args(argv)
ValidateLandingZoneCommand(args).execute()
assert "1" in caplog.messages

0 comments on commit 98e21c1

Please sign in to comment.