Skip to content

[Feature] Integrated Ruff linter#29

Merged
AmanatAliPanhwer merged 3 commits into
mainfrom
feat/24-add-linting-with-ruff
Nov 16, 2025
Merged

[Feature] Integrated Ruff linter#29
AmanatAliPanhwer merged 3 commits into
mainfrom
feat/24-add-linting-with-ruff

Conversation

@AmanatAliPanhwer

@AmanatAliPanhwer AmanatAliPanhwer commented Nov 16, 2025

Copy link
Copy Markdown
Owner

📌 Summary

Integrate Ruff linter into the project to enforce code style and catch common errors. This improves code quality and consistency.

🔧 Type of Change

  • 🐞 Bug fix
  • 🚀 New feature
  • 🧰 Code refactor
  • 🧾 Documentation update
  • 🎨 UI/UX enhancement

🧩 Related Issues

Closes #24

🧠 Changes Introduced

  • Added Ruff linter configuration to pyproject.toml.
  • Integrated a "Run linter" step into the CI/CD pipeline (.github/workflows/python-app.yml).
  • Fixed Ruff configuration issues in pyproject.toml (dependency group format, removed incompatible formatting options).

✅ Checklist

  • Code follows the project’s style guide (enforced by Ruff)
  • Tested locally without errors (Ruff runs successfully)
  • Documentation updated (if needed)
  • Commits are descriptive and meaningful

🧾 Additional Notes

The uv run ruff check command should now work as expected.

Summary by CodeRabbit

  • Chores

    • Added a dev tooling dependency and formatter configuration to enforce double-quote style.
    • Enhanced CI with an automated lint-and-fix step that runs formatting checks before tests.
  • Style

    • Applied consistent code and test formatting (quotes, imports, spacing) across the codebase to improve readability.

… handling

- Organized import statements for clarity
- Enhanced error messages for missing Supabase credentials
- Improved formatting and consistency in string concatenation
- Streamlined file upload and processing logic
- Added exception handling for upload errors
- Updated database status handling during file processing
@AmanatAliPanhwer AmanatAliPanhwer linked an issue Nov 16, 2025 that may be closed by this pull request
5 tasks
@vercel

vercel Bot commented Nov 16, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
blog Ready Ready Preview Comment Nov 16, 2025 8:38am

@coderabbitai

coderabbitai Bot commented Nov 16, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Added Ruff linting (dependency + format config), inserted a CI lint step, and applied project-wide stylistic formatting changes (quote-style normalization and minor reflows); no functional API changes aside from formatting and one constructor default quote normalization.

Changes

Cohort / File(s) Summary
CI / Workflow
.github/workflows/python-app.yml
Inserted a "Run linter" step that executes uv run lint placed after Playwright browser install and before the pytest step.
Linter config & deps
pyproject.toml
Added ruff>=0.14.5 to dev dependencies and added [tool.ruff.format] with quote-style = "double" and docstring-code-format = true.
Application formatting
app.py, worker.py
Project-wide quote/style normalization and reformatting. No behavioral changes; Worker.__init__ default argument uses normalized double-quote style.
Tests formatting
tests/conftest.py, tests/test_blog.py, tests/test_edit_post.py, tests/test_video.py, tests/test_video_player.py, tests/test_viewer.py
Consistent quoting, import reordering, and minor whitespace/line-break edits; test logic and assertions unchanged.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer / Push
  participant GH as GitHub Actions
  participant PB as "Install Playwright browsers"
  participant Lint as "Run linter (uv run lint)"
  participant Test as "Run pytest"

  Dev->>GH: push / open PR
  GH->>PB: install browsers
  PB-->>GH: done
  GH->>Lint: run `uv run lint`
  alt lint passes
    Lint-->>GH: success
    GH->>Test: run pytest
    Test-->>GH: results
  else lint fails
    Lint-->>GH: fail (stop CI)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus review areas:
    • .github/workflows/python-app.yml — verify the linter command and ordering in the job steps.
    • pyproject.toml — validate ruff version and [tool.ruff.format] keys are valid for the installed Ruff version.
    • worker.py — confirm the __init__ parameter formatting change didn't inadvertently alter callers.

