runem 0.3.0__py3-none-any.whl → 0.5.0__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.
- runem/VERSION +1 -1
- runem/blocking_print.py +37 -1
- runem/cli/initialise_options.py +26 -0
- runem/command_line.py +23 -1
- runem/config_parse.py +21 -7
- runem/job_execute.py +3 -2
- runem/runem.py +12 -6
- {runem-0.3.0.dist-info → runem-0.5.0.dist-info}/METADATA +15 -6
- {runem-0.3.0.dist-info → runem-0.5.0.dist-info}/RECORD +22 -12
- {runem-0.3.0.dist-info → runem-0.5.0.dist-info}/top_level.txt +1 -0
- scripts/test_hooks/__init__.py +0 -0
- scripts/test_hooks/json_validators.py +32 -0
- scripts/test_hooks/py.py +292 -0
- scripts/test_hooks/py.typed +0 -0
- scripts/test_hooks/runem_hooks.py +19 -0
- scripts/test_hooks/yarn.py +48 -0
- tests/cli/test_initialise_options.py +105 -0
- tests/data/help_output.3.10.txt +55 -0
- tests/data/help_output.3.11.txt +55 -0
- {runem-0.3.0.dist-info → runem-0.5.0.dist-info}/LICENSE +0 -0
- {runem-0.3.0.dist-info → runem-0.5.0.dist-info}/WHEEL +0 -0
- {runem-0.3.0.dist-info → runem-0.5.0.dist-info}/entry_points.txt +0 -0
runem/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
runem/blocking_print.py
CHANGED
@@ -1,6 +1,40 @@
|
|
1
1
|
import time
|
2
2
|
import typing
|
3
3
|
|
4
|
+
from rich.console import Console
|
5
|
+
|
6
|
+
|
7
|
+
def _reset_console() -> Console:
|
8
|
+
"""Sets the nice user-facing console.
|
9
|
+
|
10
|
+
This function exists so we can reset the output from tests.
|
11
|
+
"""
|
12
|
+
global RICH_CONSOLE # pylint: disable=global-statement
|
13
|
+
|
14
|
+
RICH_CONSOLE = Console(
|
15
|
+
log_path=False, # Do NOT print the source path.
|
16
|
+
markup=False, # Do NOT print markup e.g. `[blink]Don't Panic![/blink]`.
|
17
|
+
)
|
18
|
+
return RICH_CONSOLE
|
19
|
+
|
20
|
+
|
21
|
+
# Overridden in tests.
|
22
|
+
RICH_CONSOLE: Console = _reset_console()
|
23
|
+
|
24
|
+
|
25
|
+
def _reset_console_for_tests() -> None:
|
26
|
+
"""Overrides the console output with more deterministic version.
|
27
|
+
|
28
|
+
... so we can have deterministic tests.
|
29
|
+
"""
|
30
|
+
global RICH_CONSOLE # pylint: disable=global-statement
|
31
|
+
RICH_CONSOLE = Console(
|
32
|
+
log_path=False, # Do NOT print the source path.
|
33
|
+
log_time=False, # Do not prefix with log time e.g. `[time] log message`.
|
34
|
+
markup=False, # Do NOT print markup e.g. `[blink]Don't Panic![/blink]`.
|
35
|
+
width=999, # A very wide width.
|
36
|
+
)
|
37
|
+
|
4
38
|
|
5
39
|
def blocking_print(
|
6
40
|
msg: str = "",
|
@@ -15,9 +49,11 @@ def blocking_print(
|
|
15
49
|
already being written to (for example), i.e. the `print` would need to be a
|
16
50
|
'blocking' call, which it is not.
|
17
51
|
"""
|
52
|
+
if end is None:
|
53
|
+
end = "\n"
|
18
54
|
for _ in range(max_retries):
|
19
55
|
try:
|
20
|
-
print(msg, end=end)
|
56
|
+
RICH_CONSOLE.print(msg, end=end)
|
21
57
|
break # Success, exit the retry loop
|
22
58
|
except BlockingIOError:
|
23
59
|
time.sleep(sleep_time_s) # Wait a bit for the buffer to clear
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import argparse
|
2
|
+
|
3
|
+
from runem.config_metadata import ConfigMetadata
|
4
|
+
from runem.informative_dict import InformativeDict
|
5
|
+
from runem.types.options import OptionsWritable
|
6
|
+
|
7
|
+
|
8
|
+
def initialise_options(
|
9
|
+
config_metadata: ConfigMetadata,
|
10
|
+
args: argparse.Namespace,
|
11
|
+
) -> OptionsWritable:
|
12
|
+
"""Initialises and returns the set of options to use for this run.
|
13
|
+
|
14
|
+
Returns the options dictionary
|
15
|
+
"""
|
16
|
+
|
17
|
+
options: OptionsWritable = InformativeDict(
|
18
|
+
{option["name"]: option["default"] for option in config_metadata.options_config}
|
19
|
+
)
|
20
|
+
if config_metadata.options_config and args.overrides_on: # pragma: no branch
|
21
|
+
for option_name in args.overrides_on: # pragma: no branch
|
22
|
+
options[option_name] = True
|
23
|
+
if config_metadata.options_config and args.overrides_off: # pragma: no branch
|
24
|
+
for option_name in args.overrides_off:
|
25
|
+
options[option_name] = False
|
26
|
+
return options
|
runem/command_line.py
CHANGED
@@ -53,6 +53,14 @@ def _get_argparse_help_formatter() -> typing.Any:
|
|
53
53
|
return argparse.HelpFormatter
|
54
54
|
|
55
55
|
|
56
|
+
def error_on_log_logic(verbose: bool, silent: bool) -> None:
|
57
|
+
"""Simply errors if we get logical inconsistencies in the logging-logic."""
|
58
|
+
if verbose and silent:
|
59
|
+
log("cannot parse '--verbose' and '--silent'")
|
60
|
+
# error exit
|
61
|
+
sys.exit(1)
|
62
|
+
|
63
|
+
|
56
64
|
def parse_args(
|
57
65
|
config_metadata: ConfigMetadata, argv: typing.List[str]
|
58
66
|
) -> ConfigMetadata:
|
@@ -130,7 +138,9 @@ def parse_args(
|
|
130
138
|
nargs="+",
|
131
139
|
default=config_metadata.all_job_tags,
|
132
140
|
help=(
|
133
|
-
|
141
|
+
# TODO: clarify the logic by which we add/remove jobs based on tags
|
142
|
+
# e.g. exclusive-in, union, x-or etc.
|
143
|
+
"Only run jobs with the given tags. "
|
134
144
|
f"Defaults to '{sorted(config_metadata.all_job_tags)}'."
|
135
145
|
),
|
136
146
|
required=False,
|
@@ -238,6 +248,16 @@ def parse_args(
|
|
238
248
|
required=False,
|
239
249
|
)
|
240
250
|
|
251
|
+
parser.add_argument(
|
252
|
+
"--silent",
|
253
|
+
"-s",
|
254
|
+
dest="silent",
|
255
|
+
action=argparse.BooleanOptionalAction,
|
256
|
+
default=False,
|
257
|
+
help=("Whether to show warning messages or not. "),
|
258
|
+
required=False,
|
259
|
+
)
|
260
|
+
|
241
261
|
parser.add_argument(
|
242
262
|
"--spinner",
|
243
263
|
dest="show_spinner",
|
@@ -271,6 +291,8 @@ def parse_args(
|
|
271
291
|
|
272
292
|
args = parser.parse_args(argv[1:])
|
273
293
|
|
294
|
+
error_on_log_logic(args.verbose, args.silent)
|
295
|
+
|
274
296
|
if args.show_root_path_and_exit:
|
275
297
|
log(str(config_metadata.cfg_filepath.parent), decorate=False)
|
276
298
|
# cleanly exit
|
runem/config_parse.py
CHANGED
@@ -149,6 +149,7 @@ def parse_job_config(
|
|
149
149
|
in_out_job_names: JobNames,
|
150
150
|
in_out_phases: JobPhases,
|
151
151
|
phase_order: OrderedPhases,
|
152
|
+
silent: bool = False,
|
152
153
|
) -> None:
|
153
154
|
"""Parses and validates a job-entry read in from disk.
|
154
155
|
|
@@ -208,6 +209,7 @@ def parse_job_config(
|
|
208
209
|
in_out_job_names,
|
209
210
|
in_out_phases,
|
210
211
|
phase_order,
|
212
|
+
warn_missing_phase=(not silent),
|
211
213
|
)
|
212
214
|
except KeyError as err:
|
213
215
|
raise ValueError(
|
@@ -215,8 +217,11 @@ def parse_job_config(
|
|
215
217
|
) from err
|
216
218
|
|
217
219
|
|
218
|
-
def parse_config(
|
219
|
-
config: Config,
|
220
|
+
def parse_config( # noqa: C901
|
221
|
+
config: Config,
|
222
|
+
cfg_filepath: pathlib.Path,
|
223
|
+
silent: bool = False,
|
224
|
+
hooks_only: bool = False,
|
220
225
|
) -> typing.Tuple[
|
221
226
|
Hooks, # hooks:
|
222
227
|
OrderedPhases, # phase_order:
|
@@ -282,7 +287,10 @@ def parse_config(
|
|
282
287
|
|
283
288
|
if not phase_order:
|
284
289
|
if not hooks_only:
|
285
|
-
|
290
|
+
if silent: # pragma: no cover
|
291
|
+
pass
|
292
|
+
else:
|
293
|
+
warn("phase ordering not configured! Runs will be non-deterministic!")
|
286
294
|
phase_order = tuple(job_phases)
|
287
295
|
|
288
296
|
# now parse out the job_configs
|
@@ -301,6 +309,7 @@ def parse_config(
|
|
301
309
|
in_out_job_names=job_names,
|
302
310
|
in_out_phases=job_phases,
|
303
311
|
phase_order=phase_order,
|
312
|
+
silent=silent,
|
304
313
|
)
|
305
314
|
return (
|
306
315
|
hooks,
|
@@ -341,7 +350,9 @@ def generate_config(
|
|
341
350
|
|
342
351
|
|
343
352
|
def _load_user_hooks_from_config(
|
344
|
-
user_config: Config,
|
353
|
+
user_config: Config,
|
354
|
+
cfg_filepath: pathlib.Path,
|
355
|
+
silent: bool,
|
345
356
|
) -> Hooks:
|
346
357
|
hooks: Hooks
|
347
358
|
(
|
@@ -353,7 +364,7 @@ def _load_user_hooks_from_config(
|
|
353
364
|
_,
|
354
365
|
_,
|
355
366
|
_,
|
356
|
-
) = parse_config(user_config, cfg_filepath, hooks_only=True)
|
367
|
+
) = parse_config(user_config, cfg_filepath, silent, hooks_only=True)
|
357
368
|
return hooks
|
358
369
|
|
359
370
|
|
@@ -361,6 +372,7 @@ def load_config_metadata(
|
|
361
372
|
config: Config,
|
362
373
|
cfg_filepath: pathlib.Path,
|
363
374
|
user_configs: typing.List[typing.Tuple[Config, pathlib.Path]],
|
375
|
+
silent: bool = False,
|
364
376
|
verbose: bool = False,
|
365
377
|
) -> ConfigMetadata:
|
366
378
|
hooks: Hooks
|
@@ -380,12 +392,14 @@ def load_config_metadata(
|
|
380
392
|
job_names,
|
381
393
|
job_phases,
|
382
394
|
tags,
|
383
|
-
) = parse_config(config, cfg_filepath)
|
395
|
+
) = parse_config(config, cfg_filepath, silent)
|
384
396
|
|
385
397
|
user_config: Config
|
386
398
|
user_config_path: pathlib.Path
|
387
399
|
for user_config, user_config_path in user_configs:
|
388
|
-
user_hooks: Hooks = _load_user_hooks_from_config(
|
400
|
+
user_hooks: Hooks = _load_user_hooks_from_config(
|
401
|
+
user_config, user_config_path, silent
|
402
|
+
)
|
389
403
|
if user_hooks:
|
390
404
|
if verbose:
|
391
405
|
log(f"hooks: loading user hooks from '{str(user_config_path)}'")
|
runem/job_execute.py
CHANGED
@@ -11,7 +11,7 @@ from runem.config_metadata import ConfigMetadata
|
|
11
11
|
from runem.informative_dict import ReadOnlyInformativeDict
|
12
12
|
from runem.job import Job
|
13
13
|
from runem.job_wrapper import get_job_wrapper
|
14
|
-
from runem.log import error, log
|
14
|
+
from runem.log import error, log, warn
|
15
15
|
from runem.types.common import FilePathList, JobTags
|
16
16
|
from runem.types.filters import FilePathListLookup
|
17
17
|
from runem.types.runem_config import JobConfig
|
@@ -50,7 +50,8 @@ def job_execute_inner(
|
|
50
50
|
|
51
51
|
if not file_list:
|
52
52
|
# no files to work on
|
53
|
-
|
53
|
+
if not config_metadata.args.silent:
|
54
|
+
warn(f"skipping job '{label}', no files for job")
|
54
55
|
return {
|
55
56
|
"job": (f"{label}: no files!", timedelta(0)),
|
56
57
|
"commands": [],
|
runem/runem.py
CHANGED
@@ -36,7 +36,8 @@ from rich.console import Console, ConsoleOptions, ConsoleRenderable, RenderResul
|
|
36
36
|
from rich.spinner import Spinner
|
37
37
|
from rich.text import Text
|
38
38
|
|
39
|
-
from runem.
|
39
|
+
from runem.blocking_print import RICH_CONSOLE
|
40
|
+
from runem.command_line import error_on_log_logic, parse_args
|
40
41
|
from runem.config import load_project_config, load_user_configs
|
41
42
|
from runem.config_metadata import ConfigMetadata
|
42
43
|
from runem.config_parse import load_config_metadata
|
@@ -57,8 +58,6 @@ from runem.types.types_jobs import (
|
|
57
58
|
)
|
58
59
|
from runem.utils import printable_set
|
59
60
|
|
60
|
-
rich_console = Console()
|
61
|
-
|
62
61
|
|
63
62
|
def _determine_run_parameters(argv: typing.List[str]) -> ConfigMetadata:
|
64
63
|
"""Loads config, parsing cli input and produces the run config.
|
@@ -68,12 +67,19 @@ def _determine_run_parameters(argv: typing.List[str]) -> ConfigMetadata:
|
|
68
67
|
|
69
68
|
Return a ConfigMetadata object with all the required information.
|
70
69
|
"""
|
70
|
+
|
71
|
+
# Because we want to be able to show logging whilst parsing .runem.yml config, we
|
72
|
+
# need to check the state of the logging-verbosity switches here, manually, as well.
|
73
|
+
verbose = "--verbose" in argv
|
74
|
+
silent = ("--silent" in argv) or ("-s" in argv)
|
75
|
+
error_on_log_logic(verbose, silent)
|
76
|
+
|
71
77
|
config: Config
|
72
78
|
cfg_filepath: pathlib.Path
|
73
79
|
config, cfg_filepath = load_project_config()
|
74
80
|
user_configs: typing.List[typing.Tuple[Config, pathlib.Path]] = load_user_configs()
|
75
81
|
config_metadata: ConfigMetadata = load_config_metadata(
|
76
|
-
config, cfg_filepath, user_configs, verbose=("--verbose" in argv)
|
82
|
+
config, cfg_filepath, user_configs, silent, verbose=("--verbose" in argv)
|
77
83
|
)
|
78
84
|
|
79
85
|
# Now we parse the cli arguments extending them with information from the
|
@@ -143,7 +149,7 @@ def _update_progress(
|
|
143
149
|
|
144
150
|
last_running_jobs_set: typing.Set[str] = set()
|
145
151
|
|
146
|
-
with
|
152
|
+
with RICH_CONSOLE.status(spinner):
|
147
153
|
while is_running.value:
|
148
154
|
running_jobs_set: typing.Set[str] = set(running_jobs.values())
|
149
155
|
|
@@ -157,7 +163,7 @@ def _update_progress(
|
|
157
163
|
spinner.text = report
|
158
164
|
else:
|
159
165
|
if last_running_jobs_set != running_jobs_set:
|
160
|
-
|
166
|
+
RICH_CONSOLE.log(report)
|
161
167
|
|
162
168
|
# Sleep for reduced CPU usage
|
163
169
|
time.sleep(0.1)
|
@@ -1,15 +1,23 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: runem
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: Awesome runem created by lursight
|
5
|
-
Home-page: https://github.com/lursight/runem/
|
6
5
|
Author: lursight
|
6
|
+
License: Specify your license here
|
7
|
+
Project-URL: Homepage, https://github.com/lursight/runem/
|
8
|
+
Keywords: example,runem
|
9
|
+
Classifier: Programming Language :: Python :: 3.7
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
14
|
+
Requires-Python: >=3.7
|
7
15
|
Description-Content-Type: text/markdown
|
8
16
|
License-File: LICENSE
|
9
|
-
Requires-Dist: packaging
|
10
|
-
Requires-Dist: PyYAML
|
11
|
-
Requires-Dist: rich
|
12
|
-
Requires-Dist: typing_extensions
|
17
|
+
Requires-Dist: packaging>=22.0
|
18
|
+
Requires-Dist: PyYAML>=5.0.0
|
19
|
+
Requires-Dist: rich>10.0.0
|
20
|
+
Requires-Dist: typing_extensions>3.0.0
|
13
21
|
Provides-Extra: tests
|
14
22
|
Requires-Dist: black==24.10.0; extra == "tests"
|
15
23
|
Requires-Dist: coverage==7.5; extra == "tests"
|
@@ -153,3 +161,4 @@ Read the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
|
153
161
|
The runem mission is to improve developer velocity at
|
154
162
|
[Lursight Ltd.](https://lursight.com), read more about the runem
|
155
163
|
[mission](https://lursight.github.io/runem/docs/mission.html).
|
164
|
+
|
@@ -1,18 +1,18 @@
|
|
1
|
-
runem/VERSION,sha256=
|
1
|
+
runem/VERSION,sha256=oK1QZAE5pST4ZZEVcUW_HUZ06pwGW_6iFVjw97BEMMg,6
|
2
2
|
runem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
3
|
runem/__main__.py,sha256=dsOiVZegpfK9JOs5n7UmbX5iwwbj7iFkEbLoVeEgAn4,136
|
4
4
|
runem/base.py,sha256=EZfR7FIlwEdU9Vfe47Wk2DOO8GQqpKxxLNKp6YHueZ4,316
|
5
|
-
runem/blocking_print.py,sha256=
|
5
|
+
runem/blocking_print.py,sha256=R3c3HSnRMPCf7ykDXdKG2hKH4CzbBaxmOfP3xEU_wEI,1919
|
6
6
|
runem/cli.py,sha256=wEt_Jnumhl8SiOdKdSJzLkJpWv6n3_Odhi_HeIixr1k,134
|
7
|
-
runem/command_line.py,sha256=
|
7
|
+
runem/command_line.py,sha256=qkZFCCq9hUl6RO398SJzoigv8di5jGw2sdNwgTVBdd8,14474
|
8
8
|
runem/config.py,sha256=UiEU0Jyg5qjrNStvasWYjMOABQHhpZjbPiX3-sH_CMg,5969
|
9
9
|
runem/config_metadata.py,sha256=krDomUcADsAeUQrxwNmOS58eeaNIlqmhWIKWv8mUH4A,3300
|
10
|
-
runem/config_parse.py,sha256=
|
10
|
+
runem/config_parse.py,sha256=zXQ4rpj-igQufB5JtTsI1mOE_gBTdBcI2hI6HWU28gg,13830
|
11
11
|
runem/files.py,sha256=59boeFvUANYOS-PllIjeKIht6lNINZ43WxahDg90oAc,4392
|
12
12
|
runem/hook_manager.py,sha256=H0TL3HCqU2mgKm_-dgCD7TsK5T1bLT4g7x6kpytMPhU,4350
|
13
13
|
runem/informative_dict.py,sha256=U7p9z78UwOT4TAfng1iDXCEyeYz6C-XZlx9Z1pWNVrI,1548
|
14
14
|
runem/job.py,sha256=NOdRQnGePPyYdmIR_6JKVFzp9nbgNGetpE13bHEHaf4,3442
|
15
|
-
runem/job_execute.py,sha256
|
15
|
+
runem/job_execute.py,sha256=-76IJI0PDU_XdQiDxTKUfOHEno9pixxQb_zi58rFumo,4702
|
16
16
|
runem/job_filter.py,sha256=7vgG4YWJ9gyGBFjV7QbSojG5ofYoszAmxXx9HnMLkHo,5384
|
17
17
|
runem/job_runner_simple_command.py,sha256=iP5an6yixW8o4C0ZBtu6csb-oVK3Q62ZZgtHBmxlXaU,2428
|
18
18
|
runem/job_wrapper.py,sha256=q5GtopZ5vhSJ581rwU4-lF9KnbL3ZYgOC8fqaCnXD_g,983
|
@@ -21,9 +21,10 @@ runem/log.py,sha256=dIrocigvIJs1ZGkAzTogXkAK-0ZW3q5FkjpDgLdeW-E,630
|
|
21
21
|
runem/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
runem/report.py,sha256=IedwW9mmJfGC6vKQdKDHQH5eoiYzTWHaaD4a3J4e_Pc,9020
|
23
23
|
runem/run_command.py,sha256=Egl_j4bJ9mwi2JEFCsl0W6WH2IRgIdpMN7qdj8voClQ,6386
|
24
|
-
runem/runem.py,sha256=
|
24
|
+
runem/runem.py,sha256=9QZgmXNPXOscRRLWDgOcPZ0lYRcG7jOog1M_o3MXZbs,13667
|
25
25
|
runem/runem_version.py,sha256=MbETwZO2Tb1Y3hX_OYZjKepEMKA1cjNvr-7Cqhz6e3s,271
|
26
26
|
runem/utils.py,sha256=3N_kel9LsriiMq7kOjT14XhfxUOgz4hdDg97wlLKm3U,221
|
27
|
+
runem/cli/initialise_options.py,sha256=zx_EduWQk7yGBr3XUNrffHCSInPv05edFItHLnlo9dk,918
|
27
28
|
runem/types/__init__.py,sha256=6TzF4KV9tDGuDTr2qAXmWWkfDU52WuVlQ8Hcz48aYDk,286
|
28
29
|
runem/types/common.py,sha256=gPMSoJ3yRUYjHnoviRrpSg0gRwsGLFGWGpbTWkq4jX0,279
|
29
30
|
runem/types/errors.py,sha256=rbM5BA6UhY1X7Q0OZLUNsG7JXAjgNFTG5KQuqPNuZm8,103
|
@@ -32,11 +33,20 @@ runem/types/hooks.py,sha256=lgrv5QAuHCEzr5dXDj4-azNcs63addY9zdrGWj5zv_s,292
|
|
32
33
|
runem/types/options.py,sha256=y8_hyWYvhalC9-kZbvoDtxm0trZgyyGcswQqfuQy_pM,265
|
33
34
|
runem/types/runem_config.py,sha256=qG_bghm5Nr-ZTbaZbf1v8Fx447V-hgEvvRy5NZ3t-Io,5141
|
34
35
|
runem/types/types_jobs.py,sha256=wqiiBmRIJDbGlKcfOqewHGKx350w0p4_7pysMm7xGmo,4906
|
36
|
+
scripts/test_hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
|
+
scripts/test_hooks/json_validators.py,sha256=N2FyWcpjWzfFGycXLo-ecNLJkxTFPPbqPfVBcJLBlb4,967
|
38
|
+
scripts/test_hooks/py.py,sha256=YUbwNny7NPmv2bY7k7YcbJ-jRcnNfjQajE9Hn1MLaBc,8821
|
39
|
+
scripts/test_hooks/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
|
+
scripts/test_hooks/runem_hooks.py,sha256=FJMuDBEOz3dr9gBW3WW6yKbUJs_LFXb3klpqSzCAZRk,628
|
41
|
+
scripts/test_hooks/yarn.py,sha256=1QsG1rKAclpZoqp86ntkuvzYaYN4UkEvO0JhO2Kf5C8,1082
|
42
|
+
tests/cli/test_initialise_options.py,sha256=Ogwfqz39r2o1waXMqCC22OJsgZoLF2stwGVO5AZUc4s,3148
|
43
|
+
tests/data/help_output.3.10.txt,sha256=5TUpNITVL6pD5BpFAl-Orh3vkOpStveijZzvgJuI_sA,4280
|
44
|
+
tests/data/help_output.3.11.txt,sha256=ycrF-xKgdQ8qrWzkkR-vbHe7NulUTsCsS0_Gda8xYDs,4162
|
35
45
|
tests/test_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
46
|
tests/test_types/test_public_api.py,sha256=QHiwt7CetQur65JSbFRnOzQxhCJkX5MVLymHHVd_6yc,160
|
37
|
-
runem-0.
|
38
|
-
runem-0.
|
39
|
-
runem-0.
|
40
|
-
runem-0.
|
41
|
-
runem-0.
|
42
|
-
runem-0.
|
47
|
+
runem-0.5.0.dist-info/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
48
|
+
runem-0.5.0.dist-info/METADATA,sha256=9isKJbNwlMOME8i2ipmSBySxD-Om_tVIp0ji_3WJeRM,6215
|
49
|
+
runem-0.5.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
50
|
+
runem-0.5.0.dist-info/entry_points.txt,sha256=nu0g_vBeuPihYtimbtlNusxWovylMppvJ8UxdJlJfvM,46
|
51
|
+
runem-0.5.0.dist-info/top_level.txt,sha256=NkdxkwLKNNhxItveR2KqNqTshTZ268m5D7SjJEmG4-Y,20
|
52
|
+
runem-0.5.0.dist-info/RECORD,,
|
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import pathlib
|
2
|
+
|
3
|
+
from typing_extensions import Unpack
|
4
|
+
|
5
|
+
from runem.run_command import run_command
|
6
|
+
from runem.types import FilePathList, JobKwargs
|
7
|
+
|
8
|
+
|
9
|
+
def _json_validate(
|
10
|
+
**kwargs: Unpack[JobKwargs],
|
11
|
+
) -> None:
|
12
|
+
label = kwargs["label"]
|
13
|
+
json_files: FilePathList = kwargs["file_list"]
|
14
|
+
json_with_comments = (
|
15
|
+
"cspell.json",
|
16
|
+
"tsconfig.spec.json",
|
17
|
+
"launch.json",
|
18
|
+
"settings.json",
|
19
|
+
)
|
20
|
+
for json_file in json_files:
|
21
|
+
json_path = pathlib.Path(json_file)
|
22
|
+
if not json_path.exists():
|
23
|
+
raise RuntimeError(
|
24
|
+
f"could not find '{str(json_path)}, in {pathlib.Path('.').absolute()}"
|
25
|
+
)
|
26
|
+
if json_path.name in json_with_comments:
|
27
|
+
# until we use a validator that allows comments in json, skip these
|
28
|
+
continue
|
29
|
+
|
30
|
+
cmd = ["python", "-m", "json.tool", f"{json_file}"]
|
31
|
+
kwargs["label"] = f"{label} {json_file}"
|
32
|
+
run_command(cmd=cmd, **kwargs)
|
scripts/test_hooks/py.py
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
import pathlib
|
2
|
+
import shutil
|
3
|
+
import typing
|
4
|
+
|
5
|
+
from typing_extensions import Unpack
|
6
|
+
|
7
|
+
from runem.log import log
|
8
|
+
from runem.run_command import RunCommandUnhandledError, run_command
|
9
|
+
from runem.types import FilePathList, JobKwargs, JobName, JobReturnData, Options
|
10
|
+
|
11
|
+
|
12
|
+
def _job_py_code_reformat(
|
13
|
+
**kwargs: Unpack[JobKwargs],
|
14
|
+
) -> None:
|
15
|
+
"""Runs python formatting code in serial order as one influences the other."""
|
16
|
+
label: JobName = kwargs["label"]
|
17
|
+
options: Options = kwargs["options"]
|
18
|
+
python_files: FilePathList = kwargs["file_list"]
|
19
|
+
|
20
|
+
# put into 'check' mode if requested on the command line
|
21
|
+
extra_args = []
|
22
|
+
docformatter_extra_args = [
|
23
|
+
"--in-place",
|
24
|
+
]
|
25
|
+
if options["check-only"]:
|
26
|
+
extra_args.append("--check")
|
27
|
+
docformatter_extra_args = [] # --inplace is not compatible with --check
|
28
|
+
|
29
|
+
if options["isort"]:
|
30
|
+
isort_cmd = [
|
31
|
+
"python3",
|
32
|
+
"-m",
|
33
|
+
"isort",
|
34
|
+
"--profile",
|
35
|
+
"black",
|
36
|
+
"--treat-all-comment-as-code",
|
37
|
+
*extra_args,
|
38
|
+
*python_files,
|
39
|
+
]
|
40
|
+
kwargs["label"] = f"{label} isort"
|
41
|
+
run_command(cmd=isort_cmd, **kwargs)
|
42
|
+
|
43
|
+
if options["black"]:
|
44
|
+
black_cmd = [
|
45
|
+
"python3",
|
46
|
+
"-m",
|
47
|
+
"black",
|
48
|
+
*extra_args,
|
49
|
+
*python_files,
|
50
|
+
]
|
51
|
+
kwargs["label"] = f"{label} black"
|
52
|
+
run_command(cmd=black_cmd, **kwargs)
|
53
|
+
|
54
|
+
if options["docformatter"]:
|
55
|
+
docformatter_cmd = [
|
56
|
+
"python3",
|
57
|
+
"-m",
|
58
|
+
"docformatter",
|
59
|
+
"--wrap-summaries",
|
60
|
+
"88",
|
61
|
+
"--wrap-descriptions",
|
62
|
+
"88",
|
63
|
+
*docformatter_extra_args,
|
64
|
+
*extra_args,
|
65
|
+
*python_files,
|
66
|
+
]
|
67
|
+
allowed_exits: typing.Tuple[int, ...] = (
|
68
|
+
0, # no work/change required
|
69
|
+
3, # no errors, but code was reformatted
|
70
|
+
)
|
71
|
+
if options["check-only"]:
|
72
|
+
# in check it is ONLY ok if no work/change was required
|
73
|
+
allowed_exits = (0,)
|
74
|
+
kwargs["label"] = f"{label} docformatter"
|
75
|
+
run_command(
|
76
|
+
cmd=docformatter_cmd,
|
77
|
+
ignore_fails=False,
|
78
|
+
valid_exit_ids=allowed_exits,
|
79
|
+
**kwargs,
|
80
|
+
)
|
81
|
+
|
82
|
+
|
83
|
+
def _job_py_pylint(
|
84
|
+
**kwargs: Unpack[JobKwargs],
|
85
|
+
) -> None:
|
86
|
+
python_files: FilePathList = kwargs["file_list"]
|
87
|
+
root_path: pathlib.Path = kwargs["root_path"]
|
88
|
+
|
89
|
+
pylint_cfg = root_path / ".pylint.rc"
|
90
|
+
if not pylint_cfg.exists():
|
91
|
+
raise RuntimeError(f"PYLINT Config not found at '{pylint_cfg}'")
|
92
|
+
|
93
|
+
pylint_cmd = [
|
94
|
+
"python3",
|
95
|
+
"-m",
|
96
|
+
"pylint",
|
97
|
+
"-j1",
|
98
|
+
"--score=n",
|
99
|
+
f"--rcfile={pylint_cfg}",
|
100
|
+
*python_files,
|
101
|
+
]
|
102
|
+
run_command(cmd=pylint_cmd, **kwargs)
|
103
|
+
|
104
|
+
|
105
|
+
def _job_py_flake8(
|
106
|
+
**kwargs: Unpack[JobKwargs],
|
107
|
+
) -> None:
|
108
|
+
python_files: FilePathList = kwargs["file_list"]
|
109
|
+
root_path: pathlib.Path = kwargs["root_path"]
|
110
|
+
flake8_rc = root_path / ".flake8"
|
111
|
+
if not flake8_rc.exists():
|
112
|
+
raise RuntimeError(f"flake8 config not found at '{flake8_rc}'")
|
113
|
+
|
114
|
+
flake8_cmd = [
|
115
|
+
"python3",
|
116
|
+
"-m",
|
117
|
+
"flake8",
|
118
|
+
*python_files,
|
119
|
+
]
|
120
|
+
run_command(cmd=flake8_cmd, **kwargs)
|
121
|
+
|
122
|
+
|
123
|
+
def _job_py_mypy(
|
124
|
+
**kwargs: Unpack[JobKwargs],
|
125
|
+
) -> None:
|
126
|
+
python_files: FilePathList = kwargs["file_list"]
|
127
|
+
mypy_cmd = ["python3", "-m", "mypy", *python_files]
|
128
|
+
output = run_command(cmd=mypy_cmd, **kwargs)
|
129
|
+
if "mypy.ini" in output or "Not a boolean:" in output:
|
130
|
+
raise RunCommandUnhandledError(f"runem: mypy mis-config detected: {output}")
|
131
|
+
|
132
|
+
|
133
|
+
def _delete_old_coverage_reports(root_path: pathlib.Path) -> None:
|
134
|
+
"""To avoid false-positives on coverage we delete the coverage report files."""
|
135
|
+
old_coverage_report_files: typing.List[pathlib.Path] = list(
|
136
|
+
root_path.glob(".coverage_report*")
|
137
|
+
)
|
138
|
+
for old_coverage_report in old_coverage_report_files:
|
139
|
+
old_coverage_report.unlink()
|
140
|
+
|
141
|
+
|
142
|
+
def _job_py_pytest( # noqa: C901 # pylint: disable=too-many-branches,too-many-statements
|
143
|
+
**kwargs: Unpack[JobKwargs],
|
144
|
+
) -> JobReturnData:
|
145
|
+
label: JobName = kwargs["label"]
|
146
|
+
options: Options = kwargs["options"]
|
147
|
+
procs: int = kwargs["procs"]
|
148
|
+
root_path: pathlib.Path = kwargs["root_path"]
|
149
|
+
|
150
|
+
reports: JobReturnData = {"reportUrls": []}
|
151
|
+
# TODO: use pytest.ini config pytest
|
152
|
+
# pytest_cfg = root_path / ".pytest.ini"
|
153
|
+
# assert pytest_cfg.exists()
|
154
|
+
|
155
|
+
if not options["unit-test"]:
|
156
|
+
# we've disabled unit-testing on the cli
|
157
|
+
return reports
|
158
|
+
|
159
|
+
if options["profile"]:
|
160
|
+
raise RuntimeError("not implemented - see run_test.sh for how to implement")
|
161
|
+
|
162
|
+
pytest_path = root_path / "tests"
|
163
|
+
assert pytest_path.exists()
|
164
|
+
|
165
|
+
coverage_switches: typing.List[str] = []
|
166
|
+
coverage_cfg = root_path / ".coveragerc"
|
167
|
+
if options["coverage"]:
|
168
|
+
_delete_old_coverage_reports(root_path)
|
169
|
+
assert coverage_cfg.exists()
|
170
|
+
coverage_switches = [
|
171
|
+
"--cov=.",
|
172
|
+
f"--cov-config={str(coverage_cfg)}",
|
173
|
+
"--cov-append",
|
174
|
+
"--no-cov-on-fail", # do not show coverage terminal report when we fail
|
175
|
+
"--cov-fail-under=0", # we do coverage filing later
|
176
|
+
]
|
177
|
+
|
178
|
+
# TODO: do we want to disable logs on pytest runs?
|
179
|
+
# "PYTEST_LOG":"--no-print-logs --log-level=CRITICAL" ;
|
180
|
+
|
181
|
+
threading_switches: typing.List[str] = []
|
182
|
+
if procs == -1:
|
183
|
+
threading_switches = ["-n", "auto"]
|
184
|
+
|
185
|
+
verbose_switches: typing.List[str] = []
|
186
|
+
if "verbose" in kwargs and kwargs["verbose"]:
|
187
|
+
verbose_switches = ["-vvv"]
|
188
|
+
|
189
|
+
profile_switches: typing.List[str] = []
|
190
|
+
cmd_pytest = [
|
191
|
+
"python3",
|
192
|
+
"-m",
|
193
|
+
"pytest",
|
194
|
+
"--color=yes",
|
195
|
+
*threading_switches,
|
196
|
+
# "-c",
|
197
|
+
# str(pytest_cfg),
|
198
|
+
*coverage_switches,
|
199
|
+
"--failed-first",
|
200
|
+
"--exitfirst",
|
201
|
+
*profile_switches,
|
202
|
+
*verbose_switches,
|
203
|
+
str(pytest_path),
|
204
|
+
]
|
205
|
+
|
206
|
+
env_overrides: typing.Dict[str, str] = {}
|
207
|
+
|
208
|
+
kwargs["label"] = f"{label} pytest"
|
209
|
+
run_command(
|
210
|
+
cmd=cmd_pytest,
|
211
|
+
env_overrides=env_overrides,
|
212
|
+
**kwargs,
|
213
|
+
)
|
214
|
+
|
215
|
+
if options["coverage"]:
|
216
|
+
reports_dir: pathlib.Path = root_path / "reports"
|
217
|
+
reports_dir.mkdir(parents=False, exist_ok=True)
|
218
|
+
coverage_output_dir: pathlib.Path = reports_dir / "coverage_python"
|
219
|
+
if coverage_output_dir.exists():
|
220
|
+
shutil.rmtree(coverage_output_dir)
|
221
|
+
coverage_output_dir.mkdir(exist_ok=True)
|
222
|
+
if kwargs["verbose"]:
|
223
|
+
log("COVERAGE: Collating coverage")
|
224
|
+
# first generate the coverage report for our gitlab cicd
|
225
|
+
gen_cobertura_coverage_report_cmd = [
|
226
|
+
"python3",
|
227
|
+
"-m",
|
228
|
+
"coverage",
|
229
|
+
"xml",
|
230
|
+
"-o",
|
231
|
+
str(coverage_output_dir / "cobertura.xml"),
|
232
|
+
f"--rcfile={str(coverage_cfg)}",
|
233
|
+
]
|
234
|
+
kwargs["label"] = f"{label} coverage cobertura"
|
235
|
+
run_command(cmd=gen_cobertura_coverage_report_cmd, **kwargs)
|
236
|
+
|
237
|
+
# then a html report
|
238
|
+
gen_html_coverage_report_cmd = [
|
239
|
+
"python3",
|
240
|
+
"-m",
|
241
|
+
"coverage",
|
242
|
+
"html",
|
243
|
+
f"--rcfile={str(coverage_cfg)}",
|
244
|
+
]
|
245
|
+
kwargs["label"] = f"{label} coverage html"
|
246
|
+
run_command(cmd=gen_html_coverage_report_cmd, **kwargs)
|
247
|
+
|
248
|
+
# then a standard command-line report that causes the tests to fail.
|
249
|
+
gen_cli_coverage_report_cmd = [
|
250
|
+
"python3",
|
251
|
+
"-m",
|
252
|
+
"coverage",
|
253
|
+
"report",
|
254
|
+
"--fail-under=100",
|
255
|
+
f"--rcfile={str(coverage_cfg)}",
|
256
|
+
]
|
257
|
+
kwargs["label"] = f"{label} coverage cli"
|
258
|
+
report_html = coverage_output_dir / "index.html"
|
259
|
+
report_cobertura = coverage_output_dir / "cobertura.xml"
|
260
|
+
try:
|
261
|
+
run_command(cmd=gen_cli_coverage_report_cmd, **kwargs)
|
262
|
+
except BaseException:
|
263
|
+
print()
|
264
|
+
print(report_html)
|
265
|
+
print(report_cobertura)
|
266
|
+
raise
|
267
|
+
assert coverage_output_dir.exists(), coverage_output_dir
|
268
|
+
assert report_html.exists(), report_html
|
269
|
+
assert report_cobertura.exists(), report_cobertura
|
270
|
+
reports["reportUrls"].append(("coverage html", report_html))
|
271
|
+
reports["reportUrls"].append(("coverage cobertura", report_cobertura))
|
272
|
+
if kwargs["verbose"]:
|
273
|
+
log("COVERAGE: cli output done")
|
274
|
+
return reports
|
275
|
+
|
276
|
+
|
277
|
+
def _install_python_requirements(
|
278
|
+
**kwargs: Unpack[JobKwargs],
|
279
|
+
) -> None:
|
280
|
+
options: Options = kwargs["options"]
|
281
|
+
if not (options["install-deps"]):
|
282
|
+
# not enabled
|
283
|
+
return
|
284
|
+
cmd = [
|
285
|
+
"python3",
|
286
|
+
"-m",
|
287
|
+
"pip",
|
288
|
+
"install",
|
289
|
+
"-e",
|
290
|
+
".[tests]",
|
291
|
+
]
|
292
|
+
run_command(cmd=cmd, **kwargs)
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import pathlib
|
2
|
+
from datetime import timedelta
|
3
|
+
|
4
|
+
from typing_extensions import Unpack
|
5
|
+
|
6
|
+
from runem.types import HookKwargs
|
7
|
+
|
8
|
+
|
9
|
+
def _on_exit_hook(
|
10
|
+
**kwargs: Unpack[HookKwargs],
|
11
|
+
) -> None:
|
12
|
+
"""A noddy hook."""
|
13
|
+
assert "wall_clock_time_saved" in kwargs
|
14
|
+
wall_clock_time_saved: timedelta = kwargs["wall_clock_time_saved"]
|
15
|
+
root_path: pathlib.Path = pathlib.Path(__file__).parent.parent.parent
|
16
|
+
assert (root_path / ".runem.yml").exists()
|
17
|
+
times_log: pathlib.Path = root_path / ".times.log"
|
18
|
+
with times_log.open("a", encoding="utf-8") as file:
|
19
|
+
file.write(f"{str(wall_clock_time_saved.total_seconds())}\n")
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import pathlib
|
2
|
+
|
3
|
+
from typing_extensions import Unpack
|
4
|
+
|
5
|
+
from runem.run_command import run_command
|
6
|
+
from runem.types import JobKwargs, Options
|
7
|
+
|
8
|
+
|
9
|
+
def _job_yarn_deps(
|
10
|
+
**kwargs: Unpack[JobKwargs],
|
11
|
+
) -> None:
|
12
|
+
"""Installs the yarn deps."""
|
13
|
+
options: Options = kwargs["options"]
|
14
|
+
|
15
|
+
install_requested = options["install-deps"]
|
16
|
+
if not (install_requested):
|
17
|
+
root_path: pathlib.Path = kwargs["root_path"]
|
18
|
+
if (root_path / "node_modules").exists():
|
19
|
+
# An install was not requested, nor required.
|
20
|
+
return
|
21
|
+
|
22
|
+
install_cmd = [
|
23
|
+
"yarn",
|
24
|
+
"install",
|
25
|
+
]
|
26
|
+
|
27
|
+
run_command(cmd=install_cmd, **kwargs)
|
28
|
+
|
29
|
+
|
30
|
+
def _job_prettier(
|
31
|
+
**kwargs: Unpack[JobKwargs],
|
32
|
+
) -> None:
|
33
|
+
"""Runs prettifier on files, including json and maybe yml file.
|
34
|
+
|
35
|
+
TODO: connect me up!
|
36
|
+
"""
|
37
|
+
options: Options = kwargs["options"]
|
38
|
+
command_variant = "pretty"
|
39
|
+
if options["check-only"]:
|
40
|
+
command_variant = "prettyCheck"
|
41
|
+
|
42
|
+
pretty_cmd = [
|
43
|
+
"yarn",
|
44
|
+
"run",
|
45
|
+
command_variant,
|
46
|
+
]
|
47
|
+
|
48
|
+
run_command(cmd=pretty_cmd, **kwargs)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import pathlib
|
2
|
+
from argparse import Namespace
|
3
|
+
from collections import defaultdict
|
4
|
+
from typing import Dict
|
5
|
+
from unittest.mock import MagicMock
|
6
|
+
|
7
|
+
import pytest
|
8
|
+
|
9
|
+
from runem.command_line import initialise_options
|
10
|
+
from runem.config_metadata import ConfigMetadata
|
11
|
+
from runem.types.runem_config import JobConfig, PhaseGroupedJobs
|
12
|
+
|
13
|
+
Options = Dict[str, bool]
|
14
|
+
|
15
|
+
|
16
|
+
@pytest.fixture(name="config_metadata")
|
17
|
+
def config_metadata_fixture() -> ConfigMetadata:
|
18
|
+
config_file_path = pathlib.Path(__file__).parent / ".runem.yml"
|
19
|
+
expected_job: JobConfig = {
|
20
|
+
"addr": {
|
21
|
+
"file": "test_config_parse.py",
|
22
|
+
"function": "test_parse_config",
|
23
|
+
},
|
24
|
+
"label": "dummy job label",
|
25
|
+
"when": {
|
26
|
+
"phase": "dummy phase 1",
|
27
|
+
"tags": {"dummy tag 1", "dummy tag 2"},
|
28
|
+
},
|
29
|
+
}
|
30
|
+
expected_jobs: PhaseGroupedJobs = defaultdict(list)
|
31
|
+
expected_jobs["dummy phase 1"] = [
|
32
|
+
expected_job,
|
33
|
+
]
|
34
|
+
return ConfigMetadata(
|
35
|
+
cfg_filepath=config_file_path,
|
36
|
+
phases=("dummy phase 1",),
|
37
|
+
options_config=(
|
38
|
+
{"name": "option1", "default": True},
|
39
|
+
{"name": "option2", "default": False},
|
40
|
+
{"name": "option3", "default": True},
|
41
|
+
{"name": "option4", "default": False},
|
42
|
+
),
|
43
|
+
file_filters={
|
44
|
+
# "dummy tag": {
|
45
|
+
# "tag": "dummy tag",
|
46
|
+
# "regex": ".*1.txt", # should match just one file
|
47
|
+
# }
|
48
|
+
},
|
49
|
+
hook_manager=MagicMock(),
|
50
|
+
jobs=expected_jobs,
|
51
|
+
all_job_names=set(("dummy job label",)),
|
52
|
+
all_job_phases=set(("dummy phase 1",)),
|
53
|
+
all_job_tags=set(
|
54
|
+
(
|
55
|
+
"dummy tag 2",
|
56
|
+
"dummy tag 1",
|
57
|
+
)
|
58
|
+
),
|
59
|
+
)
|
60
|
+
|
61
|
+
|
62
|
+
def test_initialise_options_no_overrides(config_metadata: ConfigMetadata) -> None:
|
63
|
+
args = Namespace(overrides_on=[], overrides_off=[])
|
64
|
+
options = initialise_options(config_metadata, args)
|
65
|
+
assert options == {
|
66
|
+
"option1": True,
|
67
|
+
"option2": False,
|
68
|
+
"option3": True,
|
69
|
+
"option4": False,
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
def test_initialise_options_overrides_on(config_metadata: ConfigMetadata) -> None:
|
74
|
+
args = Namespace(overrides_on=["option2", "option4"], overrides_off=[])
|
75
|
+
options = initialise_options(config_metadata, args)
|
76
|
+
assert options == {
|
77
|
+
"option1": True,
|
78
|
+
"option2": True,
|
79
|
+
"option3": True,
|
80
|
+
"option4": True,
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
def test_initialise_options_overrides_off(config_metadata: ConfigMetadata) -> None:
|
85
|
+
args = Namespace(overrides_on=[], overrides_off=["option1", "option3"])
|
86
|
+
options = initialise_options(config_metadata, args)
|
87
|
+
assert options == {
|
88
|
+
"option1": False,
|
89
|
+
"option2": False,
|
90
|
+
"option3": False,
|
91
|
+
"option4": False,
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
def test_initialise_options_overrides_on_and_off(
|
96
|
+
config_metadata: ConfigMetadata,
|
97
|
+
) -> None:
|
98
|
+
args = Namespace(overrides_on=["option2"], overrides_off=["option1"])
|
99
|
+
options = initialise_options(config_metadata, args)
|
100
|
+
assert options == {
|
101
|
+
"option1": False,
|
102
|
+
"option2": True,
|
103
|
+
"option3": True,
|
104
|
+
"option4": False,
|
105
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
runem: WARNING: no phase found for 'echo "hello world!"', using 'dummy phase 1'
|
2
|
+
usage: -c [-H] [--jobs JOBS [JOBS ...]] [--not-jobs JOBS_EXCLUDED [JOBS_EXCLUDED ...]] [--phases PHASES [PHASES ...]] [--not-phases PHASES_EXCLUDED [PHASES_EXCLUDED ...]] [--tags TAGS [TAGS ...]] [--not-tags TAGS_EXCLUDED [TAGS_EXCLUDED ...]] [--dummy-option-1---complete-option] [--no-dummy-option-1---complete-option] [--dummy-option-2---minimal] [--no-dummy-option-2---minimal] [--call-graphs | --no-call-graphs] [-f | --modified-files | --no-modified-files] [-h | --git-head-files | --no-git-head-files] [--always-files ALWAYS_FILES [ALWAYS_FILES ...]] [--git-files-since-branch GIT_SINCE_BRANCH] [--procs PROCS] [--root ROOT_DIR] [--root-show | --no-root-show] [--silent | --no-silent | -s] [--spinner | --no-spinner] [--verbose | --no-verbose] [--version | --no-version | -v]
|
3
|
+
|
4
|
+
Runs the Lursight Lang test-suite
|
5
|
+
|
6
|
+
[TEST_REPLACED_OPTION_HEADER]
|
7
|
+
-H, --help show this help message and exit
|
8
|
+
--call-graphs, --no-call-graphs
|
9
|
+
-f, --modified-files, --no-modified-files
|
10
|
+
only use files that have changed (default: False)
|
11
|
+
-h, --git-head-files, --no-git-head-files
|
12
|
+
fast run of files (default: False)
|
13
|
+
--always-files ALWAYS_FILES [ALWAYS_FILES ...]
|
14
|
+
list of paths/files to always check (overriding -f/-h), if the path matches the filter regex and if file-paths exist
|
15
|
+
--git-files-since-branch GIT_SINCE_BRANCH
|
16
|
+
Get the list of paths/files changed between a branch, e.g., since 'origin/main'. Useful for checking files changed before pushing.
|
17
|
+
--procs PROCS, -j PROCS
|
18
|
+
the number of concurrent test jobs to run, -1 runs all test jobs at the same time ([TEST_REPLACED_CORES] cores available)
|
19
|
+
--root ROOT_DIR which dir to use as the base-dir for testing, defaults to directory containing the config '[TEST_REPLACED_DIR]'
|
20
|
+
--root-show, --no-root-show
|
21
|
+
show the root-path of runem and exit (default: False)
|
22
|
+
--silent, --no-silent, -s
|
23
|
+
Whether to show warning messages or not. (default: False)
|
24
|
+
--spinner, --no-spinner
|
25
|
+
Whether to show the progress spinner or not. Helps reduce log-spam in ci/cd. (default: True)
|
26
|
+
--verbose, --no-verbose
|
27
|
+
runs runem in in verbose mode, and streams jobs stdout/stderr to console (default: False)
|
28
|
+
--version, --no-version, -v
|
29
|
+
show the version of runem and exit (default: False)
|
30
|
+
|
31
|
+
jobs:
|
32
|
+
--jobs JOBS [JOBS ...]
|
33
|
+
List of job-names to run the given jobs. Other filters will modify this list. Defaults to 'dummy job label 1', 'dummy job label 2', 'echo "hello world!"', 'hello world'
|
34
|
+
--not-jobs JOBS_EXCLUDED [JOBS_EXCLUDED ...]
|
35
|
+
List of job-names to NOT run. Defaults to empty. Available options are: 'dummy job label 1', 'dummy job label 2', 'echo "hello world!"', 'hello world'
|
36
|
+
|
37
|
+
phases:
|
38
|
+
--phases PHASES [PHASES ...]
|
39
|
+
Run only the phases passed in, and can be used to change the phase order. Phases are run in the order given. Defaults to 'dummy phase 1', 'dummy phase 2'.
|
40
|
+
--not-phases PHASES_EXCLUDED [PHASES_EXCLUDED ...]
|
41
|
+
List of phases to NOT run. This option does not change the phase run order. Options are '['dummy phase 1', 'dummy phase 2']'.
|
42
|
+
|
43
|
+
tags:
|
44
|
+
--tags TAGS [TAGS ...]
|
45
|
+
Only run jobs with the given tags. Defaults to '['dummy tag 1', 'dummy tag 2', 'tag only on job 1', 'tag only on job 2']'.
|
46
|
+
--not-tags TAGS_EXCLUDED [TAGS_EXCLUDED ...]
|
47
|
+
Removes one or more tags from the list of job tags to be run. Options are '['dummy tag 1', 'dummy tag 2', 'tag only on job 1', 'tag only on job 2']'.
|
48
|
+
|
49
|
+
job-param overrides:
|
50
|
+
--dummy-option-1---complete-option, --dummy option 1 multi alias 1, --dummy option 1 multi alias 2, -x, --dummy option alias 1
|
51
|
+
a dummy option description
|
52
|
+
--no-dummy-option-1---complete-option, --no-dummy option 1 multi alias 1, --no-dummy option 1 multi alias 2, --no-x, --no-dummy option alias 1
|
53
|
+
turn off a dummy option description
|
54
|
+
--dummy-option-2---minimal
|
55
|
+
--no-dummy-option-2---minimal
|
@@ -0,0 +1,55 @@
|
|
1
|
+
runem: WARNING: no phase found for 'echo "hello world!"', using 'dummy phase 1'
|
2
|
+
usage: -c [-H] [--jobs JOBS [JOBS ...]] [--not-jobs JOBS_EXCLUDED [JOBS_EXCLUDED ...]] [--phases PHASES [PHASES ...]] [--not-phases PHASES_EXCLUDED [PHASES_EXCLUDED ...]] [--tags TAGS [TAGS ...]] [--not-tags TAGS_EXCLUDED [TAGS_EXCLUDED ...]] [--dummy-option-1---complete-option] [--no-dummy-option-1---complete-option] [--dummy-option-2---minimal] [--no-dummy-option-2---minimal] [--call-graphs | --no-call-graphs] [-f | --modified-files | --no-modified-files] [-h | --git-head-files | --no-git-head-files] [--always-files ALWAYS_FILES [ALWAYS_FILES ...]] [--git-files-since-branch GIT_SINCE_BRANCH] [--procs PROCS] [--root ROOT_DIR] [--root-show | --no-root-show] [--silent | --no-silent | -s] [--spinner | --no-spinner] [--verbose | --no-verbose] [--version | --no-version | -v]
|
3
|
+
|
4
|
+
Runs the Lursight Lang test-suite
|
5
|
+
|
6
|
+
[TEST_REPLACED_OPTION_HEADER]
|
7
|
+
-H, --help show this help message and exit
|
8
|
+
--call-graphs, --no-call-graphs
|
9
|
+
-f, --modified-files, --no-modified-files
|
10
|
+
only use files that have changed
|
11
|
+
-h, --git-head-files, --no-git-head-files
|
12
|
+
fast run of files
|
13
|
+
--always-files ALWAYS_FILES [ALWAYS_FILES ...]
|
14
|
+
list of paths/files to always check (overriding -f/-h), if the path matches the filter regex and if file-paths exist
|
15
|
+
--git-files-since-branch GIT_SINCE_BRANCH
|
16
|
+
Get the list of paths/files changed between a branch, e.g., since 'origin/main'. Useful for checking files changed before pushing.
|
17
|
+
--procs PROCS, -j PROCS
|
18
|
+
the number of concurrent test jobs to run, -1 runs all test jobs at the same time ([TEST_REPLACED_CORES] cores available)
|
19
|
+
--root ROOT_DIR which dir to use as the base-dir for testing, defaults to directory containing the config '[TEST_REPLACED_DIR]'
|
20
|
+
--root-show, --no-root-show
|
21
|
+
show the root-path of runem and exit
|
22
|
+
--silent, --no-silent, -s
|
23
|
+
Whether to show warning messages or not.
|
24
|
+
--spinner, --no-spinner
|
25
|
+
Whether to show the progress spinner or not. Helps reduce log-spam in ci/cd.
|
26
|
+
--verbose, --no-verbose
|
27
|
+
runs runem in in verbose mode, and streams jobs stdout/stderr to console
|
28
|
+
--version, --no-version, -v
|
29
|
+
show the version of runem and exit
|
30
|
+
|
31
|
+
jobs:
|
32
|
+
--jobs JOBS [JOBS ...]
|
33
|
+
List of job-names to run the given jobs. Other filters will modify this list. Defaults to 'dummy job label 1', 'dummy job label 2', 'echo "hello world!"', 'hello world'
|
34
|
+
--not-jobs JOBS_EXCLUDED [JOBS_EXCLUDED ...]
|
35
|
+
List of job-names to NOT run. Defaults to empty. Available options are: 'dummy job label 1', 'dummy job label 2', 'echo "hello world!"', 'hello world'
|
36
|
+
|
37
|
+
phases:
|
38
|
+
--phases PHASES [PHASES ...]
|
39
|
+
Run only the phases passed in, and can be used to change the phase order. Phases are run in the order given. Defaults to 'dummy phase 1', 'dummy phase 2'.
|
40
|
+
--not-phases PHASES_EXCLUDED [PHASES_EXCLUDED ...]
|
41
|
+
List of phases to NOT run. This option does not change the phase run order. Options are '['dummy phase 1', 'dummy phase 2']'.
|
42
|
+
|
43
|
+
tags:
|
44
|
+
--tags TAGS [TAGS ...]
|
45
|
+
Only run jobs with the given tags. Defaults to '['dummy tag 1', 'dummy tag 2', 'tag only on job 1', 'tag only on job 2']'.
|
46
|
+
--not-tags TAGS_EXCLUDED [TAGS_EXCLUDED ...]
|
47
|
+
Removes one or more tags from the list of job tags to be run. Options are '['dummy tag 1', 'dummy tag 2', 'tag only on job 1', 'tag only on job 2']'.
|
48
|
+
|
49
|
+
job-param overrides:
|
50
|
+
--dummy-option-1---complete-option, --dummy option 1 multi alias 1, --dummy option 1 multi alias 2, -x, --dummy option alias 1
|
51
|
+
a dummy option description
|
52
|
+
--no-dummy-option-1---complete-option, --no-dummy option 1 multi alias 1, --no-dummy option 1 multi alias 2, --no-x, --no-dummy option alias 1
|
53
|
+
turn off a dummy option description
|
54
|
+
--dummy-option-2---minimal
|
55
|
+
--no-dummy-option-2---minimal
|
File without changes
|
File without changes
|
File without changes
|