hydraflow 0.12.1__tar.gz → 0.12.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. {hydraflow-0.12.1 → hydraflow-0.12.2}/PKG-INFO +1 -1
  2. {hydraflow-0.12.1 → hydraflow-0.12.2}/pyproject.toml +1 -1
  3. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/executor/parser.py +63 -23
  4. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/test_parser.py +33 -15
  5. {hydraflow-0.12.1 → hydraflow-0.12.2}/.cursorrules +0 -0
  6. {hydraflow-0.12.1 → hydraflow-0.12.2}/.devcontainer/devcontainer.json +0 -0
  7. {hydraflow-0.12.1 → hydraflow-0.12.2}/.devcontainer/postCreate.sh +0 -0
  8. {hydraflow-0.12.1 → hydraflow-0.12.2}/.devcontainer/starship.toml +0 -0
  9. {hydraflow-0.12.1 → hydraflow-0.12.2}/.gitattributes +0 -0
  10. {hydraflow-0.12.1 → hydraflow-0.12.2}/.github/workflows/ci.yaml +0 -0
  11. {hydraflow-0.12.1 → hydraflow-0.12.2}/.github/workflows/docs.yaml +0 -0
  12. {hydraflow-0.12.1 → hydraflow-0.12.2}/.gitignore +0 -0
  13. {hydraflow-0.12.1 → hydraflow-0.12.2}/LICENSE +0 -0
  14. {hydraflow-0.12.1 → hydraflow-0.12.2}/README.md +0 -0
  15. {hydraflow-0.12.1 → hydraflow-0.12.2}/apps/quickstart.py +0 -0
  16. {hydraflow-0.12.1 → hydraflow-0.12.2}/docs/index.md +0 -0
  17. {hydraflow-0.12.1 → hydraflow-0.12.2}/docs/usage/quickstart.md +0 -0
  18. {hydraflow-0.12.1 → hydraflow-0.12.2}/mkdocs.yaml +0 -0
  19. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/__init__.py +0 -0
  20. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/cli.py +0 -0
  21. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/__init__.py +0 -0
  22. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/config.py +0 -0
  23. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/context.py +0 -0
  24. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/io.py +0 -0
  25. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/main.py +0 -0
  26. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/mlflow.py +0 -0
  27. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/core/param.py +0 -0
  28. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/entities/__init__.py +0 -0
  29. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/entities/run_collection.py +0 -0
  30. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/entities/run_data.py +0 -0
  31. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/entities/run_info.py +0 -0
  32. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/executor/__init__.py +0 -0
  33. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/executor/conf.py +0 -0
  34. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/executor/io.py +0 -0
  35. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/executor/job.py +0 -0
  36. {hydraflow-0.12.1 → hydraflow-0.12.2}/src/hydraflow/py.typed +0 -0
  37. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/__init__.py +0 -0
  38. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/__init__.py +0 -0
  39. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/app.py +0 -0
  40. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/conftest.py +0 -0
  41. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/hydraflow.yaml +0 -0
  42. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/test_run.py +0 -0
  43. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/test_setup.py +0 -0
  44. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/test_show.py +0 -0
  45. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/cli/test_version.py +0 -0
  46. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/conftest.py +0 -0
  47. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/__init__.py +0 -0
  48. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/config/__init__.py +0 -0
  49. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/config/test_config.py +0 -0
  50. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/config/test_params.py +0 -0
  51. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/__init__.py +0 -0
  52. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/chdir.py +0 -0
  53. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/log_run.py +0 -0
  54. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/start_run.py +0 -0
  55. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/test_chdir.py +0 -0
  56. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/test_log_run.py +0 -0
  57. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/context/test_start_run.py +0 -0
  58. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/io/__init__.py +0 -0
  59. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/io/hydra_dir.py +0 -0
  60. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/io/test_hydra_dir.py +0 -0
  61. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/io/test_iter_dirs.py +0 -0
  62. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/io/test_run.py +0 -0
  63. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/__init__.py +0 -0
  64. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/default.py +0 -0
  65. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/force_new_run.py +0 -0
  66. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/match_overrides.py +0 -0
  67. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/rerun_finished.py +0 -0
  68. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/skip_finished.py +0 -0
  69. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/test_default.py +0 -0
  70. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/test_force_new_run.py +0 -0
  71. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/test_match_overrides.py +0 -0
  72. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/test_rerun_finished.py +0 -0
  73. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/main/test_skip_finished.py +0 -0
  74. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/param/__init__.py +0 -0
  75. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/param/params.py +0 -0
  76. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/param/test_param.py +0 -0
  77. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/param/test_params.py +0 -0
  78. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/core/test_mlflow.py +0 -0
  79. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/__init__.py +0 -0
  80. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/filter.py +0 -0
  81. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/test_collection.py +0 -0
  82. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/test_data.py +0 -0
  83. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/test_filter.py +0 -0
  84. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/test_info.py +0 -0
  85. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/test_values.py +0 -0
  86. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/entities/values.py +0 -0
  87. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/__init__.py +0 -0
  88. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/conftest.py +0 -0
  89. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/echo.py +0 -0
  90. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/test_args.py +0 -0
  91. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/test_conf.py +0 -0
  92. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/test_io.py +0 -0
  93. {hydraflow-0.12.1 → hydraflow-0.12.2}/tests/executor/test_job.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hydraflow
