fixhunt

ruff G010: fix changes program behavior

fix-changes-behaviorlabelled safeintended-change · lowduplicate
Findings / 2026-10-17T20-24-12-113Z-iye4-ruff-G010 / r2-p004ruff 0.17.16 → 4 lines2026-10-17 20:24 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

generators vs lists, iterators consumed once, lazy vs eager evaluation

Program

before
1import logging
2logger = logging.getLogger()
3gen = (logger.warn(f'Processing {x}') for x in range(2))
4print('Second consumption:', list(gen))
after
1import logging
2logger = logging.getLogger()
3gen = (logger.warning(f'Processing {x}') for x in range(2))
4print('Second consumption:', list(gen))

Output

stdout beforeexit 0
Second consumption: [None, None]
/w/prog.py:3: DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead
stdout afterexit 0
Second consumption: [None, None]
Processing 0
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory intended-change · low

The rule replaces the deprecated `logger.warn` with `logger.warning`, which the documentation states are functionally equivalent. The observed difference is the removal of the DeprecationWarning on stderr, which is exactly the semantic change the rule intends to make.

Explanation Nemotron 3 Super unverified

The original generator expression uses `logger.warn`, which emits a deprecation warning to stderr when called; this occurs during each iteration of the generator. After rewriting to `logger.warning`, the deprecated method is replaced with its non-deprecated counterpart, so no warning is emitted. Since the first consumption of the generator (implicit in printing) now produces no stderr output, while the second consumption still yields the same list, the overall program behavior differs—specifically, the absence of the deprecation warning in stderr changes the observable output. Thus, the rewrite alters side effects and is not semantics-preserving.

Reproduce

file
prog.py (the before program)
minimized program
r2-p004.py
evidence sheet
r2-p004.md
regression fixture
r2-p004.py the minimized program with a header stating the observed change, for the tool's test suite
python3 prog.py
ruff check --preview --isolated --select G010 --fix prog.py
python3 prog.py

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

G010 fix · ruff G010 warn generator expression · Oracle warning deprecation logger usage · fix changes behavior logger.warn to warning

  • duplicate astral-sh/ruff/issues/12295 same rule G010 and same construct: accessing the deprecated `Logger.warn` method which should be rewritten to `Logger.warning`
  • related astral-sh/ruff/issues/7248 tracks implementation of flake8-logging rules including G010 but is a meta-issue not a specific defect report
  • related astral-sh/ruff/issues/2186 documents rule aliasing where G010 is an alias of PGH002 but does not describe a defect
  • related astral-sh/ruff/issues/13673 reports G rules not working with loguru, same rule family but different logger library
  • duplicate astral-sh/ruff/issues/17219 explicitly closed as duplicate of issue 12295 which is the same Logger.warn access defect
  • related astral-sh/ruff/issues/21889 BLE001 false positive with logging.warning call, same logging method but different rule and defect type
  • related astral-sh/ruff/issues/6972 G004 false positive with imported logger instances, same rule family but different construct and rule

Details

program
Generator consumed once, logger.warn inside generator expression
hazard
generators vs lists, iterators consumed once, lazy vs eager evaluation
oracle
stderr before: /w/prog.py:3: DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead stderr after: Processing 0
run
2026-10-17T20-24-12-113Z-iye4-ruff-G010
generated program (6 lines) and the fix's diff
1import logging
2logger = logging.getLogger()
3logger.setLevel(logging.INFO)
4gen = (logger.warn(f'Processing {x}') for x in range(2))
5print('First consumption:', list(gen))
6print('Second consumption:', list(gen))
--- orig.py	2026-10-17 16:24:36.818872876 -0400
+++ fixed.py	2026-10-17 16:24:37.063872256 -0400
@@ -1,6 +1,6 @@
 import logging
 logger = logging.getLogger()
 logger.setLevel(logging.INFO)
-gen = (logger.warn(f'Processing {x}') for x in range(2))
+gen = (logger.warning(f'Processing {x}') for x in range(2))
 print('First consumption:', list(gen))
 print('Second consumption:', list(gen))
rule documentation given to the models
# logging-warn (G010)

Derived from the **flake8-logging-format** linter.

Fix is always available.

## What it does
Checks for uses of `logging.warn` and `logging.Logger.warn`.

## Why is this bad?
`logging.warn` and `logging.Logger.warn` are deprecated in favor of
`logging.warning` and `logging.Logger.warning`, which are functionally
equivalent.

## Known problems

This rule detects uses of the `logging` module via a heuristic.
Specifically, it matches against:

- Uses of the `logging` module itself (e.g., `import logging; logging.info(...)`).
- Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
- Objects whose name starts with `log` or ends with `logger` or `logging`,
  when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
- Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
  used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
  when [`lint.logger-objects`] is set to `["module.logger"]`).

## Example
```python
import logging

logging.warn("Something happened")
```

Use instead:
```python
import logging

logging.warning("Something happened")
```

## Options
- `lint.logger-objects`

## References
- [Python documentation: `logging.warning`](https://docs.python.org/3/library/logging.html#logging.warning)
- [Python documentation: `logging.Logger.warning`](https://docs.python.org/3/library/logging.html#logging.Logger.warning)