hydraflow 0.10.0__tar.gz → 0.10.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.
- hydraflow-0.10.1/.cursorrules +6 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/PKG-INFO +1 -1
- {hydraflow-0.10.0 → hydraflow-0.10.1}/pyproject.toml +1 -1
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/io.py +1 -1
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/main.py +8 -4
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/entities/run_collection.py +1 -1
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/executor/job.py +8 -5
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/executor/parser.py +38 -13
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/io/test_hydra_dir.py +1 -1
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/test_match_overrides.py +8 -2
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/test_job.py +27 -8
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/test_parser.py +74 -6
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.devcontainer/devcontainer.json +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.devcontainer/postCreate.sh +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.devcontainer/starship.toml +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.gitattributes +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.github/workflows/ci.yaml +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.github/workflows/docs.yaml +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/.gitignore +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/LICENSE +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/README.md +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/apps/quickstart.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/docs/index.md +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/docs/usage/quickstart.md +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/mkdocs.yaml +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/cli.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/config.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/context.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/mlflow.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/core/param.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/entities/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/entities/run_data.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/entities/run_info.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/executor/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/executor/conf.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/executor/io.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/src/hydraflow/py.typed +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/app.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/conftest.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/hydraflow.yaml +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/test_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/test_setup.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/test_show.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/cli/test_version.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/conftest.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/config/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/config/test_config.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/config/test_params.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/chdir.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/log_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/start_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/test_chdir.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/test_log_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/context/test_start_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/io/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/io/hydra_dir.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/io/test_iter_dirs.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/io/test_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/default.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/force_new_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/match_overrides.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/rerun_finished.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/skip_finished.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/test_default.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/test_force_new_run.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/test_rerun_finished.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/main/test_skip_finished.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/param/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/param/params.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/param/test_param.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/param/test_params.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/core/test_mlflow.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/filter.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/test_collection.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/test_data.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/test_filter.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/test_info.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/test_values.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/entities/values.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/__init__.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/conftest.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/echo.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/test_args.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/test_conf.py +0 -0
- {hydraflow-0.10.0 → hydraflow-0.10.1}/tests/executor/test_io.py +0 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
You are an AI assistant specialized in Python development. Your approach emphasizes:
|
2
|
+
|
3
|
+
1. Comprehensive testing with pytest.
|
4
|
+
2. Code style consistency using Ruff.
|
5
|
+
3. Detailed documentation using docstrings and README files.
|
6
|
+
4. Generate Git commit messages in English.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hydraflow
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.1
|
4
4
|
Summary: Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments.
|
5
5
|
Project-URL: Documentation, https://daizutabi.github.io/hydraflow/
|
6
6
|
Project-URL: Source, https://github.com/daizutabi/hydraflow
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "hydraflow"
|
7
|
-
version = "0.10.
|
7
|
+
version = "0.10.1"
|
8
8
|
description = "Hydraflow integrates Hydra and MLflow to manage and track machine learning experiments."
|
9
9
|
readme = "README.md"
|
10
10
|
license = { file = "LICENSE" }
|
@@ -136,7 +136,7 @@ def load_overrides(run: Run) -> ListConfig:
|
|
136
136
|
|
137
137
|
"""
|
138
138
|
path = get_artifact_dir(run) / ".hydra/overrides.yaml"
|
139
|
-
return OmegaConf.load(path) # type: ignore
|
139
|
+
return sorted(OmegaConf.load(path)) # type: ignore
|
140
140
|
|
141
141
|
|
142
142
|
def remove_run(run: Run | Iterable[Run]) -> None:
|
@@ -154,11 +154,15 @@ def equals(run_dir: Path, config: Any, overrides: list[str] | None) -> bool:
|
|
154
154
|
"""
|
155
155
|
if overrides is None:
|
156
156
|
path = run_dir / "artifacts/.hydra/config.yaml"
|
157
|
-
|
158
|
-
|
159
|
-
|
157
|
+
|
158
|
+
if not path.exists():
|
159
|
+
return False
|
160
|
+
|
161
|
+
return OmegaConf.load(path) == config
|
162
|
+
|
163
|
+
path = run_dir / "artifacts/.hydra/overrides.yaml"
|
160
164
|
|
161
165
|
if not path.exists():
|
162
166
|
return False
|
163
167
|
|
164
|
-
return OmegaConf.load(path) ==
|
168
|
+
return sorted(OmegaConf.load(path)) == sorted(overrides)
|
@@ -116,7 +116,7 @@ class RunCollection:
|
|
116
116
|
but not in the other.
|
117
117
|
|
118
118
|
"""
|
119
|
-
runs = [run for run in self._runs if run not in other._runs]
|
119
|
+
runs = [run for run in self._runs if run not in other._runs]
|
120
120
|
return self.__class__(runs)
|
121
121
|
|
122
122
|
@property
|
@@ -99,6 +99,7 @@ def multirun(job: Job) -> None:
|
|
99
99
|
|
100
100
|
if job.run:
|
101
101
|
base_cmds = shlex.split(job.run)
|
102
|
+
|
102
103
|
for args in it:
|
103
104
|
cmds = [*base_cmds, *args]
|
104
105
|
try:
|
@@ -108,22 +109,24 @@ def multirun(job: Job) -> None:
|
|
108
109
|
raise RuntimeError(msg) from e
|
109
110
|
|
110
111
|
elif job.call:
|
111
|
-
|
112
|
-
|
112
|
+
call_name, *base_args = shlex.split(job.call)
|
113
|
+
|
114
|
+
if "." not in call_name:
|
115
|
+
msg = f"Invalid function path: {call_name}."
|
113
116
|
msg += " Expected format: 'package.module.function'"
|
114
117
|
raise ValueError(msg)
|
115
118
|
|
116
119
|
try:
|
117
|
-
module_name, func_name =
|
120
|
+
module_name, func_name = call_name.rsplit(".", 1)
|
118
121
|
module = importlib.import_module(module_name)
|
119
122
|
func = getattr(module, func_name)
|
120
123
|
except (ImportError, AttributeError, ModuleNotFoundError) as e:
|
121
|
-
msg = f"Failed to import or find function: {
|
124
|
+
msg = f"Failed to import or find function: {call_name}"
|
122
125
|
raise ValueError(msg) from e
|
123
126
|
|
124
127
|
for args in it:
|
125
128
|
try:
|
126
|
-
func(*args)
|
129
|
+
func([*base_args, *args])
|
127
130
|
except Exception as e: # noqa: PERF203
|
128
131
|
msg = f"Function call '{job.call}' failed with args: {args}"
|
129
132
|
raise RuntimeError(msg) from e
|
@@ -8,7 +8,7 @@ ranges, and expand values from string arguments.
|
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
10
|
|
11
|
-
import
|
11
|
+
import shlex
|
12
12
|
from itertools import chain, product
|
13
13
|
from typing import TYPE_CHECKING
|
14
14
|
|
@@ -289,7 +289,7 @@ def split(arg: str) -> list[str]:
|
|
289
289
|
return result
|
290
290
|
|
291
291
|
|
292
|
-
def expand_values(arg: str) ->
|
292
|
+
def expand_values(arg: str, suffix: str = "") -> Iterator[str]:
|
293
293
|
"""Expand a string argument into a list of values.
|
294
294
|
|
295
295
|
Take a string containing comma-separated values or ranges and return a list
|
@@ -297,12 +297,36 @@ def expand_values(arg: str) -> list[str]:
|
|
297
297
|
|
298
298
|
Args:
|
299
299
|
arg (str): The argument to expand.
|
300
|
+
suffix (str): The suffix to append to each value.
|
300
301
|
|
301
302
|
Returns:
|
302
|
-
|
303
|
+
Iterator[str]: An iterator of the expanded values.
|
303
304
|
|
304
305
|
"""
|
305
|
-
|
306
|
+
if suffix in SUFFIX_EXPONENT:
|
307
|
+
suffix = SUFFIX_EXPONENT[suffix]
|
308
|
+
|
309
|
+
for value in chain.from_iterable(collect_values(x) for x in split(arg)):
|
310
|
+
yield f"{value}{suffix}"
|
311
|
+
|
312
|
+
|
313
|
+
def split_arg(arg: str) -> tuple[str, str, str]:
|
314
|
+
"""Split an argument into a key, suffix, and value.
|
315
|
+
|
316
|
+
Args:
|
317
|
+
arg (str): The argument to split.
|
318
|
+
|
319
|
+
Returns:
|
320
|
+
tuple[str, str, str]: A tuple containing the key, suffix, and value.
|
321
|
+
|
322
|
+
"""
|
323
|
+
key, value = arg.split("=")
|
324
|
+
|
325
|
+
if "/" in key:
|
326
|
+
key, suffix = key.split("/", 1)
|
327
|
+
return key, suffix, value
|
328
|
+
|
329
|
+
return key, "", value
|
306
330
|
|
307
331
|
|
308
332
|
def collect_arg(arg: str) -> str:
|
@@ -318,9 +342,9 @@ def collect_arg(arg: str) -> str:
|
|
318
342
|
str: A string of the collected key and values.
|
319
343
|
|
320
344
|
"""
|
321
|
-
key,
|
322
|
-
|
323
|
-
return f"{key}={
|
345
|
+
key, suffix, value = split_arg(arg)
|
346
|
+
value = ",".join(expand_values(value, suffix))
|
347
|
+
return f"{key}={value}"
|
324
348
|
|
325
349
|
|
326
350
|
def expand_arg(arg: str) -> Iterator[str]:
|
@@ -338,26 +362,27 @@ def expand_arg(arg: str) -> Iterator[str]:
|
|
338
362
|
|
339
363
|
"""
|
340
364
|
if "|" not in arg:
|
341
|
-
key, value = arg
|
365
|
+
key, suffix, value = split_arg(arg)
|
342
366
|
|
343
|
-
for v in expand_values(value):
|
367
|
+
for v in expand_values(value, suffix):
|
344
368
|
yield f"{key}={v}"
|
345
369
|
|
346
370
|
return
|
347
371
|
|
348
372
|
args = arg.split("|")
|
349
373
|
key = ""
|
374
|
+
suffix = ""
|
350
375
|
|
351
376
|
for arg_ in args:
|
352
377
|
if "=" in arg_:
|
353
|
-
key, value = arg_
|
378
|
+
key, suffix, value = split_arg(arg_)
|
354
379
|
elif key:
|
355
380
|
value = arg_
|
356
381
|
else:
|
357
382
|
msg = f"Invalid argument: {arg_}"
|
358
383
|
raise ValueError(msg)
|
359
384
|
|
360
|
-
value = ",".join(expand_values(value))
|
385
|
+
value = ",".join(expand_values(value, suffix))
|
361
386
|
yield f"{key}={value}"
|
362
387
|
|
363
388
|
|
@@ -372,7 +397,7 @@ def collect(args: str | list[str]) -> list[str]:
|
|
372
397
|
|
373
398
|
"""
|
374
399
|
if isinstance(args, str):
|
375
|
-
args =
|
400
|
+
args = shlex.split(args)
|
376
401
|
|
377
402
|
args = [arg for arg in args if "=" in arg]
|
378
403
|
|
@@ -390,7 +415,7 @@ def expand(args: str | list[str]) -> list[list[str]]:
|
|
390
415
|
|
391
416
|
"""
|
392
417
|
if isinstance(args, str):
|
393
|
-
args =
|
418
|
+
args = shlex.split(args)
|
394
419
|
|
395
420
|
args = [arg for arg in args if "=" in arg]
|
396
421
|
|
@@ -11,8 +11,8 @@ pytestmark = pytest.mark.xdist_group(name="group5")
|
|
11
11
|
def rc(collect):
|
12
12
|
file = Path(__file__).parent / "match_overrides.py"
|
13
13
|
collect(file, ["-m", "count=1,2"])
|
14
|
-
collect(file, ["-m", "name=a,b"])
|
15
|
-
return collect(file, ["-m", "name=a,b"])
|
14
|
+
collect(file, ["-m", "name=a,b", "count=1"])
|
15
|
+
return collect(file, ["-m", "count=1", "name=a,b"])
|
16
16
|
|
17
17
|
|
18
18
|
def test_rc_len(rc: RunCollection):
|
@@ -23,3 +23,9 @@ def test_config(rc: RunCollection):
|
|
23
23
|
df = rc.data.config
|
24
24
|
assert len(df) == 4
|
25
25
|
assert len(df.drop_duplicates()) == 3
|
26
|
+
|
27
|
+
|
28
|
+
def test_equals():
|
29
|
+
from hydraflow.core.main import equals
|
30
|
+
|
31
|
+
assert equals(Path.cwd(), None, []) is False
|
@@ -94,27 +94,46 @@ def test_multirun_run_error(job: Job):
|
|
94
94
|
multirun(job)
|
95
95
|
|
96
96
|
|
97
|
-
def
|
97
|
+
def test_multirun_call(job: Job, capsys: pytest.CaptureFixture):
|
98
98
|
from hydraflow.executor.job import multirun
|
99
99
|
|
100
|
-
job.call = "
|
101
|
-
|
100
|
+
job.call = "typer.echo"
|
101
|
+
multirun(job)
|
102
|
+
out, _ = capsys.readouterr()
|
103
|
+
assert "'a=1,2', 'b=5'" in out
|
104
|
+
assert "'a=3,4', 'c=8'" in out
|
105
|
+
|
106
|
+
|
107
|
+
def test_multirun_call_args(job: Job, capsys: pytest.CaptureFixture):
|
108
|
+
from hydraflow.executor.job import multirun
|
109
|
+
|
110
|
+
job.call = "typer.echo a 'b c'"
|
111
|
+
multirun(job)
|
112
|
+
out, _ = capsys.readouterr()
|
113
|
+
assert "['a', 'b c', '--multirun'," in out
|
114
|
+
|
115
|
+
|
116
|
+
def test_multirun_call_error(job: Job):
|
117
|
+
from hydraflow.executor.job import multirun
|
118
|
+
|
119
|
+
job.call = "hydraflow.executor.job.multirun"
|
120
|
+
with pytest.raises(RuntimeError):
|
102
121
|
multirun(job)
|
103
122
|
|
104
123
|
|
105
|
-
def
|
124
|
+
def test_multirun_call_invalid(job: Job):
|
106
125
|
from hydraflow.executor.job import multirun
|
107
126
|
|
108
|
-
job.call = "
|
127
|
+
job.call = "print"
|
109
128
|
with pytest.raises(ValueError):
|
110
129
|
multirun(job)
|
111
130
|
|
112
131
|
|
113
|
-
def
|
132
|
+
def test_multirun_call_not_found(job: Job):
|
114
133
|
from hydraflow.executor.job import multirun
|
115
134
|
|
116
|
-
job.call = "
|
117
|
-
with pytest.raises(
|
135
|
+
job.call = "hydraflow.invalid"
|
136
|
+
with pytest.raises(ValueError):
|
118
137
|
multirun(job)
|
119
138
|
|
120
139
|
|
@@ -129,18 +129,37 @@ def test_collect_value(s, x):
|
|
129
129
|
def test_expand_value(s, x):
|
130
130
|
from hydraflow.executor.parser import expand_values
|
131
131
|
|
132
|
-
assert expand_values(s) == x
|
132
|
+
assert list(expand_values(s)) == x
|
133
|
+
|
134
|
+
|
135
|
+
@pytest.mark.parametrize(
|
136
|
+
("s", "x"),
|
137
|
+
[
|
138
|
+
("1,2,3", ["1e3", "2e3", "3e3"]),
|
139
|
+
("1:3,5:6", ["1e3", "2e3", "3e3", "5e3", "6e3"]),
|
140
|
+
("0:0.25:1,2.0", ["0e3", "0.25e3", "0.5e3", "0.75e3", "1.0e3", "2.0e3"]),
|
141
|
+
("3", ["3e3"]),
|
142
|
+
],
|
143
|
+
)
|
144
|
+
def test_expand_value_suffix(s, x):
|
145
|
+
from hydraflow.executor.parser import expand_values
|
146
|
+
|
147
|
+
assert list(expand_values(s, "k")) == x
|
133
148
|
|
134
149
|
|
135
150
|
@pytest.mark.parametrize(
|
136
151
|
("s", "x"),
|
137
152
|
[
|
138
153
|
("a=1", "a=1"),
|
154
|
+
("a/M=1", "a=1e6"),
|
139
155
|
("a=1,2", "a=1,2"),
|
156
|
+
("a/n=1,2", "a=1e-9,2e-9"),
|
140
157
|
("a=1:2", "a=1,2"),
|
158
|
+
("a/M=1:2", "a=1e6,2e6"),
|
141
159
|
("a=:2:3", "a=0,2"),
|
142
160
|
("a=1:3:k", "a=1e3,2e3,3e3"),
|
143
161
|
("a=1:3:k,2:4:M", "a=1e3,2e3,3e3,2e6,3e6,4e6"),
|
162
|
+
("a/m=1:3,8:10", "a=1e-3,2e-3,3e-3,8e-3,9e-3,10e-3"),
|
144
163
|
],
|
145
164
|
)
|
146
165
|
def test_collect_arg(s, x):
|
@@ -154,13 +173,17 @@ def test_collect_arg(s, x):
|
|
154
173
|
[
|
155
174
|
("a=1", ["a=1"]),
|
156
175
|
("a=1,2", ["a=1", "a=2"]),
|
176
|
+
("a/M=1,2", ["a=1e6", "a=2e6"]),
|
157
177
|
("a=1:2", ["a=1", "a=2"]),
|
178
|
+
("a/n=1:2", ["a=1e-9", "a=2e-9"]),
|
158
179
|
("a=:2:3", ["a=0", "a=2"]),
|
159
180
|
("a=1:3:k", ["a=1e3", "a=2e3", "a=3e3"]),
|
160
181
|
("a=1:3:k,2:4:M", ["a=1e3", "a=2e3", "a=3e3", "a=2e6", "a=3e6", "a=4e6"]),
|
161
182
|
("a=1,2|3,4", ["a=1,2", "a=3,4"]),
|
183
|
+
("a/G=1,2|3,4", ["a=1e9,2e9", "a=3e9,4e9"]),
|
162
184
|
("a=1:4|3:5:m", ["a=1,2,3,4", "a=3e-3,4e-3,5e-3"]),
|
163
185
|
("a=1,2|b=3,4|c=5,6", ["a=1,2", "b=3,4", "c=5,6"]),
|
186
|
+
("a/k=1,2|b/m=3,4|c/u=5,6", ["a=1e3,2e3", "b=3e-3,4e-3", "c=5e-6,6e-6"]),
|
164
187
|
],
|
165
188
|
)
|
166
189
|
def test_expand_arg(s, x):
|
@@ -179,14 +202,29 @@ def test_expand_arg_error():
|
|
179
202
|
@pytest.mark.parametrize(
|
180
203
|
("s", "x"),
|
181
204
|
[
|
182
|
-
(["a=1"], ["a=1"]),
|
205
|
+
(["a=1", "b"], ["a=1"]),
|
183
206
|
(["a=1:3"], ["a=1,2,3"]),
|
207
|
+
(["a/m=1:3"], ["a=1e-3,2e-3,3e-3"]),
|
184
208
|
(["a=1:3", "b=4:6"], ["a=1,2,3", "b=4,5,6"]),
|
209
|
+
(["a/k=1:3", "b/m=4:6"], ["a=1e3,2e3,3e3", "b=4e-3,5e-3,6e-3"]),
|
210
|
+
],
|
211
|
+
)
|
212
|
+
def test_collect_list(s, x):
|
213
|
+
from hydraflow.executor.parser import collect
|
214
|
+
|
215
|
+
assert collect(s) == x
|
216
|
+
|
217
|
+
|
218
|
+
@pytest.mark.parametrize(
|
219
|
+
("s", "x"),
|
220
|
+
[
|
185
221
|
("a=1:3\nb=4:6", ["a=1,2,3", "b=4,5,6"]),
|
222
|
+
("a/k=1:3 b=4:6", ["a=1e3,2e3,3e3", "b=4,5,6"]),
|
223
|
+
("a/n=4,5 b=c,d", ["a=4e-9,5e-9", "b=c,d"]),
|
186
224
|
("", []),
|
187
225
|
],
|
188
226
|
)
|
189
|
-
def
|
227
|
+
def test_collect_str(s, x):
|
190
228
|
from hydraflow.executor.parser import collect
|
191
229
|
|
192
230
|
assert collect(s) == x
|
@@ -195,13 +233,14 @@ def test_collect(s, x):
|
|
195
233
|
@pytest.mark.parametrize(
|
196
234
|
("s", "x"),
|
197
235
|
[
|
198
|
-
(["a=1"], [["a=1"]]),
|
199
|
-
(["a=1,2"], [["a=
|
236
|
+
(["a=1", "b"], [["a=1"]]),
|
237
|
+
(["a/k=1,2"], [["a=1e3"], ["a=2e3"]]),
|
200
238
|
(
|
201
239
|
" a=1,2\n b=3,4\n",
|
202
240
|
[["a=1", "b=3"], ["a=1", "b=4"], ["a=2", "b=3"], ["a=2", "b=4"]],
|
203
241
|
),
|
204
242
|
(["a=1:2|3,4"], [["a=1,2"], ["a=3,4"]]),
|
243
|
+
(["a/k=1:2|3,4"], [["a=1e3,2e3"], ["a=3e3,4e3"]]),
|
205
244
|
(
|
206
245
|
["a=1:2|3,4", "b=5:6|c=7,8"],
|
207
246
|
[
|
@@ -211,10 +250,39 @@ def test_collect(s, x):
|
|
211
250
|
["a=3,4", "c=7,8"],
|
212
251
|
],
|
213
252
|
),
|
253
|
+
(
|
254
|
+
["a/m=1:2|3,4", "b/k=5:6|c/u=7,8"],
|
255
|
+
[
|
256
|
+
["a=1e-3,2e-3", "b=5e3,6e3"],
|
257
|
+
["a=1e-3,2e-3", "c=7e-6,8e-6"],
|
258
|
+
["a=3e-3,4e-3", "b=5e3,6e3"],
|
259
|
+
["a=3e-3,4e-3", "c=7e-6,8e-6"],
|
260
|
+
],
|
261
|
+
),
|
262
|
+
],
|
263
|
+
)
|
264
|
+
def test_expand_list(s, x):
|
265
|
+
from hydraflow.executor.parser import expand
|
266
|
+
|
267
|
+
assert expand(s) == x
|
268
|
+
|
269
|
+
|
270
|
+
@pytest.mark.parametrize(
|
271
|
+
("s", "x"),
|
272
|
+
[
|
273
|
+
(
|
274
|
+
"a/m=1:2|3,4 b/k=5:6|c=7,8",
|
275
|
+
[
|
276
|
+
["a=1e-3,2e-3", "b=5e3,6e3"],
|
277
|
+
["a=1e-3,2e-3", "c=7,8"],
|
278
|
+
["a=3e-3,4e-3", "b=5e3,6e3"],
|
279
|
+
["a=3e-3,4e-3", "c=7,8"],
|
280
|
+
],
|
281
|
+
),
|
214
282
|
("", [[]]),
|
215
283
|
],
|
216
284
|
)
|
217
|
-
def
|
285
|
+
def test_expand_str(s, x):
|
218
286
|
from hydraflow.executor.parser import expand
|
219
287
|
|
220
288
|
assert expand(s) == x
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|