mirror of
https://github.com/wassname/optuna-dashboard.git
synced 2026-08-20 12:40:54 +08:00
Merge branch 'main' into test-orthants-mvn-gibbs-sampling
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
import base64
|
||||
import json
|
||||
import tempfile
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import optuna
|
||||
from optuna.artifacts import FileSystemArtifactStore
|
||||
from optuna.artifacts import upload_artifact
|
||||
from optuna.storages import BaseStorage
|
||||
from optuna_dashboard._app import create_app
|
||||
from optuna_dashboard.artifact import _backend
|
||||
import pytest
|
||||
|
||||
from ..wsgi_client import send_request
|
||||
|
||||
|
||||
def test_get_artifact_path() -> None:
|
||||
study = MagicMock(_study_id=0)
|
||||
@@ -12,7 +21,7 @@ def test_get_artifact_path() -> None:
|
||||
|
||||
|
||||
def test_artifact_prefix() -> None:
|
||||
actual = _backend._dashboard_trial_artifact_prefix(trial_id=0)
|
||||
actual = _backend._dashboard_artifact_prefix(trial_id=0)
|
||||
assert actual == "dashboard:artifacts:0:"
|
||||
|
||||
|
||||
@@ -80,3 +89,163 @@ def test_list_trial_artifacts(init_storage_with_artifact_meta: MagicMock) -> Non
|
||||
{"artifact_id": "id1", "filename": "bar.txt"},
|
||||
{"artifact_id": "id2", "filename": "baz.txt"},
|
||||
]
|
||||
|
||||
|
||||
def test_study_artifact_store_none() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
app = create_app(storage)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
"/artifacts/0/0",
|
||||
"GET",
|
||||
)
|
||||
assert status == 400
|
||||
|
||||
|
||||
def test_study_artifact_not_found() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
app = create_app(storage, artifact_store)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/artifacts/{study._study_id}/abc123",
|
||||
"GET",
|
||||
)
|
||||
assert status == 404
|
||||
|
||||
|
||||
def test_successful_study_artifact_retrieval() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
f.write(b"dummy_content")
|
||||
f.flush()
|
||||
artifact_id = upload_artifact(study, f.name, artifact_store=artifact_store)
|
||||
app = create_app(storage, artifact_store)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/artifacts/{study._study_id}/{artifact_id}",
|
||||
"GET",
|
||||
)
|
||||
assert status == 200
|
||||
assert body == b"dummy_content"
|
||||
|
||||
|
||||
def test_trial_artifact_store_none() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
app = create_app(storage)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
"/artifacts/0/0/0",
|
||||
"GET",
|
||||
)
|
||||
assert status == 400
|
||||
|
||||
|
||||
def test_trial_artifact_not_found() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
trial = study.ask()
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
app = create_app(storage, artifact_store)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/artifacts/{study._study_id}/{trial._trial_id}/abc123",
|
||||
"GET",
|
||||
)
|
||||
assert status == 404
|
||||
|
||||
|
||||
def test_successful_trial_artifact_retrieval() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
trial = study.ask()
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
f.write(b"dummy_content")
|
||||
f.flush()
|
||||
artifact_id = upload_artifact(trial, f.name, artifact_store=artifact_store)
|
||||
app = create_app(storage, artifact_store)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/artifacts/{study._study_id}/{trial._trial_id}/{artifact_id}",
|
||||
"GET",
|
||||
)
|
||||
assert status == 200
|
||||
assert body == b"dummy_content"
|
||||
|
||||
|
||||
DUMMY_DATA_URL = (
|
||||
f"data:text/plain; charset=utf-8,{base64.b64encode(b'dummy_content').decode('utf-8')}"
|
||||
)
|
||||
|
||||
|
||||
def test_upload_artifact_invalid_no_trial() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
|
||||
app = create_app(storage, artifact_store)
|
||||
study = optuna.create_study(storage=storage)
|
||||
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/api/artifacts/{study._study_id}/0",
|
||||
"POST",
|
||||
body=json.dumps({"file": DUMMY_DATA_URL}),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert status == 500 # TODO(contramundum53): This should return 400
|
||||
|
||||
|
||||
def test_upload_artifact_invalid_complete_trial() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
|
||||
app = create_app(storage, artifact_store)
|
||||
study = optuna.create_study(storage=storage)
|
||||
|
||||
study.add_trial(optuna.create_trial(value=1.0, distributions={}, params={}))
|
||||
trial = study.trials[-1]
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/api/artifacts/{study._study_id}/{trial._trial_id}",
|
||||
"POST",
|
||||
body=json.dumps({"file": DUMMY_DATA_URL}),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert status == 400
|
||||
|
||||
|
||||
def test_upload_artifact() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
|
||||
study = optuna.create_study(storage=storage)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
artifact_store = FileSystemArtifactStore(tmpdir)
|
||||
|
||||
app = create_app(storage, artifact_store)
|
||||
|
||||
study.add_trial(optuna.create_trial(state=optuna.trial.TrialState.RUNNING))
|
||||
trial = study.trials[-1]
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/api/artifacts/{study._study_id}/{trial._trial_id}",
|
||||
"POST",
|
||||
body=json.dumps({"file": DUMMY_DATA_URL}),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert status == 201
|
||||
res = json.loads(body)
|
||||
with open(f"{tmpdir}/{res['artifact_id']}", "r") as f:
|
||||
data = f.read()
|
||||
assert data == "dummy_content"
|
||||
|
||||
@@ -3,12 +3,12 @@ from unittest.mock import patch
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from optuna_dashboard.preferential.samplers.gp import _one_side_trunc_norm_sampling
|
||||
from optuna_dashboard.preferential.samplers.gp import _orthants_MVN_Gibbs_sampling
|
||||
import torch
|
||||
else:
|
||||
pytest.skip("BoTorch dropped Python3.7 support", allow_module_level=True)
|
||||
|
||||
@@ -36,3 +36,19 @@ def test_one_side_trunc_norm_sampling() -> None:
|
||||
assert np.allclose(
|
||||
_one_side_trunc_norm_sampling(torch.Tensor([5])).numpy(), 5.426934003050024
|
||||
)
|
||||
|
||||
def test_one_side_trunc_norm_sampling() -> None:
|
||||
for lower in np.linspace(-10, 10, 100):
|
||||
assert _one_side_trunc_norm_sampling(torch.tensor([lower], dtype=torch.float64)) >= lower
|
||||
|
||||
with patch.object(torch, "rand", return_value=torch.tensor([0.4], dtype=torch.float64)):
|
||||
sampled_value = _one_side_trunc_norm_sampling(torch.tensor([0.1], dtype=torch.float64))
|
||||
assert np.allclose(sampled_value.numpy(), 0.899967154837563)
|
||||
|
||||
with patch.object(torch, "rand", return_value=torch.tensor([0.8], dtype=torch.float64)):
|
||||
sampled_value = _one_side_trunc_norm_sampling(torch.tensor([-2.3], dtype=torch.float64))
|
||||
assert np.allclose(sampled_value.numpy(), -0.8113606739551955)
|
||||
|
||||
with patch.object(torch, "rand", return_value=torch.tensor([0.1], dtype=torch.float64)):
|
||||
sampled_value = _one_side_trunc_norm_sampling(torch.tensor([5], dtype=torch.float64))
|
||||
assert np.allclose(sampled_value.numpy(), 5.426934003050024)
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import copy
|
||||
import multiprocessing
|
||||
import pickle
|
||||
import sys
|
||||
from typing import Callable
|
||||
from unittest.mock import patch
|
||||
import uuid
|
||||
@@ -22,6 +23,10 @@ from ..storage_supplier import parametrize_storages
|
||||
from ..storage_supplier import StorageSupplier
|
||||
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
pytest.skip("BoTorch dropped Python3.7 support", allow_module_level=True)
|
||||
|
||||
|
||||
@parametrize_storages
|
||||
def test_study_set_and_get_user_attrs(storage_supplier: Callable[[], StorageSupplier]) -> None:
|
||||
with storage_supplier() as storage:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from unittest import TestCase
|
||||
|
||||
import optuna
|
||||
@@ -8,12 +9,15 @@ from optuna import get_all_study_summaries
|
||||
from optuna.study import StudyDirection
|
||||
from optuna_dashboard._app import create_app
|
||||
from optuna_dashboard._app import create_new_study
|
||||
from optuna_dashboard._note import note_str_key_prefix
|
||||
from optuna_dashboard._note import note_ver_key
|
||||
from optuna_dashboard._preference_setting import register_preference_feedback_component
|
||||
from optuna_dashboard._preferential_history import NewHistory
|
||||
from optuna_dashboard._preferential_history import remove_history
|
||||
from optuna_dashboard._preferential_history import report_history
|
||||
from optuna_dashboard._serializer import serialize_preference_history
|
||||
from optuna_dashboard.preferential import create_study
|
||||
import pytest
|
||||
|
||||
from .wsgi_client import send_request
|
||||
|
||||
@@ -105,6 +109,7 @@ class APITestCase(TestCase):
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_get_best_trials_of_preferential_study(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(n_generate=4, storage=storage)
|
||||
@@ -128,6 +133,7 @@ class APITestCase(TestCase):
|
||||
assert len(best_trials) == 1
|
||||
assert best_trials[0]["number"] == 0
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_report_preference(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(n_generate=4, storage=storage)
|
||||
@@ -161,6 +167,7 @@ class APITestCase(TestCase):
|
||||
assert better.number == 2
|
||||
assert worse.number == 1
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_report_preference_when_typo_mode(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(storage=storage, n_generate=3)
|
||||
@@ -184,6 +191,7 @@ class APITestCase(TestCase):
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_change_component(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(storage=storage, n_generate=3)
|
||||
@@ -214,6 +222,111 @@ class APITestCase(TestCase):
|
||||
assert study_detail["feedback_component_type"]["output_type"] == "artifact"
|
||||
assert study_detail["feedback_component_type"]["artifact_key"] == "image"
|
||||
|
||||
def test_save_trial_user_attrs(self) -> None:
|
||||
study = optuna.create_study()
|
||||
trials: list[optuna.Trial] = []
|
||||
for _ in range(2):
|
||||
trial = study.ask()
|
||||
trials.append(trial)
|
||||
|
||||
request_body = {
|
||||
"user_attrs": {
|
||||
"number": 0,
|
||||
},
|
||||
}
|
||||
|
||||
app = create_app(study._storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trials[0]._trial_id}/user-attrs",
|
||||
"POST",
|
||||
content_type="application/json",
|
||||
body=json.dumps(request_body),
|
||||
)
|
||||
self.assertEqual(status, 204)
|
||||
|
||||
assert study.trials[0].user_attrs == request_body["user_attrs"]
|
||||
assert study.trials[1].user_attrs == {}
|
||||
|
||||
def test_save_trial_user_attrs_empty(self) -> None:
|
||||
study = optuna.create_study()
|
||||
trial = study.ask()
|
||||
|
||||
app = create_app(study._storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial._trial_id}/user-attrs",
|
||||
"POST",
|
||||
content_type="application/json",
|
||||
body=json.dumps({}),
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
assert study.trials[0].user_attrs == {}
|
||||
|
||||
def _save_trial_note(self, request_body: dict[str, int | str]) -> tuple[int, optuna.Study]:
|
||||
study = optuna.create_study()
|
||||
trial = study.ask()
|
||||
app = create_app(study._storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/studies/{study._study_id}/{trial._trial_id}/note",
|
||||
"PUT",
|
||||
content_type="application/json",
|
||||
body=json.dumps(request_body),
|
||||
)
|
||||
return status, study
|
||||
|
||||
def test_save_trial_note_overwrite(self) -> None:
|
||||
study = optuna.create_study()
|
||||
trial = study.ask()
|
||||
app = create_app(study._storage)
|
||||
|
||||
def _get_request_body(note_version: int) -> dict[str, str | int]:
|
||||
return {"body": f"Test note ver. {note_version}.", "version": note_version}
|
||||
|
||||
for ver in range(1, 3):
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/studies/{study._study_id}/{trial._trial_id}/note",
|
||||
"PUT",
|
||||
content_type="application/json",
|
||||
body=json.dumps(_get_request_body(note_version=ver)),
|
||||
)
|
||||
assert status == 204
|
||||
# Check if the version 1 is deleted.
|
||||
expected_request_body = _get_request_body(note_version=2)
|
||||
expected_system_attrs = {
|
||||
note_ver_key(trial_id=0): expected_request_body["version"],
|
||||
f"{note_str_key_prefix(trial_id=0)}{0}": expected_request_body["body"],
|
||||
}
|
||||
for k, v in expected_system_attrs.items():
|
||||
assert k in study.system_attrs
|
||||
assert study.system_attrs[k] == v
|
||||
|
||||
def test_save_trial_note(self) -> None:
|
||||
request_body: dict[str, int | str] = {"body": "Test note.", "version": 1}
|
||||
status, study = self._save_trial_note(request_body)
|
||||
assert status == 204
|
||||
expected_system_attrs = {
|
||||
note_ver_key(0): request_body["version"],
|
||||
f"{note_str_key_prefix(0)}{0}": request_body["body"],
|
||||
}
|
||||
for k, v in expected_system_attrs.items():
|
||||
assert k in study.system_attrs
|
||||
assert study.system_attrs[k] == v
|
||||
|
||||
def test_save_trial_note_with_wrong_version(self) -> None:
|
||||
request_body: dict[str, int | str] = {"body": "Test note.", "version": 0}
|
||||
status, study = self._save_trial_note(request_body)
|
||||
assert status == 409
|
||||
assert note_ver_key(0) not in study.system_attrs
|
||||
|
||||
def test_save_trial_note_empty(self) -> None:
|
||||
status, study = self._save_trial_note(request_body={})
|
||||
assert status == 400
|
||||
assert note_ver_key(0) not in study.system_attrs
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_skip_trial(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(n_generate=4, storage=storage)
|
||||
@@ -238,6 +351,7 @@ class APITestCase(TestCase):
|
||||
assert len(best_trials) == 1
|
||||
assert best_trials[0].number == 2
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_remove_history(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(storage=storage, n_generate=3)
|
||||
@@ -271,6 +385,7 @@ class APITestCase(TestCase):
|
||||
assert histories[0]["is_removed"]
|
||||
assert len(study.get_preferences()) == 0
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_restore_history(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(storage=storage, n_generate=3)
|
||||
@@ -390,6 +505,125 @@ class APITestCase(TestCase):
|
||||
)
|
||||
self.assertEqual(status, 404)
|
||||
|
||||
def test_tell_trial_complete(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
trial_id = study.ask()._trial_id
|
||||
|
||||
app = create_app(storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial_id}/tell",
|
||||
"POST",
|
||||
body=json.dumps(
|
||||
{
|
||||
"state": "Complete",
|
||||
"values": [0, 1, 2],
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(status, 204)
|
||||
trial = storage.get_trial(trial_id)
|
||||
assert trial.state == optuna.trial.TrialState.COMPLETE
|
||||
assert trial.values == [0, 1, 2]
|
||||
|
||||
def test_tell_trial_fail(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
trial_id = study.ask()._trial_id
|
||||
|
||||
app = create_app(storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial_id}/tell",
|
||||
"POST",
|
||||
body=json.dumps(
|
||||
{
|
||||
"state": "Fail",
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(status, 204)
|
||||
trial = storage.get_trial(trial_id)
|
||||
assert trial.state == optuna.trial.TrialState.FAIL
|
||||
|
||||
def test_tell_trial_with_no_state(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
trial_id = study.ask()._trial_id
|
||||
|
||||
app = create_app(storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial_id}/tell",
|
||||
"POST",
|
||||
body=json.dumps({}),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
|
||||
def test_tell_trial_with_invalid_state(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
for state in ["Pruned", "Running", "Waiting", "Invalid"]:
|
||||
trial_id = study.ask()._trial_id
|
||||
app = create_app(storage)
|
||||
with self.subTest(state=state):
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial_id}/tell",
|
||||
"POST",
|
||||
body=json.dumps(
|
||||
{
|
||||
"state": state,
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
|
||||
def test_tell_trial_with_no_values(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
trial_id = study.ask()._trial_id
|
||||
|
||||
app = create_app(storage)
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial_id}/tell",
|
||||
"POST",
|
||||
body=json.dumps(
|
||||
{
|
||||
"state": "Complete",
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
|
||||
def test_tell_trial_with_invalid_values(self) -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
for values in [1.0, ["foo"]]:
|
||||
trial_id = study.ask()._trial_id
|
||||
app = create_app(storage)
|
||||
with self.subTest(values=values):
|
||||
status, _, _ = send_request(
|
||||
app,
|
||||
f"/api/trials/{trial_id}/tell",
|
||||
"POST",
|
||||
body=json.dumps(
|
||||
{
|
||||
"state": "Complete",
|
||||
"values": values,
|
||||
}
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(status, 400)
|
||||
|
||||
|
||||
class BottleRequestHookTestCase(TestCase):
|
||||
def test_ignore_trailing_slashes(self) -> None:
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any
|
||||
from unittest import TestCase
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
import optuna
|
||||
from optuna import create_trial
|
||||
from optuna.distributions import BaseDistribution
|
||||
@@ -254,11 +255,29 @@ class _CachedExtraStudyPropertyUserAttrs(TestCase):
|
||||
|
||||
def test_infer_sortable(self) -> None:
|
||||
user_attrs_list: list[dict[str, Any]] = [
|
||||
{"a": 1, "b": 1, "c": 1, "d": "a", "e": 1, "f": True},
|
||||
{
|
||||
"a": 1,
|
||||
"b": 1,
|
||||
"c": 1,
|
||||
"d": "a",
|
||||
"e": 1,
|
||||
"f": True,
|
||||
"g": np.float128(1.1),
|
||||
"h": np.int64(2),
|
||||
},
|
||||
{"a": 2, "b": "a", "c": "a", "d": "a"},
|
||||
{"a": 3, "b": None, "c": 3, "d": "a", "e": 3},
|
||||
]
|
||||
expected = {"a": True, "b": False, "c": False, "d": False, "e": True, "f": False}
|
||||
expected = {
|
||||
"a": True,
|
||||
"b": False,
|
||||
"c": False,
|
||||
"d": False,
|
||||
"e": True,
|
||||
"f": False,
|
||||
"g": True,
|
||||
"h": True,
|
||||
}
|
||||
|
||||
trials = []
|
||||
for user_attrs in user_attrs_list:
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import optuna
|
||||
from optuna.trial import TrialState
|
||||
from optuna_dashboard._app import create_app
|
||||
import pytest
|
||||
|
||||
from .wsgi_client import send_request
|
||||
|
||||
|
||||
def _validate_output(
|
||||
storage: optuna.storages.BaseStorage,
|
||||
correct_status: int,
|
||||
study_id: int,
|
||||
expect_no_result: bool = False,
|
||||
extra_col_names: list[str] | None = None,
|
||||
) -> None:
|
||||
app = create_app(storage)
|
||||
status, _, body = send_request(
|
||||
app,
|
||||
f"/csv/{study_id}",
|
||||
"GET",
|
||||
content_type="application/json",
|
||||
)
|
||||
assert status == correct_status
|
||||
decoded_csv = str(body.decode("utf-8"))
|
||||
if expect_no_result:
|
||||
assert "is not found" in decoded_csv
|
||||
else:
|
||||
col_names = ["Number", "State"] + ([] if extra_col_names is None else extra_col_names)
|
||||
assert all(col_name in decoded_csv for col_name in col_names)
|
||||
|
||||
|
||||
def test_download_csv_no_trial() -> None:
|
||||
def objective(trial: optuna.Trial) -> float:
|
||||
x = trial.suggest_float("x", -100, 100)
|
||||
y = trial.suggest_categorical("y", [-1, 0, 1])
|
||||
return x**2 + y
|
||||
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
study.optimize(objective, n_trials=0)
|
||||
_validate_output(storage, 200, 0)
|
||||
|
||||
|
||||
def test_download_csv_all_waiting() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
study.add_trial(optuna.trial.create_trial(state=TrialState.WAITING))
|
||||
_validate_output(storage, 200, 0)
|
||||
|
||||
|
||||
def test_download_csv_all_running() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
study.add_trial(optuna.trial.create_trial(state=TrialState.RUNNING))
|
||||
_validate_output(storage, 200, 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("study_id", [0, 1])
|
||||
def test_download_csv_fail(study_id: int) -> None:
|
||||
def objective(trial: optuna.Trial) -> float:
|
||||
x = trial.suggest_float("x", -100, 100)
|
||||
y = trial.suggest_categorical("y", [-1, 0, 1])
|
||||
return x**2 + y
|
||||
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
optuna.logging.set_verbosity(optuna.logging.ERROR)
|
||||
study.optimize(objective, n_trials=10)
|
||||
expect_no_result = study_id != 0
|
||||
cols = ["Param x", "Param y", "Value"]
|
||||
_validate_output(storage, 404 if expect_no_result else 200, study_id, expect_no_result, cols)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("is_multi_obj", [True, False])
|
||||
def test_download_csv_multi_obj(is_multi_obj: bool) -> None:
|
||||
def objective(trial: optuna.Trial) -> Any:
|
||||
x = trial.suggest_float("x", -100, 100)
|
||||
y = trial.suggest_categorical("y", [-1, 0, 1])
|
||||
if is_multi_obj:
|
||||
return x**2, y
|
||||
return x**2 + y
|
||||
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
directions = ["minimize", "minimize"] if is_multi_obj else ["minimize"]
|
||||
study = optuna.create_study(storage=storage, directions=directions)
|
||||
optuna.logging.set_verbosity(optuna.logging.ERROR)
|
||||
study.optimize(objective, n_trials=10)
|
||||
cols = ["Param x", "Param y"]
|
||||
cols += ["Objective 0", "Objective 1"] if is_multi_obj else ["Value"]
|
||||
_validate_output(storage, 200, 0, extra_col_names=cols)
|
||||
|
||||
|
||||
def test_download_csv_user_attr() -> None:
|
||||
def objective(trial: optuna.Trial) -> float:
|
||||
x = trial.suggest_float("x", -100, 100)
|
||||
y = trial.suggest_categorical("y", [-1, 0, 1])
|
||||
trial.set_user_attr("abs_y", abs(y))
|
||||
return x**2 + y
|
||||
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = optuna.create_study(storage=storage)
|
||||
optuna.logging.set_verbosity(optuna.logging.ERROR)
|
||||
study.optimize(objective, n_trials=10)
|
||||
cols = ["Param x", "Param y", "Value", "UserAttribute abs_y"]
|
||||
_validate_output(storage, 200, 0, extra_col_names=cols)
|
||||
@@ -53,3 +53,25 @@ class NoteTestCase(TestCase):
|
||||
note_dict = note.get_note_from_system_attrs(system_attrs, trial._trial_id)
|
||||
self.assertEqual(note_dict["body"], body)
|
||||
self.assertEqual(note_dict["version"], expected_ver)
|
||||
|
||||
def test_copy_notes(self) -> None:
|
||||
old_study = optuna.create_study()
|
||||
old_trials = [
|
||||
old_study.ask({"x1": optuna.distributions.FloatDistribution(0, 10)}) for _ in range(2)
|
||||
]
|
||||
storage = old_study._storage
|
||||
|
||||
notes = ["trial 0", "trial 1"]
|
||||
for trial, body in zip(old_trials, notes):
|
||||
save_note(trial, body)
|
||||
save_note(old_study, "Study")
|
||||
|
||||
new_study = optuna.create_study(storage=storage, directions=old_study.directions)
|
||||
new_study.add_trials(old_study.get_trials(deepcopy=False))
|
||||
|
||||
note.copy_notes(storage, old_study, new_study)
|
||||
system_attrs = new_study._storage.get_study_system_attrs(new_study._study_id)
|
||||
for new_trial, body in zip(new_study.get_trials(), notes):
|
||||
actual = note.get_note_from_system_attrs(system_attrs, new_trial._trial_id)
|
||||
self.assertEqual(actual["body"], body)
|
||||
self.assertEqual(get_note(new_study), "Study")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from typing import Callable
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -13,6 +14,7 @@ from optuna_dashboard._preferential_history import restore_history
|
||||
from optuna_dashboard._serializer import serialize_preference_history
|
||||
from optuna_dashboard.preferential import create_study
|
||||
from optuna_dashboard.preferential._system_attrs import _SYSTEM_ATTR_PREFIX_PREFERENCE
|
||||
import pytest
|
||||
|
||||
from .storage_supplier import parametrize_storages
|
||||
from .storage_supplier import StorageSupplier
|
||||
@@ -22,6 +24,10 @@ if TYPE_CHECKING:
|
||||
from optuna_dashboard._preferential_history import History
|
||||
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
pytest.skip("BoTorch dropped Python3.7 support", allow_module_level=True)
|
||||
|
||||
|
||||
@parametrize_storages
|
||||
def test_report_and_get_choices(storage_supplier: Callable[[], StorageSupplier]) -> None:
|
||||
with storage_supplier() as storage:
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import optuna
|
||||
from optuna_dashboard._serializer import serialize_attrs
|
||||
from optuna_dashboard._serializer import serialize_study_detail
|
||||
from optuna_dashboard._serializer import serialize_study_summary
|
||||
from optuna_dashboard._storage import get_study_summaries
|
||||
from optuna_dashboard.preferential import create_study
|
||||
import pytest
|
||||
|
||||
|
||||
def test_serialize_bytes() -> None:
|
||||
@@ -22,6 +26,33 @@ def test_serialize_dict() -> None:
|
||||
assert len(serialized) <= 1
|
||||
|
||||
|
||||
def test_serialize_numpy_integer() -> None:
|
||||
serialized = serialize_attrs(
|
||||
{
|
||||
"int8": np.int8(1),
|
||||
"int16": np.int16(1),
|
||||
"int32": np.int32(1),
|
||||
"int64": np.int64(1),
|
||||
}
|
||||
)
|
||||
assert len(serialized) == 4
|
||||
assert all([v["value"] == "1" for v in serialized])
|
||||
|
||||
|
||||
def test_serialize_numpy_floating() -> None:
|
||||
serialized = serialize_attrs(
|
||||
{
|
||||
"float16": np.float16(1.0),
|
||||
"float32": np.float32(1.0),
|
||||
"float64": np.float64(1.0),
|
||||
"float128": np.float128(1.0),
|
||||
}
|
||||
)
|
||||
assert len(serialized) == 4
|
||||
assert all([v["value"] == "1.0" for v in serialized])
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_get_study_detail_is_preferential() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
study = create_study(n_generate=4, storage=storage)
|
||||
@@ -48,6 +79,7 @@ def test_get_study_detail_is_not_preferential() -> None:
|
||||
assert not study_detail["is_preferential"]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
|
||||
def test_get_study_summary_is_preferential() -> None:
|
||||
storage = optuna.storages.InMemoryStorage()
|
||||
create_study(n_generate=4, storage=storage)
|
||||
|
||||
Reference in New Issue
Block a user