hpcflow-new2 0.2.0a179__py3-none-any.whl → 0.2.0a180__py3-none-any.whl

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 (70) hide show
  1. hpcflow/_version.py +1 -1
  2. hpcflow/data/demo_data_manifest/__init__.py +3 -0
  3. hpcflow/sdk/__init__.py +4 -1
  4. hpcflow/sdk/app.py +160 -15
  5. hpcflow/sdk/cli.py +14 -0
  6. hpcflow/sdk/cli_common.py +83 -0
  7. hpcflow/sdk/config/__init__.py +4 -0
  8. hpcflow/sdk/config/callbacks.py +25 -2
  9. hpcflow/sdk/config/cli.py +4 -1
  10. hpcflow/sdk/config/config.py +188 -14
  11. hpcflow/sdk/config/config_file.py +91 -3
  12. hpcflow/sdk/config/errors.py +33 -0
  13. hpcflow/sdk/core/__init__.py +2 -0
  14. hpcflow/sdk/core/actions.py +492 -35
  15. hpcflow/sdk/core/cache.py +22 -0
  16. hpcflow/sdk/core/command_files.py +221 -5
  17. hpcflow/sdk/core/commands.py +57 -0
  18. hpcflow/sdk/core/element.py +407 -8
  19. hpcflow/sdk/core/environment.py +92 -0
  20. hpcflow/sdk/core/errors.py +245 -61
  21. hpcflow/sdk/core/json_like.py +72 -14
  22. hpcflow/sdk/core/loop.py +122 -21
  23. hpcflow/sdk/core/loop_cache.py +34 -9
  24. hpcflow/sdk/core/object_list.py +172 -26
  25. hpcflow/sdk/core/parallel.py +14 -0
  26. hpcflow/sdk/core/parameters.py +478 -25
  27. hpcflow/sdk/core/rule.py +31 -1
  28. hpcflow/sdk/core/run_dir_files.py +12 -2
  29. hpcflow/sdk/core/task.py +407 -80
  30. hpcflow/sdk/core/task_schema.py +70 -9
  31. hpcflow/sdk/core/test_utils.py +35 -0
  32. hpcflow/sdk/core/utils.py +101 -4
  33. hpcflow/sdk/core/validation.py +13 -1
  34. hpcflow/sdk/core/workflow.py +316 -96
  35. hpcflow/sdk/core/zarr_io.py +23 -0
  36. hpcflow/sdk/data/__init__.py +13 -0
  37. hpcflow/sdk/demo/__init__.py +3 -0
  38. hpcflow/sdk/helper/__init__.py +3 -0
  39. hpcflow/sdk/helper/cli.py +9 -0
  40. hpcflow/sdk/helper/helper.py +28 -0
  41. hpcflow/sdk/helper/watcher.py +33 -0
  42. hpcflow/sdk/log.py +40 -0
  43. hpcflow/sdk/persistence/__init__.py +14 -4
  44. hpcflow/sdk/persistence/base.py +289 -23
  45. hpcflow/sdk/persistence/json.py +29 -0
  46. hpcflow/sdk/persistence/pending.py +217 -107
  47. hpcflow/sdk/persistence/store_resource.py +58 -2
  48. hpcflow/sdk/persistence/utils.py +8 -0
  49. hpcflow/sdk/persistence/zarr.py +68 -1
  50. hpcflow/sdk/runtime.py +52 -10
  51. hpcflow/sdk/submission/__init__.py +3 -0
  52. hpcflow/sdk/submission/jobscript.py +198 -9
  53. hpcflow/sdk/submission/jobscript_info.py +13 -0
  54. hpcflow/sdk/submission/schedulers/__init__.py +60 -0
  55. hpcflow/sdk/submission/schedulers/direct.py +53 -0
  56. hpcflow/sdk/submission/schedulers/sge.py +45 -7
  57. hpcflow/sdk/submission/schedulers/slurm.py +45 -8
  58. hpcflow/sdk/submission/schedulers/utils.py +4 -0
  59. hpcflow/sdk/submission/shells/__init__.py +11 -1
  60. hpcflow/sdk/submission/shells/base.py +32 -1
  61. hpcflow/sdk/submission/shells/bash.py +36 -1
  62. hpcflow/sdk/submission/shells/os_version.py +18 -6
  63. hpcflow/sdk/submission/shells/powershell.py +22 -0
  64. hpcflow/sdk/submission/submission.py +88 -3
  65. hpcflow/sdk/typing.py +10 -1
  66. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/METADATA +1 -1
  67. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/RECORD +70 -70
  68. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/LICENSE +0 -0
  69. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/WHEEL +0 -0
  70. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/entry_points.txt +0 -0
