Files
ray-project--ray/python/ray/tune/tests/test_experiment.py
T
2026-07-13 13:17:40 +08:00

118 lines
3.7 KiB
Python

import threading
import unittest
import ray
from ray.tune import CheckpointConfig, register_trainable
from ray.tune.error import TuneError
from ray.tune.experiment import Experiment, _convert_to_experiment_list
from ray.tune.utils import diagnose_serialization
class ExperimentTest(unittest.TestCase):
def tearDown(self):
ray.shutdown()
def setUp(self):
def train_fn(config):
for i in range(100):
ray.tune.report(dict(timesteps_total=i))
register_trainable("f1", train_fn)
def testConvertExperimentFromExperiment(self):
exp1 = Experiment(
**{"name": "foo", "run": "f1", "config": {"script_min_iter_time_s": 0}}
)
result = _convert_to_experiment_list(exp1)
self.assertEqual(len(result), 1)
self.assertEqual(type(result), list)
def testConvertExperimentNone(self):
result = _convert_to_experiment_list(None)
self.assertEqual(len(result), 0)
self.assertEqual(type(result), list)
def testConvertExperimentList(self):
exp1 = Experiment(
**{"name": "foo", "run": "f1", "config": {"script_min_iter_time_s": 0}}
)
result = _convert_to_experiment_list([exp1, exp1])
self.assertEqual(len(result), 2)
self.assertEqual(type(result), list)
def testConvertExperimentJSON(self):
experiment = {
"name": {"run": "f1", "config": {"script_min_iter_time_s": 0}},
"named": {"run": "f1", "config": {"script_min_iter_time_s": 0}},
}
result = _convert_to_experiment_list(experiment)
self.assertEqual(len(result), 2)
self.assertEqual(type(result), list)
def testConvertExperimentIncorrect(self):
self.assertRaises(TuneError, lambda: _convert_to_experiment_list("hi"))
def testFuncTrainableCheckpointConfigValidation(self):
"""Raise an error when trying to specify checkpoint_at_end/checkpoint_frequency
with a function trainable."""
with self.assertRaises(ValueError):
Experiment(
name="foo",
run="f1", # Will point to a wrapped function trainable
checkpoint_config=CheckpointConfig(checkpoint_at_end=True),
)
with self.assertRaises(ValueError):
Experiment(
name="foo",
run="f1",
checkpoint_config=CheckpointConfig(checkpoint_frequency=1),
)
with self.assertRaises(ValueError):
Experiment(
name="foo",
run=lambda config: 1,
checkpoint_config=CheckpointConfig(checkpoint_at_end=True),
)
def testInvalidExperimentConfig(self):
with self.assertRaises(ValueError):
Experiment(name="foo", run="f1", config="invalid")
class InvalidClass:
def to_dict(self):
return {"valid": 1}
with self.assertRaises(ValueError):
Experiment(name="foo", run="f1", config=InvalidClass())
Experiment(name="foo", run="f1", config=InvalidClass().to_dict())
class ValidateUtilTest(unittest.TestCase):
def testDiagnoseSerialization(self):
# this is not serializable
e = threading.Event()
def test(config):
print(e)
assert diagnose_serialization(test) is not True
# should help identify that 'e' should be moved into
# the `test` scope.
# correct implementation
def test(config):
e = threading.Event()
print(e)
assert diagnose_serialization(test) is True
if __name__ == "__main__":
import sys
import pytest
sys.exit(pytest.main(["-v", __file__]))