Skip to content

add C90 linting rule#536

Open
maxdorninger wants to merge 2 commits into
masterfrom
fix-c90-errors
Open

add C90 linting rule#536
maxdorninger wants to merge 2 commits into
masterfrom
fix-c90-errors

Conversation

@maxdorninger

@maxdorninger maxdorninger commented May 7, 2026

Copy link
Copy Markdown
Owner

This PR enables the C90 listing rule, which prevents too complex code.

Summary by CodeRabbit

  • Refactor
    • Improved how Jackett search queries are built for TV and movie searches, with graceful fallbacks to generic querying.
    • Reworked Torznab search-result parsing to use clearer, per-item processing while keeping existing output consistent.
    • Streamlined indexer scoring rule evaluation for more maintainable logic.
    • Tightened repository typing for schemas to better align with validation models.
  • Chores
    • Updated linting configuration to refine selected rule categories.

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 80f6468d-b35b-4517-8300-458c3ff0aea8

📥 Commits

Reviewing files that changed from the base of the PR and between ebb6cb7 and e10dfe9.

📒 Files selected for processing (1)
  • media_manager/common/repository.py
✅ Files skipped from review due to trivial changes (1)
  • media_manager/common/repository.py
📜 Recent review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (python)

📝 Walkthrough

Walkthrough

Refactors indexer parsing, query construction, and scoring into helpers, tightens repository schema typing to BaseModel, and updates Ruff rule selection.

Changes

Indexer Refactoring & Type Tightening

Layer / File(s) Summary
Type System & Config
media_manager/common/repository.py, ruff.toml
Adds EntityId = UUID | int | str, constrains BaseRepository’s schema generic to BaseModel, and updates Ruff’s extended rule selection and comment.
Torznab XML Parsing Refactoring
media_manager/indexer/indexers/torznab_mixin.py
Splits per-item search result processing into _process_item, _parse_torznab_attributes, and _add_leech_flags while keeping the same item-filtering flow.
Jackett Query Parameter Refactoring
media_manager/indexer/indexers/jackett.py
Moves TV- and movie-specific query parameter branching into dedicated helpers with the same fallback behaviour.
Indexer Scoring Rule Application Refactoring
media_manager/indexer/utils.py
Extracts title-rule and indexer-flag-rule scoring into helpers and preserves the same final score gate.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • maxdorninger/MediaManager#461: Touches media_manager/indexer/utils.py and the same scoring path, so the rule-application refactor is closely adjacent.

Poem

A rabbit hops through helper paths,
With tidy rules and gentler maths.
Query seeds and flags align,
Type bounds now sit just fine.
Soft ears twitch; the code runs clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the PR’s linting configuration change around C90.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-c90-errors

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.

@coderabbitai coderabbitai Bot added the enhancement New feature or request label May 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@media_manager/common/repository.py`:
- Line 2: Remove the now-unused module-level TypeVar import and assignment:
delete the TypeVar import from the top of the module and remove the `T =
TypeVar("T")` binding, since BaseRepository uses PEP 695 class-level type params
(`class BaseRepository[T, S: BaseModel]`) and those make the module-level `T`
and `S` TypeVar declarations dead code; ensure no other symbols reference the
removed `T` binding before committing.

In `@media_manager/indexer/indexers/jackett.py`:
- Around line 179-182: The movie query branch is incorrectly gating movie ID
params on TV capability flags; update the conditionals in the movie helper so
they check movie capabilities instead of TV ones — replace uses of
search_capabilities.supports_tv_search_tvdb with
search_capabilities.supports_movie_search_tvdb and
search_capabilities.supports_tv_search_tmdb with
search_capabilities.supports_movie_search_tmdb (keeping the param checks for
"tvdbid" and "tmdbid" and assignment to query_params["tvdbid"]/["tmdbid"]
intact) to ensure movie ID params are included when movie search support exists.

In `@media_manager/indexer/indexers/torznab_mixin.py`:
- Line 35: The code dereferences item.find("enclosure") directly (used when
setting is_usenet and later at the second occurrence), which will raise if the
enclosure node is missing; change both spots to first assign enclosure =
item.find("enclosure"), check if enclosure is None and if so log a warning
(include identifying context like item title or guid) and skip/continue that
item, otherwise access enclosure.attrib["type"] (and other attrib keys)
safely—look for the assignments to is_usenet and the later direct
enclosure.attrib usage in torznab_mixin.py and wrap them with this guard to
avoid exceptions.
- Line 83: The check for uploadvolumefactor uses int(value) which raises on
valid decimal strings like "2.0"; change the logic that currently does if
int(value) == 2 to parse as a float instead (e.g. val = float(value); if val ==
2.0) and wrap the conversion in a try/except ValueError to gracefully skip or
handle malformed values; update the comparison site that references
uploadvolumefactor/value in torznab_mixin.py so numeric decimal inputs are
accepted.

In `@media_manager/indexer/utils.py`:
- Around line 26-29: The pass/fail gate in media_manager/indexer/utils.py
currently treats query_result.score <= 0 as a failure which contradicts
downstream logic that retains score >= 0; update the condition to treat only
negative scores as failures (i.e., change the check from <= 0 to < 0 around
query_result.score) so that the function returning (query_result, True) matches
downstream filtering; keep the same return shapes (return query_result, False /
True) and adjust any nearby comments/logs referencing the threshold if present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c0cb428b-1d8c-4803-8d7d-2fa4f453d668

📥 Commits

Reviewing files that changed from the base of the PR and between 25cd4b0 and ebb6cb7.

📒 Files selected for processing (5)
  • media_manager/common/repository.py
  • media_manager/indexer/indexers/jackett.py
  • media_manager/indexer/indexers/torznab_mixin.py
  • media_manager/indexer/utils.py
  • ruff.toml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-and-push (arm64, ubuntu-24.04-arm)
  • GitHub Check: build-and-push (amd64, ubuntu-24.04)
🔇 Additional comments (3)
ruff.toml (2)

9-9: Pending-rule comment is now aligned with the config state.

Line 9 correctly removes C90 from the “to be enabled” note, which keeps the comment accurate.


12-12: C90 is correctly enabled in extend-select.

Line 12 implements the PR objective directly and cleanly.

media_manager/common/repository.py (1)

18-18: ⚡ Quick win

No action required — the project's minimum Python version (3.13) fully supports PEP 695 syntax.

The project specifies requires-python = ">=3.13" in pyproject.toml. Since PEP 695 type parameter syntax requires Python 3.12+, the code is compatible with all supported Python versions.

			> Likely an incorrect or invalid review comment.

Comment thread media_manager/common/repository.py Outdated
Comment on lines +179 to +182
elif search_capabilities.supports_tv_search_tvdb and "tvdbid" in params:
query_params["tvdbid"] = params["tvdbid"]
elif search_capabilities.supports_tv_search_tmdb and "tmdbid" in params:
query_params["tmdbid"] = params["tmdbid"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Movie query path checks TV capability flags by mistake.

At Line 179-182, the movie helper uses supports_tv_search_* flags. This can suppress valid movie ID parameters and reduce query quality.

Proposed fix
-        elif search_capabilities.supports_tv_search_tvdb and "tvdbid" in params:
+        elif search_capabilities.supports_movie_search_tvdb and "tvdbid" in params:
             query_params["tvdbid"] = params["tvdbid"]
-        elif search_capabilities.supports_tv_search_tmdb and "tmdbid" in params:
+        elif search_capabilities.supports_movie_search_tmdb and "tmdbid" in params:
             query_params["tmdbid"] = params["tmdbid"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@media_manager/indexer/indexers/jackett.py` around lines 179 - 182, The movie
query branch is incorrectly gating movie ID params on TV capability flags;
update the conditionals in the movie helper so they check movie capabilities
instead of TV ones — replace uses of search_capabilities.supports_tv_search_tvdb
with search_capabilities.supports_movie_search_tvdb and
search_capabilities.supports_tv_search_tmdb with
search_capabilities.supports_movie_search_tmdb (keeping the param checks for
"tvdbid" and "tmdbid" and assignment to query_params["tvdbid"]/["tmdbid"]
intact) to ensure movie ID params are included when movie search support exists.

