mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-07 11:28:35 -05:00
[PR #24167] ci: add ruff pyflakes-only check on backend (and unblock pre-existing violations) #50530
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/24167
Author: @turicas
Created: 4/27/2026
Status: 🔄 Open
Base:
dev← Head:ci/lint-backend-pyflakes📝 Commits (6)
ec6e77cfix(tests): add missing azure.storage.blob import6024865refactor: remove duplicate imports using ruff44ed952refactor(routers): rename duplicate route handlersa45bdffrefactor(routers/files): unify duplicated handlers5c86facfix: run ruff format (fix 'Format Backend' action)326ae3dci: add ruff pyflakes-only check on backend📊 Changes
11 files changed (+99 additions, -112 deletions)
View changed files
➕
.github/workflows/lint-backend-pyflakes.yaml(+32 -0)📝
backend/open_webui/main.py(+0 -1)📝
backend/open_webui/models/messages.py(+1 -1)📝
backend/open_webui/routers/audio.py(+0 -1)📝
backend/open_webui/routers/evaluations.py(+2 -2)📝
backend/open_webui/routers/files.py(+56 -99)📝
backend/open_webui/routers/functions.py(+1 -1)📝
backend/open_webui/routers/users.py(+0 -1)📝
backend/open_webui/tasks.py(+1 -1)📝
backend/open_webui/test/apps/webui/storage/test_provider.py(+5 -3)📝
backend/open_webui/utils/tools.py(+1 -2)📄 Description
Before submitting, make sure you've checked the following:
devbranch.devto ensure no unrelated commits (e.g. frommain) are included. Push updates to the existing PR branch instead of closing and reopening.Description
This PR adds a minimal CI job to detect logic errors (ruff pyflakes
Fcategory) at PR review time and resolves the 12pre-existing violations to unblock it.
The motivation is based on a bug that hit me in production: issue #23966 reported a
NameError: name 'requests' is not defined(v0.9.1) that broke Web search for users with the Firecrawl loader configured.ruff check --select=Fwouldhave flagged it at PR time. It was incidentally resolved in #23934 when the calling code was rewritten, but this kind
of bug will pass silently if it happens again. This CI job ensures the same class of bug is caught at PR time before
reaching dev or a release.
The same lint check would also have flagged a separate latent issue uncovered while preparing this PR:
routers/files.pyhad two route handlers sharing the Python identifierget_file_content_by_id(an F811 violation), causingfrom open_webui.routers.files import get_file_content_by_idandrequest.app.url_path_for('get_file_content_by_id', ...)to resolve to different functions in the same caller (images.py). This is exactly the kind of silent inconsistency static analysis exists to catch.The ruff version (
0.15.5) was pinned to match the version already in.pre-commit-config.yaml, so this introduces nonew dependency (it just enforces in CI what pre-commit already enforces locally).
The job uses
--output-format=githubso violations are annotated inline on the PR diff in the GitHub UI, not justburied in the workflow log.
Added
.github/workflows/lint-backend-pyflakes.yaml: ruff F-only CI check, runs on every push tomain/devand on everyPR. Job duration: ~9s.
Changed
routers/files.py: unified two duplicated/contenthandlers into a private_serve_file_contenthelper. Behaviorof both endpoints (
/{id}/contentand/{id}/content/{file_name}) is preserved.Deprecated
None.
Removed
None.
Fixed
azure.storage.blobmodule import intest/apps/webui/storage/test_provider.py(resolvesNameErroron the 3monkeypatch.setattr()calls).main.py,models/messages.py,routers/audio.py,tasks.py,utils/tools.py.routers/evaluations.pyandrouters/functions.py(Pythonidentifiers renamed, URL paths unchanged).
routers/files.pywas handled separately (see "Changed").routers/files.py: exception handler in file-content delivery now returns500for server-side errors instead of400.routers/users.py: stale blank line that was causingformat-backend.yamlto fail.Security
None.
Breaking Changes
None.
Additional Information
Following a short summary of the commits:
fix(tests): adds the missingazure.storage.blobmodule import intest_provider.py. Resolves thestatic error only (the surrounding test class has unrelated structural issues that are out of scope).
refactor: removes 6 duplicate imports acrossmain.py,models/messages.py,routers/audio.py,tasks.py,utils/tools.py(autofixed byruff check --fix --select=F811).refactor(routers): renames duplicate route handlers inevaluations.py(get_feedbackstoget_feedbacks_userandget_feedbacks_list) andfunctions.py(secondget_functionstoexport_functions).URL paths and behavior unchanged.
refactor(routers/files): unifies the twoget_file_content_by_idhandlers (they shared the Python identifierbut had subtly different logic). Extracted shared logic into a
_serve_file_contenthelper; the two endpoints(
/{id}/contentand/{id}/content/{file_name}) become thin wrappers. Also fixed a HTTP status code in theexception handler (from 400 to 500, since the failure is server-side, not client-side).
fix: runsruff formatto satisfy the existingformat-backend.yamlworkflow (a stale blank line inrouters/users.py) so it will also pass the CI.ci: adds.github/workflows/lint-backend-pyflakes.yamlrunningruff check --select=F(with some specificignores - more details below) to gatekeep these logic errors.
The CI job ignores cosmetic-only categories:
F401(unused imports - hundreds of pre-existing);F403/F405(star imports, used intentionally ininternal/wrappers.py);F541(empty f-strings);F841(unused variable in except blocks)It only fails on F codes that indicate real runtime bugs:
F821undefined name (the #23966 class)F811redefinition of unused names (e.g. duplicate route handlers)F501-F525format string mismatchesF601-F632logic errors (iswith literal etc.)F701-F707invalidbreak/continue/returnplacementScreenshots or Videos
I've built the patched image locally and checked the impact of the commits:
knowledge base creation and file upload all functional -- all of them implicitly demonstrated in the video below.
preserving multiple behavioral paths. Recorded a video walking through the primary path: clicking a PDF in a
knowledge base opens it inline in the browser. The second endpoint (
/{id}/content/{file_name}) was not exercisedin the video since
git grepconfirms it has no frontend callers, only the renamed Python handler.ruff check --select=F --ignore=F401,F403,F405,F541,F841 .found 12 errorsLint Backend (Pyflakes)workflow manually on myfork. Job ran in 9s, exit 0, no annotations.
https://github.com/user-attachments/assets/57a11e77-1154-4f0a-b498-d5758990d254
Contributor License Agreement
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.