hydraflow 0.16.2__py3-none-any.whl → 0.17.1__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.
- hydraflow/core/collection.py +613 -0
- hydraflow/core/context.py +3 -4
- hydraflow/core/group_by.py +205 -0
- hydraflow/core/run.py +111 -62
- hydraflow/core/run_collection.py +66 -483
- hydraflow/core/run_info.py +0 -9
- {hydraflow-0.16.2.dist-info → hydraflow-0.17.1.dist-info}/METADATA +1 -1
- {hydraflow-0.16.2.dist-info → hydraflow-0.17.1.dist-info}/RECORD +11 -9
- {hydraflow-0.16.2.dist-info → hydraflow-0.17.1.dist-info}/WHEEL +0 -0
- {hydraflow-0.16.2.dist-info → hydraflow-0.17.1.dist-info}/entry_points.txt +0 -0
- {hydraflow-0.16.2.dist-info → hydraflow-0.17.1.dist-info}/licenses/LICENSE +0 -0
hydraflow/core/run_collection.py
CHANGED
@@ -20,10 +20,13 @@ Example:
|
|
20
20
|
# Sort runs by specific keys
|
21
21
|
sorted_runs = runs.sort("metrics.accuracy", reverse=True)
|
22
22
|
|
23
|
-
# Group runs by model type
|
24
|
-
grouped = runs.group_by("model.type"
|
25
|
-
|
26
|
-
|
23
|
+
# Group runs by model type
|
24
|
+
grouped = runs.group_by("model.type")
|
25
|
+
|
26
|
+
# Compute aggregates on grouped data
|
27
|
+
metrics_df = grouped.agg(
|
28
|
+
avg_acc=lambda rc: sum(r.get("metrics.accuracy") for r in rc) / len(rc)
|
29
|
+
)
|
27
30
|
|
28
31
|
# Convert runs to a DataFrame for analysis
|
29
32
|
df = runs.to_frame("run_id", "model.type", "metrics.accuracy")
|
@@ -37,25 +40,19 @@ Note:
|
|
37
40
|
|
38
41
|
from __future__ import annotations
|
39
42
|
|
40
|
-
from
|
41
|
-
from dataclasses import MISSING
|
43
|
+
from functools import cached_property
|
42
44
|
from typing import TYPE_CHECKING, overload
|
43
45
|
|
44
|
-
|
45
|
-
import polars as pl
|
46
|
-
from omegaconf import OmegaConf
|
47
|
-
from polars import DataFrame, Series
|
48
|
-
|
46
|
+
from .collection import Collection
|
49
47
|
from .run import Run
|
50
48
|
|
51
49
|
if TYPE_CHECKING:
|
52
|
-
from collections.abc import Callable, Iterator
|
50
|
+
from collections.abc import Callable, Iterable, Iterator
|
51
|
+
from pathlib import Path
|
53
52
|
from typing import Any, Self
|
54
53
|
|
55
|
-
from numpy.typing import NDArray
|
56
|
-
|
57
54
|
|
58
|
-
class RunCollection[R: Run[Any, Any]](
|
55
|
+
class RunCollection[R: Run[Any, Any], I = None](Collection[R]):
|
59
56
|
"""A collection of Run instances that implements the Sequence protocol.
|
60
57
|
|
61
58
|
RunCollection provides methods for filtering, sorting, grouping, and analyzing
|
@@ -67,79 +64,6 @@ class RunCollection[R: Run[Any, Any]](Sequence[R]):
|
|
67
64
|
|
68
65
|
"""
|
69
66
|
|
70
|
-
runs: list[R]
|
71
|
-
"""A list containing the Run instances in this collection."""
|
72
|
-
|
73
|
-
def __init__(self, runs: Iterable[R]) -> None:
|
74
|
-
self.runs = list(runs)
|
75
|
-
|
76
|
-
def __repr__(self) -> str:
|
77
|
-
"""Return a string representation of the RunCollection."""
|
78
|
-
class_name = self.__class__.__name__
|
79
|
-
if not self:
|
80
|
-
return f"{class_name}(empty)"
|
81
|
-
|
82
|
-
type_name = repr(self[0])
|
83
|
-
if "(" in type_name:
|
84
|
-
type_name = type_name.split("(", 1)[0]
|
85
|
-
return f"{class_name}({type_name}, n={len(self)})"
|
86
|
-
|
87
|
-
def __len__(self) -> int:
|
88
|
-
"""Return the number of Run instances in the collection.
|
89
|
-
|
90
|
-
Returns:
|
91
|
-
int: The number of runs.
|
92
|
-
|
93
|
-
"""
|
94
|
-
return len(self.runs)
|
95
|
-
|
96
|
-
def __bool__(self) -> bool:
|
97
|
-
"""Return whether the collection contains any Run instances.
|
98
|
-
|
99
|
-
Returns:
|
100
|
-
bool: True if the collection is not empty, False otherwise.
|
101
|
-
|
102
|
-
"""
|
103
|
-
return bool(self.runs)
|
104
|
-
|
105
|
-
@overload
|
106
|
-
def __getitem__(self, index: int) -> R: ...
|
107
|
-
|
108
|
-
@overload
|
109
|
-
def __getitem__(self, index: slice) -> Self: ...
|
110
|
-
|
111
|
-
@overload
|
112
|
-
def __getitem__(self, index: Iterable[int]) -> Self: ...
|
113
|
-
|
114
|
-
def __getitem__(self, index: int | slice | Iterable[int]) -> R | Self:
|
115
|
-
"""Get a Run or a new RunCollection based on the provided index.
|
116
|
-
|
117
|
-
Args:
|
118
|
-
index: Can be one of:
|
119
|
-
- An integer to get a single Run
|
120
|
-
- A slice to get a subrange of Runs
|
121
|
-
- An iterable of integers to get specific Runs
|
122
|
-
|
123
|
-
Returns:
|
124
|
-
R | Self: A single Run if index is an integer, or a new
|
125
|
-
RunCollection if index is a slice or iterable of integers.
|
126
|
-
|
127
|
-
"""
|
128
|
-
if isinstance(index, int):
|
129
|
-
return self.runs[index]
|
130
|
-
if isinstance(index, slice):
|
131
|
-
return self.__class__(self.runs[index])
|
132
|
-
return self.__class__([self.runs[i] for i in index])
|
133
|
-
|
134
|
-
def __iter__(self) -> Iterator[R]:
|
135
|
-
"""Return an iterator over the Runs in the collection.
|
136
|
-
|
137
|
-
Returns:
|
138
|
-
Iterator[R]: An iterator yielding Run instances.
|
139
|
-
|
140
|
-
"""
|
141
|
-
return iter(self.runs)
|
142
|
-
|
143
67
|
def preload(
|
144
68
|
self,
|
145
69
|
*,
|
@@ -155,15 +79,39 @@ class RunCollection[R: Run[Any, Any]](Sequence[R]):
|
|
155
79
|
access these properties, as they will be already loaded in memory.
|
156
80
|
|
157
81
|
Args:
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
82
|
+
n_jobs (int): Number of parallel jobs to run.
|
83
|
+
- 0: Run sequentially (default)
|
84
|
+
- -1: Use all available CPU cores
|
85
|
+
- >0: Use the specified number of cores
|
86
|
+
cfg (bool): Whether to preload the configuration objects.
|
87
|
+
Defaults to True.
|
88
|
+
impl (bool): Whether to preload the implementation objects.
|
89
|
+
Defaults to True.
|
162
90
|
|
163
91
|
Returns:
|
164
92
|
Self: The same RunCollection instance with preloaded
|
165
93
|
configuration and implementation objects.
|
166
94
|
|
95
|
+
Note:
|
96
|
+
The preloading is done using joblib's threading backend,
|
97
|
+
which is suitable for I/O-bound tasks like loading
|
98
|
+
configuration files and implementation objects.
|
99
|
+
|
100
|
+
Examples:
|
101
|
+
```python
|
102
|
+
# Preload all runs sequentially
|
103
|
+
runs.preload()
|
104
|
+
|
105
|
+
# Preload using all available cores
|
106
|
+
runs.preload(n_jobs=-1)
|
107
|
+
|
108
|
+
# Preload only configurations
|
109
|
+
runs.preload(impl=False)
|
110
|
+
|
111
|
+
# Preload only implementations
|
112
|
+
runs.preload(cfg=False)
|
113
|
+
```
|
114
|
+
|
167
115
|
"""
|
168
116
|
|
169
117
|
def load(run: R) -> None:
|
@@ -220,413 +168,48 @@ class RunCollection[R: Run[Any, Any]](Sequence[R]):
|
|
220
168
|
for run in self:
|
221
169
|
run.update(key, value, force=force)
|
222
170
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
**kwargs: Any,
|
227
|
-
) -> Self:
|
228
|
-
"""Filter runs based on predicates or key-value conditions.
|
229
|
-
|
230
|
-
This method allows filtering runs using various criteria:
|
231
|
-
- Callable predicates that take a Run and return a boolean
|
232
|
-
- Key-value tuples where the key is a string and the value
|
233
|
-
is compared using the Run.predicate method
|
234
|
-
- Keyword arguments, where the key is a string and the value
|
235
|
-
is compared using the Run.predicate method
|
236
|
-
|
237
|
-
Args:
|
238
|
-
*predicates: Callable predicates or (key, value) tuples
|
239
|
-
for filtering.
|
240
|
-
**kwargs: Additional key-value pairs for filtering.
|
241
|
-
|
242
|
-
Returns:
|
243
|
-
Self: A new RunCollection containing only the runs that
|
244
|
-
match all criteria.
|
245
|
-
|
246
|
-
"""
|
247
|
-
runs = self.runs
|
248
|
-
|
249
|
-
for predicate in predicates:
|
250
|
-
if callable(predicate):
|
251
|
-
runs = [r for r in runs if predicate(r)]
|
252
|
-
else:
|
253
|
-
runs = [r for r in runs if r.predicate(*predicate)]
|
254
|
-
|
255
|
-
for key, value in kwargs.items():
|
256
|
-
runs = [r for r in runs if r.predicate(key, value)]
|
257
|
-
|
258
|
-
return self.__class__(runs)
|
259
|
-
|
260
|
-
def try_get(
|
261
|
-
self,
|
262
|
-
*predicates: Callable[[R], bool] | tuple[str, Any],
|
263
|
-
**kwargs: Any,
|
264
|
-
) -> R | None:
|
265
|
-
"""Try to get a single run matching the specified criteria.
|
266
|
-
|
267
|
-
This method applies filters and returns a single matching
|
268
|
-
run if exactly one is found, None if no runs are found,
|
269
|
-
or raises ValueError if multiple runs match.
|
270
|
-
|
271
|
-
Args:
|
272
|
-
*predicates: Callable predicates or (key, value) tuples
|
273
|
-
for filtering.
|
274
|
-
**kwargs: Additional key-value pairs for filtering.
|
275
|
-
|
276
|
-
Returns:
|
277
|
-
R | None: A single Run that matches the criteria, or None if
|
278
|
-
no matches are found.
|
279
|
-
|
280
|
-
Raises:
|
281
|
-
ValueError: If multiple runs match the criteria.
|
282
|
-
|
283
|
-
"""
|
284
|
-
runs = self.filter(*predicates, **kwargs)
|
285
|
-
|
286
|
-
n = len(runs)
|
287
|
-
if n == 0:
|
288
|
-
return None
|
289
|
-
|
290
|
-
if n == 1:
|
291
|
-
return runs[0]
|
292
|
-
|
293
|
-
msg = f"Multiple Run ({n}) found matching the criteria, "
|
294
|
-
msg += "expected exactly one"
|
295
|
-
raise ValueError(msg)
|
296
|
-
|
297
|
-
def get(
|
298
|
-
self,
|
299
|
-
*predicates: Callable[[R], bool] | tuple[str, Any],
|
300
|
-
**kwargs: Any,
|
301
|
-
) -> R:
|
302
|
-
"""Get a single run matching the specified criteria.
|
303
|
-
|
304
|
-
This method applies filters and returns a single matching run,
|
305
|
-
or raises ValueError if no runs or multiple runs match.
|
306
|
-
|
307
|
-
Args:
|
308
|
-
*predicates: Callable predicates or (key, value) tuples
|
309
|
-
for filtering.
|
310
|
-
**kwargs: Additional key-value pairs for filtering.
|
311
|
-
|
312
|
-
Returns:
|
313
|
-
R: A single Run that matches the criteria.
|
314
|
-
|
315
|
-
Raises:
|
316
|
-
ValueError: If no runs match or if multiple runs match
|
317
|
-
the criteria.
|
318
|
-
|
319
|
-
"""
|
320
|
-
if run := self.try_get(*predicates, **kwargs):
|
321
|
-
return run
|
322
|
-
|
323
|
-
raise _value_error()
|
324
|
-
|
325
|
-
def first(
|
326
|
-
self,
|
327
|
-
*predicates: Callable[[R], bool] | tuple[str, Any],
|
328
|
-
**kwargs: Any,
|
329
|
-
) -> R:
|
330
|
-
"""Get the first run matching the specified criteria.
|
331
|
-
|
332
|
-
This method applies filters and returns the first matching run,
|
333
|
-
or raises ValueError if no runs match.
|
334
|
-
|
335
|
-
Args:
|
336
|
-
*predicates: Callable predicates or (key, value) tuples
|
337
|
-
for filtering.
|
338
|
-
**kwargs: Additional key-value pairs for filtering.
|
339
|
-
|
340
|
-
Returns:
|
341
|
-
R: The first Run that matches the criteria.
|
342
|
-
|
343
|
-
Raises:
|
344
|
-
ValueError: If no runs match the criteria.
|
345
|
-
|
346
|
-
"""
|
347
|
-
if runs := self.filter(*predicates, **kwargs):
|
348
|
-
return runs[0]
|
349
|
-
|
350
|
-
raise _value_error()
|
351
|
-
|
352
|
-
def last(
|
353
|
-
self,
|
354
|
-
*predicates: Callable[[R], bool] | tuple[str, Any],
|
355
|
-
**kwargs: Any,
|
356
|
-
) -> R:
|
357
|
-
"""Get the last run matching the specified criteria.
|
358
|
-
|
359
|
-
This method applies filters and returns the last matching run,
|
360
|
-
or raises ValueError if no runs match.
|
361
|
-
|
362
|
-
Args:
|
363
|
-
*predicates: Callable predicates or (key, value) tuples
|
364
|
-
for filtering.
|
365
|
-
**kwargs: Additional key-value pairs for filtering.
|
366
|
-
|
367
|
-
Returns:
|
368
|
-
R: The last Run that matches the criteria.
|
369
|
-
|
370
|
-
Raises:
|
371
|
-
ValueError: If no runs match the criteria.
|
372
|
-
|
373
|
-
"""
|
374
|
-
if runs := self.filter(*predicates, **kwargs):
|
375
|
-
return runs[-1]
|
376
|
-
|
377
|
-
raise _value_error()
|
378
|
-
|
379
|
-
def to_list(
|
380
|
-
self,
|
381
|
-
key: str,
|
382
|
-
default: Any | Callable[[R], Any] = MISSING,
|
383
|
-
) -> list[Any]:
|
384
|
-
"""Extract a list of values for a specific key from all runs.
|
385
|
-
|
386
|
-
Args:
|
387
|
-
key: The key to extract from each run.
|
388
|
-
default: The default value to return if the key is not found.
|
389
|
-
If a callable, it will be called with the Run instance
|
390
|
-
and the value returned will be used as the default.
|
391
|
-
|
392
|
-
Returns:
|
393
|
-
list[Any]: A list containing the values for the
|
394
|
-
specified key from each run.
|
395
|
-
|
396
|
-
"""
|
397
|
-
return [run.get(key, default) for run in self]
|
398
|
-
|
399
|
-
def to_numpy(
|
400
|
-
self,
|
401
|
-
key: str,
|
402
|
-
default: Any | Callable[[R], Any] = MISSING,
|
403
|
-
) -> NDArray:
|
404
|
-
"""Extract values for a specific key from all runs as a NumPy array.
|
405
|
-
|
406
|
-
Args:
|
407
|
-
key: The key to extract from each run.
|
408
|
-
default: The default value to return if the key is not found.
|
409
|
-
If a callable, it will be called with the Run instance
|
410
|
-
and the value returned will be used as the default.
|
411
|
-
|
412
|
-
Returns:
|
413
|
-
NDArray: A NumPy array containing the values for the
|
414
|
-
specified key from each run.
|
415
|
-
|
416
|
-
"""
|
417
|
-
return np.array(self.to_list(key, default))
|
418
|
-
|
419
|
-
def to_series(
|
420
|
-
self,
|
421
|
-
key: str,
|
422
|
-
default: Any | Callable[[R], Any] = MISSING,
|
423
|
-
*,
|
424
|
-
name: str | None = None,
|
425
|
-
) -> Series:
|
426
|
-
"""Extract values for a specific key from all runs as a Polars series.
|
427
|
-
|
428
|
-
Args:
|
429
|
-
key: The key to extract from each run.
|
430
|
-
default: The default value to return if the key is not found.
|
431
|
-
If a callable, it will be called with the Run instance
|
432
|
-
and the value returned will be used as the default.
|
433
|
-
name: The name of the series. If not provided, the key will be used.
|
434
|
-
|
435
|
-
Returns:
|
436
|
-
Series: A Polars series containing the values for the
|
437
|
-
specified key from each run.
|
438
|
-
|
439
|
-
"""
|
440
|
-
return Series(name or key, self.to_list(key, default))
|
441
|
-
|
442
|
-
def unique(
|
443
|
-
self,
|
444
|
-
key: str,
|
445
|
-
default: Any | Callable[[R], Any] = MISSING,
|
446
|
-
) -> NDArray:
|
447
|
-
"""Get the unique values for a specific key across all runs.
|
448
|
-
|
449
|
-
Args:
|
450
|
-
key: The key to extract unique values for.
|
451
|
-
default: The default value to return if the key is not found.
|
452
|
-
If a callable, it will be called with the Run instance
|
453
|
-
and the value returned will be used as the default.
|
454
|
-
|
455
|
-
Returns:
|
456
|
-
NDArray: A NumPy array containing the unique values for the
|
457
|
-
specified key.
|
458
|
-
|
459
|
-
"""
|
460
|
-
return np.unique(self.to_numpy(key, default), axis=0)
|
461
|
-
|
462
|
-
def n_unique(
|
463
|
-
self,
|
464
|
-
key: str,
|
465
|
-
default: Any | Callable[[R], Any] = MISSING,
|
466
|
-
) -> int:
|
467
|
-
"""Count the number of unique values for a specific key across all runs.
|
468
|
-
|
469
|
-
Args:
|
470
|
-
key: The key to count unique values for.
|
471
|
-
default: The default value to return if the key is not found.
|
472
|
-
If a callable, it will be called with the Run instance
|
473
|
-
and the value returned will be used as the default.
|
474
|
-
|
475
|
-
Returns:
|
476
|
-
int: The number of unique values for the specified key.
|
477
|
-
|
478
|
-
"""
|
479
|
-
return len(self.unique(key, default))
|
480
|
-
|
481
|
-
def sort(self, *keys: str, reverse: bool = False) -> Self:
|
482
|
-
"""Sort runs based on one or more keys.
|
483
|
-
|
484
|
-
Args:
|
485
|
-
*keys: The keys to sort by, in order of priority.
|
486
|
-
reverse: Whether to sort in descending order (default is
|
487
|
-
ascending).
|
171
|
+
@cached_property
|
172
|
+
def impls(self) -> Collection[I]:
|
173
|
+
"""Get the implementation objects for all runs in the collection.
|
488
174
|
|
489
175
|
Returns:
|
490
|
-
|
491
|
-
the specified keys.
|
176
|
+
Collection[Any]: A collection of implementation objects for all runs.
|
492
177
|
|
493
178
|
"""
|
494
|
-
|
495
|
-
return self
|
496
|
-
|
497
|
-
arrays = [self.to_numpy(key) for key in keys]
|
498
|
-
index = np.lexsort(arrays[::-1])
|
179
|
+
return Collection(run.impl for run in self)
|
499
180
|
|
500
|
-
|
501
|
-
|
181
|
+
def iterdir(self, relative_dir: str = "") -> Iterator[Path]:
|
182
|
+
"""Iterate over the artifact directories for all runs in the collection.
|
502
183
|
|
503
|
-
|
504
|
-
|
505
|
-
def to_frame(
|
506
|
-
self,
|
507
|
-
*keys: str,
|
508
|
-
defaults: dict[str, Any | Callable[[R], Any]] | None = None,
|
509
|
-
**kwargs: Callable[[R], Any],
|
510
|
-
) -> DataFrame:
|
511
|
-
"""Convert the collection to a Polars DataFrame.
|
184
|
+
This method yields all files and directories in the specified
|
185
|
+
relative directory for each run in the collection.
|
512
186
|
|
513
187
|
Args:
|
514
|
-
|
515
|
-
|
516
|
-
will be used.
|
517
|
-
defaults (dict[str, Any | Callable[[R], Any]] | None): Default
|
518
|
-
values for the keys. If a callable, it will be called with
|
519
|
-
the Run instance and the value returned will be used as the
|
520
|
-
default.
|
521
|
-
**kwargs (Callable[[R], Any]): Additional columns to compute
|
522
|
-
using callables that take a Run and return a value.
|
188
|
+
relative_dir (str): The relative directory within the artifacts
|
189
|
+
directory to iterate over.
|
523
190
|
|
524
|
-
|
525
|
-
|
526
|
-
|
191
|
+
Yields:
|
192
|
+
Path: Each path in the specified directory for each run
|
193
|
+
in the collection.
|
527
194
|
|
528
195
|
"""
|
529
|
-
if defaults is None:
|
530
|
-
defaults = {}
|
531
|
-
|
532
|
-
if keys:
|
533
|
-
df = DataFrame(
|
534
|
-
{key: self.to_list(key, defaults.get(key, MISSING)) for key in keys},
|
535
|
-
)
|
536
|
-
else:
|
537
|
-
df = DataFrame(r.to_dict() for r in self)
|
538
|
-
|
539
|
-
if not kwargs:
|
540
|
-
return df
|
541
|
-
|
542
|
-
columns = [Series(k, [v(r) for r in self]) for k, v in kwargs.items()]
|
543
|
-
return df.with_columns(*columns)
|
544
|
-
|
545
|
-
def _group_by(self, *keys: str) -> dict[Any, Self]:
|
546
|
-
result: dict[Any, Self] = {}
|
547
|
-
|
548
196
|
for run in self:
|
549
|
-
|
550
|
-
key = keys_[0] if len(keys) == 1 else tuple(keys_)
|
197
|
+
yield from run.path(relative_dir).iterdir()
|
551
198
|
|
552
|
-
|
553
|
-
|
554
|
-
result[key].runs.append(run)
|
555
|
-
|
556
|
-
return result
|
557
|
-
|
558
|
-
@overload
|
559
|
-
def group_by(self, *keys: str) -> dict[Any, Self]: ...
|
560
|
-
|
561
|
-
@overload
|
562
|
-
def group_by(
|
563
|
-
self,
|
564
|
-
*keys: str,
|
565
|
-
**kwargs: Callable[[Self | Sequence[R]], Any],
|
566
|
-
) -> DataFrame: ...
|
567
|
-
|
568
|
-
def group_by(
|
569
|
-
self,
|
570
|
-
*keys: str,
|
571
|
-
**kwargs: Callable[[Self | Sequence[R]], Any],
|
572
|
-
) -> dict[Any, Self] | DataFrame:
|
573
|
-
"""Group runs by one or more keys.
|
199
|
+
def glob(self, pattern: str, relative_dir: str = "") -> Iterator[Path]:
|
200
|
+
"""Glob the artifact directories for all runs in the collection.
|
574
201
|
|
575
|
-
This method
|
576
|
-
|
577
|
-
(no kwargs provided)
|
578
|
-
- A Polars DataFrame with group keys and aggregated
|
579
|
-
values (kwargs provided)
|
202
|
+
This method yields all paths matching the specified pattern
|
203
|
+
in the relative directory for each run in the collection.
|
580
204
|
|
581
205
|
Args:
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
accept a RunCollection or Sequence[Run] and return a value.
|
206
|
+
pattern (str): The glob pattern to match files or directories.
|
207
|
+
relative_dir (str): The relative directory within the artifacts
|
208
|
+
directory to search in.
|
586
209
|
|
587
|
-
|
588
|
-
|
589
|
-
group keys to RunCollections, or a Polars DataFrame with
|
590
|
-
group keys and aggregated values.
|
210
|
+
Yields:
|
211
|
+
Path: Each path matching the pattern for each run in the collection.
|
591
212
|
|
592
213
|
"""
|
593
|
-
|
594
|
-
|
595
|
-
return gp
|
596
|
-
|
597
|
-
if len(keys) == 1:
|
598
|
-
df = DataFrame({keys[0]: list(gp)})
|
599
|
-
else:
|
600
|
-
df = DataFrame(dict(zip(keys, k, strict=True)) for k in gp)
|
601
|
-
columns = [pl.Series(k, [v(r) for r in gp.values()]) for k, v in kwargs.items()]
|
602
|
-
return df.with_columns(*columns)
|
603
|
-
|
604
|
-
|
605
|
-
def to_hashable(value: Any) -> Hashable:
|
606
|
-
"""Convert a value to a hashable instance.
|
607
|
-
|
608
|
-
This function handles various types of values and converts them to
|
609
|
-
hashable equivalents for use in dictionaries and sets.
|
610
|
-
|
611
|
-
Args:
|
612
|
-
value: The value to convert to a hashable instance.
|
613
|
-
|
614
|
-
Returns:
|
615
|
-
A hashable version of the input value.
|
616
|
-
|
617
|
-
"""
|
618
|
-
if OmegaConf.is_list(value): # Is ListConfig hashable?
|
619
|
-
return tuple(value)
|
620
|
-
if isinstance(value, Hashable):
|
621
|
-
return value
|
622
|
-
if isinstance(value, np.ndarray):
|
623
|
-
return tuple(value.tolist())
|
624
|
-
try:
|
625
|
-
return tuple(value)
|
626
|
-
except TypeError:
|
627
|
-
return str(value)
|
628
|
-
|
629
|
-
|
630
|
-
def _value_error() -> ValueError:
|
631
|
-
msg = "No Run found matching the specified criteria"
|
632
|
-
return ValueError(msg)
|
214
|
+
for run in self:
|
215
|
+
yield from run.path(relative_dir).glob(pattern)
|
hydraflow/core/run_info.py
CHANGED
@@ -19,7 +19,6 @@ from .io import get_experiment_name
|
|
19
19
|
|
20
20
|
if TYPE_CHECKING:
|
21
21
|
from pathlib import Path
|
22
|
-
from typing import Any
|
23
22
|
|
24
23
|
|
25
24
|
@dataclass
|
@@ -51,11 +50,3 @@ class RunInfo:
|
|
51
50
|
contain the expected format).
|
52
51
|
"""
|
53
52
|
return get_experiment_name(self.run_dir.parent)
|
54
|
-
|
55
|
-
def to_dict(self) -> dict[str, Any]:
|
56
|
-
"""Convert the RunInfo to a dictionary."""
|
57
|
-
return {
|
58
|
-
"run_id": self.run_id,
|
59
|
-
"run_dir": self.run_dir.as_posix(),
|
60
|
-
"job_name": self.job_name,
|
61
|
-
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hydraflow
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.17.1
|
4
4
|
Summary: HydraFlow seamlessly integrates Hydra and MLflow to streamline ML experiment management, combining Hydra's configuration management with MLflow's tracking capabilities.
|
5
5
|
Project-URL: Documentation, https://daizutabi.github.io/hydraflow/
|
6
6
|
Project-URL: Source, https://github.com/daizutabi/hydraflow
|
@@ -2,20 +2,22 @@ hydraflow/__init__.py,sha256=8UraqH00Qp0In301ZUmQBRTIGbV1L5zSZACOUlIRPn8,727
|
|
2
2
|
hydraflow/cli.py,sha256=3rGr___wwp8KazjLGQ7JO_IgAMqLyMlcVSs_QJK7g0Y,3135
|
3
3
|
hydraflow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
hydraflow/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
hydraflow/core/
|
5
|
+
hydraflow/core/collection.py,sha256=RSYgS4VsGjSm0Inrz4GAng_jmm-Ct_VSDmZ9rvKFQQw,19472
|
6
|
+
hydraflow/core/context.py,sha256=6vpwe0Xfl6mzh2hHLE-4uB9Hjew-CK4pA0KFihQ80U8,4168
|
7
|
+
hydraflow/core/group_by.py,sha256=Pnw-oA5aXHeRG9lMLz-bKc8drqQ8LIRsWzvVn153iyQ,5488
|
6
8
|
hydraflow/core/io.py,sha256=B3-jPuJWttRgpbIpy_XA-Z2qpXzNF1ATwyYEwA7Pv3w,5172
|
7
9
|
hydraflow/core/main.py,sha256=pgr2b9A4VoZuwbApE71NElmV64MFJv8UKda05q4uCqk,6010
|
8
|
-
hydraflow/core/run.py,sha256=
|
9
|
-
hydraflow/core/run_collection.py,sha256=
|
10
|
-
hydraflow/core/run_info.py,sha256=
|
10
|
+
hydraflow/core/run.py,sha256=Kbq4s47f6KDNeyNUwrUpW55FrWlf5CCpmdgVCMakU2g,14046
|
11
|
+
hydraflow/core/run_collection.py,sha256=_LxPM9ZvbKfCBbptKltD8HKeecMVb5Bp_dsUHdrR0rk,6773
|
12
|
+
hydraflow/core/run_info.py,sha256=SMOTZXEa7OBV_XjTyctk5gJGrggmYwhePvRF8CLF1kU,1616
|
11
13
|
hydraflow/executor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
14
|
hydraflow/executor/aio.py,sha256=xXsmBPIPdBlopv_1h0FdtOvoKUcuW7PQeKCV2d_lN9I,2122
|
13
15
|
hydraflow/executor/conf.py,sha256=8Xq4UAenRKJIl1NBgNbSfv6VUTJhdwPLayZIEAsiBR0,414
|
14
16
|
hydraflow/executor/io.py,sha256=18wnHpCMQRGYL-oN2841h9W2aSW_X2SmO68Lx-3FIbU,1043
|
15
17
|
hydraflow/executor/job.py,sha256=6QeJ18OMeocXeM04rCYL46GgArfX1SvZs9_4HTomTgE,5436
|
16
18
|
hydraflow/executor/parser.py,sha256=RxP8qpDaJ8VLqZ51VlPFyVitWctObhkE_3iPIsY66Cs,14610
|
17
|
-
hydraflow-0.
|
18
|
-
hydraflow-0.
|
19
|
-
hydraflow-0.
|
20
|
-
hydraflow-0.
|
21
|
-
hydraflow-0.
|
19
|
+
hydraflow-0.17.1.dist-info/METADATA,sha256=HroJv34p_tEkHIP4JrCPprN3-pr3L2BeQcfqgJfQxeM,7535
|
20
|
+
hydraflow-0.17.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
21
|
+
hydraflow-0.17.1.dist-info/entry_points.txt,sha256=XI0khPbpCIUo9UPqkNEpgh-kqK3Jy8T7L2VCWOdkbSM,48
|
22
|
+
hydraflow-0.17.1.dist-info/licenses/LICENSE,sha256=IGdDrBPqz1O0v_UwCW-NJlbX9Hy9b3uJ11t28y2srmY,1062
|
23
|
+
hydraflow-0.17.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|