update: optimize config.py
This commit is contained in:
@@ -3,12 +3,24 @@ try:
|
||||
except ImportError:
|
||||
# Fallback when using the package in dev mode without installing
|
||||
# in editable mode with pip. It is highly recommended to install
|
||||
# the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
|
||||
# the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-install/
|
||||
import warnings
|
||||
warnings.warn("Importing 'opencode_bridge' outside a proper installation.")
|
||||
__version__ = "dev"
|
||||
from .config import OpencodeConfig
|
||||
from .routes import setup_route_handlers
|
||||
|
||||
# Re-export OpencodeConfig at module level so the JupyterApp CLI parser
|
||||
# (which auto-discovers Configurable subclasses from extension-point
|
||||
# modules) recognises ``--OpencodeConfig.<trait>`` flags.
|
||||
__all__ = [
|
||||
"OpencodeConfig",
|
||||
"setup_route_handlers",
|
||||
"_jupyter_labextension_paths",
|
||||
"_jupyter_server_extension_points",
|
||||
"_load_jupyter_server_extension",
|
||||
]
|
||||
|
||||
|
||||
def _jupyter_labextension_paths():
|
||||
return [{
|
||||
@@ -26,11 +38,25 @@ def _jupyter_server_extension_points():
|
||||
def _load_jupyter_server_extension(server_app):
|
||||
"""Registers the API handler to receive HTTP requests from the frontend extension.
|
||||
|
||||
Also instantiates the :class:`OpencodeConfig` configurable (with the
|
||||
server app as parent so CLI / config-file overrides take effect) and
|
||||
exposes it to request handlers via
|
||||
``web_app.settings["opencode_bridge"]``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
server_app: jupyterlab.labapp.LabApp
|
||||
JupyterLab application instance
|
||||
"""
|
||||
# Belt-and-suspenders: ensure the CLI parser recognises --OpencodeConfig.*
|
||||
# even on JupyterApp versions that don't auto-discover Configurable
|
||||
# subclasses from extension-point modules.
|
||||
if OpencodeConfig not in server_app.classes:
|
||||
server_app.classes.append(OpencodeConfig)
|
||||
|
||||
cfg = OpencodeConfig(parent=server_app)
|
||||
server_app.web_app.settings["opencode_bridge"] = cfg
|
||||
|
||||
setup_route_handlers(server_app.web_app)
|
||||
name = "opencode_bridge"
|
||||
server_app.log.info(f"Registered {name} server extension")
|
||||
|
||||
+113
-11
@@ -1,10 +1,22 @@
|
||||
"""Configuration resolution for the opencode-bridge extension.
|
||||
|
||||
All connection fields (URL / user / password / request timeout) are resolved
|
||||
exclusively from environment variables + built-in defaults at server startup.
|
||||
They are NOT stored in the JupyterLab plugin settings.
|
||||
Connection fields (URL / user / password / request timeout) are resolved
|
||||
in the following priority order, highest first:
|
||||
|
||||
1. ``--OpencodeConfig.<trait>`` CLI flag (e.g. ``--OpencodeConfig.url=...``)
|
||||
2. ``c.OpencodeConfig.<trait>`` line in a Jupyter config file
|
||||
3. ``OPENCODE_BRIDGE_*`` environment variable
|
||||
4. Built-in default
|
||||
|
||||
The ``OpencodeConfig`` class is a ``traitlets.config.Configurable``; the
|
||||
Jupyter server extension instantiates it with ``parent=server_app`` and
|
||||
stashes it on ``web_app.settings["opencode_bridge"]`` so handlers can pick
|
||||
it up via ``resolve_config``.
|
||||
|
||||
Env vars (kept for backward compatibility — also the default-value source
|
||||
for the traitlets so a fresh ``OpencodeConfig()`` with no overrides still
|
||||
honours them):
|
||||
|
||||
Env vars:
|
||||
OPENCODE_BRIDGE_URL — OpenCode Serve base URL (default http://127.0.0.1:4096)
|
||||
OPENCODE_BRIDGE_USER — HTTP Basic Auth username (default 'opencode')
|
||||
OPENCODE_BRIDGE_PASSWORD — HTTP Basic Auth password (default '' = no auth)
|
||||
@@ -15,6 +27,9 @@ from __future__ import annotations
|
||||
import os
|
||||
from typing import NamedTuple, Optional, Tuple
|
||||
|
||||
from traitlets import Int, Unicode, default
|
||||
from traitlets.config import Configurable
|
||||
|
||||
|
||||
ENV_URL = "OPENCODE_BRIDGE_URL"
|
||||
ENV_USER = "OPENCODE_BRIDGE_USER"
|
||||
@@ -40,19 +55,106 @@ class OpenCodeConfig(NamedTuple):
|
||||
return (self.user, self.password)
|
||||
|
||||
|
||||
def resolve_config(jupyter_settings: dict) -> OpenCodeConfig:
|
||||
"""Resolve OpenCode connection config from environment variables + defaults.
|
||||
class OpencodeConfig(Configurable):
|
||||
"""Traitlets-configurable connection settings for the opencode-bridge server extension.
|
||||
|
||||
The `jupyter_settings` argument is accepted for API compatibility but no
|
||||
fields are read from it — all connection config is now startup-only
|
||||
(environment variables).
|
||||
Exposed to ``jupyter lab`` / ``jupyter server`` as ``--OpencodeConfig.<trait>``
|
||||
and to ``jupyter_server_config.py`` as ``c.OpencodeConfig.<trait>``. Defaults
|
||||
fall back to the ``OPENCODE_BRIDGE_*`` env vars and then to built-in defaults,
|
||||
so the legacy env-var-only flow keeps working unchanged.
|
||||
"""
|
||||
_ = jupyter_settings # intentionally unused; see module docstring
|
||||
|
||||
url = Unicode(
|
||||
DEFAULT_URL,
|
||||
config=True,
|
||||
help=(
|
||||
"Base URL of the locally-running OpenCode Serve process. "
|
||||
"Overrides the OPENCODE_BRIDGE_URL env var."
|
||||
),
|
||||
)
|
||||
|
||||
user = Unicode(
|
||||
DEFAULT_USER,
|
||||
config=True,
|
||||
help=(
|
||||
"HTTP Basic Auth username for OpenCode Serve. "
|
||||
"Overrides the OPENCODE_BRIDGE_USER env var."
|
||||
),
|
||||
)
|
||||
|
||||
password = Unicode(
|
||||
"",
|
||||
config=True,
|
||||
help=(
|
||||
"HTTP Basic Auth password for OpenCode Serve (empty = no auth). "
|
||||
"Overrides the OPENCODE_BRIDGE_PASSWORD env var."
|
||||
),
|
||||
)
|
||||
|
||||
request_timeout_seconds = Int(
|
||||
DEFAULT_REQUEST_TIMEOUT,
|
||||
config=True,
|
||||
help=(
|
||||
"Per-request timeout in seconds when calling OpenCode Serve. "
|
||||
"Overrides the OPENCODE_BRIDGE_TIMEOUT env var."
|
||||
),
|
||||
)
|
||||
|
||||
@default("url")
|
||||
def _default_url(self) -> str:
|
||||
return os.environ.get(ENV_URL) or DEFAULT_URL
|
||||
|
||||
@default("user")
|
||||
def _default_user(self) -> str:
|
||||
return os.environ.get(ENV_USER) or DEFAULT_USER
|
||||
|
||||
@default("password")
|
||||
def _default_password(self) -> str:
|
||||
return os.environ.get(ENV_PASSWORD) or ""
|
||||
|
||||
@default("request_timeout_seconds")
|
||||
def _default_request_timeout_seconds(self) -> int:
|
||||
return int(os.environ.get(ENV_TIMEOUT) or DEFAULT_REQUEST_TIMEOUT)
|
||||
|
||||
|
||||
def _to_opencode_config(bridge) -> OpenCodeConfig:
|
||||
"""Project an :class:`OpencodeConfig` (or duck-typed equivalent) to the
|
||||
internal ``OpenCodeConfig`` NamedTuple consumed by ``OpenCodeClient``.
|
||||
"""
|
||||
return OpenCodeConfig(
|
||||
url=bridge.url,
|
||||
user=bridge.user,
|
||||
password=bridge.password,
|
||||
request_timeout_seconds=bridge.request_timeout_seconds,
|
||||
)
|
||||
|
||||
|
||||
def resolve_config(jupyter_settings) -> OpenCodeConfig:
|
||||
"""Resolve OpenCode connection config into an ``OpenCodeConfig`` NamedTuple.
|
||||
|
||||
Accepts either a settings dict (legacy) or an :class:`OpencodeConfig`
|
||||
instance directly, because request handlers call
|
||||
``resolve_config(handler.settings.get("opencode_bridge", {}))`` and pass
|
||||
the inner value (which is now an ``OpencodeConfig`` instance after the
|
||||
server extension's load hook populates it).
|
||||
|
||||
Source order (highest priority first):
|
||||
|
||||
1. The argument itself is an :class:`OpencodeConfig` instance.
|
||||
2. ``jupyter_settings["opencode_bridge"]`` is an :class:`OpencodeConfig`
|
||||
instance (legacy call style).
|
||||
3. Otherwise fall back to env vars + built-in defaults.
|
||||
"""
|
||||
if isinstance(jupyter_settings, OpencodeConfig):
|
||||
return _to_opencode_config(jupyter_settings)
|
||||
bridge = (jupyter_settings or {}).get("opencode_bridge")
|
||||
if isinstance(bridge, OpencodeConfig):
|
||||
return _to_opencode_config(bridge)
|
||||
return OpenCodeConfig(
|
||||
url=os.environ.get(ENV_URL) or DEFAULT_URL,
|
||||
user=os.environ.get(ENV_USER) or DEFAULT_USER,
|
||||
password=os.environ.get(ENV_PASSWORD) or "",
|
||||
request_timeout_seconds=int(
|
||||
os.environ.get(ENV_TIMEOUT) or DEFAULT_REQUEST_TIMEOUT
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user