snk-cli 0.0.1__tar.gz → 0.1.1__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.1.1/.github/workflows/mkdocs.yml +23 -0
  2. {snk_cli-0.0.1 → snk_cli-0.1.1}/PKG-INFO +7 -2
  3. snk_cli-0.1.1/README.md +6 -0
  4. snk_cli-0.1.1/docs/index.md +8 -0
  5. snk_cli-0.1.1/docs/reference/cli.md +2 -0
  6. snk_cli-0.1.1/docs/reference/config.md +4 -0
  7. snk_cli-0.1.1/docs/reference/dynamic_typer.md +2 -0
  8. snk_cli-0.1.1/docs/reference/options.md +4 -0
  9. snk_cli-0.1.1/docs/reference/subcommands.md +12 -0
  10. snk_cli-0.1.1/docs/reference/testing.md +2 -0
  11. snk_cli-0.1.1/docs/reference/utils.md +2 -0
  12. snk_cli-0.1.1/docs/reference/validate.md +2 -0
  13. snk_cli-0.1.1/docs/reference/workflow.md +2 -0
  14. snk_cli-0.1.1/mkdocs.yml +44 -0
  15. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/__about__.py +1 -1
  16. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/cli.py +47 -29
  17. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/config/config.py +45 -4
  18. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/config/utils.py +13 -6
  19. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/dynamic_typer.py +58 -14
  20. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/options/utils.py +10 -5
  21. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/config.py +10 -5
  22. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/run.py +50 -26
  23. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/testing.py +9 -1
  24. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/utils.py +23 -3
  25. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/validate.py +10 -6
  26. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/workflow.py +35 -15
  27. snk_cli-0.1.1/tests/conftest.py +18 -0
  28. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_cli/test_run.py +8 -7
  29. snk_cli-0.1.1/tests/test_cli/test_snk_config.py +29 -0
  30. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_cli/test_workflow_cli.py +0 -1
  31. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_dynamic_typer.py +8 -0
  32. snk_cli-0.1.1/tests/utils.py +22 -0
  33. snk_cli-0.0.1/README.md +0 -1
  34. snk_cli-0.0.1/tests/conftest.py +0 -38
  35. snk_cli-0.0.1/tests/test_cli/test_snk_config.py +0 -17
  36. snk_cli-0.0.1/tests/utils.py +0 -7
  37. {snk_cli-0.0.1 → snk_cli-0.1.1}/.github/workflows/publish.yml +0 -0
  38. {snk_cli-0.0.1 → snk_cli-0.1.1}/.github/workflows/tests.yml +0 -0
  39. {snk_cli-0.0.1 → snk_cli-0.1.1}/.gitignore +0 -0
  40. {snk_cli-0.0.1 → snk_cli-0.1.1}/LICENSE.txt +0 -0
  41. {snk_cli-0.0.1 → snk_cli-0.1.1}/pyproject.toml +0 -0
  42. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/__init__.py +0 -0
  43. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/config/__init__.py +0 -0
  44. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/options/__init__.py +0 -0
  45. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/options/option.py +0 -0
  46. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/__init__.py +0 -0
  47. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/env.py +0 -0
  48. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/profile.py +0 -0
  49. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/script.py +0 -0
  50. {snk_cli-0.0.1 → snk_cli-0.1.1}/src/snk_cli/subcommands/utils.py +0 -0
  51. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/__init__.py +0 -0
  52. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/artic_v4.1.bed +0 -0
  53. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/config.yaml +0 -0
  54. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/cov.fasta +0 -0
  55. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/print_config/Snakefile +0 -0
  56. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/print_config/cli.py +0 -0
  57. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/print_config/config.yaml +0 -0
  58. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/print_config/snk.yaml +0 -0
  59. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/cli.py +0 -0
  60. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/config.yaml +0 -0
  61. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/resources/data.txt +0 -0
  62. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/snk.yaml +0 -0
  63. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/things/__about__.py +0 -0
  64. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/workflow/Snakefile +0 -0
  65. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/workflow/envs/python.yml +0 -0
  66. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/workflow/profiles/base/config.yaml +0 -0
  67. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/workflow/profiles/slurm/config.yaml +0 -0
  68. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/data/workflow/workflow/scripts/hello.py +0 -0
  69. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_cli/__init__.py +0 -0
  70. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_cli/test_dynamic_options.py +0 -0
  71. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_cli/test_subcommands.py +0 -0
  72. {snk_cli-0.0.1 → snk_cli-0.1.1}/tests/test_cli/test_validate.py +0 -0