is_usenet = (
item.find("enclosure").attrib["type"] != "application/x-bittorrent"
)
is_usenet = item.find("enclosure").attrib["type"] != "application/x-bittorrent"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard enclosure access before using attrib fields.

At Line 35 and Line 53, item.find("enclosure") is dereferenced directly. A missing enclosure node will raise and discard the item via the outer exception path; handle this explicitly and skip cleanly with a warning.

Proposed fix
-        is_usenet = item.find("enclosure").attrib["type"] != "application/x-bittorrent"
+        enclosure = item.find("enclosure")
+        if enclosure is None:
+            log.warning("Torznab item missing enclosure, skipping.")
+            return None
+        is_usenet = enclosure.attrib.get("type") != "application/x-bittorrent"
...
-            download_url=str(item.find("enclosure").attrib["url"]),
+            download_url=str(enclosure.attrib.get("url", "")),

Also applies to: 53-53

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@media_manager/indexer/indexers/torznab_mixin.py` at line 35, The code
dereferences item.find("enclosure") directly (used when setting is_usenet and
later at the second occurrence), which will raise if the enclosure node is
missing; change both spots to first assign enclosure = item.find("enclosure"),
check if enclosure is None and if so log a warning (include identifying context
like item title or guid) and skip/continue that item, otherwise access
enclosure.attrib["type"] (and other attrib keys) safely—look for the assignments
to is_usenet and the later direct enclosure.attrib usage in torznab_mixin.py and
wrap them with this guard to avoid exceptions.

elif name == "downloadvolumefactor":
self._add_leech_flags(float(value), flags)
elif name == "uploadvolumefactor":
if int(value) == 2:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

uploadvolumefactor parsing can fail for decimal values.

At Line 83, int(value) will fail for valid values like "2.0", which can cause items to be dropped. Parse as float and compare numerically.

Proposed fix
-                elif name == "uploadvolumefactor":
-                    if int(value) == 2:
+                elif name == "uploadvolumefactor":
+                    if float(value) == 2.0:
                         flags.append("doubleupload")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if int(value) == 2:
elif name == "uploadvolumefactor":
if float(value) == 2.0:
flags.append("doubleupload")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@media_manager/indexer/indexers/torznab_mixin.py` at line 83, The check for
uploadvolumefactor uses int(value) which raises on valid decimal strings like
"2.0"; change the logic that currently does if int(value) == 2 to parse as a
float instead (e.g. val = float(value); if val == 2.0) and wrap the conversion
in a try/except ValueError to gracefully skip or handle malformed values; update
the comparison site that references uploadvolumefactor/value in torznab_mixin.py
so numeric decimal inputs are accepted.

Comment on lines +26 to +29
if query_result.score <= 0:
return query_result, False

return query_result, True

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Non-positive pass check conflicts with downstream retention of zero-score results.

At Line 26, score 0 is marked as failed, but downstream filtering still keeps score >= 0, so zero-score entries are effectively retained despite failing. This causes inconsistent scoring behaviour and misleading logs.

Proposed fix
-    if query_result.score <= 0:
+    if query_result.score < 0:
         return query_result, False
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if query_result.score <= 0:
return query_result, False
return query_result, True
if query_result.score < 0:
return query_result, False
return query_result, True
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@media_manager/indexer/utils.py` around lines 26 - 29, The pass/fail gate in
media_manager/indexer/utils.py currently treats query_result.score <= 0 as a
failure which contradicts downstream logic that retains score >= 0; update the
condition to treat only negative scores as failures (i.e., change the check from
<= 0 to < 0 around query_result.score) so that the function returning
(query_result, True) matches downstream filtering; keep the same return shapes
(return query_result, False / True) and adjust any nearby comments/logs
referencing the threshold if present.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant