refac: modernize type annotations (PEP 604 / PEP 585)

This commit is contained in:
Timothy Jaeryang Baek committed 2026-05-12 17:10:15 +09:00
1 parent a59c967d7e
commit 6d0295588e
197 files changed
+3265 -3488

No files matched your search

+28 -29
View File
@@ -10,10 +10,9 @@ from functools import reduce
from typing import Any, Optional, Union
import redis
from sqlalchemy import JSON, Column, DateTime, Integer, func, select
from open_webui.internal.db import Base, get_async_db, get_db
from open_webui.utils.redis import get_redis_connection
from sqlalchemy import JSON, Column, DateTime, Integer, func, select
log = logging.getLogger(__name__)
@@ -22,7 +21,7 @@ log = logging.getLogger(__name__)
class ConfigTable(Base):
__tablename__ = "config"
__tablename__ = 'config'
id = Column(Integer, primary_key=True)
data = Column(JSON, nullable=False)
@@ -37,7 +36,7 @@ class ConfigTable(Base):
class ConfigState:
"""In-memory mirror of the single-row config JSON blob."""
__slots__ = ("_data",)
__slots__ = ('_data',)
def __init__(self) -> None:
self._data: dict[str, Any] = {}
@@ -49,12 +48,12 @@ class ConfigState:
def read(self, path: str) -> Any:
return reduce(
lambda n, k: n.get(k) if isinstance(n, dict) else None,
path.split("."),
path.split('.'),
self._data,
)
def write(self, path: str, value: Any) -> None:
keys = path.split(".")
keys = path.split('.')
reduce(lambda d, k: d.setdefault(k, {}), keys[:-1], self._data)[keys[-1]] = value
def replace(self, data: dict) -> None:
@@ -63,7 +62,7 @@ class ConfigState:
def load(self) -> dict:
with get_db() as db:
row = db.query(ConfigTable).order_by(ConfigTable.id.desc()).first()
self._data = row.data if row else {"version": 0, "ui": {}}
self._data = row.data if row else {'version': 0, 'ui': {}}
return self._data
def persist(self, data: dict | None = None) -> None:
@@ -123,7 +122,7 @@ def initialize(*, enable_persistent: bool = True, enable_oauth_persistent: bool
class ConfigVar:
__slots__ = ("env_name", "config_path", "env_value", "config_value", "value")
__slots__ = ('env_name', 'config_path', 'env_value', 'config_value', 'value')
def __init__(self, env_name: str, config_path: str, env_value: Any) -> None:
self.env_name = env_name
@@ -132,7 +131,7 @@ class ConfigVar:
self.config_value = STATE.read(config_path)
if self.config_value is not None and _persist_enabled:
if config_path.startswith("oauth.") and not _oauth_persist_enabled:
if config_path.startswith('oauth.') and not _oauth_persist_enabled:
log.info("Skipping DB value for '%s' (OAuth persistence disabled)", env_name)
self.value = env_value
else:
@@ -147,22 +146,22 @@ class ConfigVar:
return str(self.value)
def __repr__(self) -> str:
return f"<ConfigVar {self.env_name}={self.value!r}>"
return f'<ConfigVar {self.env_name}={self.value!r}>'
@property
def __dict__(self): # type: ignore[override]
raise TypeError(f"ConfigVar('{self.env_name}') cannot be cast to dict; use .value")
def __getattribute__(self, item: str):
if item == "__dict__":
raise TypeError("ConfigVar cannot be cast to dict; use .value")
if item == '__dict__':
raise TypeError('ConfigVar cannot be cast to dict; use .value')
return super().__getattribute__(item)
def refresh(self) -> None:
current = STATE.read(self.config_path)
if current is not None:
self.value = current
log.info("Refreshed %s → %s", self.env_name, self.value)
log.info('Refreshed %s → %s', self.env_name, self.value)
def commit(self) -> None:
log.info("Persisting '%s'", self.env_name)
@@ -189,18 +188,18 @@ class AppConfig:
redis_url: Optional[str] = None,
redis_sentinels: Optional[list] = None,
redis_cluster: bool = False,
redis_key_prefix: str = "open-webui",
redis_key_prefix: str = 'open-webui',
) -> None:
super().__setattr__("_entries", {})
super().__setattr__("_key_prefix", redis_key_prefix)
super().__setattr__('_entries', {})
super().__setattr__('_key_prefix', redis_key_prefix)
rc: Union[redis.Redis, redis.cluster.RedisCluster, None] = None
if redis_url:
rc = get_redis_connection(redis_url, redis_sentinels or [], redis_cluster, decode_responses=True)
super().__setattr__("_rc", rc)
super().__setattr__('_rc', rc)
def __setattr__(self, name: str, value: Any) -> None:
entries: dict = super().__getattribute__("_entries")
entries: dict = super().__getattribute__('_entries')
if isinstance(value, ConfigVar):
entries[name] = value
@@ -213,11 +212,11 @@ class AppConfig:
except RuntimeError:
entries[name].commit()
rc = super().__getattribute__("_rc")
rc = super().__getattribute__('_rc')
if rc and _persist_enabled:
prefix = super().__getattribute__("_key_prefix")
prefix = super().__getattribute__('_key_prefix')
try:
rc.set(f"{prefix}:config:{name}", json.dumps(entries[name].value))
rc.set(f'{prefix}:config:{name}', json.dumps(entries[name].value))
except Exception as exc:
log.error("Redis write failed for '%s': %s", name, exc)
@@ -228,15 +227,15 @@ class AppConfig:
log.error("Async persist failed for '%s': %s", name, exc)
def __getattr__(self, name: str) -> Any:
entries = super().__getattribute__("_entries")
entries = super().__getattribute__('_entries')
if name not in entries:
raise AttributeError(f"No config key '{name}'")
rc = super().__getattribute__("_rc")
rc = super().__getattribute__('_rc')
if rc and _persist_enabled:
prefix = super().__getattribute__("_key_prefix")
prefix = super().__getattribute__('_key_prefix')
try:
raw = rc.get(f"{prefix}:config:{name}")
raw = rc.get(f'{prefix}:config:{name}')
if raw is not None:
decoded = json.loads(raw)
if entries[name].value != decoded:
@@ -248,12 +247,12 @@ class AppConfig:
return entries[name].value
def _sync_to_redis(self) -> None:
rc = super().__getattribute__("_rc")
rc = super().__getattribute__('_rc')
if not rc or not _persist_enabled:
return
prefix = super().__getattribute__("_key_prefix")
for name, s in super().__getattribute__("_entries").items():
prefix = super().__getattribute__('_key_prefix')
for name, s in super().__getattribute__('_entries').items():
try:
rc.set(f"{prefix}:config:{name}", json.dumps(s.value))
rc.set(f'{prefix}:config:{name}', json.dumps(s.value))
except Exception as exc:
log.error("Redis sync failed for '%s': %s", name, exc)
+19 -18
View File
@@ -1,35 +1,36 @@
import os
import sys
from __future__ import annotations
import json
import logging
import os
import sys
from contextlib import asynccontextmanager, contextmanager
from typing import Any, Optional
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
from open_webui.env import (
OPEN_WEBUI_DIR,
DATABASE_URL,
DATABASE_SCHEMA,
DATABASE_ENABLE_SESSION_SHARING,
DATABASE_ENABLE_SQLITE_WAL,
DATABASE_POOL_MAX_OVERFLOW,
DATABASE_POOL_RECYCLE,
DATABASE_POOL_SIZE,
DATABASE_POOL_TIMEOUT,
DATABASE_ENABLE_SQLITE_WAL,
DATABASE_ENABLE_SESSION_SHARING,
DATABASE_SQLITE_PRAGMA_SYNCHRONOUS,
DATABASE_SCHEMA,
DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT,
DATABASE_SQLITE_PRAGMA_CACHE_SIZE,
DATABASE_SQLITE_PRAGMA_TEMP_STORE,
DATABASE_SQLITE_PRAGMA_MMAP_SIZE,
DATABASE_SQLITE_PRAGMA_JOURNAL_SIZE_LIMIT,
DATABASE_SQLITE_PRAGMA_MMAP_SIZE,
DATABASE_SQLITE_PRAGMA_SYNCHRONOUS,
DATABASE_SQLITE_PRAGMA_TEMP_STORE,
DATABASE_URL,
ENABLE_DB_MIGRATIONS,
OPEN_WEBUI_DIR,
)
from sqlalchemy import Dialect, create_engine, MetaData, event, types
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy import Dialect, MetaData, create_engine, event, types
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker, Session
from sqlalchemy.pool import QueuePool, NullPool
from sqlalchemy.orm import Session, scoped_session, sessionmaker
from sqlalchemy.pool import NullPool, QueuePool
from sqlalchemy.sql.type_api import _T
from typing_extensions import Self
@@ -120,10 +121,10 @@ class JSONField(types.TypeDecorator):
impl = types.Text
cache_ok = True
def process_bind_param(self, value: Optional[_T], dialect: Dialect) -> Any:
def process_bind_param(self, value: _T | None, dialect: Dialect) -> Any:
return json.dumps(value)
def process_result_value(self, value: Optional[_T], dialect: Dialect) -> Any:
def process_result_value(self, value: _T | None, dialect: Dialect) -> Any:
if value is not None:
return json.loads(value)
@@ -374,7 +375,7 @@ async def get_async_db():
@asynccontextmanager
async def get_async_db_context(db: Optional[AsyncSession] = None):
async def get_async_db_context(db: AsyncSession | None = None):
"""Async context manager that reuses an existing session if provided and session sharing is enabled."""
if isinstance(db, AsyncSession) and DATABASE_ENABLE_SESSION_SHARING:
yield db