seqslab-cli 3.3.5__tar.gz → 3.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {seqslab-cli-3.3.5/python/seqslab_cli.egg-info → seqslab-cli-3.3.7}/PKG-INFO +1 -1
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/__init__.py +1 -1
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/commands.py +125 -48
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/runsheet/runsheet.py +11 -2
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/commands.py +1 -3
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/commands.py +41 -32
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/internal/parameters.py +86 -40
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/resource/base.py +15 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/template/base.py +5 -1
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7/python/seqslab_cli.egg-info}/PKG-INFO +1 -1
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/LICENSE +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/MANIFEST.in +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/README.md +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/auth/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/auth/azuread.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/auth/commands.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/cli.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/color.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/context.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/api/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/api/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/api/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/api/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/api/template.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/internal/aiocopy.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/internal/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/internal/utils.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/storage/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/storage/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/storage/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/utils/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/utils/atgxmetadata.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/utils/biomimetype.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/drs/utils/progressbar.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/exceptions.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/organization/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/organization/commands.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/organization/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/organization/resource/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/plugin.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/commands.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/internal/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/resource/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/role/resource/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/runsheet/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/sample_sheet/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/sample_sheet/_version.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/sample_sheet/util.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/commands.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/internal/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/resource/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/scr/resource/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/session_logger.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/settings.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/statusbar.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/internal/utils.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/register/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/register/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/register/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/register/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/register/template.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/resource/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/resource/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/resource/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/template/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/template/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/trs/template/template.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/usage_logger.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/commands.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/internal/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/resource/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/user/resource/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/resource/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/resource/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/template/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/wes/template/template.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/commands.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/internal/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/internal/common.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/resource/__init__.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/resource/azure.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab/workspace/resource/base.py +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab_cli.egg-info/SOURCES.txt +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab_cli.egg-info/dependency_links.txt +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab_cli.egg-info/entry_points.txt +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab_cli.egg-info/requires.txt +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab_cli.egg-info/top_level.txt +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/python/seqslab_cli.egg-info/zip-safe +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/requirements.txt +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/setup.cfg +0 -0
- {seqslab-cli-3.3.5 → seqslab-cli-3.3.7}/setup.py +0 -0
|
@@ -886,52 +886,6 @@ class BaseDatahub:
|
|
|
886
886
|
|
|
887
887
|
return results
|
|
888
888
|
|
|
889
|
-
@command(aliases=["deregister"])
|
|
890
|
-
@argument(
|
|
891
|
-
"id",
|
|
892
|
-
type=List[str],
|
|
893
|
-
positional=False,
|
|
894
|
-
description="Specify the IDs of the DRS objects that you want to delete "
|
|
895
|
-
"(optional).",
|
|
896
|
-
)
|
|
897
|
-
@argument(
|
|
898
|
-
"names",
|
|
899
|
-
type=List[str],
|
|
900
|
-
positional=False,
|
|
901
|
-
description="Specify the names of the DRS objects that you want to delete "
|
|
902
|
-
"(optional).",
|
|
903
|
-
)
|
|
904
|
-
@argument(
|
|
905
|
-
"tags",
|
|
906
|
-
type=List[str],
|
|
907
|
-
positional=False,
|
|
908
|
-
description="Specify the labels of the DRS objects that you want to delete "
|
|
909
|
-
"(optional).",
|
|
910
|
-
)
|
|
911
|
-
def deregister(
|
|
912
|
-
self,
|
|
913
|
-
id: List[str] = [],
|
|
914
|
-
tags: List[str] = [],
|
|
915
|
-
names: List[str] = [],
|
|
916
|
-
) -> int:
|
|
917
|
-
"""
|
|
918
|
-
Deregister DRS objects by DRS ID, DRS name, or DRS tag.
|
|
919
|
-
"""
|
|
920
|
-
if not id and not names and not tags:
|
|
921
|
-
cprint(
|
|
922
|
-
"Must specify one of the IDs, names or tags to identify DRS objects for deletion",
|
|
923
|
-
"red",
|
|
924
|
-
)
|
|
925
|
-
return errno.ENOENT
|
|
926
|
-
|
|
927
|
-
resps = asyncio.run(
|
|
928
|
-
utils.drs_delete(id, names, tags, query_opts="?backend_content=false")
|
|
929
|
-
)
|
|
930
|
-
for r in resps:
|
|
931
|
-
cprint(r, "yellow")
|
|
932
|
-
|
|
933
|
-
return 0
|
|
934
|
-
|
|
935
889
|
@command(aliases=["clean"])
|
|
936
890
|
@argument(
|
|
937
891
|
"id",
|
|
@@ -974,6 +928,10 @@ class BaseDatahub:
|
|
|
974
928
|
resps = asyncio.run(
|
|
975
929
|
utils.drs_delete(id, names, tags, query_opts="?backend_content=true")
|
|
976
930
|
)
|
|
931
|
+
if isinstance(resps, int):
|
|
932
|
+
cprint(f"Delete with return code {resps}", "red")
|
|
933
|
+
return resps
|
|
934
|
+
|
|
977
935
|
for r in resps:
|
|
978
936
|
cprint(r, "yellow")
|
|
979
937
|
|
|
@@ -1090,7 +1048,9 @@ class BaseDatahub:
|
|
|
1090
1048
|
fq_paths = BaseDatahub.find_fastq_paths(fastq_path, fastq_signature)
|
|
1091
1049
|
|
|
1092
1050
|
if run_sheet.SampleSheet.is_single_end:
|
|
1093
|
-
assert
|
|
1051
|
+
assert (
|
|
1052
|
+
len(fq_paths) == 1
|
|
1053
|
+
), f"{str(fq_paths)} does not contain exactly one fastq path"
|
|
1094
1054
|
sample_meta["Pair"] = "1"
|
|
1095
1055
|
upload_info.append(
|
|
1096
1056
|
{
|
|
@@ -1110,7 +1070,9 @@ class BaseDatahub:
|
|
|
1110
1070
|
)
|
|
1111
1071
|
|
|
1112
1072
|
if run_sheet.SampleSheet.is_paired_end:
|
|
1113
|
-
assert
|
|
1073
|
+
assert (
|
|
1074
|
+
len(fq_paths) == 2
|
|
1075
|
+
), f"{str(fq_paths)} does not contain exactly two fastq paths"
|
|
1114
1076
|
fq_paths.sort()
|
|
1115
1077
|
sample_meta["Pair"] = "1"
|
|
1116
1078
|
upload_info.append(
|
|
@@ -1455,6 +1417,121 @@ class BaseDatahub:
|
|
|
1455
1417
|
api_backend = drs_register().load_register(workspace)
|
|
1456
1418
|
return api_backend.get_drs(drs_id=id)
|
|
1457
1419
|
|
|
1420
|
+
@exception_handler
|
|
1421
|
+
def _patch_add_read_drs(self, add_reads_id: str, workspace: str, tag: str):
|
|
1422
|
+
results = self._get(add_reads_id, workspace)
|
|
1423
|
+
if isinstance(results, int):
|
|
1424
|
+
return results
|
|
1425
|
+
cprint(f"Found Add Reads target DRS object {add_reads_id}", color="yellow")
|
|
1426
|
+
tags = [item["name"] for item in results["tags"]] + [tag]
|
|
1427
|
+
patch_payload = {"tags": tags}
|
|
1428
|
+
results = self._change(add_reads_id, **patch_payload)
|
|
1429
|
+
if isinstance(results, int):
|
|
1430
|
+
return results
|
|
1431
|
+
cprint(
|
|
1432
|
+
f"Add Reads target DRS object {add_reads_id} patched with tags {tags}",
|
|
1433
|
+
color="yellow",
|
|
1434
|
+
)
|
|
1435
|
+
return add_reads_id
|
|
1436
|
+
|
|
1437
|
+
@command(aliases=["add-reads"])
|
|
1438
|
+
@argument(
|
|
1439
|
+
"workspace",
|
|
1440
|
+
type=str,
|
|
1441
|
+
positional=False,
|
|
1442
|
+
description="Specify the workspace based on the signed in account (required).",
|
|
1443
|
+
)
|
|
1444
|
+
@argument(
|
|
1445
|
+
"run_sheet",
|
|
1446
|
+
type=str,
|
|
1447
|
+
positional=False,
|
|
1448
|
+
description="Specify the Run Sheet file path (required).",
|
|
1449
|
+
)
|
|
1450
|
+
@argument(
|
|
1451
|
+
"seq_run_id",
|
|
1452
|
+
type=str,
|
|
1453
|
+
positional=False,
|
|
1454
|
+
description="Specify a runsheet header field as a sequencer run identifier; the specified value will be "
|
|
1455
|
+
"used as a sequencer run specific label for future dataset management (optional).",
|
|
1456
|
+
)
|
|
1457
|
+
def add_reads_runsheet(
|
|
1458
|
+
self,
|
|
1459
|
+
workspace,
|
|
1460
|
+
run_sheet: str,
|
|
1461
|
+
seq_run_id: str = "",
|
|
1462
|
+
) -> int:
|
|
1463
|
+
"""
|
|
1464
|
+
Identify and Patch existing DRS object with add-reads runsheet label for runsheet-based run triggering for
|
|
1465
|
+
DRS auto-matching
|
|
1466
|
+
"""
|
|
1467
|
+
if not self._valide_workspace(workspace):
|
|
1468
|
+
logging.error("Workspace not found")
|
|
1469
|
+
cprint("Workspace not found.", "red")
|
|
1470
|
+
return errno.EINVAL
|
|
1471
|
+
|
|
1472
|
+
# SampleSheetV2 based RunSheet SeqsLab fields
|
|
1473
|
+
seqslab_section = "SeqsLabRunSheet"
|
|
1474
|
+
seqslab_format = "SeqsLabColumnFormat"
|
|
1475
|
+
seqslab_sep = "#"
|
|
1476
|
+
rs = RunSheet(run_sheet, seqslab_section, seqslab_format, seqslab_sep)
|
|
1477
|
+
|
|
1478
|
+
# set base tags
|
|
1479
|
+
base_tgs = ""
|
|
1480
|
+
try:
|
|
1481
|
+
if seq_run_id:
|
|
1482
|
+
base_tgs = f"{rs.SampleSheet.Header[seq_run_id]}/"
|
|
1483
|
+
except KeyError:
|
|
1484
|
+
print(
|
|
1485
|
+
f"Given base_label_field not found in SampleSheet Header {seq_run_id}"
|
|
1486
|
+
)
|
|
1487
|
+
return errno.EINVAL
|
|
1488
|
+
|
|
1489
|
+
add_reads = False
|
|
1490
|
+
for sa in rs.SampleSheet.samples:
|
|
1491
|
+
if rs.SampleSheet.is_single_end:
|
|
1492
|
+
assert not sa.to_json().get("Add_Read2_ID") and not sa.to_json().get(
|
|
1493
|
+
"Add_Read2_Label"
|
|
1494
|
+
), "columns Add_Read2_ID and Add_Read2_Label should be blank for single_end sequencer run"
|
|
1495
|
+
if (add_read1_id := sa.to_json().get("Add_Read1_ID")) and (
|
|
1496
|
+
add_read1_label := sa.to_json().get("Add_Read1_Label")
|
|
1497
|
+
):
|
|
1498
|
+
add_reads = True
|
|
1499
|
+
ret = self._patch_add_read_drs(
|
|
1500
|
+
add_read1_id,
|
|
1501
|
+
workspace,
|
|
1502
|
+
f"{base_tgs}{sa.get('Run_Name', rs.SampleSheet.Header.Date)}/"
|
|
1503
|
+
f"{add_read1_label}",
|
|
1504
|
+
)
|
|
1505
|
+
if isinstance(ret, int):
|
|
1506
|
+
return ret
|
|
1507
|
+
if rs.SampleSheet.is_paired_end:
|
|
1508
|
+
if (add_read1_id := sa.to_json().get("Add_Read1_ID")) and (
|
|
1509
|
+
add_read1_label := sa.to_json().get("Add_Read1_Label")
|
|
1510
|
+
):
|
|
1511
|
+
add_reads = True
|
|
1512
|
+
ret = self._patch_add_read_drs(
|
|
1513
|
+
add_read1_id,
|
|
1514
|
+
workspace,
|
|
1515
|
+
f"{base_tgs}{sa.get('Run_Name', rs.SampleSheet.Header.Date)}/{add_read1_label}",
|
|
1516
|
+
)
|
|
1517
|
+
if isinstance(ret, int):
|
|
1518
|
+
return ret
|
|
1519
|
+
if (add_read2_id := sa.to_json().get("Add_Read2_ID")) and (
|
|
1520
|
+
add_read2_label := sa.to_json().get("Add_Read2_Label")
|
|
1521
|
+
):
|
|
1522
|
+
add_reads = True
|
|
1523
|
+
ret = self._patch_add_read_drs(
|
|
1524
|
+
add_read2_id,
|
|
1525
|
+
workspace,
|
|
1526
|
+
f"{base_tgs}{sa.get('Run_Name', rs.SampleSheet.Header.Date)}/{add_read2_label}",
|
|
1527
|
+
)
|
|
1528
|
+
if isinstance(ret, int):
|
|
1529
|
+
return ret
|
|
1530
|
+
|
|
1531
|
+
if not add_reads:
|
|
1532
|
+
cprint("No DRS object is patched in this operation", color="yellow")
|
|
1533
|
+
return 0
|
|
1534
|
+
|
|
1458
1535
|
|
|
1459
1536
|
@command
|
|
1460
1537
|
class Datahub(BaseDatahub):
|
|
@@ -16,18 +16,25 @@ class Run:
|
|
|
16
16
|
- ``"Run_Name"``
|
|
17
17
|
- ``"Workflow_URL"``
|
|
18
18
|
- ``"Runtimes"``
|
|
19
|
+
- ``"Run_Schedule_ID``
|
|
19
20
|
|
|
20
21
|
A run may include multiple samples. For samples in a Run Sheet, samples with the same Run_Name will be clustered
|
|
21
22
|
as a single run.
|
|
22
23
|
"""
|
|
23
24
|
|
|
24
25
|
def __init__(
|
|
25
|
-
self,
|
|
26
|
+
self,
|
|
27
|
+
samples: List[Sample],
|
|
28
|
+
run_name: str,
|
|
29
|
+
workflow_url: str,
|
|
30
|
+
runtimes: str,
|
|
31
|
+
run_schedule_id: str = None,
|
|
26
32
|
) -> None:
|
|
27
33
|
self.sample_sheet: Optional[SampleSheet] = None
|
|
28
34
|
self.run_name = run_name
|
|
29
35
|
self.workflow_url = workflow_url
|
|
30
36
|
self.runtimes = runtimes
|
|
37
|
+
self.run_schedule_id = run_schedule_id
|
|
31
38
|
self.samples = []
|
|
32
39
|
if not workflow_url.endswith("/"):
|
|
33
40
|
raise ValueError(
|
|
@@ -40,6 +47,7 @@ class Run:
|
|
|
40
47
|
s.get("Run_Name") == self.run_name
|
|
41
48
|
and s.get("Workflow_URL") == self.workflow_url
|
|
42
49
|
and s.get("Runtimes") == self.runtimes
|
|
50
|
+
and s.get("Run_Schedule_ID") == self.run_schedule_id
|
|
43
51
|
):
|
|
44
52
|
self.samples.append(s)
|
|
45
53
|
|
|
@@ -162,6 +170,7 @@ class RunSheet:
|
|
|
162
170
|
sample.get("Run_Name"),
|
|
163
171
|
sample.get("Workflow_URL"),
|
|
164
172
|
sample.get("Runtimes"),
|
|
173
|
+
sample.get("Run_Schedule_ID"),
|
|
165
174
|
)
|
|
166
175
|
rn = sample.get("Run_Name")
|
|
167
176
|
if rsig in runs and rn in run_name_set:
|
|
@@ -174,7 +183,7 @@ class RunSheet:
|
|
|
174
183
|
f"Inconsistent run_name/run_name_set {rn}/{run_name_set} and run sig/runs {rsig}/{runs.keys()}"
|
|
175
184
|
)
|
|
176
185
|
for k, v in runs.items():
|
|
177
|
-
self._runs.append(Run(v, k[0], k[1], k[2]))
|
|
186
|
+
self._runs.append(Run(v, k[0], k[1], k[2], k[3]))
|
|
178
187
|
|
|
179
188
|
@property
|
|
180
189
|
def runs(self) -> List:
|
|
@@ -408,9 +408,7 @@ class BaseTools:
|
|
|
408
408
|
positional=False,
|
|
409
409
|
description="Specify whether to force reload system cache for SCR (optional, default = False).",
|
|
410
410
|
)
|
|
411
|
-
def images(
|
|
412
|
-
self, scr_id: str, repositories: List[str] = [], reload: bool = False
|
|
413
|
-
) -> int:
|
|
411
|
+
def images(self, scr_id: str, repositories: List[str], reload: bool = False) -> int:
|
|
414
412
|
"""
|
|
415
413
|
List image tags and details of given repositories in an SCR.
|
|
416
414
|
"""
|
|
@@ -19,13 +19,13 @@ from seqslab.auth.commands import BaseAuth
|
|
|
19
19
|
from seqslab.exceptions import exception_handler
|
|
20
20
|
from seqslab.runsheet.runsheet import Run, RunSheet
|
|
21
21
|
from seqslab.trs.register.common import trs_register
|
|
22
|
-
from seqslab.wes import API_HOSTNAME, __version__
|
|
23
|
-
from seqslab.wes.internal import parameters
|
|
24
22
|
from seqslab.workspace.internal.common import get_factory as get_workspace_factory
|
|
25
23
|
from tenacity import retry, stop_after_attempt, wait_fixed
|
|
26
24
|
from termcolor import cprint
|
|
27
25
|
from tzlocal import get_localzone
|
|
28
26
|
|
|
27
|
+
from . import API_HOSTNAME, __version__
|
|
28
|
+
from .internal import parameters
|
|
29
29
|
from .resource.common import get_factory
|
|
30
30
|
|
|
31
31
|
"""
|
|
@@ -494,38 +494,32 @@ class BaseJobs:
|
|
|
494
494
|
request_path = f"{working_dir}/{rpath}-request.json"
|
|
495
495
|
wf_info = run.workflow_url.split("versions")[1].strip("/").split("/")
|
|
496
496
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
)
|
|
497
|
+
resource = get_factory().load_resource()
|
|
498
|
+
if run.run_schedule_id:
|
|
499
|
+
req = resource.get_schedule(run.run_schedule_id).get("request")
|
|
500
|
+
params = req.get("workflow_params")
|
|
501
|
+
backend_params = req.get("workflow_backend_params")
|
|
501
502
|
else:
|
|
502
|
-
execs_path = f"{working_dir}/{execs}"
|
|
503
503
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
raise Exception(
|
|
522
|
-
f"Unable to generate workflow_params based on given exec_path, with error code {params}"
|
|
504
|
+
if not execs:
|
|
505
|
+
trs_register().load_resource().get_execs_json(
|
|
506
|
+
workflow_url=run.workflow_url, download_path=execs_path
|
|
507
|
+
)
|
|
508
|
+
else:
|
|
509
|
+
execs_path = f"{working_dir}/{execs}"
|
|
510
|
+
|
|
511
|
+
ops = resource.list_operator_pipelines(page=1, page_size=1000)["results"]
|
|
512
|
+
opp_w_args = [
|
|
513
|
+
op["id"]
|
|
514
|
+
for op in ops
|
|
515
|
+
for operator in op["operators"]
|
|
516
|
+
if isinstance(operator, dict) and operator.get("arguments")
|
|
517
|
+
]
|
|
518
|
+
params = parameters.workflow_params(
|
|
519
|
+
execs_path,
|
|
520
|
+
opp_w_args,
|
|
523
521
|
)
|
|
524
|
-
|
|
525
|
-
request = {
|
|
526
|
-
"name": run.run_name,
|
|
527
|
-
"workflow_params": params,
|
|
528
|
-
"workflow_backend_params": parameters.workflow_backend_params(
|
|
522
|
+
backend_params = parameters.workflow_backend_params(
|
|
529
523
|
execs_path,
|
|
530
524
|
workspace,
|
|
531
525
|
run.runtimes,
|
|
@@ -533,7 +527,22 @@ class BaseJobs:
|
|
|
533
527
|
trust,
|
|
534
528
|
kernel_version,
|
|
535
529
|
token_lifetime,
|
|
536
|
-
)
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
if is_runsheet_template:
|
|
533
|
+
params = parameters.runsheet_rendering(
|
|
534
|
+
params, run, fq_signature, is_single_end
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
if not isinstance(params, dict):
|
|
538
|
+
raise Exception(
|
|
539
|
+
f"Unable to generate workflow_params based on given exec_path, with error code {params}"
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
request = {
|
|
543
|
+
"name": run.run_name,
|
|
544
|
+
"workflow_params": params,
|
|
545
|
+
"workflow_backend_params": backend_params,
|
|
537
546
|
"workflow_url": run.workflow_url,
|
|
538
547
|
"workflow_type_version": "1.0",
|
|
539
548
|
"workflow_type": wf_info[1],
|
|
@@ -31,26 +31,38 @@ laws and state trade secret laws, punishable by civil and criminal penalties.
|
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def
|
|
34
|
+
def label2fqn(run: Run):
|
|
35
35
|
r1fqn = set(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
list(
|
|
37
|
+
map(
|
|
38
|
+
lambda sample: (
|
|
39
|
+
re.sub(r"(/\d+)*$", "", sample.Read1_Label),
|
|
40
|
+
".".join(re.sub(r"(/\d+)*$", "", sample.Read1_Label).split("/")),
|
|
41
|
+
),
|
|
42
|
+
run.samples,
|
|
43
|
+
)
|
|
44
|
+
)
|
|
40
45
|
)
|
|
41
|
-
assert len(r1fqn) == 1
|
|
42
46
|
r2fqn = set(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
list(
|
|
48
|
+
map(
|
|
49
|
+
lambda sample: (
|
|
50
|
+
re.sub(r"(/\d+)*$", "", sample.Read2_Label),
|
|
51
|
+
".".join(re.sub(r"(/\d+)*$", "", sample.Read2_Label).split("/")),
|
|
52
|
+
),
|
|
53
|
+
run.samples,
|
|
54
|
+
)
|
|
55
|
+
)
|
|
47
56
|
)
|
|
48
|
-
assert len(r2fqn) == 1
|
|
49
57
|
if not r1fqn and not r2fqn:
|
|
50
58
|
raise Exception(
|
|
51
59
|
"runsheet template without Read1_Label and Read2_Label assignment"
|
|
52
60
|
)
|
|
53
|
-
|
|
61
|
+
# normalize r1fqn and r2fqn length
|
|
62
|
+
list_r2fqn = (
|
|
63
|
+
list(r2fqn) if len(r2fqn) == len(r1fqn) else [("", "") for item in r1fqn]
|
|
64
|
+
)
|
|
65
|
+
return list(r1fqn), list_r2fqn
|
|
54
66
|
|
|
55
67
|
|
|
56
68
|
def is_castable_to_int(s):
|
|
@@ -113,13 +125,68 @@ def _fastq_expr(rule: str, meta: dict) -> str:
|
|
|
113
125
|
return expr
|
|
114
126
|
|
|
115
127
|
|
|
128
|
+
def validate_execs(exec_content: dict):
|
|
129
|
+
inputs = exec_content.get("inputs")
|
|
130
|
+
datasets = exec_content.get("connections")
|
|
131
|
+
for fqn in datasets:
|
|
132
|
+
if fqn not in inputs:
|
|
133
|
+
cprint(f"datasets FQN {fqn} not in inputs.json", "red")
|
|
134
|
+
return False
|
|
135
|
+
return True
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def runsheet_rendering(params: dict, run: Run, fq_sig: str, is_single_end: bool):
|
|
139
|
+
# inputs.json rendering based on runsheet info for both normal runs and add-reads runs, also reset datasets section
|
|
140
|
+
tpl_r1fqn, tpl_r2fqn = label2fqn(run)
|
|
141
|
+
for idx in range(0, len(tpl_r1fqn)):
|
|
142
|
+
r1lbpfx = tpl_r1fqn[idx][0]
|
|
143
|
+
r2lbpfx = tpl_r2fqn[idx][0]
|
|
144
|
+
lb1 = []
|
|
145
|
+
lb2 = []
|
|
146
|
+
na1 = []
|
|
147
|
+
na2 = []
|
|
148
|
+
for sa in run.samples:
|
|
149
|
+
info_dic = {k.replace(" ", "_"): v for k, v in sa.to_json().items()}
|
|
150
|
+
|
|
151
|
+
lbo1 = sa.Read1_Label
|
|
152
|
+
lba1 = sa.to_json().get("Add_Read1_Label", "")
|
|
153
|
+
if r1lbpfx in lbo1:
|
|
154
|
+
lb1.append(lbo1)
|
|
155
|
+
na1.append(f"{_fastq_expr(fq_sig, info_dic)}_r1")
|
|
156
|
+
if r1lbpfx in lba1:
|
|
157
|
+
lb1.append(lba1)
|
|
158
|
+
na1.append(f"{_fastq_expr(fq_sig, info_dic)}_org_r1")
|
|
159
|
+
|
|
160
|
+
lbo2 = sa.Read2_Label
|
|
161
|
+
lba2 = sa.to_json().get("Add_Read2_Label", "")
|
|
162
|
+
if r2lbpfx in lbo2:
|
|
163
|
+
lb2.append(lbo2)
|
|
164
|
+
na2.append(f"{_fastq_expr(fq_sig, info_dic)}_r2")
|
|
165
|
+
if r2lbpfx in lba2:
|
|
166
|
+
lb2.append(lba2)
|
|
167
|
+
na2.append(f"{_fastq_expr(fq_sig, info_dic)}_org_r2")
|
|
168
|
+
|
|
169
|
+
r1fqn = tpl_r1fqn[idx][1]
|
|
170
|
+
r2fqn = tpl_r2fqn[idx][1]
|
|
171
|
+
if r1fqn == r2fqn:
|
|
172
|
+
params["inputs"][r1fqn] = populate_fqn(lb1 + lb2, na1 + na2)
|
|
173
|
+
params["datasets"][r1fqn] = None
|
|
174
|
+
return params
|
|
175
|
+
else:
|
|
176
|
+
params["inputs"][r1fqn] = populate_fqn(lb1, na1)
|
|
177
|
+
params["datasets"][r1fqn] = None
|
|
178
|
+
|
|
179
|
+
if r2fqn:
|
|
180
|
+
assert is_single_end is False, "R2FQN should not be set for single end run"
|
|
181
|
+
params["inputs"][r2fqn] = populate_fqn(lb2, na2)
|
|
182
|
+
params["datasets"][r2fqn] = None
|
|
183
|
+
|
|
184
|
+
return params
|
|
185
|
+
|
|
186
|
+
|
|
116
187
|
def workflow_params(
|
|
117
188
|
execs_json: str,
|
|
118
|
-
|
|
119
|
-
is_runsheet_template: bool,
|
|
120
|
-
is_single_end: bool,
|
|
121
|
-
fq_sig: str,
|
|
122
|
-
opp_w_args: dict,
|
|
189
|
+
opp_w_args: list,
|
|
123
190
|
) -> dict:
|
|
124
191
|
"""
|
|
125
192
|
Create workflow_params.json.
|
|
@@ -132,33 +199,12 @@ def workflow_params(
|
|
|
132
199
|
try:
|
|
133
200
|
with open(execs_json, "r") as f:
|
|
134
201
|
t_content = json.loads(f.read())
|
|
202
|
+
if not validate_execs(t_content):
|
|
203
|
+
return errno.EINVAL
|
|
135
204
|
|
|
136
205
|
params = WorkflowParamsTemplate().create(
|
|
137
206
|
ex_template=t_content, opp_w_args=opp_w_args
|
|
138
207
|
)
|
|
139
|
-
|
|
140
|
-
if is_runsheet_template:
|
|
141
|
-
r1fqn, r2fqn = validate_label_column(run)
|
|
142
|
-
lb1 = [sa.Read1_Label for sa in run.samples]
|
|
143
|
-
lb2 = [sa.Read2_Label for sa in run.samples]
|
|
144
|
-
na1 = [
|
|
145
|
-
f'{_fastq_expr(fq_sig, {k.replace(" ", "_"): v for k, v in sa.to_json().items()})}_r1'
|
|
146
|
-
for sa in run.samples
|
|
147
|
-
]
|
|
148
|
-
na2 = [
|
|
149
|
-
f'{_fastq_expr(fq_sig, {k.replace(" ", "_"): v for k, v in sa.to_json().items()})}_r2'
|
|
150
|
-
for sa in run.samples
|
|
151
|
-
]
|
|
152
|
-
|
|
153
|
-
if r1fqn == r2fqn:
|
|
154
|
-
params["inputs"][r1fqn] = populate_fqn(lb1 + lb2, na1 + na2)
|
|
155
|
-
return params
|
|
156
|
-
else:
|
|
157
|
-
params["inputs"][r1fqn] = populate_fqn(lb1, na1)
|
|
158
|
-
|
|
159
|
-
if r2fqn:
|
|
160
|
-
assert is_single_end is False
|
|
161
|
-
params["inputs"][r2fqn] = populate_fqn(lb2, na2)
|
|
162
208
|
return params
|
|
163
209
|
except zipfile.BadZipfile as error:
|
|
164
210
|
cprint(f"{error}", "red")
|
|
@@ -56,6 +56,9 @@ class BaseResource(ABC):
|
|
|
56
56
|
f"{WES_BASE_URL}runtime-options/{{name}}?backend={{backend}}"
|
|
57
57
|
)
|
|
58
58
|
WES_SCHEDULES_URL = f"{WES_BASE_URL}schedules/?backend={{backend}}"
|
|
59
|
+
WES_SCHEDULES_OBJECT_URL = (
|
|
60
|
+
f"{WES_BASE_URL}schedules/{{obj_id}}/?backend={{backend}}"
|
|
61
|
+
)
|
|
59
62
|
|
|
60
63
|
class Response(NamedTuple):
|
|
61
64
|
status: int
|
|
@@ -376,3 +379,15 @@ class BaseResource(ABC):
|
|
|
376
379
|
raise err
|
|
377
380
|
|
|
378
381
|
return response
|
|
382
|
+
|
|
383
|
+
def get_schedule(self, schedule_id) -> dict:
|
|
384
|
+
ctx = context.get_context()
|
|
385
|
+
backend = ctx.args.backend
|
|
386
|
+
token = BaseAuth.get_token().get("tokens").get("access")
|
|
387
|
+
with requests.get(
|
|
388
|
+
url=f"{self.WES_SCHEDULES_OBJECT_URL.format(obj_id=schedule_id, backend=backend)}",
|
|
389
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
390
|
+
) as response:
|
|
391
|
+
if response.status_code not in [requests.codes.ok]:
|
|
392
|
+
raise requests.HTTPError(response.text)
|
|
393
|
+
return json.loads(response.content)
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
class WorkflowParamsTemplate:
|
|
2
2
|
def create(self, ex_template: dict, opp_w_args: dict) -> dict:
|
|
3
|
-
operator_pipelines =
|
|
3
|
+
operator_pipelines = (
|
|
4
|
+
self.operator_pipelines(ex_template, opp_w_args)
|
|
5
|
+
if "tasks" not in ex_template
|
|
6
|
+
else (ex_template["tasks"])
|
|
7
|
+
)
|
|
4
8
|
return {
|
|
5
9
|
"inputs": ex_template.get("inputs"),
|
|
6
10
|
"datasets": ex_template.get("connections", None),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|