Possibly related PRs

  • Create python-app.yml #14 — Modified the GitHub Actions Python workflow to add CI linting (used flake8); related because both change CI lint steps.

Poem

🐰 I hopped through lines with gentle paws,

Double quotes set tidy laws,
Ruff trimmed edges, neat and bright,
CI checks through day and night,
I nibble whitespace — code just right.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The PR description follows the template structure with all major sections completed (Summary, Type of Change, Related Issues, Changes Introduced, Checklist, Additional Notes) and clearly explains the Ruff integration effort.
Linked Issues check ✅ Passed The PR addresses all key objectives from issue #24: adds Ruff to dev dependencies, provides configuration in pyproject.toml, integrates into CI/CD pipeline, and runs initial lint pass fixing style issues across the codebase.
Out of Scope Changes check ✅ Passed All changes are scoped to Ruff integration and style enforcement as defined in issue #24. The code refactoring (quoting, formatting, imports) across app.py, worker.py, and test files are direct results of running the Ruff linter as required.
Title check ✅ Passed The title '[Feature] Integrated Ruff linter' directly matches the main change: integrating Ruff linter configuration and CI workflow setup for code style enforcement.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/24-add-linting-with-ruff

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AmanatAliPanhwer AmanatAliPanhwer marked this pull request as ready for review November 16, 2025 07:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app.py (1)

317-378: Day filter window uses the wrong year/month variables (date‑range bug)

In the /filter route’s day filter, the upper bound is built using current_year/current_month instead of next_year_for_day/next_month_for_day. For dates at or near the end of a month (or year), this can produce an upper bound earlier than the lower bound and yield no results.

For example, filtering on day "31" of a 31‑day month will set next_day = 1 and next_month_for_day = current_month + 1, but the lt(...) boundary still uses current_month, so the interval becomes inconsistent.

I recommend constructing the range using actual datetime arithmetic. For instance:

-        if day != "any":
-            current_year = year if year != "any" else str(datetime.now().year)
-            current_month = month if month != "any" else str(datetime.now().month)
-            next_day = int(day) + 1
-            next_month_for_day = int(current_month)
-            next_year_for_day = int(current_year)
-            if next_day > 28:
-                try:
-                    datetime(int(current_year), int(current_month), next_day)
-                except ValueError:
-                    next_day = 1
-                    next_month_for_day += 1
-                    if next_month_for_day > 12:
-                        next_month_for_day = 1
-                        next_year_for_day += 1
-
-            query = query.gte(
-                TIMESTAMP_FIELD,
-                f"{current_year}-{current_month.zfill(2)}-{day.zfill(2)}T00:00:00Z",
-            ).lt(
-                TIMESTAMP_FIELD,
-                f"{current_year}-{current_month.zfill(2)}-{str(next_day).zfill(2)}T00:00:00Z",
-            )
+        if day != "any":
+            current_year = int(year) if year != "any" else datetime.now().year
+            current_month = int(month) if month != "any" else datetime.now().month
+            current_day = int(day)
+
+            start_dt = datetime(current_year, current_month, current_day)
+            end_dt = start_dt + timedelta(days=1)
+
+            query = query.gte(
+                TIMESTAMP_FIELD,
+                start_dt.strftime("%Y-%m-%dT%H:%M:%SZ"),
+            ).lt(
+                TIMESTAMP_FIELD,
+                end_dt.strftime("%Y-%m-%dT%H:%M:%SZ"),
+            )

This avoids manual calendar edge cases entirely.

🧹 Nitpick comments (12)
.github/workflows/python-app.yml (1)

41-42: Ensure uv run lint is wired to an actual command/script

The workflow assumes a lint entrypoint exists; if there’s no [project.scripts] (or equivalent) defining lint, this step will fail at runtime. Please confirm there is a lint script configured (e.g., wrapping ruff check .), or consider calling uv run ruff check . directly here.

pyproject.toml (1)

20-29: Ruff integration looks good; consider centralizing lint rules

Adding ruff>=0.14.5 to dev and the basic [tool.ruff.format] section is fine and consistent with the rest of the PR. As a follow-up (optional), you might add a [tool.ruff.lint] section (e.g., select, ignore, line-length) so lint configuration is explicit and version-controlled rather than relying on defaults.

app.py (7)

28-33: Hard‑coded timezone in get_local_timestamp

get_local_timestamp is fixed to "Asia/Karachi". If you ever need to deploy this app in other regions or make it configurable per environment, consider driving the timezone from an environment variable (with "Asia/Karachi" as a default) instead of hard-coding it.


99-127: Dynamic timestamp field resolution is robust but runs at import time

The resolve_timestamp_field() helper is a nice way to adapt to schema differences and has a sensible fallback to "timestamp". Just be aware it runs at import time and does a live Supabase query; if environment variables are misconfigured or Supabase is temporarily unavailable, importing app.py will log errors and still fall back to "timestamp". That’s fine for this app, but if you later move toward more structured startup/health-check flows, this logic might belong in an explicit initialization phase.


179-207: Home route timestamp/video handling looks correct and defensive

The updated home() route wiring — dynamic select_fields, safe parsing with dateutil.parser, and separate video lookup with .single() — is consistent and has sensible fallbacks for failures. The Markup(post.get("content", "")) usage is appropriate given content is admin-authored; just keep in mind this trusts HTML from your DB, so if you ever allow untrusted authors you’ll want explicit sanitization.


256-303: Year/month/day aggregation queries are fine but could be reduced

The logic to build available_years, available_months, and available_days via three separate ordered queries works and is easy to follow. If this ever shows up in profiles as a hot path, you could reduce trips to Supabase by deriving these from a single query or by caching the results for some TTL, but that’s an optimization rather than a requirement.


490-517: Persistent login cookie lacks security attributes

The “remember me” cookie is functional, but it’s being set without httponly, secure, or samesite flags, which weakens your auth posture (particularly if you ever serve over HTTPS and/or are concerned about CSRF and XSS).

Consider tightening this:

-                    response.set_cookie("remember_me", token, max_age=30 * 24 * 60 * 60)
+                    response.set_cookie(
+                        "remember_me",
+                        token,
+                        max_age=30 * 24 * 60 * 60,
+                        httponly=True,
+                        secure=True,  # if you’re serving over HTTPS
+                        samesite="Lax",
+                    )

and mirroring these attributes when deleting the cookie.


901-939: Admin inspect endpoint and key masking look good; consider logging level

The /admin/inspect route’s key masking and summary info (supabase_url, masked key, bucket, max_id, counts) look sensible and gated on "admin" in session. If you ever add structured logging, consider emitting these diagnostics via a logger rather than relying solely on JSON responses or print, but the current behavior is acceptable for an admin diagnostics page.


942-947: Mismatch between upload storage path and Worker’s temp directory

Here you serve from "tmp/uploads" (relative), while Worker writes video files under "/tmp/uploads" (absolute). If you expect /uploads/<filename> to serve files written by Worker, these two paths won’t line up on most systems.

Either align the paths (e.g., both use /tmp/uploads) or derive from a shared config constant to avoid drift.

worker.py (2)

65-83: Broad exception in _upload_folder_to_supabase

Catching a bare Exception and just print‑ing the error is acceptable for a best‑effort helper, but it does make it harder to detect and retry partial failures. Consider at least logging which files failed (you already do) and optionally surfacing a summary back to the caller (e.g., a list of failed paths) so callers can decide whether to treat the operation as fatal.


86-128: Add timeout and cleanup to video processing HTTP call

_process_file does the right thing in terms of status transitions (“processing” → “processed”/“failed”) and cleanup on Supabase, but a couple of operational improvements would help:

  • requests.post(...) has no timeout, so a hung external service can stall the worker indefinitely.
  • The local temp file under /tmp/uploads is never removed, so repeated processing can slowly fill the filesystem.

Consider something like:

-            with open(video_file_path, "rb") as video:
-                res = requests.post(
-                    f"https://ffmpeg.pythonanywhere.com/upload/{file_id}",
-                    files={"file": video},
-                )
+            with open(video_file_path, "rb") as video:
+                res = requests.post(
+                    f"https://ffmpeg.pythonanywhere.com/upload/{file_id}",
+                    files={"file": video},
+                    timeout=60,
+                )
@@
-        except Exception as e:
-            self.supabase_client.table("videos").update({"status": "failed"}).eq(
-                "id", file_id
-            ).execute()
-            raise RuntimeError(f"Error processing file: {e}")
+        except Exception as e:
+            self.supabase_client.table("videos").update({"status": "failed"}).eq(
+                "id", file_id
+            ).execute()
+            raise RuntimeError(f"Error processing file: {e}")
+        finally:
+            try:
+                os.remove(video_file_path)
+            except OSError:
+                pass

This keeps behavior the same while avoiding indefinite hangs and temp‑file buildup.

tests/conftest.py (1)

21-45: Process startup logic is fine; watch shell=True on Windows

The flask_app_url fixture’s process startup logic looks reasonable and isolates test env via a copied env dict. Using shell=True with a constant command on Windows is acceptable here, but if you ever start interpolating user or configuration input into that command, it would be safer to switch to a direct argv invocation without shell=True.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0255bbf and ef5496b.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • .github/workflows/python-app.yml (1 hunks)
  • app.py (9 hunks)
  • pyproject.toml (1 hunks)
  • tests/conftest.py (3 hunks)
  • tests/test_blog.py (9 hunks)
  • tests/test_edit_post.py (9 hunks)
  • tests/test_video.py (2 hunks)
  • tests/test_video_player.py (6 hunks)
  • tests/test_viewer.py (4 hunks)
  • worker.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
app.py (2)
worker.py (3)
  • Worker (11-128)
  • save_file (30-50)
  • queue_file (52-63)
static/js/script.js (4)
  • response (16-20)
  • response (27-31)
  • data (21-21)
  • data (32-32)
tests/test_video.py (2)
tests/test_video_player.py (1)
  • validate_test_video_file (9-19)
tests/conftest.py (3)
  • flask_app_url (18-67)
  • page (71-76)
  • admin_logged_in_page (81-90)
tests/test_blog.py (1)
tests/conftest.py (2)
  • page (71-76)
  • flask_app_url (18-67)
tests/test_edit_post.py (1)
tests/conftest.py (3)
  • page (71-76)
  • flask_app_url (18-67)
  • admin_logged_in_page (81-90)
tests/test_video_player.py (1)
tests/conftest.py (2)
  • page (71-76)
  • flask_app_url (18-67)
tests/test_viewer.py (1)
tests/conftest.py (3)
  • page (71-76)
  • flask_app_url (18-67)
  • admin_logged_in_page (81-90)
🪛 Ruff (0.14.4)
app.py

174-174: Do not catch blind exception: Exception

(BLE001)


198-198: Do not catch blind exception: Exception

(BLE001)


240-240: Do not catch blind exception: Exception

(BLE001)


247-247: Unsafe use of markupsafe.Markup detected

(S704)


303-303: Do not catch blind exception: Exception

(BLE001)


383-383: Do not catch blind exception: Exception

(BLE001)


417-417: Unsafe use of markupsafe.Markup detected

(S704)


476-476: Do not catch blind exception: Exception

(BLE001)


517-517: Do not catch blind exception: Exception

(BLE001)


540-540: Do not catch blind exception: Exception

(BLE001)


576-576: Do not catch blind exception: Exception

(BLE001)


592-592: Do not catch blind exception: Exception

(BLE001)


649-649: Do not catch blind exception: Exception

(BLE001)


664-664: Do not catch blind exception: Exception

(BLE001)


686-686: Do not catch blind exception: Exception

(BLE001)


721-721: Do not catch blind exception: Exception

(BLE001)


748-748: Do not catch blind exception: Exception

(BLE001)


761-761: Do not catch blind exception: Exception

(BLE001)


806-806: Do not catch blind exception: Exception

(BLE001)


813-813: Do not catch blind exception: Exception

(BLE001)


857-857: Do not catch blind exception: Exception

(BLE001)


