[PR #24167] ci: add ruff pyflakes-only check on backend (and unblock pre-existing violations) #66388

Open
opened 2026-05-06 12:43:53 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/24167
Author: @turicas
Created: 4/27/2026
Status: 🔄 Open

Base: devHead: ci/lint-backend-pyflakes


📝 Commits (6)

  • ec6e77c fix(tests): add missing azure.storage.blob import
  • 6024865 refactor: remove duplicate imports using ruff
  • 44ed952 refactor(routers): rename duplicate route handlers
  • a45bdff refactor(routers/files): unify duplicated handlers
  • 5c86fac fix: run ruff format (fix 'Format Backend' action)
  • 326ae3d ci: 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:

  • Target branch: Verify that the pull request targets the dev branch.
  • Description: Provide a concise description of the changes made in this pull request down below.
  • Changelog: Ensure a changelog entry following the format of Keep a Changelog is added at the bottom of the PR description.
  • Documentation: N/A.
  • Dependencies: No new dependencies.
  • Testing: Perform manual tests to verify the implemented fix/feature works as intended AND does not break any other functionality. Include reproducible steps to demonstrate the issue before the fix. Test edge cases (URL encoding, HTML entities, types). Take this as an opportunity to make screenshots of the feature/fix and include them in the PR description.
  • Agentic AI Code: Confirm this Pull Request is not written by any AI Agent or has at least gone through additional human review AND manual testing. If any AI Agent is the co-author of this PR, it may lead to immediate closure of the PR.
  • Code review: Have you performed a self-review of your code, addressing any coding standard issues and ensuring adherence to the project's coding standards?
  • Design & Architecture: Prefer smart defaults over adding new settings; use local state for ephemeral UI logic. Open a Discussion for major architectural or UX changes.
  • Git Hygiene: Keep PRs atomic (one logical change). Clean up commits and rebase on dev to ensure no unrelated commits (e.g. from main) are included. Push updates to the existing PR branch instead of closing and reopening.
  • Title Prefix: To clearly categorize this pull request, prefix the pull request title using one of the following (...)
    • ci: Changes to our continuous integration processes or workflows
    • fix: Bug fix or error correction

Description

This PR adds a minimal CI job to detect logic errors (ruff pyflakes F category) at PR review time and resolves the 12
pre-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=F would
have 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.py had two route handlers sharing the Python identifier get_file_content_by_id (an F811 violation), causing from open_webui.routers.files import get_file_content_by_id and request.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 no
new dependency (it just enforces in CI what pre-commit already enforces locally).

The job uses --output-format=github so violations are annotated inline on the PR diff in the GitHub UI, not just
buried in the workflow log.

Added

  • .github/workflows/lint-backend-pyflakes.yaml: ruff F-only CI check, runs on every push to main/dev and on every
    PR. Job duration: ~9s.

Changed

  • routers/files.py: unified two duplicated /content handlers into a private _serve_file_content helper. Behavior
    of both endpoints (/{id}/content and /{id}/content/{file_name}) is preserved.

Deprecated

None.

Removed

None.

Fixed

  • azure.storage.blob module import in test/apps/webui/storage/test_provider.py (resolves NameError on the 3
    monkeypatch.setattr() calls).
  • 6 duplicate imports across main.py, models/messages.py, routers/audio.py, tasks.py, utils/tools.py.
  • 2 duplicate FastAPI route handler function names in routers/evaluations.py and routers/functions.py (Python
    identifiers renamed, URL paths unchanged). routers/files.py was handled separately (see "Changed").
  • routers/files.py: exception handler in file-content delivery now returns 500 for server-side errors instead of
    400.
  • routers/users.py: stale blank line that was causing format-backend.yaml to fail.

Security

None.

Breaking Changes

None.

Additional Information

Following a short summary of the commits:

  1. fix(tests): adds the missing azure.storage.blob module import in test_provider.py. Resolves the
    static error only (the surrounding test class has unrelated structural issues that are out of scope).
  2. refactor: removes 6 duplicate imports across main.py, models/messages.py, routers/audio.py, tasks.py,
    utils/tools.py (autofixed by ruff check --fix --select=F811).
  3. refactor(routers): renames duplicate route handlers in evaluations.py (get_feedbacks to
    get_feedbacks_user and get_feedbacks_list) and functions.py (second get_functions to export_functions).
    URL paths and behavior unchanged.
  4. refactor(routers/files): unifies the two get_file_content_by_id handlers (they shared the Python identifier
    but had subtly different logic). Extracted shared logic into a _serve_file_content helper; the two endpoints
    (/{id}/content and /{id}/content/{file_name}) become thin wrappers. Also fixed a HTTP status code in the
    exception handler (from 400 to 500, since the failure is server-side, not client-side).
  5. fix: runs ruff format to satisfy the existing format-backend.yaml workflow (a stale blank line in
    routers/users.py) so it will also pass the CI.
  6. ci: adds .github/workflows/lint-backend-pyflakes.yaml running ruff check --select=F (with some specific
    ignores - 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 in internal/wrappers.py);
  • F541 (empty f-strings);
  • F841 (unused variable in except blocks)

It only fails on F codes that indicate real runtime bugs:

  • F821 undefined name (the #23966 class)
  • F811 redefinition of unused names (e.g. duplicate route handlers)
  • F501-F525 format string mismatches
  • F601-F632 logic errors (is with literal etc.)
  • F701-F707 invalid break/continue/return placement

Screenshots or Videos

I've built the patched image locally and checked the impact of the commits:

  • Smoke test (commits 2, 3, 5): app boots cleanly with no import errors, login works, settings screen renders,
    knowledge base creation and file upload all functional -- all of them implicitly demonstrated in the video below.
  • Commit 4 - serving files behavior: the refactor unifies two diverged handlers, so correctness depends on
    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 exercised
    in the video since git grep confirms it has no frontend callers, only the renamed Python handler.
  • Lint check end-to-end:
    • Before any commits, running ruff check --select=F --ignore=F401,F403,F405,F541,F841 . found 12 errors
    • After all commits all checks passed!
  • Commit 6 - CI workflow on fork: triggered the new Lint Backend (Pyflakes) workflow manually on my
    fork
    . Job ran in 9s, exit 0, no annotations.

https://github.com/user-attachments/assets/57a11e77-1154-4f0a-b498-d5758990d254

Contributor License Agreement

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/24167 **Author:** [@turicas](https://github.com/turicas) **Created:** 4/27/2026 **Status:** 🔄 Open **Base:** `dev` ← **Head:** `ci/lint-backend-pyflakes` --- ### 📝 Commits (6) - [`ec6e77c`](https://github.com/open-webui/open-webui/commit/ec6e77c9ac1b92486b8c04db8c7abda1da61402d) fix(tests): add missing azure.storage.blob import - [`6024865`](https://github.com/open-webui/open-webui/commit/6024865957bd5b491bfb1be9206c470ad115e28c) refactor: remove duplicate imports using ruff - [`44ed952`](https://github.com/open-webui/open-webui/commit/44ed95288221731758f4f752a975c0541f0fe3b8) refactor(routers): rename duplicate route handlers - [`a45bdff`](https://github.com/open-webui/open-webui/commit/a45bdff75261c8313cf51429d77d3c742c6e2470) refactor(routers/files): unify duplicated handlers - [`5c86fac`](https://github.com/open-webui/open-webui/commit/5c86face30209f8796a08bf9fa86bf29a6d40bfa) fix: run ruff format (fix 'Format Backend' action) - [`326ae3d`](https://github.com/open-webui/open-webui/commit/326ae3d32666e40ceefdfd15a800561a1611d729) ci: add ruff pyflakes-only check on backend ### 📊 Changes **11 files changed** (+99 additions, -112 deletions) <details> <summary>View changed files</summary> ➕ `.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) </details> ### 📄 Description **Before submitting, make sure you've checked the following:** - [x] **Target branch:** Verify that the pull request targets the `dev` branch. - [x] **Description:** Provide a concise description of the changes made in this pull request down below. - [x] **Changelog:** Ensure a changelog entry following the format of [Keep a Changelog](https://keepachangelog.com/) is added at the bottom of the PR description. - [x] **Documentation:** N/A. - [x] **Dependencies:** No new dependencies. - [x] **Testing:** Perform manual tests to **verify the implemented fix/feature works as intended AND does not break any other functionality**. Include reproducible steps to demonstrate the issue before the fix. Test edge cases (URL encoding, HTML entities, types). Take this as an opportunity to **make screenshots of the feature/fix and include them in the PR description**. - [x] **Agentic AI Code:** Confirm this Pull Request is **not written by any AI Agent** or has at least **gone through additional human review AND manual testing**. If any AI Agent is the co-author of this PR, it may lead to immediate closure of the PR. - [x] **Code review:** Have you performed a self-review of your code, addressing any coding standard issues and ensuring adherence to the project's coding standards? - [x] **Design & Architecture:** Prefer smart defaults over adding new settings; use local state for ephemeral UI logic. Open a Discussion for major architectural or UX changes. - [x] **Git Hygiene:** Keep PRs atomic (one logical change). Clean up commits and rebase on `dev` to ensure no unrelated commits (e.g. from `main`) are included. Push updates to the existing PR branch instead of closing and reopening. - [x] **Title Prefix:** To clearly categorize this pull request, prefix the pull request title using one of the following (...) - **ci**: Changes to our continuous integration processes or workflows - **fix**: Bug fix or error correction ## Description This PR adds a minimal CI job to detect logic errors (ruff pyflakes `F` category) at PR review time and resolves the 12 pre-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=F` would have 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.py` had two route handlers sharing the Python identifier `get_file_content_by_id` (an F811 violation), causing `from open_webui.routers.files import get_file_content_by_id` and `request.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 no new dependency (it just enforces in CI what pre-commit already enforces locally). The job uses `--output-format=github` so violations are annotated inline on the PR diff in the GitHub UI, not just buried in the workflow log. ## Added - `.github/workflows/lint-backend-pyflakes.yaml`: ruff F-only CI check, runs on every push to `main`/`dev` and on every PR. Job duration: ~9s. ## Changed - `routers/files.py`: unified two duplicated `/content` handlers into a private `_serve_file_content` helper. Behavior of both endpoints (`/{id}/content` and `/{id}/content/{file_name}`) is preserved. ## Deprecated None. ## Removed None. ## Fixed - `azure.storage.blob` module import in `test/apps/webui/storage/test_provider.py` (resolves `NameError` on the 3 `monkeypatch.setattr()` calls). - 6 duplicate imports across `main.py`, `models/messages.py`, `routers/audio.py`, `tasks.py`, `utils/tools.py`. - 2 duplicate FastAPI route handler function names in `routers/evaluations.py` and `routers/functions.py` (Python identifiers renamed, URL paths unchanged). `routers/files.py` was handled separately (see "Changed"). - `routers/files.py`: exception handler in file-content delivery now returns `500` for server-side errors instead of `400`. - `routers/users.py`: stale blank line that was causing `format-backend.yaml` to fail. ## Security None. ## Breaking Changes None. ## Additional Information Following a short summary of the commits: 1. **`fix(tests)`**: adds the missing `azure.storage.blob` module import in `test_provider.py`. Resolves the static error only (the surrounding test class has unrelated structural issues that are out of scope). 2. **`refactor`**: removes 6 duplicate imports across `main.py`, `models/messages.py`, `routers/audio.py`, `tasks.py`, `utils/tools.py` (autofixed by `ruff check --fix --select=F811`). 3. **`refactor(routers)`**: renames duplicate route handlers in `evaluations.py` (`get_feedbacks` to `get_feedbacks_user` and `get_feedbacks_list`) and `functions.py` (second `get_functions` to `export_functions`). URL paths and behavior unchanged. 4. **`refactor(routers/files)`**: unifies the two `get_file_content_by_id` handlers (they shared the Python identifier but had subtly different logic). Extracted shared logic into a `_serve_file_content` helper; the two endpoints (`/{id}/content` and `/{id}/content/{file_name}`) become thin wrappers. Also fixed a HTTP status code in the exception handler (from 400 to 500, since the failure is server-side, not client-side). 5. **`fix`**: runs `ruff format` to satisfy the existing `format-backend.yaml` workflow (a stale blank line in `routers/users.py`) so it will also pass the CI. 6. **`ci`**: adds `.github/workflows/lint-backend-pyflakes.yaml` running `ruff check --select=F` (with some specific ignores - 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 in `internal/wrappers.py`); - `F541` (empty f-strings); - `F841` (unused variable in except blocks) It only fails on F codes that indicate real runtime bugs: - `F821` undefined name (the #23966 class) - `F811` redefinition of unused names (e.g. duplicate route handlers) - `F501`-`F525` format string mismatches - `F601`-`F632` logic errors (`is` with literal etc.) - `F701`-`F707` invalid `break`/`continue`/`return` placement ## Screenshots or Videos I've built the patched image locally and checked the impact of the commits: - **Smoke test (commits 2, 3, 5):** app boots cleanly with no import errors, login works, settings screen renders, knowledge base creation and file upload all functional -- all of them implicitly demonstrated in the video below. - **Commit 4 - serving files behavior:** the refactor unifies two diverged handlers, so correctness depends on 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 exercised in the video since `git grep` confirms it has no frontend callers, only the renamed Python handler. - **Lint check end-to-end:** - Before any commits, running `ruff check --select=F --ignore=F401,F403,F405,F541,F841 .` found 12 errors - After all commits all checks passed! - **Commit 6 - CI workflow on fork:** triggered the new `Lint Backend (Pyflakes)` [workflow manually on my fork](https://github.com/turicas/open-webui/actions/runs/24971160561). Job ran in 9s, exit 0, no annotations. https://github.com/user-attachments/assets/57a11e77-1154-4f0a-b498-d5758990d254 ## Contributor License Agreement <!-- 🚨 DO NOT DELETE THE TEXT BELOW 🚨 Keep the "Contributor License Agreement" confirmation text intact. Deleting it will trigger the CLA-Bot to INVALIDATE your PR. Your PR will NOT be reviewed or merged until you check the box below confirming that you have read and agree to the terms of the CLA. --> - [x] By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-06 12:43:53 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#66388