Skip to content

chore: bump pre-commit hooks and apply lint cleanup#4701

Draft
rnetser wants to merge 2 commits intoRedHatQE:mainfrom
rnetser:chore/pre-commit-lint-cleanup
Draft

chore: bump pre-commit hooks and apply lint cleanup#4701
rnetser wants to merge 2 commits intoRedHatQE:mainfrom
rnetser:chore/pre-commit-lint-cleanup

Conversation

@rnetser
Copy link
Copy Markdown
Collaborator

@rnetser rnetser commented May 3, 2026

What this PR does / why we need it:

Replaces #4424 with a cleaner set of pre-commit and lint changes.

Hook bumps:

  • ruff v0.15.1 → v0.15.12
  • mypy v1.20.0 → v1.20.2

Ignore rules added to prevent CI failures from pre-existing code:

  • pyproject.toml (ruff): preview rules exposed by v0.15.12 that need per-file refactoring (DTZ, BLE001, PYI, SIM, TRY, PLW, EXE, PERF, etc.)
  • .flake8: rules now handled by ruff (N815, N802, E501, F821, E201, W503, N818) — prevents ruff/flake8 conflicts on # noqa comments

Code fixes applied (safe, auto-fixable):

  • Remove obsolete # -*- coding: utf-8 -*- headers (UP009)
  • Remove stale # noqa comments no longer needed by ruff v0.15.12
  • Fix root logger usage: logging.error()LOGGER.error() (LOG015)
  • Ruff formatting adjustments

Assisted-by: Claude noreply@anthropic.com

Which issue(s) this PR fixes:

Replaces #4424

Special notes for reviewer:

The ignored rules represent pre-existing issues exposed by ruff v0.15.12 preview mode — each should be addressed in dedicated follow-up PRs. pre-commit.ci runs on ALL files (not just changed), so all pre-existing violations must be either fixed or ignored.

jira-ticket:

Signed-off-by: Ruth Netser rnetser@redhat.com

Summary by CodeRabbit

  • Bug Fixes

    • Fixed exception handling and control flow in backup and network functionality
    • Corrected crypto policy and conflict detection logic in tests
    • Improved HTTP archive download efficiency
  • Chores

    • Modernized type annotations and imports throughout codebase
    • Updated pre-commit hook versions and linting configuration
    • Removed deprecated encoding declarations and code style comments
    • Simplified dictionary iteration patterns and conditional logic

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

📝 Walkthrough

Walkthrough

Modernized Python typings/imports and lint configs across the repository (PEP 604 unions, built-in generics, move Generator to collections.abc, remove inline noqa/encoding headers), bumped pre-commit hook versions, and added a new session-scoped network sanity autouse fixture for network test prerequisites.


Changes

Type & Lint Modernization