882-882: Do not catch blind exception: Exception

(BLE001)


890-890: Unsafe use of markupsafe.Markup detected

(S704)


930-930: Do not catch blind exception: Exception

(BLE001)


936-936: Do not catch blind exception: Exception

(BLE001)


958-958: Do not catch blind exception: Exception

(BLE001)

tests/test_video.py

13-15: Avoid specifying long messages outside the exception class

(TRY003)

tests/conftest.py

31-31: subprocess call with shell=True identified, security issue

(S602)


32-32: Starting a process with a partial executable path

(S607)


40-40: Starting a process with a partial executable path

(S607)


62-62: subprocess call: check for execution of untrusted input

(S603)


63-63: Starting a process with a partial executable path

(S607)

tests/test_video_player.py

15-17: Avoid specifying long messages outside the exception class

(TRY003)

worker.py

13-13: Probable insecure usage of temporary file or directory: "/tmp"

(S108)


22-24: Avoid specifying long messages outside the exception class

(TRY003)


83-83: Do not catch blind exception: Exception

(BLE001)


94-94: Avoid specifying long messages outside the exception class

(TRY003)


109-109: Probable use of requests call without timeout

(S113)


117-117: Abstract raise to an inner function

(TRY301)


117-117: Avoid specifying long messages outside the exception class

(TRY003)


124-124: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (8)
app.py (1)

949-965: Main entrypoint is robust and consistent

The main guard’s use of HOST/PORT environment variables, explicit threaded=True, and the structured error handling with traceback.print_exc() and sys.exit(1) is solid. No issues here.

worker.py (1)

11-28: Worker initialization and scheduler wiring look good

The Worker constructor’s upload folder setup, APScheduler background scheduler, and Supabase client creation are coherent. The explicit check for missing SUPABASE_URL/SUPABASE_KEY with a ValueError should fail fast in misconfigured environments, which is helpful.

tests/conftest.py (1)

79-90: Admin login fixture matches app behavior

The admin_logged_in_page fixture correctly drives the login form using the same environment variables as the app (ADMIN_USERNAME/ADMIN_PASSWORD) and asserts redirection to /. This is a good end‑to‑end check of the login flow and will catch regressions around the credentials screen.

tests/test_video_player.py (1)

1-131: Formatting improvements align with Ruff integration.

The import reordering, quote standardization, and whitespace adjustments throughout this file successfully align with the configured Ruff style. All changes are non-functional and improve consistency.

tests/test_video.py (1)

1-158: Formatting improvements align with Ruff integration.

The import reordering, quote standardization, multi-line assertion formatting, and spacing adjustments successfully align with the configured Ruff style. All changes maintain test functionality while improving code consistency.

tests/test_blog.py (1)

1-179: Formatting improvements align with Ruff integration.

The import spacing, quote standardization to double quotes, and multi-line formatting adjustments (including the PNG byte literal and URL regex expectation) successfully align with the configured Ruff style. All changes are non-functional and improve consistency across the test suite.

tests/test_viewer.py (1)

1-112: Formatting improvements align with Ruff integration.

The import spacing, multi-line locator formatting (lines 84-86), and whitespace adjustments successfully align with the configured Ruff style. All changes are non-functional and improve consistency.

tests/test_edit_post.py (1)

1-152: Formatting improvements align with Ruff integration.

The import spacing, PNG byte literal multi-line formatting (lines 87-89, 113-115), function signature wrapping (lines 103-105), and other whitespace adjustments successfully align with the configured Ruff style. All changes are non-functional and improve consistency across the test suite.

Comment thread app.py
Comment thread app.py
Comment thread tests/conftest.py
@AmanatAliPanhwer AmanatAliPanhwer changed the title Refactor Worker class in worker.py for improved readability and error… [Feature] Integrated Ruff linter Nov 16, 2025
@AmanatAliPanhwer AmanatAliPanhwer merged commit 4409646 into main Nov 16, 2025
3 of 4 checks passed
@AmanatAliPanhwer AmanatAliPanhwer deleted the feat/24-add-linting-with-ruff branch November 16, 2025 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add linting with Ruff

1 participant