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.
Files changed (72) hide show
  1. {snk_cli-0.7.2 → snk_cli-0.8.0}/.github/workflows/publish.yml +1 -1
  2. {snk_cli-0.7.2 → snk_cli-0.8.0}/.github/workflows/tests.yml +9 -7
  3. {snk_cli-0.7.2 → snk_cli-0.8.0}/PKG-INFO +5 -3
  4. {snk_cli-0.7.2 → snk_cli-0.8.0}/pyproject.toml +13 -6
  5. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/__about__.py +1 -1
  6. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/conda.py +12 -4
  7. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/dynamic_typer.py +16 -6
  8. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/env.py +12 -3
  9. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/run.py +30 -25
  10. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/testing.py +3 -2
  11. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/conftest.py +0 -3
  12. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_run.py +1 -1
  13. snk_cli-0.8.0/tests/test_conda_env.py +24 -0
  14. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_dynamic_typer.py +23 -1
  15. snk_cli-0.7.2/tests/test_conda_env.py +0 -11
  16. {snk_cli-0.7.2 → snk_cli-0.8.0}/.gitignore +0 -0
  17. {snk_cli-0.7.2 → snk_cli-0.8.0}/LICENSE.txt +0 -0
  18. {snk_cli-0.7.2 → snk_cli-0.8.0}/README.md +0 -0
  19. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/index.md +0 -0
  20. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/cli.md +0 -0
  21. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/config.md +0 -0
  22. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/dynamic_typer.md +0 -0
  23. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/options.md +0 -0
  24. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/subcommands.md +0 -0
  25. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/testing.md +0 -0
  26. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/utils.md +0 -0
  27. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/validate.md +0 -0
  28. {snk_cli-0.7.2 → snk_cli-0.8.0}/docs/reference/workflow.md +0 -0
  29. {snk_cli-0.7.2 → snk_cli-0.8.0}/mkdocs.yml +0 -0
  30. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/__init__.py +0 -0
  31. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/cli.py +0 -0
  32. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/config/__init__.py +0 -0
  33. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/config/config.py +0 -0
  34. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/config/utils.py +0 -0
  35. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/options/__init__.py +0 -0
  36. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/options/option.py +0 -0
  37. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/options/utils.py +0 -0
  38. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/__init__.py +0 -0
  39. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/config.py +0 -0
  40. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/profile.py +0 -0
  41. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/subcommands/script.py +0 -0
  42. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/utils.py +0 -0
  43. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/validate.py +0 -0
  44. {snk_cli-0.7.2 → snk_cli-0.8.0}/src/snk_cli/workflow.py +0 -0
  45. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/__init__.py +0 -0
  46. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/artic_v4.1.bed +0 -0
  47. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/config.yaml +0 -0
  48. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/cov.fasta +0 -0
  49. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/Snakefile +0 -0
  50. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/cli.py +0 -0
  51. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/config.yaml +0 -0
  52. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/print_config/snk.yaml +0 -0
  53. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/cli.py +0 -0
  54. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/config.yaml +0 -0
  55. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/resources/data.txt +0 -0
  56. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/snk.yaml +0 -0
  57. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/things/__about__.py +0 -0
  58. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/Snakefile +0 -0
  59. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/envs/wget.yml +0 -0
  60. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/profiles/base/config.yaml +0 -0
  61. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/profiles/slurm/config.yaml +0 -0
  62. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/data/workflow/workflow/scripts/hello.py +0 -0
  63. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_SnkConfig.py +0 -0
  64. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/__init__.py +0 -0
  65. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_dynamic_options.py +0 -0
  66. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_profile.py +0 -0
  67. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_snk_config.py +0 -0
  68. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_subcommands.py +0 -0
  69. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_validate.py +0 -0
  70. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_cli/test_workflow_cli.py +0 -0
  71. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/test_types.py +0 -0
  72. {snk_cli-0.7.2 → snk_cli-0.8.0}/tests/utils.py +0 -0
@@ -14,7 +14,7 @@ jobs:
14
14
  - uses: actions/setup-python@v4
15
15
  with:
16
16
  python-version: 3.x
17
- - uses: actions/cache@v2
17
+ - uses: actions/cache@v5
18
18
  with:
19
19
  key: ${{ github.ref }}
20
20
  path: .cache
@@ -17,16 +17,18 @@ jobs:
17
17
  runs-on: ubuntu-latest
18
18
  strategy:
19
19
  matrix:
20
- python-version: [3.8, 3.9, "3.10", 3.11, 3.12]
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.7.2
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.9–3.12
49
- python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
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 = [">8"] # Compatible only with Python 3.11 and 3.12
53
- python = ["3.11", "3.12"]
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,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2024-present Wytamma Wirth <wytamma.wirth@me.com>
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
- __version__ = "0.7.2"
4
+ __version__ = "0.8.0"
@@ -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 8 of snakemake
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(Persistence):
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 click import Tuple
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 = Tuple([str, str])
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
- with ProcessPoolExecutor(max_workers=max_workers) as executor:
164
- status_codes = executor.map(create_conda_environment_wrapper, env_args)
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 is_snakemake_version_8_or_above
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
- args.extend(
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.append("--conda-frontend=mamba")
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 not cleanup:
399
- return
400
- for copied_resource in copied_resources:
401
- if copied_resource.exists():
402
- if self.verbose:
403
- self.log(
404
- f"Deleting '{copied_resource.name}' resource...",
405
- color=typer.colors.MAGENTA,
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(mix_stderr=False)
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
@@ -1,10 +1,7 @@
1
- from typing import Tuple
2
1
  import pytest
3
2
  from pathlib import Path
4
3
  from .utils import SnkCliRunner
5
- from snk_cli.config import SnkConfig
6
4
  from snk_cli import CLI
7
- import yaml
8
5
 
9
6
  @pytest.fixture()
10
7
  def example_config():
@@ -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