Skip to content

Conversation

@berland
Copy link
Contributor

@berland berland commented Jan 5, 2026

Issue
Resolves ruff check --select PT

Approach
Mostly manual fixes, one commit pr. rule. Biggest commit is fixed by ruff itself with `--unsafe-fixes .

  • PR title captures the intent of the changes, and is fitting for release notes.
  • Added appropriate release note label
  • Commit history is consistent and clean, in line with the contribution guidelines.
  • Make sure unit tests pass locally after every commit (git rebase -i main --exec 'just rapid-tests')

When applicable

  • When there are user facing changes: Updated documentation
  • New behavior or changes to existing untested code: Ensured that unit tests are added (See Ground Rules).
  • Large PR: Prepare changes in small commits for more convenient review
  • Bug fix: Add regression test for the bug
  • Bug fix: Add backport label to latest release (format: 'backport release-branch-name')

berland added 12 commits January 5, 2026 14:01
* Why is this bad?
`pytest.warns(Warning)` will catch any `Warning` and may catch warnings that
are unrelated to the code under test. To avoid this, `pytest.warns` should
be called with a `match` parameter.
* Why is this bad?
Such a parameter will always have the default value during the test
regardless of whether a fixture with the same name is defined.
* What it does
Checks for unnecessary `request.addfinalizer` usages in `pytest` fixtures.

* Why is this bad?
`pytest` offers two ways to perform cleanup in fixture code. The first is
sequential (via the `yield` statement), the second callback-based (via
`request.addfinalizer`).

The sequential approach is more readable and should be preferred, unless
the fixture uses the "factory as fixture" pattern.
* What it does
Checks for `assert` statements in `except` clauses.

* Why is this bad?
When testing for exceptions, `pytest.raises()` should be used instead of
`assert` statements in `except` clauses, as it's more explicit and
idiomatic. Further, `pytest.raises()` will fail if the exception is _not_
raised, unlike the `assert` statement.
* What it does
Checks for `pytest.warns` context managers with multiple statements.

This rule allows `pytest.warns` bodies to contain `for`
loops with empty bodies (e.g., `pass` or `...` statements), to test
iterator behavior.

* Why is this bad?
When `pytest.warns` is used as a context manager and contains multiple
statements, it can lead to the test passing when it should instead fail.

A `pytest.warns` context manager should only contain a single
simple statement that triggers the expected warning.
* What it does
Checks for incorrect import of pytest.

* Why is this bad?
For consistency, `pytest` should be imported as `import pytest` and its members should be
accessed in the form of `pytest.xxx.yyy` for consistency
* What it does
Checks for `pytest` test functions that should be decorated with
`@pytest.mark.usefixtures`.

* Why is this bad?
In `pytest`, fixture injection is used to activate fixtures in a test
function.

Fixtures can be injected either by passing them as parameters to the test
function, or by using the `@pytest.mark.usefixtures` decorator.

If the test function depends on the fixture being activated, but does not
use it in the test body or otherwise rely on its return value, prefer
the `@pytest.mark.usefixtures` decorator, to make the dependency explicit
and avoid the confusion caused by unused arguments.
* What it does
Checks for assertions that combine multiple independent conditions.

* Why is this bad?
Composite assertion statements are harder to debug upon failure, as the
failure message will not indicate which condition failed.
* What it does
Checks for duplicate test cases in `pytest.mark.parametrize`.

* Why is this bad?
Duplicate test cases are redundant and should be removed.
* What it does
Checks for argument-free `@pytest.fixture()` decorators with or without
parentheses.

* Why is this bad?
If a `@pytest.fixture()` doesn't take any arguments, the parentheses are
optional.

Either removing those unnecessary parentheses _or_ requiring them for all
fixtures is fine, but it's best to be consistent. The rule defaults to
removing unnecessary parentheses, to match the documentation of the
official pytest projects.
* What it does
Checks for unnecessary `yield` expressions in `pytest` fixtures.

* Why is this bad?
In `pytest` fixtures, the `yield` expression should only be used for fixtures
that include teardown code, to clean up the fixture after the test function
has finished executing.
* What it does
Checks for `pytest.raises` calls without a `match` parameter.

* Why is this bad?
`pytest.raises(Error)` will catch any `Error` and may catch errors that are
unrelated to the code under test. To avoid this, `pytest.raises` should be
called with a `match` parameter.
@berland berland self-assigned this Jan 5, 2026
@berland berland added this to SCOUT Jan 5, 2026
@berland berland moved this to In Progress in SCOUT Jan 5, 2026
@berland berland added the release-notes:skip If there should be no mention of this in release notes label Jan 5, 2026
@codecov-commenter
Copy link

codecov-commenter commented Jan 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.56%. Comparing base (7d7a64e) to head (690a460).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12569      +/-   ##
==========================================
- Coverage   90.58%   90.56%   -0.02%     
==========================================
  Files         435      435              
  Lines       29915    29916       +1     
==========================================
- Hits        27098    27093       -5     
- Misses       2817     2823       +6     
Flag Coverage Δ
cli-tests 37.31% <0.00%> (-0.01%) ⬇️
gui-tests 68.62% <100.00%> (ø)
performance-and-unit-tests 73.91% <50.00%> (-0.03%) ⬇️
test 38.08% <50.00%> (+<0.01%) ⬆️

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.

* What it does
Checks for `pytest.raises` context managers with multiple statements.

This rule allows `pytest.raises` bodies to contain `for`
loops with empty bodies (e.g., `pass` or `...` statements), to test
iterator behavior.

* Why is this bad?
When a `pytest.raises` is used as a context manager and contains multiple
statements, it can lead to the test passing when it actually should fail.

A `pytest.raises` context manager should only contain a single simple
statement that raises the expected exception.
* What it does
Checks for the type of parameter values passed to `pytest.mark.parametrize`.

* Why is this bad?
The `argvalues` argument of `pytest.mark.parametrize` takes an iterator of
parameter values, which can be provided as lists or tuples.

To aid in readability, it's recommended to use a consistent style for the
list of values rows, and, in the case of multiple parameters, for each row
of values.
Resolved using "ruff --fix --unsafe-fixes"

* What it does
Checks for the type of parameter names passed to `pytest.mark.parametrize`.

* Why is this bad?
The `argnames` argument of `pytest.mark.parametrize` takes a string or
a sequence of strings. For a single parameter, it's preferable to use a
string. For multiple parameters, it's preferable to use the style
configured via the [`lint.flake8-pytest-style.parametrize-names-type`] setting.
@berland berland force-pushed the ruff_pytest_rule_by_rule branch from a139e6b to 690a460 Compare January 5, 2026 13:37
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 5, 2026

CodSpeed Performance Report

Merging #12569 will not alter performance

Comparing berland:ruff_pytest_rule_by_rule (690a460) with main (b8a7508)

Summary

✅ 22 untouched

@berland berland moved this from In Progress to Ready for Review in SCOUT Jan 5, 2026
Copy link
Contributor

@verveerpj verveerpj left a comment

Choose a reason for hiding this comment

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

Apart from one small comment, LGTM!

):
deserialized_workflow_job = ErtScriptWorkflow.model_validate(serialized_job)
assert deserialized_workflow_job == ertscript_workflow_job
ErtScriptWorkflow.model_validate(serialized_job)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it valid to remove the assert?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good observation! This is one of the "bugs" that ruff exposes to us. The assert has never been run, since there is always a KeyError on the line above, and the assert is not even valid (deserialized_workflow_job is never bound).

@github-project-automation github-project-automation bot moved this from Ready for Review to Reviewed in SCOUT Jan 6, 2026
@berland berland merged commit e212883 into equinor:main Jan 6, 2026
35 checks passed
@github-project-automation github-project-automation bot moved this from Reviewed to Done in SCOUT Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-notes:skip If there should be no mention of this in release notes

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants