mirror of
https://github.com/open-webui/open-webui.git
synced 2026-09-28 01:31:28 +00:00
fix(db): aiosqlite shim — bytecode fallback when source inspection fails
Address PR review findings 1 & 2 on the detection heuristic:
The previous gate relied solely on `inspect.getsource()` matching
the substring `self._connection.stop`. Two failure modes:
1. Source-unavailable builds — zipped distributions, pyc-only
installs, frozen runtimes — return OSError from
`inspect.getsource`, so the gate silently skipped patching and
the multi-page `terminate_force_close() not implemented`
tracebacks reappeared. Hard-to-diagnose because startup looks
successful.
2. Brittle text matching — minor upstream formatting changes to
the same buggy logic could bypass the substring check.
Factor the detection into `_looks_buggy(original)` with two signals
in order of preference:
* Source text inspection (precise, obvious).
* Bytecode `co_names` inspection — works on every CPython build
exposing `__code__`. Any function that does
`self._connection.stop` puts both `_connection` and `stop`
into `co_names`, regardless of whitespace or refactoring.
If neither inspection succeeds, patch defensively: the user
explicitly reported the noisy ERROR behaviour, so a
possibly-redundant shim beats silently restoring it.
Per user direction the third reviewer suggestion (regression test
coverage) is not added in this PR.
https://claude.ai/code/session_01JSr4NZSskEUQvoJnavVXh8
This commit is contained in:
parent
a03bde4701
commit
4c45ab659a
1 changed files with 53 additions and 11 deletions
|
|
@ -45,9 +45,11 @@ created. To keep the blast radius small the install is:
|
|||
`_terminate_force_close` symbol (older or upstream-fixed
|
||||
versions);
|
||||
* a no-op if the upstream implementation has already moved off the
|
||||
`self._connection.stop` reference — detected by inspecting the
|
||||
original source — so a future SQLAlchemy fix isn't shadowed by
|
||||
this shim;
|
||||
`self._connection.stop` reference — detected via source
|
||||
inspection with a bytecode fallback (so the heuristic still
|
||||
works on zipped, pyc-only or otherwise stripped builds where
|
||||
`inspect.getsource()` raises) — so a future SQLAlchemy fix
|
||||
isn't shadowed by this shim;
|
||||
* idempotent so repeated imports don't stack patches.
|
||||
|
||||
The caller in `internal.db` only invokes `install()` when the runtime
|
||||
|
|
@ -63,6 +65,53 @@ import logging
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _looks_buggy(original) -> bool:
|
||||
"""Return True if `original` looks like the buggy upstream impl
|
||||
that references `self._connection.stop`.
|
||||
|
||||
Two signals, in order of preference:
|
||||
|
||||
1. Source text inspection — exact and obvious, but fails on
|
||||
deployments where source isn't on disk (zipped distributions,
|
||||
pyc-only installs, frozen runtimes).
|
||||
2. Bytecode `co_names` inspection — works on every CPython build
|
||||
that exposes `__code__`. Both `_connection` and `stop` appear
|
||||
in `co_names` whenever the function does an attribute access of
|
||||
the form `self._connection.stop`, regardless of whitespace or
|
||||
formatting changes.
|
||||
|
||||
If neither inspection succeeds we err on the side of patching:
|
||||
the upstream `_terminate_force_close` already raised
|
||||
`NotImplementedError` for us once (which is why we're here), and
|
||||
a possibly-redundant shim is preferable to silently restoring the
|
||||
multi-page ERROR traceback the user explicitly reported.
|
||||
"""
|
||||
try:
|
||||
original_source = inspect.getsource(original)
|
||||
except (OSError, TypeError):
|
||||
original_source = None
|
||||
|
||||
if original_source is not None:
|
||||
return 'self._connection.stop' in original_source
|
||||
|
||||
code = getattr(original, '__code__', None)
|
||||
if code is not None:
|
||||
names = set(getattr(code, 'co_names', ()))
|
||||
if {'_connection', 'stop'}.issubset(names):
|
||||
return True
|
||||
# Bytecode says it's not the buggy shape — believe it.
|
||||
return False
|
||||
|
||||
# Neither source nor bytecode available. Patch defensively; the
|
||||
# caller already established that the buggy `NotImplementedError`
|
||||
# path is the existing behaviour.
|
||||
log.debug(
|
||||
'aiosqlite shim: could not inspect upstream _terminate_force_close '
|
||||
'via source or bytecode; applying compatibility patch defensively.'
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def install() -> None:
|
||||
try:
|
||||
from sqlalchemy.dialects.sqlite import aiosqlite as _sa_aiosqlite
|
||||
|
|
@ -80,14 +129,7 @@ def install() -> None:
|
|||
if getattr(original, '__open_webui_patched__', False):
|
||||
return # Idempotent — already applied.
|
||||
|
||||
# Only patch the specific buggy implementation. If upstream has
|
||||
# changed how `_terminate_force_close` is implemented (no longer
|
||||
# touching `self._connection.stop`) defer to whatever they ship.
|
||||
try:
|
||||
original_source = inspect.getsource(original)
|
||||
except (OSError, TypeError):
|
||||
original_source = ''
|
||||
if 'self._connection.stop' not in original_source:
|
||||
if not _looks_buggy(original):
|
||||
return
|
||||
|
||||
def _terminate_force_close(self) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue