mirror of
https://github.com/wassname/optuna-dashboard.git
synced 2026-09-11 12:30:25 +08:00
Merge pull request #167 from optuna/stable-interface
Provide stable Python API
This commit is contained in:
@@ -102,6 +102,19 @@ You can walk-through trials by filtering and sorting.
|
||||
|
||||

|
||||
|
||||
## Python Interface
|
||||
|
||||
### `run_server(storage: Union[str, BaseStorage], host: str = 'localhost', port: int = 8080) -> NoReturn`
|
||||
|
||||
Start running optuna-dashboard and blocks until the server terminates.
|
||||
This function uses wsgiref module which is not intended for the production
|
||||
use. If you want to run optuna-dashboard more secure and/or more fast,
|
||||
please use WSGI server like Gunicorn or uWSGI via `wsgi()` function.
|
||||
|
||||
### `wsgi(storage: Union[str, BaseStorage]) -> WSGIApplication`
|
||||
|
||||
This function exposes WSGI interface for people who want to run on the
|
||||
production-class WSGI servers like Gunicorn or uWSGI.
|
||||
|
||||
## Submitting patches
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import optuna
|
||||
def objective(trial):
|
||||
x = trial.suggest_float("x", -100, 100)
|
||||
y = trial.suggest_categorical("y", [-1, 0, 1])
|
||||
return x ** 2 + y
|
||||
return x**2 + y
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from .app import run_server # noqa
|
||||
from .app import wsgi # noqa
|
||||
|
||||
|
||||
__version__ = "0.5.0"
|
||||
|
||||
@@ -6,11 +6,13 @@ import logging
|
||||
import os
|
||||
import threading
|
||||
import traceback
|
||||
import typing
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import cast
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import NoReturn
|
||||
from typing import Optional
|
||||
from typing import TypeVar
|
||||
from typing import Union
|
||||
@@ -20,10 +22,13 @@ from bottle import Bottle
|
||||
from bottle import redirect
|
||||
from bottle import request
|
||||
from bottle import response
|
||||
from bottle import run
|
||||
from bottle import static_file
|
||||
import optuna
|
||||
from optuna.exceptions import DuplicatedStudyError
|
||||
from optuna.storages import BaseStorage
|
||||
from optuna.storages import RDBStorage
|
||||
from optuna.storages import RedisStorage
|
||||
from optuna.study import Study
|
||||
from optuna.study import StudyDirection
|
||||
from optuna.study import StudySummary
|
||||
@@ -34,6 +39,9 @@ from . import serializer
|
||||
from .search_space import get_search_space
|
||||
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from _typeshed.wsgi import WSGIApplication
|
||||
|
||||
BottleViewReturn = Union[str, bytes, Dict[str, Any], BaseResponse]
|
||||
BottleView = TypeVar("BottleView", bound=Callable[..., BottleViewReturn])
|
||||
|
||||
@@ -274,3 +282,31 @@ def create_app(storage: BaseStorage) -> Bottle:
|
||||
return static_file(filename, root=STATIC_DIR)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def get_storage(storage: Union[str, BaseStorage]) -> BaseStorage:
|
||||
if isinstance(storage, str):
|
||||
if storage.startswith("redis"):
|
||||
return RedisStorage(storage)
|
||||
else:
|
||||
return RDBStorage(storage)
|
||||
return storage
|
||||
|
||||
|
||||
def run_server( # type: ignore
|
||||
storage: Union[str, BaseStorage], host: str = "localhost", port: int = 8080
|
||||
) -> NoReturn:
|
||||
"""Start running optuna-dashboard and blocks until the server terminates.
|
||||
This function uses wsgiref module which is not intended for the production
|
||||
use. If you want to run optuna-dashboard more secure and/or more fast,
|
||||
please use WSGI server like Gunicorn or uWSGI via `wsgi()` function.
|
||||
"""
|
||||
app = create_app(get_storage(storage))
|
||||
run(app, host=host, port=port)
|
||||
|
||||
|
||||
def wsgi(storage: Union[str, BaseStorage]) -> "WSGIApplication":
|
||||
"""This function exposes WSGI interface for people who want to run on the
|
||||
production-class WSGI servers like Gunicorn or uWSGI.
|
||||
"""
|
||||
return create_app(get_storage(storage))
|
||||
|
||||
@@ -6,8 +6,8 @@ from optuna.storages import BaseStorage
|
||||
from optuna.storages import RDBStorage
|
||||
from optuna.storages import RedisStorage
|
||||
|
||||
from . import __version__
|
||||
from .app import create_app
|
||||
from .version import __version__
|
||||
|
||||
|
||||
AUTO_RELOAD = os.environ.get("OPTUNA_DASHBOARD_AUTO_RELOAD") == "1"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
__version__ = "0.5.0"
|
||||
+10
-11
@@ -1,17 +1,16 @@
|
||||
import io
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
import typing
|
||||
from typing import Dict
|
||||
from typing import Iterable
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
from bottle import Bottle
|
||||
|
||||
WSGIEnv = Dict[str, Any] # Cannot use TypedDict because of 'HTTP_' variables
|
||||
StartResponse = Callable[[str, List[Tuple[str, str]]], None]
|
||||
WSGIApp = Callable[[WSGIEnv, StartResponse], Iterable[bytes]]
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from _typeshed.wsgi import WSGIEnvironment
|
||||
|
||||
|
||||
def create_wsgi_env(
|
||||
@@ -21,7 +20,7 @@ def create_wsgi_env(
|
||||
body: bytes,
|
||||
queries: Dict[str, str],
|
||||
headers: Dict[str, str],
|
||||
) -> WSGIEnv:
|
||||
) -> "WSGIEnvironment":
|
||||
# 'key1=value1&key2=value2'
|
||||
query_string = "&".join([f"{k}={v}" for k, v in queries.items()])
|
||||
|
||||
@@ -48,7 +47,7 @@ def create_wsgi_env(
|
||||
|
||||
|
||||
def send_request(
|
||||
app: WSGIApp,
|
||||
app: Bottle,
|
||||
path: str,
|
||||
method: str,
|
||||
body: Union[str, bytes] = b"",
|
||||
@@ -68,10 +67,10 @@ def send_request(
|
||||
headers = headers or {}
|
||||
queries = queries or {}
|
||||
env = create_wsgi_env(path, method, content_type, bytes_body, queries, headers)
|
||||
body = b""
|
||||
response_body = b""
|
||||
iterable_body = app(env, start_response)
|
||||
for b in iterable_body:
|
||||
body += b
|
||||
response_body += b
|
||||
|
||||
status_code = int(status.split()[0])
|
||||
return status_code, response_headers, body
|
||||
return status_code, response_headers, response_body
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = optuna-dashboard
|
||||
version = attr: optuna_dashboard.version.__version__
|
||||
version = attr: optuna_dashboard.__version__
|
||||
|
||||
url = https://github.com/optuna/optuna-dashboard
|
||||
author = Masashi Shibata
|
||||
|
||||
@@ -12,7 +12,7 @@ import optuna
|
||||
from pyppeteer import launch
|
||||
from pyppeteer.page import Page
|
||||
|
||||
from optuna_dashboard.app import create_app
|
||||
from optuna_dashboard import wsgi
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -94,7 +94,7 @@ def create_dummy_storage() -> optuna.storages.InMemoryStorage:
|
||||
def objective_multi(trial: optuna.Trial) -> Tuple[float, float]:
|
||||
x = trial.suggest_float("x", 0, 5)
|
||||
y = trial.suggest_float("y", 0, 3)
|
||||
v0 = 4 * x ** 2 + 4 * y ** 2
|
||||
v0 = 4 * x**2 + 4 * y**2
|
||||
v1 = (x - 5) ** 2 + (y - 5) ** 2
|
||||
return v0, v1
|
||||
|
||||
@@ -110,13 +110,13 @@ def create_dummy_storage() -> optuna.storages.InMemoryStorage:
|
||||
if category == "foo":
|
||||
x = trial.suggest_float("x1", 0, 5)
|
||||
y = trial.suggest_float("y1", 0, 3)
|
||||
v0 = 4 * x ** 2 + 4 * y ** 2
|
||||
v0 = 4 * x**2 + 4 * y**2
|
||||
v1 = (x - 5) ** 2 + (y - 5) ** 2
|
||||
return v0, v1
|
||||
else:
|
||||
x = trial.suggest_float("x2", 0, 5)
|
||||
y = trial.suggest_float("y2", 0, 3)
|
||||
v0 = 2 * x ** 2 + 2 * y ** 2
|
||||
v0 = 2 * x**2 + 2 * y**2
|
||||
v1 = (x - 2) ** 2 + (y - 3) ** 2
|
||||
return v0, v1
|
||||
|
||||
@@ -130,7 +130,7 @@ def create_dummy_storage() -> optuna.storages.InMemoryStorage:
|
||||
def objective_prune_without_report(trial: optuna.Trial) -> float:
|
||||
x = trial.suggest_float("x", -15, 30)
|
||||
y = trial.suggest_float("y", -15, 30)
|
||||
v = x ** 2 + y ** 2
|
||||
v = x**2 + y**2
|
||||
if v > 100:
|
||||
raise optuna.TrialPruned()
|
||||
return v
|
||||
@@ -201,7 +201,7 @@ def main() -> None:
|
||||
else:
|
||||
storage = optuna.storages.RDBStorage(args.storage)
|
||||
|
||||
app = create_app(storage)
|
||||
app = wsgi(storage)
|
||||
httpd = make_server(args.host, args.port, app)
|
||||
thread = threading.Thread(target=httpd.serve_forever)
|
||||
thread.start()
|
||||
|
||||
Reference in New Issue
Block a user