3
- Version: 0.12.1
3
+ Version: 0.12.2
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.12.1"
7
+ version = "0.12.2"
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" }
@@ -48,7 +48,7 @@ def to_number(x: str) -> int | float:
48
48
  return int(x)
49
49
 
50
50
 
51
- def count_decimal_places(x: str) -> int:
51
+ def count_decimal_digits(x: str) -> int:
52
52
  """Count decimal places in a string.
53
53
 
54
54
  Examine a string representing a number and returns the count
@@ -62,13 +62,13 @@ def count_decimal_places(x: str) -> int:
62
62
  int: The number of decimal places.
63
63
 
64
64
  Examples:
65
- >>> count_decimal_places("1")
65
+ >>> count_decimal_digits("1")
66
66
  0
67
- >>> count_decimal_places("-1.2")
67
+ >>> count_decimal_digits("-1.2")
68
68
  1
69
- >>> count_decimal_places("1.234")
69
+ >>> count_decimal_digits("1.234")
70
70
  3
71
- >>> count_decimal_places("-1.234e-10")
71
+ >>> count_decimal_digits("-1.234e-10")
72
72
  3
73
73
 
74
74
  """
@@ -82,6 +82,50 @@ def count_decimal_places(x: str) -> int:
82
82
  return len(decimal_part)
83
83
 
84
84
 
85
+ def count_integer_digits(num_str: str) -> int:
86
+ """Count the number of digits in the integer part of a number.
87
+
88
+ Consider only the integer part of a number, even if it is in
89
+ scientific notation.
90
+
91
+ Args:
92
+ num_str (str): The string representing a number.
93
+
94
+ Returns:
95
+ int: The number of digits in the integer part of a number.
96
+ (excluding the sign)
97
+
98
+ Examples:
99
+ >>> count_integer_digits("123")
100
+ 3
101
+ >>> count_integer_digits("-123.45")
102
+ 3
103
+ >>> count_integer_digits("+0.00123")
104
+ 1
105
+ >>> count_integer_digits("-1.200")
106
+ 1
107
+ >>> count_integer_digits("+1.20e3")
108
+ 1
109
+ >>> count_integer_digits("-0.120e-3")
110
+ 1
111
+ >>> count_integer_digits(".123")
112
+ 0
113
+
114
+ """
115
+ if num_str.startswith(("+", "-")):
116
+ num_str = num_str[1:]
117
+
118
+ if "e" in num_str.lower():
119
+ num_str = num_str.lower().split("e")[0]
120
+
121
+ if "." in num_str:
122
+ int_part = num_str.split(".")[0]
123
+ if not int_part:
124
+ return 0
125
+ return len(int_part)
126
+ return len(num_str)
127
+
128
+
85
129
  def is_number(x: str) -> bool:
86
130
  """Check if a string represents a valid number.
87
131
 
@@ -158,26 +202,18 @@ def _arange(start: float, step: float, stop: float) -> list[float]:
158
202
  if step == 0:
159
203
  raise ValueError("Step cannot be zero")
160
204
 
161
- epsilon = 1e-10
162
-
163
- decimal_places = max(
164
- count_decimal_places(str(start)),
165
- count_decimal_places(str(step)),
166
- count_decimal_places(str(stop)),
167
- )
205
+ epsilon = min(abs(start), abs(stop)) * 1e-5
168
206
 
169
207
  result = []
170
208
  current = start
171
209
 
172
210
  if step > 0:
173
211
  while current <= stop + epsilon:
174
- rounded = round(current, decimal_places)
175
- result.append(rounded)
212
+ result.append(current)
176
213
  current += step
177
214
  else:
178
215
  while current >= stop - epsilon:
179
- rounded = round(current, decimal_places)
180
- result.append(rounded)
216
+ result.append(current)
181
217
  current += step
182
218
 
183
219
  return result
@@ -344,8 +380,9 @@ def collect_values(arg: str) -> list[str]:
344
380
  if all(isinstance(x, int) for x in rng):
345
381
  values = [str(x) for x in _arange(*rng)]
346
382
  else:
347
- n = max(*(count_decimal_places(x) for x in arg.split(":")))
348
- values = [str(round(x, n)) for x in _arange(*rng)]
383
+ n = max(*(count_integer_digits(x) for x in arg.split(":")))
384
+ m = max(*(count_decimal_digits(x) for x in arg.split(":")))
385
+ values = [f"{x:.{n + m}g}" for x in _arange(*rng)]
349
386
 
350
387
  return [add_exponent(x, exponent) for x in values]
351
388
 
@@ -415,8 +452,9 @@ def split(arg: str) -> list[str]:
415
452
  def expand_values(arg: str, suffix: str = "") -> Iterator[str]:
416
453
  """Expand a string argument into a list of values.
