snk-cli 0.7.2__tar.gz → 0.8.0__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.
- {snk_cli-0.7.2 → snk_cli-0.8.0}/.github/workflows/publish.yml +1 -1
- {snk_cli-0.7.2 → snk_cli-0.8.0}/.github/workflows/tests.yml +9 -7
- {snk_cli-0.7.2 → snk_cli-0.8.0}/PKG-INFO +5 -3
- {snk_cli-0.7.2 → snk_cli-0.8.0}/pyproject.toml +13 -6
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/__about__.py +1 -1
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/conda.py +12 -4
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/dynamic_typer.py +16 -6
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/env.py +12 -3
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/run.py +30 -25
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/testing.py +3 -2
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/conftest.py +0 -3
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_run.py +1 -1
- snk_cli-0.8.0/tests/test_conda_env.py +24 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_dynamic_typer.py +23 -1
- snk_cli-0.7.2/tests/test_conda_env.py +0 -11
- {snk_cli-0.7.2 → snk_cli-0.8.0}/.gitignore +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/LICENSE.txt +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/README.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/index.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/cli.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/config.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/dynamic_typer.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/options.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/subcommands.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/testing.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/utils.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/validate.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/workflow.md +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/mkdocs.yml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/__init__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/cli.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/config/__init__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/config/config.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/config/utils.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/options/__init__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/options/option.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/options/utils.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/__init__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/config.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/profile.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/script.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/utils.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/validate.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/workflow.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/__init__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/artic_v4.1.bed +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/config.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/cov.fasta +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/Snakefile +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/cli.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/config.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/snk.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/cli.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/config.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/resources/data.txt +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/snk.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/things/__about__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/Snakefile +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/envs/wget.yml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/profiles/base/config.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/profiles/slurm/config.yaml +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/scripts/hello.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_SnkConfig.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/__init__.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_dynamic_options.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_profile.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_snk_config.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_subcommands.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_validate.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_workflow_cli.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_types.py +0 -0
- {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/utils.py +0 -0
|
@@ -17,16 +17,18 @@ jobs:
|
|
|
17
17
|
runs-on: ubuntu-latest
|
|
18
18
|
strategy:
|
|
19
19
|
matrix:
|
|
20
|
-
python-version: [3.
|
|
21
|
-
snakemake-version: ["==7.32.4", ">8"]
|
|
20
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
21
|
+
snakemake-version: ["==7.32.4", ">8,<9", ">=9,<10"]
|
|
22
22
|
exclude:
|
|
23
23
|
# Exclude incompatible combinations
|
|
24
|
-
- python-version: 3.8
|
|
25
|
-
snakemake-version: ">8"
|
|
26
|
-
- python-version: 3.9
|
|
27
|
-
snakemake-version: ">8"
|
|
28
24
|
- python-version: "3.10"
|
|
29
|
-
snakemake-version: ">8"
|
|
25
|
+
snakemake-version: ">8,<9"
|
|
26
|
+
- python-version: "3.10"
|
|
27
|
+
snakemake-version: ">=9,<10"
|
|
28
|
+
include:
|
|
29
|
+
- python-version: "3.14"
|
|
30
|
+
snakemake-version: ">=9.22,<10"
|
|
31
|
+
|
|
30
32
|
steps:
|
|
31
33
|
- name: Checkout repository
|
|
32
34
|
uses: actions/checkout@v4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: snk-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Project-URL: Documentation, https://github.com/wytamma/snk-cli#readme
|
|
5
5
|
Project-URL: Issues, https://github.com/wytamma/snk-cli/issues
|
|
6
6
|
Project-URL: Source, https://github.com/wytamma/snk-cli
|
|
@@ -14,16 +14,18 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
19
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
20
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
21
|
Requires-Python: >=3.8
|
|
20
22
|
Requires-Dist: art~=5.9
|
|
21
|
-
Requires-Dist: datrie>=0.8.2
|
|
22
23
|
Requires-Dist: makefun~=1.15
|
|
23
24
|
Requires-Dist: pulp<2.8
|
|
24
25
|
Requires-Dist: rich>=10.11.0
|
|
25
26
|
Requires-Dist: shellingham>=1.3.0
|
|
26
|
-
Requires-Dist: snakemake>=7
|
|
27
|
+
Requires-Dist: snakemake>=7; python_version < '3.14'
|
|
28
|
+
Requires-Dist: snakemake>=9.22; python_version >= '3.14'
|
|
27
29
|
Requires-Dist: typer~=0.9
|
|
28
30
|
Description-Content-Type: text/markdown
|
|
29
31
|
|
|
@@ -21,18 +21,20 @@ classifiers = [
|
|
|
21
21
|
"Programming Language :: Python :: 3.10",
|
|
22
22
|
"Programming Language :: Python :: 3.11",
|
|
23
23
|
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
24
26
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
25
27
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
26
28
|
]
|
|
27
29
|
dependencies = [
|
|
28
|
-
"snakemake>=7",
|
|
30
|
+
"snakemake>=7; python_version < '3.14'",
|
|
31
|
+
"snakemake>=9.22; python_version >= '3.14'",
|
|
29
32
|
"typer~=0.9",
|
|
30
33
|
"shellingham >=1.3.0",
|
|
31
34
|
"rich >=10.11.0",
|
|
32
35
|
"pulp<2.8", # Pin pulp <2.8 for snakemake: https://github.com/snakemake/snakemake/issues/2607
|
|
33
36
|
"art~=5.9",
|
|
34
37
|
"makefun~=1.15",
|
|
35
|
-
"datrie>=0.8.2",
|
|
36
38
|
]
|
|
37
39
|
|
|
38
40
|
[project.urls]
|
|
@@ -45,12 +47,16 @@ path = "src/snk_cli/__about__.py"
|
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
[[tool.hatch.envs.snakemake.matrix]]
|
|
48
|
-
snakemake = ["==7.32.4"] # Compatible with Python 3.
|
|
49
|
-
python = ["3.
|
|
50
|
+
snakemake = ["==7.32.4"] # Compatible with Python 3.10–3.13
|
|
51
|
+
python = ["3.10", "3.11", "3.12", "3.13"]
|
|
52
|
+
|
|
53
|
+
[[tool.hatch.envs.snakemake.matrix]]
|
|
54
|
+
snakemake = [">8,<9", ">=9,<10"]
|
|
55
|
+
python = ["3.11", "3.12", "3.13"]
|
|
50
56
|
|
|
51
57
|
[[tool.hatch.envs.snakemake.matrix]]
|
|
52
|
-
snakemake = ["
|
|
53
|
-
python = ["3.
|
|
58
|
+
snakemake = [">=9.22,<10"] # Python 3.14 support starts with Snakemake 9.22
|
|
59
|
+
python = ["3.14"]
|
|
54
60
|
|
|
55
61
|
[tool.hatch.envs.default]
|
|
56
62
|
dependencies = [
|
|
@@ -69,6 +75,7 @@ cov = [
|
|
|
69
75
|
"test-cov",
|
|
70
76
|
"cov-report",
|
|
71
77
|
]
|
|
78
|
+
list-deps = "pip list"
|
|
72
79
|
|
|
73
80
|
[[tool.hatch.envs.all.matrix]]
|
|
74
81
|
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
# This file contains functions to create and manage conda environments for snakemake workflows
|
|
2
|
-
# it needs to work with v 7 and
|
|
2
|
+
# it needs to work with v 7, 8 and 9 of snakemake
|
|
3
3
|
#
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from packaging import version
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
+
import inspect
|
|
7
8
|
import os
|
|
8
9
|
|
|
9
10
|
from snk_cli.utils import check_command_available
|
|
10
11
|
from snakemake.deployment.conda import Env
|
|
11
|
-
from snakemake.persistence import Persistence
|
|
12
12
|
import snakemake
|
|
13
13
|
|
|
14
14
|
snakemake_version = version.parse(snakemake.__version__)
|
|
15
15
|
is_snakemake_version_8_or_above = snakemake_version >= version.parse('8')
|
|
16
|
+
is_snakemake_version_9_or_above = snakemake_version >= version.parse('9')
|
|
16
17
|
|
|
17
18
|
@dataclass
|
|
18
|
-
class PersistenceMock
|
|
19
|
+
class PersistenceMock:
|
|
19
20
|
"""
|
|
20
21
|
Mock for workflow.persistence
|
|
21
22
|
"""
|
|
@@ -27,9 +28,14 @@ class PersistenceMock(Persistence):
|
|
|
27
28
|
container_img_path: Path = None
|
|
28
29
|
aux_path: Path = None
|
|
29
30
|
|
|
31
|
+
def __post_init__(self):
|
|
32
|
+
for path in (self.conda_env_path, self.conda_env_archive_path):
|
|
33
|
+
if path:
|
|
34
|
+
Path(path).mkdir(parents=True, exist_ok=True)
|
|
35
|
+
|
|
30
36
|
|
|
31
37
|
def get_frontend():
|
|
32
|
-
if check_command_available("mamba"):
|
|
38
|
+
if check_command_available("mamba") and not is_snakemake_version_9_or_above:
|
|
33
39
|
conda_frontend = "mamba"
|
|
34
40
|
else:
|
|
35
41
|
conda_frontend = "conda"
|
|
@@ -70,6 +76,7 @@ def create_workflow_v8(
|
|
|
70
76
|
WorkflowSettings,
|
|
71
77
|
StorageSettings,
|
|
72
78
|
)
|
|
79
|
+
workflow_kwargs = {"logger_manager": None} if "logger_manager" in inspect.signature(Workflow).parameters else {}
|
|
73
80
|
conda_frontend = get_frontend()
|
|
74
81
|
workflow = Workflow(
|
|
75
82
|
config_settings=ConfigSettings(),
|
|
@@ -80,6 +87,7 @@ def create_workflow_v8(
|
|
|
80
87
|
conda_frontend=conda_frontend,
|
|
81
88
|
conda_prefix=conda_prefix
|
|
82
89
|
),
|
|
90
|
+
**workflow_kwargs,
|
|
83
91
|
)
|
|
84
92
|
persistence = PersistenceMock(
|
|
85
93
|
conda_env_path=Path(conda_prefix).resolve() if conda_prefix else None,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import typer
|
|
2
|
-
from
|
|
3
|
-
from typing import List, Callable, get_origin
|
|
2
|
+
from typing import List, Callable, get_args, get_origin
|
|
4
3
|
from inspect import signature, Parameter
|
|
5
4
|
from makefun import with_signature
|
|
6
5
|
from enum import Enum
|
|
@@ -159,10 +158,7 @@ class DynamicTyper:
|
|
|
159
158
|
annotation_type = Enum(f'{option.name}', {str(e): annotation_type(e) for e in option.choices})
|
|
160
159
|
click_type = None
|
|
161
160
|
if get_origin(annotation_type) is dict or annotation_type is dict:
|
|
162
|
-
click_type =
|
|
163
|
-
if hasattr(annotation_type, '__args__') and len(annotation_type.__args__) == 2:
|
|
164
|
-
click_type = Tuple([str, annotation_type.__args__[1]])
|
|
165
|
-
annotation_type = List[Tuple]
|
|
161
|
+
annotation_type, click_type = self._get_dict_cli_types(annotation_type)
|
|
166
162
|
if type(default) is dict:
|
|
167
163
|
default = [[k, v] for k, v in default.items()]
|
|
168
164
|
return Parameter(
|
|
@@ -179,6 +175,20 @@ class DynamicTyper:
|
|
|
179
175
|
annotation=annotation_type,
|
|
180
176
|
)
|
|
181
177
|
|
|
178
|
+
@staticmethod
|
|
179
|
+
def _get_dict_cli_types(dict_type):
|
|
180
|
+
"""
|
|
181
|
+
Return the annotation and parser type for a repeatable key-value option.
|
|
182
|
+
|
|
183
|
+
Typer uses the outer List to make an option repeatable, but does not
|
|
184
|
+
support parameterized tuples inside a List. The unparameterized tuple
|
|
185
|
+
accurately describes each parsed value, while click_type supplies the
|
|
186
|
+
concrete key and value parsers.
|
|
187
|
+
"""
|
|
188
|
+
type_args = get_args(dict_type)
|
|
189
|
+
value_type = type_args[1] if len(type_args) == 2 else str
|
|
190
|
+
return List[tuple], (str, value_type)
|
|
191
|
+
|
|
182
192
|
def check_if_option_passed_via_command_line(self, option: Option):
|
|
183
193
|
"""
|
|
184
194
|
Check if an option is passed via the command line.
|
|
@@ -12,6 +12,10 @@ from ..workflow import Workflow
|
|
|
12
12
|
from rich.console import Console
|
|
13
13
|
from rich.syntax import Syntax
|
|
14
14
|
from snakemake.deployment.conda import Conda, CreateCondaEnvironmentException
|
|
15
|
+
try:
|
|
16
|
+
from snakemake_interface_common.exceptions import WorkflowError
|
|
17
|
+
except ImportError:
|
|
18
|
+
from snakemake.exceptions import WorkflowError
|
|
15
19
|
|
|
16
20
|
from concurrent.futures import ProcessPoolExecutor
|
|
17
21
|
|
|
@@ -30,7 +34,7 @@ def create_conda_environment_wrapper(args):
|
|
|
30
34
|
env_path = Path(env_path_str).resolve()
|
|
31
35
|
try:
|
|
32
36
|
conda_environment_factory(env_path, conda_prefix_dir).create()
|
|
33
|
-
except CreateCondaEnvironmentException as e:
|
|
37
|
+
except (CreateCondaEnvironmentException, WorkflowError) as e:
|
|
34
38
|
typer.secho(str(e), fg="red", err=True)
|
|
35
39
|
return 1
|
|
36
40
|
return 0
|
|
@@ -160,8 +164,13 @@ class EnvApp(DynamicTyper):
|
|
|
160
164
|
)
|
|
161
165
|
for path in env_paths
|
|
162
166
|
]
|
|
163
|
-
|
|
164
|
-
status_codes =
|
|
167
|
+
if max_workers == 1:
|
|
168
|
+
status_codes = [
|
|
169
|
+
create_conda_environment_wrapper(args) for args in env_args
|
|
170
|
+
]
|
|
171
|
+
else:
|
|
172
|
+
with ProcessPoolExecutor(max_workers=max_workers) as executor:
|
|
173
|
+
status_codes = list(executor.map(create_conda_environment_wrapper, env_args))
|
|
165
174
|
if any(status_codes):
|
|
166
175
|
self.error("Failed to create all conda environments!")
|
|
167
176
|
if names:
|
|
@@ -5,7 +5,10 @@ from contextlib import contextmanager
|
|
|
5
5
|
|
|
6
6
|
from snk_cli.dynamic_typer import DynamicTyper
|
|
7
7
|
from snk_cli.options.option import Option
|
|
8
|
-
from snk_cli.conda import
|
|
8
|
+
from snk_cli.conda import (
|
|
9
|
+
is_snakemake_version_8_or_above,
|
|
10
|
+
is_snakemake_version_9_or_above,
|
|
11
|
+
)
|
|
9
12
|
from ..workflow import Workflow
|
|
10
13
|
from snk_cli.utils import (
|
|
11
14
|
parse_config_args,
|
|
@@ -219,21 +222,24 @@ class RunApp(DynamicTyper):
|
|
|
219
222
|
)
|
|
220
223
|
|
|
221
224
|
if conda_found and self.snk_config.conda and not no_conda:
|
|
222
|
-
|
|
223
|
-
[
|
|
224
|
-
"--use-conda",
|
|
225
|
-
f"--conda-prefix={self.conda_prefix_dir}",
|
|
226
|
-
]
|
|
227
|
-
)
|
|
228
|
-
if not check_command_available("mamba"):
|
|
229
|
-
if verbose:
|
|
230
|
-
self.log(
|
|
231
|
-
"Could not find mamba, using conda instead...",
|
|
232
|
-
color=typer.colors.MAGENTA,
|
|
233
|
-
)
|
|
234
|
-
args.append("--conda-frontend=conda")
|
|
225
|
+
if is_snakemake_version_9_or_above: # support for mamba deprecated since v8.20.6(#3121)
|
|
226
|
+
args.extend(["--software-deployment-method", "conda"])
|
|
235
227
|
else:
|
|
236
|
-
args.
|
|
228
|
+
args.extend(
|
|
229
|
+
[
|
|
230
|
+
"--use-conda",
|
|
231
|
+
f"--conda-prefix={self.conda_prefix_dir}",
|
|
232
|
+
]
|
|
233
|
+
)
|
|
234
|
+
if not check_command_available("mamba"):
|
|
235
|
+
if verbose:
|
|
236
|
+
self.log(
|
|
237
|
+
"Could not find mamba, using conda instead...",
|
|
238
|
+
color=typer.colors.MAGENTA,
|
|
239
|
+
)
|
|
240
|
+
args.append("--conda-frontend=conda")
|
|
241
|
+
else:
|
|
242
|
+
args.append("--conda-frontend=mamba")
|
|
237
243
|
|
|
238
244
|
if verbose:
|
|
239
245
|
args.insert(0, "--verbose")
|
|
@@ -395,16 +401,15 @@ class RunApp(DynamicTyper):
|
|
|
395
401
|
)
|
|
396
402
|
yield
|
|
397
403
|
finally:
|
|
398
|
-
if
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
)
|
|
407
|
-
remove_resource(copied_resource)
|
|
404
|
+
if cleanup:
|
|
405
|
+
for copied_resource in copied_resources:
|
|
406
|
+
if copied_resource.exists():
|
|
407
|
+
if self.verbose:
|
|
408
|
+
self.log(
|
|
409
|
+
f"Deleting '{copied_resource.name}' resource...",
|
|
410
|
+
color=typer.colors.MAGENTA,
|
|
411
|
+
)
|
|
412
|
+
remove_resource(copied_resource)
|
|
408
413
|
|
|
409
414
|
def execute_snakemake(args):
|
|
410
415
|
"""
|
|
@@ -17,11 +17,12 @@ class SnkCliRunner:
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
cli: CLI
|
|
20
|
-
runner = CliRunner(
|
|
20
|
+
runner = CliRunner()
|
|
21
21
|
|
|
22
22
|
def invoke(self, args: List[str]) -> Result:
|
|
23
|
+
args = [str(arg) for arg in args]
|
|
23
24
|
old_argv = sys.argv
|
|
24
25
|
sys.argv = ['cli'] + args # ensure that the CLI is invoked with the correct arguments
|
|
25
26
|
result = self.runner.invoke(self.cli.app, args)
|
|
26
27
|
sys.argv = old_argv
|
|
27
|
-
return result
|
|
28
|
+
return result
|
|
@@ -47,4 +47,4 @@ def test_snakemake_help(local_runner: SnkCliRunner):
|
|
|
47
47
|
def test_snakemake_version(local_runner: SnkCliRunner):
|
|
48
48
|
res = local_runner(["run", "--snake-v"])
|
|
49
49
|
assert res.exit_code == 0, res.stderr
|
|
50
|
-
assert res.stdout.startswith("7.32.4") or res.stdout.startswith("8.")
|
|
50
|
+
assert res.stdout.startswith("7.32.4") or res.stdout.startswith("8.") or res.stdout.startswith("9.")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from snk_cli.conda import conda_environment_factory
|
|
2
|
+
from snakemake.deployment.conda import Env
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_conda_env(tmp_path):
|
|
7
|
+
env = conda_environment_factory("tests/data/workflow/workflow/envs/wget.yml", tmp_path)
|
|
8
|
+
assert isinstance(env, Env)
|
|
9
|
+
assert not Path(env.address).exists()
|
|
10
|
+
env.create()
|
|
11
|
+
assert Path(env.address).exists()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_conda_env_content(tmp_path):
|
|
15
|
+
env_file = Path("tests/data/workflow/workflow/envs/wget.yml").resolve()
|
|
16
|
+
env = conda_environment_factory(env_file, tmp_path)
|
|
17
|
+
assert env.content == env_file.read_bytes()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_conda_env_factory_creates_prefix(tmp_path):
|
|
21
|
+
env_file = Path("tests/data/workflow/workflow/envs/wget.yml").resolve()
|
|
22
|
+
conda_prefix = tmp_path / "conda"
|
|
23
|
+
conda_environment_factory(env_file, conda_prefix)
|
|
24
|
+
assert conda_prefix.exists()
|
|
@@ -4,6 +4,7 @@ from snk_cli.dynamic_typer import DynamicTyper
|
|
|
4
4
|
from snk_cli.options import Option
|
|
5
5
|
from inspect import signature, Parameter
|
|
6
6
|
import typer
|
|
7
|
+
from typing import Dict, List
|
|
7
8
|
|
|
8
9
|
class SubApp(DynamicTyper):
|
|
9
10
|
def __init__(self):
|
|
@@ -94,6 +95,27 @@ def test_create_cli_parameter(dynamic_typer):
|
|
|
94
95
|
assert param.kind == Parameter.POSITIONAL_OR_KEYWORD
|
|
95
96
|
|
|
96
97
|
|
|
98
|
+
def test_create_dict_cli_parameter(dynamic_typer):
|
|
99
|
+
option = Option(
|
|
100
|
+
name="labels",
|
|
101
|
+
type=Dict[str, int],
|
|
102
|
+
required=False,
|
|
103
|
+
default={"first": 1},
|
|
104
|
+
help="Labels",
|
|
105
|
+
short=None,
|
|
106
|
+
updated=False,
|
|
107
|
+
original_key="labels",
|
|
108
|
+
flag="--labels",
|
|
109
|
+
short_flag=None,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
param = dynamic_typer._create_cli_parameter(option)
|
|
113
|
+
|
|
114
|
+
assert param.annotation == List[tuple]
|
|
115
|
+
assert param.default.click_type == (str, int)
|
|
116
|
+
assert param.default.default == [["first", 1]]
|
|
117
|
+
|
|
118
|
+
|
|
97
119
|
|
|
98
120
|
def test_add_dynamic_options(dynamic_typer):
|
|
99
121
|
def func(name: str):
|
|
@@ -145,4 +167,4 @@ def test_calling_cli_produces_help(dynamic_app: DynamicTyper, capsys):
|
|
|
145
167
|
except SystemExit:
|
|
146
168
|
pass
|
|
147
169
|
captured = capsys.readouterr()
|
|
148
|
-
assert "Usage" in captured.out
|
|
170
|
+
assert "Usage" in captured.out
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from snk_cli.conda import conda_environment_factory
|
|
2
|
-
from snakemake.deployment.conda import Env
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def test_conda_env(tmp_path):
|
|
7
|
-
env = conda_environment_factory("tests/data/workflow/workflow/envs/wget.yml", tmp_path)
|
|
8
|
-
assert isinstance(env, Env)
|
|
9
|
-
assert not Path(env.address).exists()
|
|
10
|
-
env.create()
|
|
11
|
-
assert Path(env.address).exists()
|
|
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
|