jsonify-optuna 0.1.0__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.
@@ -0,0 +1,5 @@
1
+ from jsonify_optuna.jsonify_optuna import jsonify
2
+ from jsonify_optuna.jsonify_optuna import load_study
3
+
4
+
5
+ __all__ = ["jsonify", "load_study"]
@@ -0,0 +1,109 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ import optuna
6
+ from optuna.trial import TrialState
7
+
8
+
9
+ if TYPE_CHECKING:
10
+ from typing import Any
11
+ from typing import Literal
12
+ from typing import TypedDict
13
+
14
+ from optuna.distributions import CategoricalChoiceType
15
+
16
+ class NumericalDistributionType(TypedDict):
17
+ low: int | float
18
+ high: int | float
19
+ step: int | float | None
20
+ log: bool
21
+
22
+ class CategoricalDistributionType(TypedDict):
23
+ choices: list[CategoricalChoiceType]
24
+
25
+ class TrialType(TypedDict):
26
+ state: Literal["running", "waiting", "completepruned", "fail"]
27
+ values: list[float]
28
+ params: dict[str, int | float | CategoricalChoiceType]
29
+ user_attrs: dict[str, Any]
30
+ intermediate_values: list[float]
31
+ distributions: dict[str, NumericalDistributionType | CategoricalDistributionType]
32
+
33
+ class StudyType:
34
+ trials: list[TrialType]
35
+ best_trial_indices: list[int]
36
+ directions: list[Literal["minimize", "maximize"]]
37
+ user_attrs: dict[str, Any]
38
+ metric_names: list[str]
39
+
40
+
41
+ def jsonify(
42
+ study: optuna.Study, *, states: list[TrialState] | None = None, deepcopy: bool = True
43
+ ) -> StudyType:
44
+ states = states or [state for state in TrialState]
45
+ study_json = {
46
+ "directions": [dire.name.lower() for dire in study.directions],
47
+ "user_attrs": study.user_attrs,
48
+ "metric_names": study.metric_names,
49
+ }
50
+ best_trial_numbers = set(t.number for t in study.best_trials)
51
+ best_trial_indices = []
52
+ results = []
53
+ for t in study.get_trials(deepcopy=deepcopy):
54
+ if t.state not in states:
55
+ continue
56
+ if t.number in best_trial_numbers:
57
+ best_trial_indices.append(len(results))
58
+ dists = {}
59
+ for p, d in t.distributions.items():
60
+ if isinstance(d, optuna.distributions.CategoricalDistribution):
61
+ dists[p] = {"choices": d.choices}
62
+ continue
63
+ assert isinstance(
64
+ d, (optuna.distributions.IntDistribution, optuna.distributions.FloatDistribution)
65
+ )
66
+ dists[p] = {"low": d.low, "high": d.high, "step": d.step, "log": d.log}
67
+ row = {
68
+ "state": t.state.name.lower(),
69
+ "values": t.values,
70
+ "params": t.params,
71
+ "user_attrs": t.user_attrs,
72
+ "intermediate_values": t.intermediate_values,
73
+ "distributions": dists,
74
+ }
75
+ results.append(row)
76
+ study_json |= {"trials": results, "best_trial_indices": best_trial_indices}
77
+ return study_json
78
+
79
+
80
+ def load_study(
81
+ *,
82
+ study_name: str | None = None,
83
+ storage: optuna.storages.BaseStorage | None = None,
84
+ journal_path: str | None = None,
85
+ rdb_url: str | None = None,
86
+ ) -> optuna.Study:
87
+ if storage is not None:
88
+ if rdb_url is not None or journal_path is not None:
89
+ raise ValueError(
90
+ f"storage is provided but either {rdb_url=} or {journal_path=} is also specified."
91
+ )
92
+ elif rdb_url is not None:
93
+ if journal_path is not None:
94
+ raise ValueError(f"Specify only one of {rdb_url=} or {journal_path=}.")
95
+ storage = optuna.storages.RDBStorage(rdb_url)
96
+ elif journal_path:
97
+ journal_file = optuna.storages.journal.JournalFileBackend(journal_path)
98
+ storage = optuna.storages.JournalStorage(journal_file)
99
+ else:
100
+ raise ValueError("No storage was specified.")
101
+ assert isinstance(storage, optuna.storages.BaseStorage), "MyPy Redefinition"
102
+ study_names = [study.study_name for study in storage.get_all_studies()]
103
+ if study_name is None and len(study_names) == 1:
104
+ return optuna.load_study(storage=storage, study_name=study_names[0])
105
+ if study_name is None:
106
+ raise ValueError(f"Specify `study_name` from {study_names=}.")
107
+ if study_name not in study_names:
108
+ raise ValueError(f"Specify `study_name` from {study_names=} but got {study_name=}.")
109
+ return optuna.load_study(storage=storage, study_name=study_name)
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: jsonify-optuna
3
+ Version: 0.1.0
4
+ Summary: Convert an Optuna Study into a JSON-serializable dict.
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: optuna>=4.9.0
7
+ Description-Content-Type: text/markdown
8
+
9
+ # jsonify-optuna
10
+
11
+ Convert an [Optuna](https://github.com/optuna/optuna) Study into a plain, JSON-serializable Python dict.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install jsonify-optuna
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Convert an in-memory study to a JSON-friendly dict:
22
+
23
+ ```python
24
+ import optuna
25
+ from jsonify_optuna import jsonify
26
+ from optuna.trial import TrialState
27
+
28
+ def objective(trial):
29
+ x = trial.suggest_float("x", -10.0, 10.0)
30
+ return x ** 2
31
+
32
+ study = optuna.create_study(direction="minimize")
33
+ study.optimize(objective, n_trials=20)
34
+ result = jsonify(study, states=[TrialState.COMPLETE])
35
+ # This includes all the trials.
36
+ result = jsonify(study)
37
+ ```
38
+
39
+ If you have a study stored in a backend, you can load it as follows:
40
+
41
+ ```python
42
+ from jsonify_optuna import load_study
43
+
44
+ # From an RDB (SQLite, PostgreSQL, etc.)
45
+ study = load_study(rdb_url="sqlite:///example.db", study_name="my_study")
46
+
47
+ # From a journal file
48
+ study = load_study(journal_path="journal.log", study_name="my_study")
49
+
50
+ # From a storage object directly
51
+ study = load_study(storage=my_storage, study_name="my_study")
52
+ ```
53
+
54
+ > [!NOTE]
55
+ > When the storage contains exactly one study, `study_name` can be omitted.
56
+
57
+ ## API Reference
58
+
59
+ ### `jsonify(study, *, states=None, deepcopy=True)`
60
+
61
+ | Parameter | Type | Description |
62
+ |-----------|------|-------------|
63
+ | `study` | `optuna.Study` | The study to convert. |
64
+ | `states` | `list[TrialState] \| None` | Filter trials by state. `None` includes all states. |
65
+ | `deepcopy` | `bool` | Whether to deep-copy trials from storage. Default `True`. |
66
+
67
+ Returns a dict with:
68
+
69
+ | Key | Type | Description |
70
+ |-----|------|-------------|
71
+ | `directions` | `list[str]` | `"minimize"` or `"maximize"` per objective. |
72
+ | `user_attrs` | `dict` | Study-level user attributes. |
73
+ | `metric_names` | `list[str] \| None` | Metric names if set, else `None`. |
74
+ | `trials` | `list[dict]` | Trial dicts (see below). |
75
+ | `best_trial_indices` | `list[int]` | Indices into `trials` for Pareto-front trials. |
76
+
77
+ Each trial dict contains:
78
+
79
+ | Key | Type | Description |
80
+ |-----|------|-------------|
81
+ | `state` | `str` | `"complete"`, `"pruned"`, `"fail"`, `"running"`, or `"waiting"`. |
82
+ | `values` | `list[float] \| None` | Objective values. `None` if not complete. |
83
+ | `params` | `dict` | Parameter name-value pairs. |
84
+ | `user_attrs` | `dict` | Trial-level user attributes. |
85
+ | `intermediate_values` | `dict[int, float]` | Step-value pairs from `trial.report()`. |
86
+ | `distributions` | `dict` | Parameter distributions (see below). |
87
+
88
+ Distribution formats:
89
+
90
+ - **Int/Float**: `{"low": ..., "high": ..., "step": ..., "log": ...}`
91
+ - **Categorical**: `{"choices": [...]}`
92
+
93
+ ### `load_study(*, study_name=None, storage=None, journal_path=None, rdb_url=None)`
94
+
95
+ | Parameter | Type | Description |
96
+ |-----------|------|-------------|
97
+ | `study_name` | `str \| None` | Study name. Optional when storage has exactly one study. |
98
+ | `storage` | `BaseStorage \| None` | An Optuna storage object. |
99
+ | `journal_path` | `str \| None` | Path to a journal log file. |
100
+ | `rdb_url` | `str \| None` | SQLAlchemy-style database URL. |
101
+
102
+ Exactly one of `storage`, `journal_path`, or `rdb_url` must be provided.
@@ -0,0 +1,5 @@
1
+ jsonify_optuna/__init__.py,sha256=E41S1z9of4nzR_wRJEGkHaY0B8XLyJhDjMWxP7vcVH0,141
2
+ jsonify_optuna/jsonify_optuna.py,sha256=yW5V-46_ba-lnIlq1AW1-30eVOtFLe_uW185s0QaBRU,4078
3
+ jsonify_optuna-0.1.0.dist-info/METADATA,sha256=dbvGicgEcwcDMSO4_6KmBaMUksRg0PsxKk99G_ByVgI,3340
4
+ jsonify_optuna-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
5
+ jsonify_optuna-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any