417
454
 
418
- Take a string containing comma-separated values or ranges and return a list
419
- of all individual values. Handle numeric ranges and special characters.
455
+ Take a string containing comma-separated values or ranges
456
+ and return a list of all individual values.
457
+ Handle numeric ranges and special characters.
420
458
 
421
459
  Args:
422
460
  arg (str): The argument to expand.
@@ -439,7 +477,8 @@ def split_arg(arg: str) -> tuple[str, str, str]:
439
477
  arg (str): The argument to split.
440
478
 
441
479
  Returns:
442
- tuple[str, str, str]: A tuple containing the key, suffix, and value.
480
+ tuple[str, str, str]: A tuple containing the key,
481
+ suffix, and value.
443
482
 
444
483
  """
445
484
  if "=" not in arg:
@@ -458,8 +497,9 @@ def split_arg(arg: str) -> tuple[str, str, str]:
458
497
  def collect_arg(arg: str) -> str:
459
498
  """Collect a string of expanded key-value pairs.
460
499
 
461
- Take a key-value pair argument and concatenates all expanded values with commas,
462
- returning a single string suitable for command-line usage.
500
+ Take a key-value pair argument and concatenates all expanded
501
+ values with commas, returning a single string suitable for
502
+ command-line usage.
463
503
 
464
504
  Args:
465
505
  arg (str): The argument to collect.
@@ -1,3 +1,4 @@
1
+ import numpy as np
1
2
  import pytest
2
3
 
3
4
 
@@ -12,10 +13,20 @@ def test_to_number(s, x):
12
13
  ("s", "x"),
13
14
  [("1", 0), ("1.2", 1), ("1.234", 3), ("123.", 0), ("", 0), ("1.234e-10", 3)],
14
15
  )
15
- def test_count_decimal_places(s, x):
16
- from hydraflow.executor.parser import count_decimal_places
16
+ def test_count_decimal_digits(s, x):
17
+ from hydraflow.executor.parser import count_decimal_digits
17
18
 
18
- assert count_decimal_places(s) == x
19
+ assert count_decimal_digits(s) == x
20
+
21
+
22
+ @pytest.mark.parametrize(
23
+ ("s", "x"),
24
+ [("1", 1), ("1.2", 1), ("1.234", 1), ("123.", 3), ("", 0), ("1.234e-10", 1)],
25
+ )
26
+ def test_count_integer_digits(s, x):
27
+ from hydraflow.executor.parser import count_integer_digits
28
+
29
+ assert count_integer_digits(s) == x
19
30
 
20
31
 
21
32
  @pytest.mark.parametrize(
@@ -55,6 +66,7 @@ def test_get_range_errors(arg, expected_exception, expected_message):
55
66
  [
56
67
  (1.0, 2.0, 5.0, [1.0, 3.0, 5.0]),
57
68
  (1.2, 0.1, 1.4, [1.2, 1.3, 1.4]),
69
+ (1.2e-12, 0.1e-12, 1.4e-12, [1.2e-12, 1.3e-12, 1.4e-12]),
58
70
  (1.4, -0.1, 1.2, [1.4, 1.3, 1.2]),
59
71
  (1.02e-3, 0.01e-3, 1.04e-3, [0.00102, 0.00103, 0.00104]),
60
72
  ],
@@ -62,7 +74,7 @@ def test_get_range_errors(arg, expected_exception, expected_message):
62
74
  def test_arange(start, step, stop, expected):
63
75
  from hydraflow.executor.parser import _arange
64
76
 
65
- assert _arange(start, step, stop) == expected
77
+ np.testing.assert_allclose(_arange(start, step, stop), expected)
66
78
 
67
79
 
68
80
  def test_arange_error():
@@ -109,21 +121,27 @@ def test_split_suffix(s, x):
109
121
  ("1:M", ["1e6"]),
110
122
  ("0.234p", ["0.234p"]),
111
123
  ("1:3", ["1", "2", "3"]),
112
- ("0:0.25:1", ["0", "0.25", "0.5", "0.75", "1.0"]),
124
+ ("0:0.25:1", ["0", "0.25", "0.5", "0.75", "1"]),
125
+ ("10:0.25:11", ["10", "10.25", "10.5", "10.75", "11"]),
113
126
  (":3", ["0", "1", "2", "3"]),
114
127
  ("5:7", ["5", "6", "7"]),
115
128
  ("-1:1", ["-1", "0", "1"]),
116
- ("1:0.5:2", ["1", "1.5", "2.0"]),
117
- ("1.:0.5:2", ["1.0", "1.5", "2.0"]),
118
- ("2:0.5:3", ["2", "2.5", "3.0"]),
119
- ("-1:0.5:1", ["-1", "-0.5", "0.0", "0.5", "1.0"]),
129
+ ("1:0.5:2", ["1", "1.5", "2"]),
130
+ ("1.:0.5:2", ["1", "1.5", "2"]),
131
+ ("2:0.5:3", ["2", "2.5", "3"]),
132
+ ("-1:0.5:1", ["-1", "-0.5", "0", "0.5", "1"]),
120
133
  ("4:-1:2", ["4", "3", "2"]),
121
- ("4.5:-1.5:2", ["4.5", "3.0"]),
122
- ("4.5:-1.5:1.5", ["4.5", "3.0", "1.5"]),
123
- ("4.5:-1.5:-4.5", ["4.5", "3.0", "1.5", "0.0", "-1.5", "-3.0", "-4.5"]),
134
+ ("4.5:-1.5:2", ["4.5", "3"]),
135
+ ("4.5:-1.5:1.5", ["4.5", "3", "1.5"]),
136
+ ("4.5:-1.5:-4.5", ["4.5", "3", "1.5", "0", "-1.5", "-3", "-4.5"]),
124
137
  ("1:2:u", ["1e-6", "2e-6"]),
125
- ("1:.25:2:n", ["1e-9", "1.25e-9", "1.5e-9", "1.75e-9", "2.0e-9"]),
138
+ ("1:.25:2:n", ["1e-9", "1.25e-9", "1.5e-9", "1.75e-9", "2e-9"]),
126
139
  ("1.2:0.1:1.4:k", ["1.2e3", "1.3e3", "1.4e3"]),
140
+ ("1.2e-3:0.1e-3:1.4e-3", ["0.0012", "0.0013", "0.0014"]),
141
+ ("1.2e-12:0.1e-12:1.4e-12", ["1.2e-12", "1.3e-12", "1.4e-12"]),
142
+ ("1.22e-6:0.01e-6:1.24e-6", ["1.22e-06", "1.23e-06", "1.24e-06"]),
143
+ ("1.2e3:0.1e3:1.4e3", ["1.2e+03", "1.3e+03", "1.4e+03"]),
144
+ ("1.2e6:0.1e6:1.4e6", ["1.2e+06", "1.3e+06", "1.4e+06"]),
127
145
  ("1:2:e2", ["1e2", "2e2"]),
128
146
  (":2:e2", ["0", "1e2", "2e2"]),
129
147
  ("-2:2:k", ["-2e3", "-1e3", "0", "1e3", "2e3"]),
@@ -141,7 +159,7 @@ def test_collect_value(s, x):
141
159
  [
142
160
  ("1,2,3", ["1", "2", "3"]),
143
161
  ("1:3,5:6", ["1", "2", "3", "5", "6"]),
144
- ("0:0.25:1,2.0", ["0", "0.25", "0.5", "0.75", "1.0", "2.0"]),
162
+ ("0:0.25:1,2.0", ["0", "0.25", "0.5", "0.75", "1", "2.0"]),
145
163
  ("3", ["3"]),
146
164
  ("3:k", ["3e3"]),
147
165
  ("1:3:k,3:2:7:M", ["1e3", "2e3", "3e3", "3e6", "5e6", "7e6"]),
@@ -164,7 +182,7 @@ def test_expand_value(s, x):
164
182
  [
165
183
  ("1,2,3", ["1e3", "2e3", "3e3"]),
166
184
  ("1:3,5:6", ["1e3", "2e3", "3e3", "5e3", "6e3"]),
167
- ("0:0.25:1,2.0", ["0e3", "0.25e3", "0.5e3", "0.75e3", "1.0e3", "2.0e3"]),
185
+ ("0:0.25:1,2.0", ["0e3", "0.25e3", "0.5e3", "0.75e3", "1e3", "2.0e3"]),
168
186
  ("3", ["3e3"]),
169
187
  ],
170
188
  )
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