hpcflow/sdk/cli_common.py CHANGED
@@ -7,10 +7,14 @@ from hpcflow.sdk.persistence import ALL_STORE_FORMATS, DEFAULT_STORE_FORMAT
7
7
 
8
8
 
9
9
  def sub_tasks_callback(ctx, param, value):
10
+ """
11
+ Parse subtasks.
12
+ """
10
13
  if value:
11
14
  return [int(i) for i in value.split(",")]
12
15
 
13
16
 
17
+ #: Standard option
14
18
  format_option = click.option(
15
19
  "--format",
16
20
  type=click.Choice(ALL_TEMPLATE_FORMATS),
@@ -20,11 +24,13 @@ format_option = click.option(
20
24
  "particular format."
21
25
  ),
22
26
  )
27
+ #: Standard option
23
28
  path_option = click.option(
24
29
  "--path",
25
30
  type=click.Path(exists=True),
26
31
  help="The directory path into which the new workflow will be generated.",
27
32
  )
33
+ #: Standard option
28
34
  name_option = click.option(
29
35
  "--name",
30
36
  help=(
@@ -33,6 +39,7 @@ name_option = click.option(
33
39
  "will be used, in combination with a date-timestamp."
34
40
  ),
35
41
  )
42
+ #: Standard option
36
43
  overwrite_option = click.option(
37
44
  "--overwrite",
38
45
  is_flag=True,
@@ -42,12 +49,15 @@ overwrite_option = click.option(
42
49
  "the existing directory will be overwritten."
43
50
  ),
44
51
  )
52
+ #: Standard option
45
53
  store_option = click.option(
46
54
  "--store",
47
55
  type=click.Choice(ALL_STORE_FORMATS),
48
56
  help="The persistent store type to use.",
49
57
  default=DEFAULT_STORE_FORMAT,
50
58
  )
59
+
60
+ #: Standard option
51
61
  ts_fmt_option = click.option(
52
62
  "--ts-fmt",
53
63
  help=(
@@ -56,6 +66,7 @@ ts_fmt_option = click.option(
56
66
  "should not include a time zone name."
57
67
  ),
58
68
  )
69
+ #: Standard option
59
70
  ts_name_fmt_option = click.option(
60
71
  "--ts-name-fmt",
61
72
  help=(
@@ -63,6 +74,8 @@ ts_name_fmt_option = click.option(
63
74
  "includes a timestamp."
64
75
  ),
65
76
  )
77
+
78
+ #: Standard option
66
79
  variables_option = click.option(
67
80
  "-v",
68
81
  "--var",
@@ -74,6 +87,7 @@ variables_option = click.option(
74
87
  "string. Multiple variable values can be specified."
75
88
  ),
76
89
  )
90
+ #: Standard option
77
91
  js_parallelism_option = click.option(
78
92
  "--js-parallelism",
79
93
  help=(
@@ -84,23 +98,27 @@ js_parallelism_option = click.option(
84
98
  ),
85
99
  type=click.BOOL,
86
100
  )
101
+ #: Standard option
87
102
  wait_option = click.option(
88
103
  "--wait",
89
104
  help=("If True, this command will block until the workflow execution is complete."),
90
105
  is_flag=True,
91
106
  default=False,
92
107
  )
108
+ #: Standard option
93
109
  add_to_known_opt = click.option(
94
110
  "--add-to-known/--no-add-to-known",
95
111
  default=True,
96
112
  help="If True, add this submission to the known-submissions file.",
97
113
  )
114
+ #: Standard option
98
115
  print_idx_opt = click.option(
99
116
  "--print-idx",
100
117
  help="If True, print the submitted jobscript indices for each submission index.",
101
118
  is_flag=True,
102
119
  default=False,
103
120
  )
121
+ #: Standard option
104
122
  tasks_opt = click.option(
105
123
  "--tasks",
106
124
  help=(
@@ -109,22 +127,27 @@ tasks_opt = click.option(
109
127
  ),
110
128
  callback=sub_tasks_callback,
111
129
  )
130
+ #: Standard option
112
131
  cancel_opt = click.option(
113
132
  "--cancel",
114
133
  help="Immediately cancel the submission. Useful for testing and benchmarking.",
115
134
  is_flag=True,
116
135
  default=False,
117
136
  )
137
+ #: Standard option
118
138
  submit_status_opt = click.option(
119
139
  "--status/--no-status",
120
140
  help="If True, display a live status to track submission progress.",
121
141
  default=True,
122
142
  )
143
+ #: Standard option
123
144
  make_status_opt = click.option(
124
145
  "--status/--no-status",
125
146
  help="If True, display a live status to track workflow creation progress.",
126
147
  default=True,
127
148
  )
149
+
150
+ #: Standard option
128
151
  zip_path_opt = click.option(
129
152
  "--path",
130
153
  default=".",
@@ -134,15 +157,21 @@ zip_path_opt = click.option(
134
157
  "path is assumed to be the full file path to the new zip file."
135
158
  ),
136
159
  )
160
+ #: Standard option
137
161
  zip_overwrite_opt = click.option(
138
162
  "--overwrite",
139
163
  is_flag=True,
140
164
  default=False,
141
165
  help="If set, any existing file will be overwritten.",
142
166
  )
167
+ #: Standard option
143
168
  zip_log_opt = click.option("--log", help="Path to a log file to use during zipping.")
169
+ #: Standard option
144
170
  zip_include_execute_opt = click.option("--include-execute", is_flag=True)
171
+ #: Standard option
145
172
  zip_include_rechunk_backups_opt = click.option("--include-rechunk-backups", is_flag=True)
173
+
174
+ #: Standard option
146
175
  unzip_path_opt = click.option(
147
176
  "--path",
148
177
  default=".",
@@ -152,12 +181,16 @@ unzip_path_opt = click.option(
152
181
  "Otherwise, this path will represent the new workflow directory path."
153
182
  ),
154
183
  )
184
+ #: Standard option
155
185
  unzip_log_opt = click.option("--log", help="Path to a log file to use during unzipping.")
186
+
187
+ #: Standard option
156
188
  rechunk_backup_opt = click.option(
157
189
  "--backup/--no-backup",
158
190
  default=True,
159
191
  help=("First copy a backup of the array to a directory ending in `.bak`."),
160
192
  )
193
+ #: Standard option
161
194
  rechunk_chunk_size_opt = click.option(
162
195
  "--chunk-size",
163
196
  type=click.INT,
@@ -168,8 +201,58 @@ rechunk_chunk_size_opt = click.option(
168
201
  "array's shape)."
169
202
  ),
170
203
  )
204
+ #: Standard option
171
205
  rechunk_status_opt = click.option(
172
206
  "--status/--no-status",
173
207
  default=True,
174
208
  help="If True, display a live status to track rechunking progress.",
175
209
  )
210
+
211
+
212
+ def _add_doc_from_help(*args):
213
+ """
214
+ Attach the ``help`` field of each of its arguments as its ``__doc__``.
215
+ Only necessary because the wrappers in Click don't do this for us.
216
+
217
+ :meta private:
218
+ """
219
+ # Yes, this is ugly!
220
+ from types import SimpleNamespace
221
+
222
+ for opt in args:
223
+ ns = SimpleNamespace()
224
+ params = getattr(opt(ns), "__click_params__", [])
225
+ if params:
226
+ help = getattr(params[0], "help", "")
227
+ if help:
228
+ opt.__doc__ = f"Click option decorator: {help}"
229
+
230
+
231
+ _add_doc_from_help(
232
+ format_option,
233
+ path_option,
234
+ name_option,
235
+ overwrite_option,
236
+ store_option,
237
+ ts_fmt_option,
238
+ ts_name_fmt_option,
239
+ variables_option,
240
+ js_parallelism_option,
241
+ wait_option,
242
+ add_to_known_opt,
243
+ print_idx_opt,
244
+ tasks_opt,
245
+ cancel_opt,
246
+ submit_status_opt,
247
+ make_status_opt,
248
+ zip_path_opt,
249
+ zip_overwrite_opt,
250
+ zip_log_opt,
251
+ zip_include_execute_opt,
252
+ zip_include_rechunk_backups_opt,
253
+ unzip_path_opt,
254
+ unzip_log_opt,
255
+ rechunk_backup_opt,
256
+ rechunk_chunk_size_opt,
257
+ rechunk_status_opt,
258
+ )
@@ -1 +1,5 @@
1
+ """
2
+ Configuration loading and manipulation.
3
+ """
4
+
1
5
  from .config import Config, ConfigFile, ConfigOptions, DEFAULT_CONFIG
@@ -10,7 +10,9 @@ from hpcflow.sdk.submission.shells import get_supported_shells
10
10
 
11
11
 
12
12
  def callback_vars(config, value):
13
- """Substitute configuration variables."""
13
+ """
14
+ Callback that substitutes configuration variables.
15
+ """
14
16
 
15
17
  def vars_repl(match_obj):
16
18
  var_name = match_obj.groups()[0]
@@ -27,6 +29,9 @@ def callback_vars(config, value):
27
29
 
28
30
 
29
31
  def callback_file_paths(config, file_path):
32
+ """
33
+ Callback that resolves file paths.
34
+ """
30
35
  if isinstance(file_path, list):
31
36
  return [config._resolve_path(i) for i in file_path]
32
37
  else:
@@ -34,6 +39,9 @@ def callback_file_paths(config, file_path):
34
39
 
35
40
 
36
41
  def callback_bool(config, value):
42
+ """
43
+ Callback that coerces values to boolean.
44
+ """
37
45
  if not isinstance(value, bool):
38
46
  if value.lower() == "true":
39
47
  return True
@@ -45,6 +53,9 @@ def callback_bool(config, value):
45
53
 
46
54
 
47
55
  def callback_lowercase(config, value):
56
+ """
57
+ Callback that forces a string to lower case.
58
+ """
48
59
  if isinstance(value, list):
49
60
  return [i.lower() for i in value]
50
61
  elif isinstance(value, dict):
@@ -54,6 +65,9 @@ def callback_lowercase(config, value):
54
65
 
55
66
 
56
67
  def exists_in_schedulers(config, value):
68
+ """
69
+ Callback that tests that a value is a supported scheduler name.
70
+ """
57
71
  if value not in config.schedulers:
58
72
  raise ValueError(
59
73
  f"Cannot set default scheduler; {value!r} is not a supported scheduler "
@@ -64,6 +78,9 @@ def exists_in_schedulers(config, value):
64
78
 
65
79
 
66
80
  def callback_supported_schedulers(config, schedulers):
81
+ """
82
+ Callback that tests that all values are names of supported schedulers.
83
+ """
67
84
  # validate against supported schedulers according to the OS - this won't validate that
68
85
  # a particular scheduler actually exists on this system:
69
86
  available = config._app.get_OS_supported_schedulers()
@@ -122,6 +139,9 @@ def callback_scheduler_set_up(config, schedulers):
122
139
 
123
140
 
124
141
  def callback_supported_shells(config, shell_name):
142
+ """
143
+ Callback that tests if a shell names is supported on this OS.
144
+ """
125
145
  supported = get_supported_shells(os.name)
126
146
  if shell_name not in supported:
127
147
  raise UnsupportedShellError(shell=shell_name, supported=supported)
@@ -146,11 +166,14 @@ def set_callback_file_paths(config, value):
146
166
 
147
167
 
148
168
  def check_load_data_files(config, value):
149
- """Check data files (e.g. task schema files) can be loaded successfully. This is only
169
+ """Check data files (e.g., task schema files) can be loaded successfully. This is only
150
170
  done on `config.set` (and not on `config.get` or `config._validate`) because it could
151
171
  be expensive in the case of remote files."""
152
172
  config._app.reload_template_components(warn=False)
153
173
 
154
174
 
155
175
  def callback_update_log_console_level(config, value):
176
+ """
177
+ Callback to set the logging level.
178
+ """
156
179
  config._app.log.update_console_level(value)
hpcflow/sdk/config/cli.py CHANGED
@@ -44,7 +44,10 @@ def warning_formatter(func=custom_warning_formatter):
44
44
 
45
45
 
46
46
  def CLI_exception_wrapper_gen(*exception_cls):
47
- """Decorator factory"""
47
+ """
48
+ Decorator factory that enhances the wrapped function to display a nice message on
49
+ success or failure.
50
+ """
48
51
 
49
52
  def CLI_exception_wrapper(func):
50
53
  """Decorator
@@ -1,3 +1,7 @@
1
+ """
2
+ Configuration system class.
3
+ """
4
+
1
5
  from __future__ import annotations
2
6
  import contextlib
3
7
 
@@ -61,6 +65,7 @@ from .errors import (
61
65
  logger = logging.getLogger(__name__)
62
66
 
63
67
  _DEFAULT_SHELL = DEFAULT_SHELL_NAMES[os.name]
68
+ #: The default configuration descriptor.
64
69
  DEFAULT_CONFIG = {
65
70
  "invocation": {"environment_setup": None, "match": {}},
66
71
  "config": {
@@ -82,12 +87,17 @@ DEFAULT_CONFIG = {
82
87
  class ConfigOptions:
83
88
  """Application-level options for configuration"""
84
89
 
90
+ #: The default directory.
85
91
  default_directory: Union[Path, str]
92
+ #: The environment variable containing the directory name.
86
93
  directory_env_var: str
94
+ #: The default configuration.
87
95
  default_config: Optional[Dict] = field(
88
96
  default_factory=lambda: deepcopy(DEFAULT_CONFIG)
89
97
  )
98
+ #: Any extra schemas to apply.
90
99
  extra_schemas: Optional[List[Schema]] = field(default_factory=lambda: [])
100
+ #: Default directory of known configurations.
91
101
  default_known_configs_dir: Optional[str] = None
92
102
 
93
103
  def __post_init__(self):
@@ -96,7 +106,9 @@ class ConfigOptions:
96
106
  self._configurable_keys = cfg_keys
97
107
 
98
108
  def init_schemas(self):
99
- # Get allowed configurable keys from config schemas:
109
+ """
110
+ Get allowed configurable keys from config schemas.
111
+ """
100
112
  cfg_schemas = [get_schema("config_schema.yaml")] + self.extra_schemas
101
113
  cfg_keys = []
102
114
  for cfg_schema in cfg_schemas:
@@ -130,18 +142,114 @@ class ConfigOptions:
130
142
  class Config:
131
143
  """Application configuration as defined in one or more config files.
132
144
 
145
+ This class supports indexing into the collection of properties via Python dot notation.
146
+
133
147
  Notes
134
148
  -----
135
149
  On modifying/setting existing values, modifications are not automatically copied
136
- to the configuration file; use `save()` to save to the file. Items in `overrides`
150
+ to the configuration file; use :meth:`save()` to save to the file. Items in `overrides`
137
151
  are not saved into the file.
138
152
 
139
153
  `schedulers` is used for specifying the available schedulers on this machine, and the
140
- default arguments that should be used when initialising the `Scheduler` object.
154
+ default arguments that should be used when initialising the
155
+ :py:class:`Scheduler` object.
141
156
 
142
157
  `shells` is used for specifying the default arguments that should be used when
143
- initialising the `Shell` object.
144
-
158
+ initialising the :py:class:`Shell` object.
159
+
160
+ Parameters
161
+ ----------
162
+ app:
163
+ The main hpcflow application instance.
164
+ config_file:
165
+ The configuration file that contains this config.
166
+ options:
167
+ Configuration options to be applied.
168
+ logger:
169
+ Where to log messages relating to configuration.
170
+ config_key:
171
+ The name of the configuration within the configuration file.
172
+ uid: int
173
+ User ID.
174
+ callbacks: dict
175
+ Overrides for the callback system.
176
+ variables: dict[str, str]
177
+ Variables to substitute when processing the configuration.
178
+
179
+ Attributes
180
+ ----------
181
+ config_directory:
182
+ The directory containing the configuration file.
183
+ config_file_name:
184
+ The name of the configuration file.
185
+ config_file_path:
186
+ The full path to the configuration file.
187
+ config_file_contents:
188
+ The cached contents of the configuration file.
189
+ config_key:
190
+ The primary key to select the configuration within the configuration file.
191
+ config_schemas:
192
+ The schemas that apply to the configuration file.
193
+ host_user_id:
194
+ User ID as understood by the script.
195
+ host_user_id_file_path:
196
+ Where user ID information is stored.
197
+ invoking_user_id:
198
+ User ID that created the workflow.
199
+ machine:
200
+ Machine to submit to.
201
+ Mapped to a field in the configuration file.
202
+ user_name:
203
+ User to submit as.
204
+ Mapped to a field in the configuration file.
205
+ user_orcid:
206
+ User's ORCID.
207
+ Mapped to a field in the configuration file.
208
+ user_affiliation:
209
+ User's institutional affiliation.
210
+ Mapped to a field in the configuration file.
211
+ linux_release_file:
212
+ Where to get the description of the Linux release version data.
213
+ Mapped to a field in the configuration file.
214
+ log_file_path:
215
+ Where to log to.
216
+ Mapped to a field in the configuration file.
217
+ log_file_level:
218
+ At what level to do logging to the file.
219
+ Mapped to a field in the configuration file.
220
+ log_console_level:
221
+ At what level to do logging to the console. Usually coarser than to a file.
222
+ Mapped to a field in the configuration file.
223
+ task_schema_sources:
224
+ Where to get task schemas.
225
+ Mapped to a field in the configuration file.
226
+ parameter_sources:
227
+ Where to get parameter descriptors.
228
+ Mapped to a field in the configuration file.
229
+ command_file_sources:
230
+ Where to get command files.
231
+ Mapped to a field in the configuration file.
232
+ environment_sources:
233
+ Where to get execution environment descriptors.
234
+ Mapped to a field in the configuration file.
235
+ default_scheduler:
236
+ The name of the default scheduler.
237
+ Mapped to a field in the configuration file.
238
+ default_shell:
239
+ The name of the default shell.
240
+ Mapped to a field in the configuration file.
241
+ schedulers:
242
+ Settings for supported scheduler(s).
243
+ Mapped to a field in the configuration file.
244
+ shells:
245
+ Settings for supported shell(s).
246
+ Mapped to a field in the configuration file.
247
+ demo_data_dir:
248
+ Location of demo data.
249
+ Mapped to a field in the configuration file.
250
+ demo_data_manifest_file:
251
+ Where the manifest describing the demo data is.
252
+ Mapped to a field in the configuration file.
145
253
  """
146
254
 
147
255
  def __init__(
@@ -517,7 +625,16 @@ class Config:
517
625
  print(f"value is already: {callback_val!r}")
518
626
 
519
627
  def set(self, path: str, value, is_json=False, quiet=False):
520
- """Set the value of a configuration item."""
628
+ """
629
+ Set the value of a configuration item.
630
+
631
+ Parameters
632
+ ----------
633
+ path:
634
+ Which configuration item to set.
635
+ value:
636
+ What to set it to.
637
+ """
521
638
  self._logger.debug(f"Attempting to set config item {path!r} to {value!r}.")
522
639
 
523
640
  if is_json:
@@ -542,7 +659,18 @@ class Config:
542
659
  self._set(name, root, quiet=quiet)
543
660
 
544
661
  def unset(self, name):
545
- """Unset the value of a configuration item."""
662
+ """
663
+ Unset the value of a configuration item.
664
+
665
+ Parameters
666
+ ----------
667
+ name: str
668
+ The name of the configuration item.
669
+
670
+ Notes
671
+ -----
672
+ Only top level configuration items may be unset.
673
+ """
546
674
  if name not in self._configurable_keys:
547
675
  raise ConfigNonConfigurableError(name=name)
548
676
  if name in self._unset_keys or not self._file.is_item_set(self._config_key, name):
@@ -564,6 +692,14 @@ class Config:
564
692
  ret_parts=False,
565
693
  default=None,
566
694
  ):
695
+ """
696
+ Get the value of a configuration item.
697
+
698
+ Parameters
699
+ ----------
700
+ path: str
701
+ The name of or path to the configuration item.
702
+ """
567
703
  parts = path.split(".")
568
704
  root = deepcopy(self._get(parts[0], callback=callback))
569
705
  try:
@@ -582,7 +718,16 @@ class Config:
582
718
  return tuple(ret)
583
719
 
584
720
  def append(self, path, value, is_json=False):
585
- """Append a value to a list-like configuration item."""
721
+ """
722
+ Append a value to a list-like configuration item.
723
+
724
+ Parameters
725
+ ----------
726
+ path: str
727
+ The name of or path to the configuration item.
728
+ value:
729
+ The value to append.
730
+ """
586
731
  if is_json:
587
732
  value = self._parse_JSON(path, value)
588
733
 
@@ -612,7 +757,16 @@ class Config:
612
757
  self._set(parts[0], root)
613
758
 
614
759
  def prepend(self, path, value, is_json=False):
615
- """Prepend a value to a list-like configuration item."""
760
+ """
761
+ Prepend a value to a list-like configuration item.
762
+
763
+ Parameters
764
+ ----------
765
+ path: str
766
+ The name of or path to the configuration item.
767
+ value:
768
+ The value to prepend.
769
+ """
616
770
  if is_json:
617
771
  value = self._parse_JSON(path, value)
618
772
 
@@ -638,7 +792,16 @@ class Config:
638
792
  self._set(parts[0], root)
639
793
 
640
794
  def pop(self, path, index):
641
- """Remove a value from a specified index of a list-like configuration item."""
795
+ """
796
+ Remove a value from a specified index of a list-like configuration item.
797
+
798
+ Parameters
799
+ ----------
800
+ path: str
801
+ The name of or path to the configuration item.
802
+ index: int
803
+ Where to remove the value from. 0 for the first item, -1 for the last.
804
+ """
642
805
 
643
806
  existing, root, parts = self.get(
644
807
  path,
@@ -674,8 +837,10 @@ class Config:
674
837
 
675
838
  Parameters
676
839
  ----------
677
- path
840
+ path: str
678
841
  A dot-delimited string of the nested path to update.
842
+ value: dict
843
+ A dictionary to merge in.
679
844
  """
680
845
 
681
846
  if is_json:
@@ -739,12 +904,18 @@ class Config:
739
904
  self._app.reset_config()
740
905
 
741
906
  def add_scheduler(self, scheduler, **defaults):
907
+ """
908
+ Add a scheduler.
909
+ """
742
910
  if scheduler in self.get("schedulers"):
743
911
  print(f"Scheduler {scheduler!r} already exists.")
744
912
  return
745
913
  self.update(f"schedulers.{scheduler}.defaults", defaults)
746
914
 
747
915
  def add_shell(self, shell, **defaults):
916
+ """
917
+ Add a shell.
918
+ """
748
919
  if shell in self.get("shells"):
749
920
  return
750
921
  if shell.lower() == "wsl":
@@ -753,6 +924,9 @@ class Config:
753
924
  self.update(f"shells.{shell}.defaults", defaults)
754
925
 
755
926
  def add_shell_WSL(self, **defaults):
927
+ """
928
+ Add shell with WSL prefix.
929
+ """
756
930
  if "WSL_executable" not in defaults:
757
931
  defaults["WSL_executable"] = "wsl.exe"
758
932
  self.add_shell("wsl", **defaults)
@@ -763,13 +937,13 @@ class Config:
763
937
 
764
938
  Parameters
765
939
  ----------
766
- file_path
940
+ file_path:
767
941
  Local or remote path to a config import YAML file which may have top-level
768
942
  keys "invocation" and "config".
769
- rename
943
+ rename:
770
944
  If True, the current config will be renamed to the stem of the file specified
771
945
  in `file_path`. Ignored if `make_new` is True.
772
- make_new
946
+ make_new:
773
947
  If True, add the config items as a new config, rather than modifying the
774
948
  current config. The name of the new config will be the stem of the file
775
949
  specified in `file_path`.