@@ -0,0 +1,23 @@
1
+
2
+ name: mkdocs
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - main
8
+ permissions:
9
+ contents: write
10
+ jobs:
11
+ deploy:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ - uses: actions/setup-python@v4
16
+ with:
17
+ python-version: 3.x
18
+ - uses: actions/cache@v2
19
+ with:
20
+ key: ${{ github.ref }}
21
+ path: .cache
22
+ - run: pip install "mkdocstrings==0.22.0" "mkdocstrings-python==1.3.*" "mkdocs-material"
23
+ - run: mkdocs gh-deploy --force
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: snk-cli
3
- Version: 0.0.1
3
+ Version: 0.1.1
4
4
  Project-URL: Documentation, https://github.com/unknown/snk-cli#readme
5
5
  Project-URL: Issues, https://github.com/unknown/snk-cli/issues
6
6
  Project-URL: Source, https://github.com/unknown/snk-cli
@@ -27,3 +27,8 @@ Requires-Dist: typer[all]~=0.9.0
27
27
  Description-Content-Type: text/markdown
28
28
 
29
29
  # snk-cli
30
+ [![PyPI - Version](https://img.shields.io/pypi/v/snk-cli.svg)](https://pypi.org/project/snk-cli)
31
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/snk-cli.svg)](https://pypi.org/project/snk-cli)
32
+ [![write-the - docs](https://badgen.net/badge/write-the/docs/blue?icon=https://raw.githubusercontent.com/Wytamma/write-the/master/images/write-the-icon.svg)](https://write-the.wytamma.com/)
33
+
34
+ Used internally by [snk](https://snk.wytamma.com/) to generate dynamic [snakemake](https://snakemake.github.io/) CLIs. You can use `snk-cli` to build self contained snakemake tools. See here for more details -> [https://snk.wytamma.com/workflow_packages](https://snk.wytamma.com/workflow_packages/)
@@ -0,0 +1,6 @@
1
+ # snk-cli
2
+ [![PyPI - Version](https://img.shields.io/pypi/v/snk-cli.svg)](https://pypi.org/project/snk-cli)
3
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/snk-cli.svg)](https://pypi.org/project/snk-cli)
4
+ [![write-the - docs](https://badgen.net/badge/write-the/docs/blue?icon=https://raw.githubusercontent.com/Wytamma/write-the/master/images/write-the-icon.svg)](https://write-the.wytamma.com/)
5
+
6
+ Used internally by [snk](https://snk.wytamma.com/) to generate dynamic [snakemake](https://snakemake.github.io/) CLIs. You can use `snk-cli` to build self contained snakemake tools. See here for more details -> [https://snk.wytamma.com/workflow_packages](https://snk.wytamma.com/workflow_packages/)
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Home
3
+ ---
4
+ # snk-cli
5
+
6
+ The dynamic CLI from [snk](https://snk.wytamma.com/).
7
+
8
+ This site primary holds the reference docs for snk-cli
@@ -0,0 +1,2 @@
1
+ ::: src.snk_cli.cli
2
+
@@ -0,0 +1,4 @@
1
+ ::: src.snk_cli.config.config
2
+
3
+ ::: src.snk_cli.config.utils
4
+
@@ -0,0 +1,2 @@
1
+ ::: src.snk_cli.dynamic_typer
2
+
@@ -0,0 +1,4 @@
1
+ ::: src.snk_cli.options.option
2
+
3
+ ::: src.snk_cli.options.utils
4
+
@@ -0,0 +1,12 @@
1
+ ::: src.snk_cli.subcommands.run
2
+
3
+ ::: src.snk_cli.subcommands.config
4
+
5
+ ::: src.snk_cli.subcommands.env
6
+
7
+ ::: src.snk_cli.subcommands.profile
8
+
9
+ ::: src.snk_cli.subcommands.utils
10
+
11
+ ::: src.snk_cli.subcommands.script
12
+
@@ -0,0 +1,2 @@
1
+ ::: src.snk_cli.testing
2
+
@@ -0,0 +1,2 @@
1
+ ::: src.snk_cli.utils
2
+
@@ -0,0 +1,2 @@
1
+ ::: src.snk_cli.validate
2
+
@@ -0,0 +1,2 @@
1
+ ::: src.snk_cli.workflow
2
+
@@ -0,0 +1,44 @@
1
+
2
+ site_name: snk_cli
3
+ # repo_url: https://github.com/wytamma/write-the
4
+
5
+ theme:
6
+ name: "material"
7
+ # homepage: https://write-the.wytamma.com
8
+ # logo: assets/logo.png
9
+ # favicon: images/favicon.png
10
+ palette:
11
+ - scheme: default
12
+ toggle:
13
+ icon: material/brightness-7
14
+ name: Switch to dark mode
15
+ - scheme: slate
16
+ toggle:
17
+ icon: material/brightness-4
18
+ name: Switch to light mode
19
+ features:
20
+ - toc.follow
21
+ - content.action.edit
22
+
23
+ extra:
24
+ social:
25
+ - icon: fontawesome/solid/robot
26
+ link: https://github.com/Wytamma/write-the
27
+ name: Generated with write-the
28
+
29
+ plugins:
30
+ - search
31
+ - mkdocstrings:
32
+ handlers:
33
+ python:
34
+ options:
35
+ docstring_style: "google"
36
+
37
+ markdown_extensions:
38
+ - pymdownx.highlight:
39
+ anchor_linenums: true
40
+ line_spans: __span
41
+ pygments_lang_class: true
42
+ - pymdownx.inlinehilite
43
+ - pymdownx.snippets
44
+ - pymdownx.superfences
@@ -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.0.1"
4
+ __version__ = "0.1.1"
@@ -24,10 +24,13 @@ from snk_cli.workflow import Workflow
24
24
  class CLI(DynamicTyper):
25
25
  """
26
26
  Constructor for the dynamic Snk CLI class.
27
+
27
28
  Args:
28
29
  workflow_dir_path (Path): Path to the workflow directory.
30
+
29
31
  Side Effects:
30
32
  Initializes the CLI class.
33
+
31
34
  Examples:
32
35
  >>> CLI(Path('/path/to/workflow'))
33
36
  """
@@ -58,10 +61,10 @@ class CLI(DynamicTyper):
58
61
  )
59
62
  else:
60
63
  self.snk_config = snk_config
61
- if self.snk_config.version:
62
- self.version = self.snk_config.version
63
- else:
64
+ if self.workflow.version:
64
65
  self.version = self.workflow.version
66
+ else:
67
+ self.version = self.snk_config.version
65
68
  self.options = build_dynamic_cli_options(self.snakemake_config, self.snk_config)
66
69
  self.snakefile = self._find_snakefile()
67
70
  self.conda_prefix_dir = self.workflow.conda_prefix_dir
@@ -88,31 +91,35 @@ class CLI(DynamicTyper):
88
91
  invoke_without_command=True,
89
92
  context_settings={"help_option_names": ["-h", "--help"]},
90
93
  )
91
- self.register_command(self.info, help="Show information about the workflow.")
92
-
93
- run_app = RunApp(
94
- conda_prefix_dir=self.conda_prefix_dir,
95
- snk_config=self.snk_config,
96
- singularity_prefix_dir=self.singularity_prefix_dir,
97
- snakefile=self.snakefile,
98
- workflow=self.workflow,
99
- verbose=self.verbose,
100
- logo=self.logo,
101
- dynamic_run_options=self.options,
102
- )
94
+
103
95
  # Subcommands
104
- self.register_command(
105
- run_app,
106
- name="run",
107
- )
108
- self.register_command(
109
- ConfigApp(
96
+ if "info" in self.snk_config.commands:
97
+ self.register_command(self.info, help="Show information about the workflow.")
98
+
99
+ if "run" in self.snk_config.commands:
100
+ run_app = RunApp(
101
+ conda_prefix_dir=self.conda_prefix_dir,
102
+ snk_config=self.snk_config,
103
+ singularity_prefix_dir=self.singularity_prefix_dir,
104
+ snakefile=self.snakefile,
110
105
  workflow=self.workflow,
111
- options=self.options,
112
- ),
113
- name="config",
114
- )
115
- if self.workflow.environments:
106
+ verbose=self.verbose,
107
+ logo=self.logo,
108
+ dynamic_run_options=self.options,
109
+ )
110
+ self.register_command(
111
+ run_app,
112
+ name="run",
113
+ )
114
+ if "config" in self.snk_config.commands:
115
+ self.register_command(
116
+ ConfigApp(
117
+ workflow=self.workflow,
118
+ options=self.options,
119
+ ),
120
+ name="config",
121
+ )
122
+ if self.workflow.environments and "env" in self.snk_config.commands:
116
123
  self.register_group(
117
124
  EnvApp(
118
125
  workflow=self.workflow,
@@ -123,7 +130,7 @@ class CLI(DynamicTyper):
123
130
  name="env",
124
131
  help="Access the workflow conda environments.",
125
132
  )
126
- if self.workflow.scripts:
133
+ if self.workflow.scripts and "script" in self.snk_config.commands:
127
134
  self.register_group(
128
135
  ScriptApp(
129
136
  workflow=self.workflow,
@@ -134,7 +141,7 @@ class CLI(DynamicTyper):
134
141
  name="script",
135
142
  help="Access the workflow scripts.",
136
143
  )
137
- if self.workflow.profiles:
144
+ if self.workflow.profiles and "profile" in self.snk_config.commands:
138
145
  self.register_group(
139
146
  ProfileApp(
140
147
  workflow=self.workflow,
@@ -185,10 +192,14 @@ class CLI(DynamicTyper):
185
192
  ):
186
193
  """
187
194
  Create a logo for the CLI.
195
+
188
196
  Args:
189
- font (str): The font to use for the logo.
197
+ tagline (str, optional): The tagline to include in the logo. Defaults to "A Snakemake workflow CLI generated with snk".
198
+ font (str, optional): The font to use for the logo. Defaults to "small".
199
+
190
200
  Returns:
191
201
  str: The logo.
202
+
192
203
  Examples:
193
204
  >>> CLI._create_logo()
194
205
  """
@@ -203,8 +214,13 @@ class CLI(DynamicTyper):
203
214
  def _find_snakefile(self):
204
215
  """
205
216
  Search possible snakefile locations.
217
+
206
218
  Returns:
207
219
  Path: The path to the snakefile.
220
+
221
+ Raises:
222
+ FileNotFoundError: If the snakefile is not found.
223
+
208
224
  Examples:
209
225
  >>> CLI._find_snakefile()
210
226
  """
@@ -216,8 +232,10 @@ class CLI(DynamicTyper):
216
232
  def info(self):
217
233
  """
218
234
  Display information about current workflow install.
235
+
219
236
  Returns:
220
237
  str: A JSON string containing information about the current workflow install.
238
+
221
239
  Examples:
222
240
  >>> CLI.info()
223
241
  """
@@ -7,18 +7,58 @@ import yaml
7
7
 
8
8
 
9
9
  class SnkConfigError(Exception):
10
- """Base class for all SNK config exceptions"""
10
+ """
11
+ Base class for all SNK config exceptions.
12
+ """
11
13
 
12
14
  class InvalidSnkConfigError(SnkConfigError, ValueError):
13
- """Thrown if the given SNK config appears to have an invalid format."""
15
+ """
16
+ Thrown if the given SNK config appears to have an invalid format.
17
+ """
14
18
 
15
19
  class MissingSnkConfigError(SnkConfigError, FileNotFoundError):
16
- """Thrown if the given SNK config file cannot be found."""
20
+ """
21
+ Thrown if the given SNK config file cannot be found.
22
+ """
17
23
 
18
24
  @dataclass
19
25
  class SnkConfig:
20
26
  """
21
27
  A dataclass for storing Snakemake workflow configuration.
28
+
29
+ Attributes:
30
+ art (str, optional): The art to display in the CLI. Defaults to None.
31
+ logo (str, optional): The logo to display in the CLI. Defaults to None.
32
+ tagline (str): The tagline to display in the CLI. Defaults to "A Snakemake workflow CLI generated with Snk".
33
+ font (str): The font size for the CLI. Defaults to "small".
34
+ version (Optional[str], optional): The version of the workflow. Defaults to None.
35
+ conda (bool): Whether to use conda for managing environments. Defaults to True.
36
+ resources (List[Path]): List of paths to additional resources. Defaults to an empty list.
37
+ symlink_resources (bool): Whether to symlink resources instead of copying them. Defaults to False.
38
+ skip_missing (bool): Whether to skip missing CLI options. Defaults to False.
39
+ additional_snakemake_args (List[str]): List of additional Snakemake command-line arguments. Defaults to an empty list.
40
+ commands (List[str]): List of subcommands to include in the CLI. Defaults to ["run", "script", "env", "profile", "info", "config"].
41
+ cli (dict): Dictionary of CLI options and their values. Defaults to an empty dictionary.
42
+ _snk_config_path (Path): The path to the SNK config file. Defaults to None.
43
+
44
+ Methods:
45
+ from_path(snk_config_path: Path) -> SnkConfig:
46
+ Load and validate Snk config from file.
47
+
48
+ from_workflow_dir(workflow_dir_path: Path, create_if_not_exists: bool = False) -> SnkConfig:
49
+ Load and validate SNK config from workflow directory.
50
+
51
+ validate_resources(resources: List[Path]) -> None:
52
+ Validate resources.
53
+
54
+ add_resources(resources: List[Path], workflow_dir_path: Path = None) -> None:
55
+ Add resources to the SNK config.
56
+
57
+ to_yaml(path: Path) -> None:
58
+ Write SNK config to YAML file.
59
+
60
+ save() -> None:
61
+ Save SNK config.
22
62
  """
23
63
 
24
64
  art: str = None
@@ -28,10 +68,11 @@ class SnkConfig:
28
68
  version: Optional[str] = None
29
69
  conda: bool = True
30
70
  resources: List[Path] = field(default_factory=list)
71
+ symlink_resources: bool = False
31
72
  skip_missing: bool = False # skip any missing cli options (i.e. those not in the snk file)
32
73
  additional_snakemake_args: List[str] = field(default_factory=list)
74
+ commands: List[str] = field(default_factory=lambda: ["run", "script", "env", "profile", "info", "config"])
33
75
  cli: dict = field(default_factory=dict)
34
- symlink_resources: bool = False
35
76
  _snk_config_path: Path = None
36
77
 
37
78
  @classmethod
@@ -3,17 +3,24 @@ from snakemake import load_configfile
3
3
 
4
4
  def get_version_from_config(config_path: Path, config_dict: dict = None) -> str:
5
5
  """
6
- Get the version from config. If dict not provided, load from file.
7
- If the version is a path to a __about__ file, load the version from the file.
8
- Path must be relative to the config file.
6
+ Get the version from the config file or config dictionary.
7
+
9
8
  Args:
10
9
  config_path (Path): Path to the config file.
11
- config_dict (dict): Config dict.
10
+ config_dict (dict, optional): Config dictionary. Defaults to None.
11
+
12
12
  Returns:
13
- str: Version.
13
+ str: The version.
14
+
15
+ Raises:
16
+ FileNotFoundError: If the version file (__about__.py) is not found.
17
+ KeyError: If the __version__ key is not found in the version file.
18
+
14
19
  Examples:
15
- >>> get_version_from_config_dict({"version": "0.1.0"})
20
+ >>> get_version_from_config(Path("config.yaml"))
16
21
  '0.1.0'
22
+ >>> get_version_from_config(Path("config.yaml"), {"version": "0.2.0"})
23
+ '0.2.0'
17
24
  """
18
25
  if not config_dict:
19
26
  config_dict = load_configfile(config_path)
@@ -10,27 +10,41 @@ import sys
10
10
  class DynamicTyper:
11
11
  app: typer.Typer
12
12
 
13
- def __init_subclass__(cls, **kwargs):
14
- super().__init_subclass__(**kwargs)
15
- cls.app = typer.Typer()
13
+ def __init__(self):
14
+ self.app = typer.Typer()
16
15
 
17
16
  def __call__(self):
18
17
  """
19
18
  Invoke the CLI.
19
+
20
20
  Side Effects:
21
21
  Invokes the CLI.
22
+
22
23
  Examples:
23
24
  >>> CLI(Path('/path/to/workflow'))()
24
25
  """
25
- self.app()
26
+ self._set_app()
27
+
28
+ def _set_app(self):
29
+ """
30
+ Set the app attribute.
31
+
32
+ Side Effects:
33
+ Sets the app attribute to a Typer object.
34
+ """
35
+ if not hasattr(self, "app"):
36
+ self.app = typer.Typer()
26
37
 
27
38
  def register_default_command(self, command: Callable, **command_kwargs) -> None:
28
39
  """
29
40
  Register a default command to the CLI.
41
+
30
42
  Args:
31
43
  command (Callable): The command to register.
44
+
32
45
  Side Effects:
33
46
  Registers the command to the CLI.
47
+
34
48
  Examples:
35
49
  >>> CLI.register_default_command(my_command)
36
50
  """
@@ -65,13 +79,19 @@ class DynamicTyper:
65
79
  ) -> None:
66
80
  """
67
81
  Register a command to the CLI.
82
+
68
83
  Args:
69
84
  command (Callable): The command to register.
85
+ dynamic_options (List[Option], optional): A list of dynamic options to add to the command.
86
+
70
87
  Side Effects:
71
88
  Registers the command to the CLI.
89
+
72
90
  Examples:
73
91
  >>> CLI.register_command(my_command)
92
+ >>> CLI.register_command(my_command, dynamic_options=[option1, option2])
74
93
  """
94
+ self._set_app()
75
95
  if dynamic_options is not None:
76
96
  command = self.add_dynamic_options(command, dynamic_options)
77
97
  if isinstance(command, DynamicTyper):
@@ -82,34 +102,45 @@ class DynamicTyper:
82
102
  def register_callback(self, command: Callable, **command_kwargs) -> None:
83
103
  """
84
104
  Register a callback to the CLI.
105
+
85
106
  Args:
86
107
  command (Callable): The callback to register.
108
+
87
109
  Side Effects:
88
110
  Registers the callback to the CLI.
111
+
89
112
  Examples:
90
113
  >>> CLI.register_callback(my_callback)
91
114
  """
115
+ self._set_app()
92
116
  self.app.callback(**command_kwargs)(command)
93
117
 
94
118
  def register_group(self, group: "DynamicTyper", **command_kwargs) -> None:
95
119
  """
96
- Register a subcommand group group to the CLI.
120
+ Register a subcommand group to the CLI.
121
+
97
122
  Args:
98
123
  group (DynamicTyper): The subcommand group to register.
124
+
99
125
  Side Effects:
100
126
  Registers the subcommand group to the CLI.
127
+
101
128
  Examples:
102
- >>> CLI.register_app(my_group)
129
+ >>> CLI.register_group(my_group)
103
130
  """
131
+ self._set_app()
104
132
  self.app.add_typer(group.app, **command_kwargs)
105
133
 
106
134
  def _create_cli_parameter(self, option: Option):
107
135
  """
108
136
  Creates a parameter for a CLI option.
137
+
109
138
  Args:
110
139
  option (Option): An Option object containing the option's name, type, required status, default value, and help message.
140
+
111
141
  Returns:
112
142
  Parameter: A parameter object for the CLI option.
143
+
113
144
  Examples:
114
145
  >>> option = Option(name='foo', type='int', required=True, default=0, help='A number')
115
146
  >>> create_cli_parameter(option)
@@ -131,8 +162,10 @@ class DynamicTyper:
131
162
  def check_if_option_passed_via_command_line(self, option: Option):
132
163
  """
133
164
  Check if an option is passed via the command line.
165
+
134
166
  Args:
135
167
  option (Option): An Option object containing the option's name, type, required status, default value, and help message.
168
+
136
169
  Returns:
137
170
  bool: Whether the option is passed via the command line.
138
171
  """
@@ -148,15 +181,17 @@ class DynamicTyper:
148
181
  def add_dynamic_options(self, func: Callable, options: List[Option]):
149
182
  """
150
183
  Function to add dynamic options to a command.
184
+
151
185
  Args:
152
- command (Callable): The command to which the dynamic options should be added.
153
- options (List[dict]): A list of dictionaries containing the option's name, type, required status, default value, and help message.
186
+ func (Callable): The command to which the dynamic options should be added.
187
+ options (List[Option]): A list of Option objects containing the options to add.
188
+
154
189
  Returns:
155
190
  Callable: A function with the dynamic options added.
191
+
156
192
  Examples:
157
- >>> my_func = add_dynamic_options_to_function(my_func, [{'name': 'foo', 'type': 'int', 'required': True, 'default': 0, 'help': 'A number'}])
193
+ >>> my_func = add_dynamic_options_to_function(my_func, [option1, option2])
158
194
  >>> my_func
159
- <function my_func at 0x7f8f9f9f9f90>
160
195
  """
161
196
  func_sig = signature(func)
162
197
  params = list(func_sig.parameters.values())
@@ -168,13 +203,16 @@ class DynamicTyper:
168
203
  def func_wrapper(*args, **kwargs):
169
204
  """
170
205
  Wraps a function with dynamic options.
206
+
171
207
  Args:
172
- *args: Variable length argument list.
173
- **kwargs: Arbitrary keyword arguments.
208
+ *args: Variable length argument list.
209
+ **kwargs: Arbitrary keyword arguments.
210
+
174
211
  Returns:
175
- Callable: A wrapped function with the dynamic options added.
212
+ Callable: A wrapped function with the dynamic options added.
213
+
176
214
  Notes:
177
- This function is used in the `add_dynamic_options_to_function` function.
215
+ This function is used in the `add_dynamic_options_to_function` function.
178
216
  """
179
217
  flat_config = None
180
218
 
@@ -216,6 +254,7 @@ class DynamicTyper:
216
254
  def error(self, msg, exit=True):
217
255
  """
218
256
  Logs an error message (red) and exits (optional).
257
+
219
258
  Args:
220
259
  msg (str): The error message to log.
221
260
  exit (bool): Whether to exit after logging the error message.
@@ -227,6 +266,7 @@ class DynamicTyper:
227
266
  def success(self, msg):
228
267
  """
229
268
  Logs a success message (green).
269
+
230
270
  Args:
231
271
  msg (str): The success message to log.
232
272
  """
@@ -235,14 +275,18 @@ class DynamicTyper:
235
275
  def log(self, msg, color="yellow", stderr=True):
236
276
  """
237
277
  Logs a message (yellow).
278
+
238
279
  Args:
239
280
  msg (str): The message to log.
281
+ color (str, optional): The color of the log message. Defaults to "yellow".
282
+ stderr (bool, optional): Whether to log the message to stderr. Defaults to True.
240
283
  """
241
284
  typer.secho(msg, fg=color, err=stderr)
242
285
 
243
286
  def echo(self, msg):
244
287
  """
245
288
  Prints a message.
289
+
246
290
  Args:
247
291
  msg (str): The message to print.
248
292
  """
@@ -37,13 +37,16 @@ def create_option_from_annotation(
37
37
  ) -> Option:
38
38
  """
39
39
  Create an Option object from a given annotation.
40
+
40
41
  Args:
41
- annotation_key: The key in the annotations.
42
- annotation_values: The dictionary of annotation values.
43
- default_values: default value from config.
42
+ annotation_key (str): The key in the annotations.
43
+ annotation_values (dict): The dictionary of annotation values.
44
+ default_values (dict): Default value from config.
45
+ from_annotation (bool, optional): Whether the option is from an annotation. Defaults to False.
46
+
44
47
  Returns:
45
- An Option object.
46
- """
48
+ Option: An Option object.
49
+ """
47
50
  config_default = default_values.get(annotation_key, None)
48
51
 
49
52
  default = annotation_values.get(f"{annotation_key}:default", config_default)
@@ -83,9 +86,11 @@ def build_dynamic_cli_options(
83
86
  ) -> List[dict]:
84
87
  """
85
88
  Builds a list of options from a snakemake config and a snk config.
89
+
86
90
  Args:
87
91
  snakemake_config (dict): A snakemake config.
88
92
  snk_config (SnkConfig): A snk config.
93
+
89
94
  Returns:
90
95
  List[dict]: A list of options.
91
96
  """