Layer / File(s) Summary
Linting configuration
.flake8, pyproject.toml, .pre-commit-config.yaml
Added Ruff/Flake8 ignore lists and bumped pre-commit hook revisions (ruff-pre-commit v0.15.1→v0.15.12, mirrors-mypy v1.20.0→v1.20.2`).
Forward-ref / concrete types
libs/net/traffic_generator.py, libs/net/netattachdef.py, libs/storage/config.py, utilities/oadp.py, tests/infrastructure/vm_console_proxy/utils.py
Replaced string forward-reference annotations with direct types and replaced Type with type where applicable.
Generator / typing import consolidation
many tests/*, utilities/*, libs/* (e.g., tests/utils.py, utilities/infra.py, utilities/storage.py, tests/storage/*, tests/network/*)
Switched Generator imports from typing to collections.abc; removed Dict/List/Optional in favor of built-in dict[...]/list[...] and `X
Noqa / encoding cleanup
libs/vm/spec.py, many tests/global_config_*.py, multiple test modules
Removed inline # noqa directives and removed # -*- coding: utf-8 -*- headers; class declarations modernized (e.g., class X(object)class X).
Type-only lightweight edits
libs/net/netattachdef.py, libs/storage/config.py, utilities/virt.py
Minor annotation changes (e.g., list["IpamStatic.Address"]list[IpamStatic.Address]; Optional[int] → `int

Network Sanity & Fixtures

Layer / File(s) Summary
New network fixtures
tests/network/conftest.py
Introduced comprehensive session-scoped fixtures (cluster MTU, hardware MTU, network overhead, OVN detection, virt-handler pod, SR-IOV worker selection, VLAN index helpers) and helper get_index_number()/index_number() fixtures.
Autouse sanity gate
tests/network/conftest.py
Added autouse, session-scoped network_sanity fixture that inspects collected tests' markers, validates cluster capabilities (multi-NIC, SR-IOV operator/policy, at least two SR-IOV workers, DPDK, service-mesh, jumbo-frame MTU threshold, IPv4/IPv6 support, nmstate pods, MTV operator), aggregates failures, and exits pytest with return code 91 and JUnit XML when prerequisites fail.
Network dataclasses & helpers
tests/network/libs/cluster_user_defined_network.py, tests/network/*
Added `routeTarget: str

Behavioral & Quality Adjustments (scattered)

Layer / File(s) Summary
Container membership / iteration simplifications
many tests/*, utilities/*, scripts/*
Replaced .keys()/.items() patterns with direct in dict membership or direct iteration; adjusted a few comprehensions to iterate .items() when clearer.
Datetime UTC standardization
tests/conftest.py, tests/observability/*, tests/storage/test_cdi_certificate.py
Replaced timezone.utc with UTC from datetime for uniform timestamp handling.
Exception / logging refinements
tests/infrastructure/vm_console_proxy/utils.py, utilities/operator.py, tests/virt/cluster/longevity_tests/utils.py, tests/network/provider_migration/libprovider.py
Improved logging before re-raising, corrected exception types, and clarified control flow for some error raises.
I/O streaming optimization
utilities/infra.py, utilities/storage.py
Replaced per-chunk write loops with writelines(created_request.iter_content(...)) for streamed downloads.
Small test fixes/refactors
various tests/install_upgrade_operators/*, tests/virt/*
Corrected iteration/lookup bugs in a few tests, simplified assertions and message formatting; removed redundant list/set wrappers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@codecov
Copy link
Copy Markdown

codecov Bot commented May 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.67%. Comparing base (b4ad2e0) to head (6c55700).
⚠️ Report is 118 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4701      +/-   ##
==========================================
+ Coverage   98.63%   98.67%   +0.03%     
==========================================
  Files          25       25              
  Lines        2420     2483      +63     
==========================================
+ Hits         2387     2450      +63     
  Misses         33       33              
Flag Coverage Δ
utilities 98.67% <100.00%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@openshift-virtualization-qe-bot
Copy link
Copy Markdown

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: A tracking issue is created for this PR and will be closed when the PR is merged or closed
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified
  • Labels: Enabled categories: branch, can-be-merged, cherry-pick, has-conflicts, hold, needs-rebase, size, verified, wip

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)
  • /regenerate-welcome - Regenerate this welcome message

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest verify-bugs-are-open - verify-bugs-are-open
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. LGTM Count: Minimum 2 /lgtm from reviewers
  3. Status Checks: All required status checks must pass
  4. No Blockers: No wip, hold, has-conflicts labels and PR must be mergeable (no conflicts)
  5. Verified: PR must be marked as verified

📊 Review Process

Approvers and Reviewers

Approvers:

  • EdDev
  • dshchedr
  • jpeimer
  • myakove
  • rnetser
  • vsibirsk

Reviewers:

  • Ahmad-Hafe
  • Anatw
  • EdDev
  • OhadRevah
  • RoniKishner
  • SamAlber
  • acinko-rh
  • akri3i
  • albarker-rh
  • azhivovk
  • dalia-frank
  • dshchedr
  • ema-aka-young
  • frenzyfriday
  • geetikakay
  • hmeir
  • josemacassan
  • jpeimer
  • kbidarkar
  • kgoldbla
  • kshvaika
  • mijankow
  • nirdothan
  • orelmisan
  • qwang1
  • rlobillo
  • rnetser
  • sarahbx
  • servolkov
  • vsibirsk
  • yossisegev
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
AI Features
  • Cherry-Pick Conflict Resolution: Enabled (claude/claude-opus-4-6[1m])

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is removed on new commits unless the push is detected as a clean rebase
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@openshift-virtualization-qe-bot
Copy link
Copy Markdown

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

@openshift-virtualization-qe-bot
Copy link
Copy Markdown

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

@openshift-virtualization-qe-bot
Copy link
Copy Markdown

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

1 similar comment
@openshift-virtualization-qe-bot-2
Copy link
Copy Markdown
Contributor

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

@openshift-virtualization-qe-bot-3
Copy link
Copy Markdown
Contributor

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

1 similar comment
@openshift-virtualization-qe-bot-2
Copy link
Copy Markdown
Contributor

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

@openshift-virtualization-qe-bot-3
Copy link
Copy Markdown
Contributor

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

@openshift-virtualization-qe-bot-3
Copy link
Copy Markdown
Contributor

/retest all

Auto-triggered: Files in this PR were modified by merged PR #4584.

Overlapping files

tests/global_config_multiarch.py

rnetser and others added 2 commits May 3, 2026 15:36
Bump pre-commit hooks:
- ruff v0.15.1 → v0.15.12
- mypy v1.20.0 → v1.20.2

Add ignore rules for ruff preview rules needing separate fixes
(DTZ, BLE001, PYI, SIM102/114/117, PLW, F821, etc) and flake8
rules now handled by ruff (N815, N802, E501, F821, E201, W503,
N818).

Apply safe fixes repo-wide:
- Remove obsolete utf-8 coding headers (UP009)
- Remove stale noqa comments (including F821 in global_config files)
- Simplify dict patterns (SIM118, PLC0206, PERF102)
- Simplify comparisons (SIM201)
- Remove unnecessary wrappers (C403, C408, C414)
- Use f-strings (UP031)
- Extract default arg function call (B008)
- Fix root logger usage (LOG015)
- Ruff formatting

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: rnetser <rnetser@redhat.com>
@rnetser
Copy link
Copy Markdown
Collaborator Author

rnetser commented May 3, 2026

@coderabbitai[bot]

The following review comments were reviewed and a decision was made:

tests/network/provider_migration/libprovider.py:16 (outside diff) — Move the long error message into IfaceNotFoundError to resolve Ruff TRY003.

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

utilities/sanity.py:297 (outside diff) — Preserve stack trace with from clause when re-raising

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

utilities/sanity.py:198 (outside diff) — Replace bare Exception catch with specific exception types

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

tests/virt/upgrade/utils.py:88 (outside diff) — HIGH: Fix timezone-naive datetime.strptime() comparisons rather than suppressing DTZ007.

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

utilities/unittests/test_pytest_matrix_utils.py:295 (outside diff) — LOW: immediate_matrix missing from TestMatrixFunctionSignatures

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

utilities/unittests/test_pytest_matrix_utils.py:127 (outside diff) — CRITICAL: Wrong @patch target for cache_admin_client — test will fail

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

tests/global_config_s390x.py:28 (outside diff) — Inconsistent F821 suppression removal.

Addressed: Fixed — removed remaining F821 noqa suppressions for consistency since F821 is now globally ignored.

tests/global_config_oci.py:38 (outside diff) — Inconsistent F821 suppression removal.

Addressed: Fixed — removed remaining F821 noqa suppressions for consistency since F821 is now globally ignored.

tests/global_config_ibm_spectrum_sc.py:27 (outside diff) — Inconsistent F821 suppression removal.

Addressed: Fixed — removed remaining F821 noqa suppressions for consistency since F821 is now globally ignored.

tests/observability/metrics/test_vms_metrics.py:47 (outside diff) — Add an explicit return None (or raise) when READY condition is absent.

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

.pre-commit-config.yaml:1 (outside diff) — HIGH: Restore required PR template sections in the PR description.

Not addressed: The PR description already contains all required template sections (What/Why, Issues, Notes, Jira). They are present in the GitHub PR.

tests/observability/metrics/utils.py:370 (outside diff) — HIGH: Boolean accumulator can hide a later RX/TX mismatch

Not addressed: This is a pre-existing code pattern, not introduced by this PR. Out of scope for a lint cleanup PR — should be addressed in a dedicated follow-up.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

Tip

For best results, initiate chat on the files or code changes.

@rnetser Thanks for the thorough triage! Here's a summary of how I'm processing each decision:

✅ Resolved (Addressed):

  • tests/global_config_s390x.py:28, tests/global_config_oci.py:38, tests/global_config_ibm_spectrum_sc.py:27 — F821 noqa consistency fixed. I'll mark these resolved.

🔁 Deferred (Pre-existing, out of scope):
All 8 "Not addressed" items are acknowledged as pre-existing patterns. I've noted these for future reviews.

⚠️ One item worth flagging:
The utilities/unittests/test_pytest_matrix_utils.py:127 — wrong @patch target for cache_admin_client — was rated CRITICAL because it means the test may not actually mock what it intends to, potentially passing when it shouldn't. Even though it's pre-existing, would you like me to open a follow-up issue to track the fix? It's a quick targeted fix and the risk of silent test misvalidation is real.

[resolve]


✏️ Learnings added
Learnt from: rnetser
URL: https://github.com/RedHatQE/openshift-virtualization-tests/pull/4701

Timestamp: 2026-05-03T15:38:39.584Z
Learning: In the RedHatQE/openshift-virtualization-tests repository, lint cleanup PRs (e.g. pre-commit hook bumps with ruff/mypy) should NOT be asked to fix pre-existing code patterns that are outside the diff. Issues like bare `except Exception`, missing `raise ... from`, timezone-naive datetime comparisons, implicit `return None`, TRY003 long error messages in exceptions, and boolean accumulator logic in utility functions are pre-existing and should only be addressed in dedicated follow-up PRs, not in automated lint-cleanup PRs.

Learnt from: rnetser
URL: https://github.com/RedHatQE/openshift-virtualization-tests/pull/4701

Timestamp: 2026-05-03T15:38:39.584Z
Learning: In the RedHatQE/openshift-virtualization-tests repository, when F821 (undefined name) is globally suppressed via flake8/ruff ignore rules, all inline `# noqa: F821` comments across all `tests/global_config_*.py` files should be removed for consistency.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@openshift-virtualization-qe-bot-2
Copy link
Copy Markdown
Contributor

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

1 similar comment
@openshift-virtualization-qe-bot-5
Copy link
Copy Markdown

qwang1 can not be added as reviewer. Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.: 422 {"message": "Reviews may only be requested from collaborators. One or more of the users or teams you specified is not a collaborator of the RedHatQE/openshift-virtualization-tests repository.", "documentation_url": "https://docs.github.com/rest/pulls/review-requests#request-reviewers-for-a-pull-request", "status": "422"}

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 (8)
tests/global_config_s390x.py (1)

28-37: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: Initialize config before first read to prevent undefined-name failure

if not config: on Line 28 reads config before it is defined in-module, which triggers Ruff F821 and can raise NameError depending on import context. This breaks lint stability for this cleanup PR.

Proposed fix
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
+config: dict[str, Any] = globals().get("config", {})
+
+for _dir in dir():
     val = locals()[_dir]
     if type(val) not in [bool, list, dict, str]:
         continue
@@
-    config[_dir] = locals()[_dir]
+    config[_dir] = val

As per coding guidelines "**/*.py: NEVER add # noqa ... If a linter complains, fix the code instead."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config_s390x.py` around lines 28 - 37, The code reads the
variable config before it's defined causing a NameError/linter F821; initialize
config at the top of this block and remove the pre-read check: ensure config is
declared as an empty dict (e.g., config: dict[str, Any] = {}) before any use,
then replace the `if not config:` guard with logic that uses the existing config
(or a simple existence check like `if config is None:` only if you intend None
as a sentinel), and keep the rest of the loop that inspects locals()[_dir], the
type check, the skip for `encoding`/`py_file`, and the assignment `config[_dir]
= locals()[_dir]` intact so subsequent uses of config are safe.
tests/global_config.py (1)

252-262: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: Fix undefined config access at module load

Line 252 references config before guaranteed initialization, which triggers F821 and can break when no injected global exists.

Proposed fix
+config: dict[str, Any] = {}
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
     val = locals()[_dir]
     if type(val) not in [bool, list, dict, str, int, set]:
         continue
@@
     if _dir in ["encoding", "py_file"]:
         continue
 
     config[_dir] = locals()[_dir]

As per coding guidelines: "**/*.py: NEVER add # noqa... If a linter complains, fix the code instead."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config.py` around lines 252 - 262, The code reads the name
`config` before ensuring it exists (the `if not config:` check can raise
NameError/F821); initialize or reference it safely before use: check presence
via `"config" in locals()` or use `locals().get("config")` and only assign
`config = {}` if missing/falsey, then proceed to use `config` when populating
entries for `_dir`; update the block around `_dir`/locals() to use a safe lookup
(e.g., use locals().get("_dir") and locals().get("config")) and ensure `config`
is defined as a dict prior to adding keys so symbols like `config`, `_dir`, and
the locals() access are robust at module load.
tests/global_config_ibm_spectrum_sc.py (1)

27-36: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: config is read before guaranteed initialization

Line 27 hits an undefined-name path (if not config) before a reliable assignment. This is lint-visible (F821) and environment-sensitive.

Proposed fix
+config: dict[str, Any] = {}
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
     val = locals()[_dir]
     if type(val) not in [bool, list, dict, str]:
         continue
@@
     if _dir in ["encoding", "py_file"]:
         continue
 
     config[_dir] = locals()[_dir]

As per coding guidelines: "**/*.py: NEVER add # noqa... If a linter complains, fix the code instead."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config_ibm_spectrum_sc.py` around lines 27 - 36, The code reads
variable config before it's guaranteed to exist, causing a potential NameError;
initialize config before the "if not config" check (e.g., ensure config = {} is
assigned earlier) or replace the check with a safe existence test like "'config'
in locals() and config" so the subsequent use of config and assignments to
config[_dir] are always valid; update the block that references config,
locals()[_dir], and _dir (the surrounding loop/section) to ensure config is
defined prior to any reads and then proceed with the existing type checks and
assignments.
tests/global_config_rh_it.py (1)

30-39: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: Initialize config explicitly before first read

Line 30 reads config before guaranteed initialization, which is why Ruff reports F821 and why this pattern is brittle outside injected contexts.

Proposed fix
+config: dict[str, Any] = {}
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
     val = locals()[_dir]
     if type(val) not in [bool, list, dict, str]:
         continue
@@
     if _dir in ["encoding", "py_file"]:
         continue
 
     config[_dir] = locals()[_dir]

As per coding guidelines: "**/*.py: NEVER add # noqa... If a linter complains, fix the code instead."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config_rh_it.py` around lines 30 - 39, The code reads the
variable config before it is guaranteed to exist, causing F821; fix by ensuring
config is initialized before any reads/conditionals that reference it (e.g.,
assign a default dict to config if it's not already defined in locals() or use
config = globals().get('config', {}) before the existing if-not-config check).
Update references around the config variable and the loop using _dir and
locals() so that config is always a dict before you do "if not config" or
"config[_dir] = ..."; ensure you remove the inline type-only assignment pattern
and instead create a real initialized dict for config.
tests/global_config_interop.py (1)

10-19: ⚠️ Potential issue | 🟠 Major

HIGH: config is read before initialization (line 10), causing NameError.

The global config declaration doesn't create the variable—it only marks it as global. Since config is never assigned before the loop starts, line 10's if not config: will raise a NameError at runtime. Initialize config once before the loop:

Proposed fix
 global config
 global_config = pytest_testconfig.load_python(py_file="tests/global_config.py", encoding="utf-8")
 
+config: dict[str, Any] = {}
 
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
     val = locals()[_dir]

Per coding guidelines: NEVER add # noqa or linter suppressions—fix the code instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config_interop.py` around lines 10 - 19, The code reads config
before it's initialized causing a NameError; initialize config once before the
loop (ensure a top-level assignment like config = {} before any use) and then
remove the conditional `if not config:` inside the loop, keeping the rest of the
logic that checks `val = locals()[_dir]`, the type filter `if type(val) not in
[bool, list, dict, str]: continue`, the exclusions `if _dir in ["encoding",
"py_file"]: continue`, and the assignment `config[_dir] = locals()[_dir]` so
that `config` is always defined when referenced.
tests/global_config_multiarch.py (1)

57-66: ⚠️ Potential issue | 🟠 Major

HIGH: config is accessed at line 57 before initialization, causing NameError at runtime.

The global variable config is declared at line 17 but never initialized. The conditional check if not config: at line 57 attempts to access an undefined name on the first loop iteration. Move the initialization before the loop to ensure config exists when the condition is evaluated.

Proposed fix
 global config

 storage_class_matrix = [
     ...
 ]

 storage_class_a = StorageClassNames.IO2_CSI
 storage_class_b = StorageClassNames.IO2_CSI

 os_matrix = {
     ...
 }

+config: dict[str, Any] = globals().get("config", {})
+
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
     val = locals()[_dir]
     if type(val) not in [bool, list, dict, str]:
         continue

     if _dir in ["encoding", "py_file"]:
         continue

     config[_dir] = locals()[_dir]

This eliminates the undefined-name hazard per the guideline: Never use linter suppressions—fix the code directly. The initialization uses globals().get() to safely default to an empty dict while respecting any external configuration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config_multiarch.py` around lines 57 - 66, The code accesses
config before it’s guaranteed to exist; initialize or fetch it from globals
before the loop so the check `if not config:` cannot raise NameError—e.g.,
ensure `config = globals().get("config", {})` is executed prior to using
`config`, then keep the rest of the loop that reads `val = locals()[_dir]`,
checks `type(val)`, skips `["encoding", "py_file"]`, and assigns `config[_dir] =
locals()[_dir]`; this preserves external `config` if present and avoids the
undefined-name error for the `config` symbol.
tests/global_config_arm64.py (1)

57-66: ⚠️ Potential issue | 🔴 Critical

HIGH: config is not defined and will cause NameError on line 57.

The global config statement at line 17 is only a scope declaration—it does not initialize the variable. The loop at line 56 immediately accesses config on line 57 without prior assignment, which will fail on the first iteration because the name does not exist in the module scope.

Initialize config before the loop starts:

Proposed fix
 global config
 
 Images.Cirros.RAW_IMG_XZ = "cirros-0.4.0-aarch64-disk.raw.xz"
@@ -54,8 +54,7 @@ instance_type_fedora_os_list = [OS_FLAVOR_FEDORA]
 
 instance_type_rhel_os_list = [RHEL10_PREFERENCE]
 instance_type_fedora_os_list = [OS_FLAVOR_FEDORA]
+config: dict[str, Any] = {}
 
 for _dir in dir():
-    if not config:
-        config: dict[str, Any] = {}
     val = locals()[_dir]

Per coding guidelines: NEVER suppress linter warnings with # noqa or # type: ignore—fix the code instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/global_config_arm64.py` around lines 57 - 66, The code references the
module variable config inside the loop (check "if not config:" and assignment to
config[_dir]) but config is never initialized, causing a NameError; before the
loop that iterates over _dir and uses locals()[_dir], initialize config to an
empty dict (e.g., set config: dict[str, Any] = {} in the same scope where global
config is declared) or replace the conditional with a direct assignment so that
config exists before any access; update the symbol "config" accordingly and keep
the rest of the loop logic (checks on locals()[_dir], skipping "encoding" and
"py_file", and assigning config[_dir] = locals()[_dir]) unchanged.
tests/observability/metrics/test_vms_metrics.py (1)

47-51: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

MEDIUM: Fail fast when READY condition is missing

get_last_transition_time has an implicit None path. That turns a missing READY condition into a later timeout, which obscures the real failure source. Make the fallback explicit.

Suggested fix
-def get_last_transition_time(vm):
+def get_last_transition_time(vm) -> int:
     for condition in vm.instance.get("status", {}).get("conditions"):
         if condition.get("type") == vm.Condition.READY:
             last_transition_time = condition.get("lastTransitionTime")
             return int((datetime.strptime(last_transition_time, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)).timestamp())
+    raise AssertionError(f"READY condition not found for VM {vm.name}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/observability/metrics/test_vms_metrics.py` around lines 47 - 51,
get_last_transition_time silently returns None when no READY condition is
present; change it to fail fast by explicitly checking the conditions for
vm.Condition.READY and raising a clear exception (e.g., ValueError or
RuntimeError) if the READY condition is missing. Locate the function
get_last_transition_time and the loop that inspects vm.instance.get("status",
{}).get("conditions"), keep the existing parsing and timestamp conversion for
the READY condition, but after the loop raise an error (including identifying
info from vm such as an id or name if available) so callers immediately see the
missing READY condition.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.flake8:
- Around line 6-13: Remove F821 from the global ignore list in the ignore block
and instead add a per-file-ignores section that scopes F821 to only the legacy
files that genuinely need undefined-name suppression; specifically, edit the
ignore block to drop "F821" and add a "per-file-ignores =" mapping (e.g.,
"legacy_module.py: F821" or "path/to/legacy/*.py: F821") so undefined-name
checks run everywhere else while preserving F821 only for identified legacy
files.

In `@pyproject.toml`:
- Around line 34-37: Update the per-file-ignores entry so only F821 is scoped to
the dynamic-loading files (e.g., tests/global_config*.py) and remove PLE0704
from that per-file list; specifically, add or change the per-file-ignores rule
to map tests/global_config*.py -> F821 (keeping PLE0704 in the global
ignore/violation list), and ensure any references to
pytest_testconfig.load_python() and use of locals() remain uncovered by the
PLE0704 per-file exception so bare-raise violations elsewhere (in test
utilities) remain detected.

In `@utilities/virt.py`:
- Line 2817: Replace the ambiguous boolean chain flagged by RUF021 by making the
intent explicit: change the condition that uses migration_network and
migration_network_on_pod (currently written as "migration_network and
migration_network_on_pod or not migration_network and not
migration_network_on_pod") to an equality comparison using migration_network ==
migration_network_on_pod so the precedence is unambiguous and ruff no longer
complains; alternatively, if you prefer the original dual-branch logic, add
parentheses around each conjunction (e.g., (migration_network and
migration_network_on_pod) or (not migration_network and not
migration_network_on_pod)) to satisfy RUF021.

---

Outside diff comments:
In `@tests/global_config_arm64.py`:
- Around line 57-66: The code references the module variable config inside the
loop (check "if not config:" and assignment to config[_dir]) but config is never
initialized, causing a NameError; before the loop that iterates over _dir and
uses locals()[_dir], initialize config to an empty dict (e.g., set config:
dict[str, Any] = {} in the same scope where global config is declared) or
replace the conditional with a direct assignment so that config exists before
any access; update the symbol "config" accordingly and keep the rest of the loop
logic (checks on locals()[_dir], skipping "encoding" and "py_file", and
assigning config[_dir] = locals()[_dir]) unchanged.

In `@tests/global_config_ibm_spectrum_sc.py`:
- Around line 27-36: The code reads variable config before it's guaranteed to
exist, causing a potential NameError; initialize config before the "if not
config" check (e.g., ensure config = {} is assigned earlier) or replace the
check with a safe existence test like "'config' in locals() and config" so the
subsequent use of config and assignments to config[_dir] are always valid;
update the block that references config, locals()[_dir], and _dir (the
surrounding loop/section) to ensure config is defined prior to any reads and
then proceed with the existing type checks and assignments.

In `@tests/global_config_interop.py`:
- Around line 10-19: The code reads config before it's initialized causing a
NameError; initialize config once before the loop (ensure a top-level assignment
like config = {} before any use) and then remove the conditional `if not
config:` inside the loop, keeping the rest of the logic that checks `val =
locals()[_dir]`, the type filter `if type(val) not in [bool, list, dict, str]:
continue`, the exclusions `if _dir in ["encoding", "py_file"]: continue`, and
the assignment `config[_dir] = locals()[_dir]` so that `config` is always
defined when referenced.

In `@tests/global_config_multiarch.py`:
- Around line 57-66: The code accesses config before it’s guaranteed to exist;
initialize or fetch it from globals before the loop so the check `if not
config:` cannot raise NameError—e.g., ensure `config = globals().get("config",
{})` is executed prior to using `config`, then keep the rest of the loop that
reads `val = locals()[_dir]`, checks `type(val)`, skips `["encoding",
"py_file"]`, and assigns `config[_dir] = locals()[_dir]`; this preserves
external `config` if present and avoids the undefined-name error for the
`config` symbol.

In `@tests/global_config_rh_it.py`:
- Around line 30-39: The code reads the variable config before it is guaranteed
to exist, causing F821; fix by ensuring config is initialized before any
reads/conditionals that reference it (e.g., assign a default dict to config if
it's not already defined in locals() or use config = globals().get('config', {})
before the existing if-not-config check). Update references around the config
variable and the loop using _dir and locals() so that config is always a dict
before you do "if not config" or "config[_dir] = ..."; ensure you remove the
inline type-only assignment pattern and instead create a real initialized dict
for config.

In `@tests/global_config_s390x.py`:
- Around line 28-37: The code reads the variable config before it's defined
causing a NameError/linter F821; initialize config at the top of this block and
remove the pre-read check: ensure config is declared as an empty dict (e.g.,
config: dict[str, Any] = {}) before any use, then replace the `if not config:`
guard with logic that uses the existing config (or a simple existence check like
`if config is None:` only if you intend None as a sentinel), and keep the rest
of the loop that inspects locals()[_dir], the type check, the skip for
`encoding`/`py_file`, and the assignment `config[_dir] = locals()[_dir]` intact
so subsequent uses of config are safe.

In `@tests/global_config.py`:
- Around line 252-262: The code reads the name `config` before ensuring it
exists (the `if not config:` check can raise NameError/F821); initialize or
reference it safely before use: check presence via `"config" in locals()` or use
`locals().get("config")` and only assign `config = {}` if missing/falsey, then
proceed to use `config` when populating entries for `_dir`; update the block
around `_dir`/locals() to use a safe lookup (e.g., use locals().get("_dir") and
locals().get("config")) and ensure `config` is defined as a dict prior to adding
keys so symbols like `config`, `_dir`, and the locals() access are robust at
module load.

In `@tests/observability/metrics/test_vms_metrics.py`:
- Around line 47-51: get_last_transition_time silently returns None when no
READY condition is present; change it to fail fast by explicitly checking the
conditions for vm.Condition.READY and raising a clear exception (e.g.,
ValueError or RuntimeError) if the READY condition is missing. Locate the
function get_last_transition_time and the loop that inspects
vm.instance.get("status", {}).get("conditions"), keep the existing parsing and
timestamp conversion for the READY condition, but after the loop raise an error
(including identifying info from vm such as an id or name if available) so
callers immediately see the missing READY condition.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 52882623-8261-4408-b6d7-4e7feb2b372d

📥 Commits

Reviewing files that changed from the base of the PR and between aaa8f34 and 6c55700.

⛔ Files ignored due to path filters (3)
  • AGENTS.md is excluded by !**/*.md
  • docs/QUARANTINE_GUIDELINES.md is excluded by !**/*.md
  • docs/SOFTWARE_TEST_DESCRIPTION.md is excluded by !**/*.md
📒 Files selected for processing (127)
  • .flake8
  • .pre-commit-config.yaml
  • conftest.py
  • libs/net/netattachdef.py
  • libs/net/traffic_generator.py
  • libs/storage/config.py
  • libs/vm/spec.py
  • pyproject.toml
  • scripts/quarantine_stats/generate_dashboard.py
  • scripts/tests_analyzer/pytest_marker_analyzer.py
  • tests/chaos/oadp/conftest.py
  • tests/conftest.py
  • tests/global_config.py
  • tests/global_config_amd64.py
  • tests/global_config_arm64.py
  • tests/global_config_aro.py
  • tests/global_config_aws.py
  • tests/global_config_ibm_spectrum_sc.py
  • tests/global_config_interop.py
  • tests/global_config_interop_sno.py
  • tests/global_config_lvms.py
  • tests/global_config_multiarch.py
  • tests/global_config_nfs.py
  • tests/global_config_oci.py
  • tests/global_config_rh_it.py
  • tests/global_config_s390x.py
  • tests/global_config_sno.py
  • tests/global_config_sno_hpp.py
  • tests/infrastructure/golden_images/update_boot_source/test_ssp_data_sources.py
  • tests/infrastructure/golden_images/update_boot_source/utils.py
  • tests/infrastructure/instance_types/test_common_vm_preference.py
  • tests/infrastructure/vm_console_proxy/utils.py
  • tests/infrastructure/workload_availability/remediation_fencing_mhc/test_ha_vm.py
  • tests/install_upgrade_operators/crypto_policy/test_hco_override_api_server_crypto_policy.py
  • tests/install_upgrade_operators/crypto_policy/test_update_specific_component_crypto_policy.py
  • tests/install_upgrade_operators/csv/csv_permissions_audit/test_csv_permissions_audit.py
  • tests/install_upgrade_operators/json_patch/test_json_patch_annotation_cdi.py
  • tests/install_upgrade_operators/json_patch/test_json_patch_annotation_cnao.py
  • tests/install_upgrade_operators/json_patch/test_json_patch_annotation_kubevirt.py
  • tests/install_upgrade_operators/json_patch/test_json_patch_annotation_multiple_updates.py
  • tests/install_upgrade_operators/json_patch/test_json_patch_annotation_ssp.py
  • tests/install_upgrade_operators/must_gather/test_must_gather.py
  • tests/install_upgrade_operators/must_gather/utils.py
  • tests/install_upgrade_operators/node_component/utils.py
  • tests/install_upgrade_operators/resource_params/utils.py
  • tests/install_upgrade_operators/security/scc/test_cnv_deployment_required_scc.py
  • tests/install_upgrade_operators/security/scc/test_cnv_pods_scc.py
  • tests/install_upgrade_operators/security/scc/test_default_scc.py
  • tests/install_upgrade_operators/security/selinux/test_selinux_launcher_type.py
  • tests/network/conftest.py
  • tests/network/general/test_bridge_marker.py
  • tests/network/kubemacpool/explicit_range/conftest.py
  • tests/network/kubemacpool/utils.py
  • tests/network/l2_bridge/libl2bridge.py
  • tests/network/libs/cluster_user_defined_network.py
  • tests/network/libs/label_selector.py
  • tests/network/localnet/liblocalnet.py
  • tests/network/migration/test_migration.py
  • tests/network/nmstate/conftest.py
  • tests/network/nmstate/test_connectivity_after_nmstate_changes.py
  • tests/network/provider_migration/libprovider.py
  • tests/network/sriov/libsriov.py
  • tests/network/user_defined_network/ip_specification/conftest.py
  • tests/network/user_defined_network/test_user_defined_network_passt.py
  • tests/observability/metrics/test_vms_metrics.py
  • tests/observability/metrics/utils.py
  • tests/scale/test_scale_benchmark.py
  • tests/storage/cdi_config/conftest.py
  • tests/storage/cdi_upload/test_upload.py
  • tests/storage/cdi_upload/test_upload_virtctl.py
  • tests/storage/cdi_upload/utils.py
  • tests/storage/conftest.py
  • tests/storage/cross_cluster_live_migration/utils.py
  • tests/storage/golden_image/test_cached_snapshots.py
  • tests/storage/hpp/test_hostpath.py
  • tests/storage/hpp/test_hpp_node_placement.py
  • tests/storage/online_resize/conftest.py
  • tests/storage/online_resize/test_online_resize.py
  • tests/storage/online_resize/utils.py
  • tests/storage/snapshots/conftest.py
  • tests/storage/snapshots/test_snapshots.py
  • tests/storage/storage_migration/utils.py
  • tests/storage/test_cdi_certificate.py
  • tests/storage/test_cdi_resources.py
  • tests/storage/test_data_protection.py
  • tests/storage/test_disk_preallocation.py
  • tests/storage/test_local_storage.py
  • tests/storage/test_wffc.py
  • tests/storage/utils.py
  • tests/storage/vm_export/utils.py
  • tests/utils.py
  • tests/virt/cluster/common_templates/centos/test_centos_os_support.py
  • tests/virt/cluster/common_templates/custom_namespace/utils.py
  • tests/virt/cluster/common_templates/fedora/test_fedora_os_support.py
  • tests/virt/cluster/common_templates/general/test_base_template.py
  • tests/virt/cluster/common_templates/general/test_template_validator.py
  • tests/virt/cluster/common_templates/rhel/test_rhel_os_support.py
  • tests/virt/cluster/common_templates/utils.py
  • tests/virt/cluster/general/mass_machine_type_transition_tests/test_mass_machine_type_transition.py
  • tests/virt/cluster/longevity_tests/utils.py
  • tests/virt/cluster/migration_and_maintenance/test_evictionstrategy.py
  • tests/virt/node/descheduler/conftest.py
  • tests/virt/node/general/test_windows_vtpm_bitlocker.py
  • tests/virt/node/gpu/vgpu/test_rhel_vm_with_vgpu.py
  • tests/virt/node/high_performance_vm/test_numa.py
  • tests/virt/node/hyperv_support/test_hyperv_features_in_vm.py
  • tests/virt/upgrade/utils.py
  • tests/virt/utils.py
  • utilities/console.py
  • utilities/constants.py
  • utilities/infra.py
  • utilities/logger.py
  • utilities/network.py
  • utilities/oadp.py
  • utilities/operator.py
  • utilities/sanity.py
  • utilities/storage.py
  • utilities/unittests/test_data_collector.py
  • utilities/unittests/test_database.py
  • utilities/unittests/test_guest_support.py
  • utilities/unittests/test_hco.py
  • utilities/unittests/test_oadp.py
  • utilities/unittests/test_operator.py
  • utilities/unittests/test_pytest_matrix_utils.py
  • utilities/unittests/test_pytest_utils.py
  • utilities/unittests/test_ssp.py
  • utilities/virt.py
💤 Files with no reviewable changes (27)
  • tests/install_upgrade_operators/security/scc/test_cnv_deployment_required_scc.py
  • tests/network/nmstate/conftest.py
  • tests/storage/online_resize/conftest.py
  • tests/storage/hpp/test_hpp_node_placement.py
  • tests/storage/online_resize/utils.py
  • tests/storage/cdi_upload/test_upload.py
  • tests/network/general/test_bridge_marker.py
  • tests/storage/snapshots/conftest.py
  • tests/storage/test_local_storage.py
  • tests/storage/conftest.py
  • tests/network/migration/test_migration.py
  • tests/infrastructure/workload_availability/remediation_fencing_mhc/test_ha_vm.py
  • tests/storage/test_wffc.py
  • tests/install_upgrade_operators/security/scc/test_cnv_pods_scc.py
  • tests/storage/snapshots/test_snapshots.py
  • tests/install_upgrade_operators/must_gather/test_must_gather.py
  • tests/virt/cluster/common_templates/general/test_template_validator.py
  • tests/install_upgrade_operators/security/selinux/test_selinux_launcher_type.py
  • tests/storage/test_data_protection.py
  • tests/install_upgrade_operators/security/scc/test_default_scc.py
  • tests/storage/cdi_config/conftest.py
  • utilities/unittests/test_oadp.py
  • tests/storage/online_resize/test_online_resize.py
  • tests/storage/hpp/test_hostpath.py
  • tests/storage/test_disk_preallocation.py
  • tests/chaos/oadp/conftest.py
  • tests/network/conftest.py

Comment thread .flake8
Comment on lines +6 to +13
ignore =
N815,
N802,
E501,
F821,
E201,
W503,
N818,
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: Avoid globally disabling F821

Adding F821 to global ignore suppresses undefined-name detection repo-wide, which can mask real defects. Limit this to explicit legacy files via per-file-ignores instead of blanket ignore.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.flake8 around lines 6 - 13, Remove F821 from the global ignore list in the
ignore block and instead add a per-file-ignores section that scopes F821 to only
the legacy files that genuinely need undefined-name suppression; specifically,
edit the ignore block to drop "F821" and add a "per-file-ignores =" mapping
(e.g., "legacy_module.py: F821" or "path/to/legacy/*.py: F821") so
undefined-name checks run everywhere else while preserving F821 only for
identified legacy files.

Comment thread pyproject.toml
Comment on lines +34 to +37
"F821", # undefined name — used in global_config files (dynamic loading)
"PIE810", # call startswith/endswith once with tuple
"PLE0704", # bare raise not inside exception handler
"SIM103", # return condition directly
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify which files currently trigger these rules before narrowing scope.
# Expected: findings are limited to intended legacy global_config files.
uv run ruff check --select F821,PLE0704 --output-format grouped . || true

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 124


🏁 Script executed:

#!/bin/bash
# Check if ruff is available and try to run it directly
which ruff && ruff check --select F821,PLE0704 --output-format grouped . 2>/dev/null || echo "ruff check failed, trying alternative approach"

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 192


🏁 Script executed:

#!/bin/bash
# Explore the project structure to understand the codebase layout
find . -type f -name "*.py" | grep -E "(global_config|test)" | head -20

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 905


🏁 Script executed:

#!/bin/bash
# Check the current pyproject.toml to see the exact ignore configuration
cat -n pyproject.toml | head -50

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 2716


🏁 Script executed:

#!/bin/bash
# Search for files with "global_config" in their name
find . -type f -name "*global_config*" -o -name "*global*config*"

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 645


🏁 Script executed:

#!/bin/bash
# Search for bare raise statements in the codebase to understand PLE0704 usage
rg "^\s*raise\s*$" --type py -l 2>/dev/null | head -20

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 1009


🏁 Script executed:

#!/bin/bash
# Search for undefined name patterns (F821 typically appears in files with dynamic loading)
# Look for eval, exec, locals(), globals() patterns
rg "(eval|exec|locals\(\)|globals\(\)|__getattr__|__import__|importlib.import)" --type py -l 2>/dev/null | head -20

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 627


🏁 Script executed:

#!/bin/bash
# Examine one of the global_config files to understand the F821 violations
head -50 ./tests/global_config.py

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 1384


🏁 Script executed:

#!/bin/bash
# Search for undefined name patterns in global_config files
rg "F821" ./tests/global_config*.py 2>/dev/null || echo "No explicit F821 markers found"
# Try to understand what might trigger F821 - look for variable usage that's not defined locally
rg "^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*=" ./tests/global_config.py | head -30

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 1566


🏁 Script executed:

#!/bin/bash
# Check if there are OTHER files outside global_config that might have F821 violations
# that would be affected by the global ignore rule
rg "^[a-zA-Z_][a-zA-Z0-9_]*\s*=" --type py -A 2 | grep -v "global_config" | head -50

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 2368


🏁 Script executed:

#!/bin/bash
# Get more of the global_config.py file to see F821 violations
tail -100 ./tests/global_config.py | head -80

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 3259


🏁 Script executed:

#!/bin/bash
# Search for bare raise statements specifically in global_config files
echo "=== Bare raise in global_config files ==="
rg "^\s*raise\s*$" ./tests/global_config*.py -A 2 -B 2 2>/dev/null | head -40

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 125


🏁 Script executed:

#!/bin/bash
# Count bare raise statements in global_config vs other test files
echo "=== Bare raise in global_config files ==="
rg "^\s*raise\s*$" ./tests/global_config*.py 2>/dev/null | wc -l
echo "=== Bare raise in OTHER test files (non-global_config) ==="
rg "^\s*raise\s*$" ./tests --glob='!global_config*.py' 2>/dev/null | wc -l

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 190


🏁 Script executed:

#!/bin/bash
# Check for undefined name (F821) in global_config files - these would trigger without the ignore
echo "=== Looking for undefined variables in global_config.py ==="
cat ./tests/global_config.py | grep -E "^\s+[a-zA-Z_][a-zA-Z0-9_]*\s*=" | tail -50

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Search for variable references that aren't defined locally in global_config
# This is what F821 would catch - variables used but not defined
echo "=== Variables used in global_config that might trigger F821 ==="
rg "^[a-zA-Z_][a-zA-Z0-9_]*\s*=" ./tests/global_config.py -A 1 | grep -v "^--$" | head -60

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 2404


🏁 Script executed:

#!/bin/bash
# Check what PLW0604 (the other global_config-specific ignore) is about
# Search for "global" keyword usage
echo "=== Global statements in global_config files ==="
rg "^global\s+" ./tests/global_config*.py 2>/dev/null

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 946


🏁 Script executed:

#!/bin/bash
# Let's check the exact content around the bare raise statements in other test files
echo "=== Sample of bare raise in test utilities ==="
rg "^\s*raise\s*$" ./tests -B 3 -A 1 --max-count=10 2>/dev/null

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 45491


🏁 Script executed:

#!/bin/bash
# Double-check: are there ANY undefined names (F821) currently in global_config files?
# Let's look at the actual dynamic loading pattern
grep -n "pytest_testconfig.load_python\|locals()\|globals()" ./tests/global_config.py

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 267


🏁 Script executed:

#!/bin/bash
# Final verification: List all currently ignored rules and confirm which ones are truly needed for global_config
echo "=== Checking if PLE0704 is actually used in global_config files ==="
rg "except|try|raise" ./tests/global_config.py | head -20

Repository: RedHatQE/openshift-virtualization-tests

Length of output: 318


Scope F821 correctly, but PLE0704 is not present in global_config files.

F821 violations in tests/global_config*.py are due to dynamic loading patterns (pytest_testconfig.load_python(), locals()) and should be scoped per-file. However, PLE0704 (bare raise) does not occur in these files—the 106 bare raise violations are in other test utilities and are correctly inside exception handlers. Scoping PLE0704 to global_config would not address the actual violations elsewhere and could mask issues if moved later.

Only F821 needs per-file scoping:

Proposed scoped configuration
 [tool.ruff.lint]
 ignore = [
   "SIM102",  # collapsible-if
   ...
-  "F821",    # undefined name — used in global_config files
-  "PLE0704", # bare raise not inside exception handler
   ...
 ]

+[tool.ruff.lint.per-file-ignores]
+"tests/global_config*.py" = ["F821"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pyproject.toml` around lines 34 - 37, Update the per-file-ignores entry so
only F821 is scoped to the dynamic-loading files (e.g., tests/global_config*.py)
and remove PLE0704 from that per-file list; specifically, add or change the
per-file-ignores rule to map tests/global_config*.py -> F821 (keeping PLE0704 in
the global ignore/violation list), and ensure any references to
pytest_testconfig.load_python() and use of locals() remain uncovered by the
PLE0704 per-file exception so bare-raise violations elsewhere (in test
utilities) remain detected.

Comment thread utilities/virt.py
if migration_network and migration_network_on_pod:
verified_pods_list.append(pod)
elif not migration_network and not migration_network_on_pod:
if migration_network and migration_network_on_pod or not migration_network and not migration_network_on_pod:
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH — Fix ruff RUF021: unparenthesized and/or chain makes precedence ambiguous

Ruff 0.15.12 (the version this PR is bumping to) fires RUF021 on this line:

if migration_network and migration_network_on_pod or not migration_network and not migration_network_on_pod:

Python's precedence evaluates this as (migration_network and migration_network_on_pod) or (not migration_network and not migration_network_on_pod), which is logically equivalent to migration_network == migration_network_on_pod. The behavior is correct, but ruff flags the missing parentheses as a readability hazard — and the PR's own goal is to make pre-commit run --all-files pass. Since the coding guidelines say "If a linter complains, fix the code instead" and RUF021 is not listed in the project's pyproject.toml ignores, this will keep failing CI.

Simplest fix that satisfies both the linter and the readability intent:

🔧 Proposed fix
-        if migration_network and migration_network_on_pod or not migration_network and not migration_network_on_pod:
+        if migration_network == migration_network_on_pod:

If you'd prefer to keep the explicit double-branch form, at minimum parenthesize to silence RUF021:

Alternative: parenthesized form
-        if migration_network and migration_network_on_pod or not migration_network and not migration_network_on_pod:
+        if (migration_network and migration_network_on_pod) or (not migration_network and not migration_network_on_pod):
🧰 Tools
🪛 Ruff (0.15.12)

[warning] 2817-2817: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear

Parenthesize the and subexpression

(RUF021)


[warning] 2817-2817: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear

Parenthesize the and subexpression

(RUF021)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utilities/virt.py` at line 2817, Replace the ambiguous boolean chain flagged
by RUF021 by making the intent explicit: change the condition that uses
migration_network and migration_network_on_pod (currently written as
"migration_network and migration_network_on_pod or not migration_network and not
migration_network_on_pod") to an equality comparison using migration_network ==
migration_network_on_pod so the precedence is unambiguous and ruff no longer
complains; alternatively, if you prefer the original dual-branch logic, add
parentheses around each conjunction (e.g., (migration_network and
migration_network_on_pod) or (not migration_network and not
migration_network_on_pod)) to satisfy RUF021.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants