fixhunt

ruff G010: fix changes program behavior

fix-changes-behaviorlabelled safereal · mediumduplicate
Findings / 2026-10-17T20-24-12-113Z-iye4-ruff-G010 / r2-p005ruff 0.17.111 → 11 lines2026-10-17 20:24 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

If the logger object is conditionally assigned (e.g., logger = debug_logger if DEBUG else null_logger) and only one branch defines .warn, the rewrite may incorrectly apply to a fallback object lacking

Program

before
1DEBUG = False
2class DebugLogger:
3 def warn(self, msg):
4 print(f'DEBUG WARN: {msg}')
5class NullLogger:
6 pass # No warn or warning
7logger = DebugLogger() if DEBUG else NullLogger()
8try:
9 logger.warn('test')
10except AttributeError as e:
11 print(type(e).__name__, str(e))
after
1DEBUG = False
2class DebugLogger:
3 def warn(self, msg):
4 print(f'DEBUG WARN: {msg}')
5class NullLogger:
6 pass # No warn or warning
7logger = DebugLogger() if DEBUG else NullLogger()
8try:
9 logger.warning('test')
10except AttributeError as e:
11 print(type(e).__name__, str(e))

Output

stdout beforeexit 0
AttributeError 'NullLogger' object has no attribute 'warn'
stdout afterexit 0
AttributeError 'NullLogger' object has no attribute 'warning'
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory real · medium

The rule rewrites logger.warn to logger.warning assuming the logger object has a warning method, but the program uses a custom NullLogger class that lacks both warn and warning methods. The fix changes which AttributeError is raised, altering the program's observable behavior in a way the documentation does not account for, since the heuristic matched the variable name 'logger' but the object does not conform to the logging module's interface.

Explanation Nemotron 3 Super unverified

The original call uses method name `warn`, which exists only on `DebugLogger`. When `DEBUG` is false, `logger` becomes a `NullLogger` lacking `warn`, raising an `AttributeError` for missing `warn`. After rewriting to `warning`, the same `NullLogger` still lacks this method, so it raises an `AttributeError` for missing `warning`. Although both cases raise `AttributeError`, the error message differs because it reports the absent method name (`warn` vs `warning`). Since the program’s output includes this message, the change alters observable behavior, violating semantic equivalence despite both branches raising the same exception type. The fix assumes method name interchangeability, but the error message depends on the exact attribute accessed.

Reproduce

file
prog.py (the before program)
minimized program
r2-p005.py
evidence sheet
r2-p005.md
regression fixture
r2-p005.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 method name change · DebugLogger NullLogger warn call · attribute error on missing method

Details

program
Conditionally assigned logger missing .warning in fallback
hazard
If the logger object is conditionally assigned (e.g., logger = debug_logger if DEBUG else null_logger) and only one branch defines .warn, the rewrite may incorrectly apply to a fallback object lacking
oracle
stdout before: AttributeError 'NullLogger' object has no attribute 'warn' stdout after: AttributeError 'NullLogger' object has no attribute 'warning'
run
2026-10-17T20-24-12-113Z-iye4-ruff-G010
generated program (11 lines) and the fix's diff
1DEBUG = False
2class DebugLogger:
3 def warn(self, msg):
4 print(f'DEBUG WARN: {msg}')
5class NullLogger:
6 pass # No warn or warning
7logger = DebugLogger() if DEBUG else NullLogger()
8try:
9 logger.warn('test')
10except AttributeError as e:
11 print(type(e).__name__, str(e))
--- orig.py	2026-10-17 16:24:37.206871895 -0400
+++ fixed.py	2026-10-17 16:24:37.375871469 -0400
@@ -6,6 +6,6 @@
     pass  # No warn or warning
 logger = DebugLogger() if DEBUG else NullLogger()
 try:
-    logger.warn('test')
+    logger.warning('test')
 except AttributeError as e:
     print(type(e).__name__, str(e))
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)