ruff B028
labelled unknown
Analysis Nemotron 3 Super
Flags calls to warnings.warn missing an explicit stacklevel argument.
Fix: Adds ', stacklevel=2' as the last positional or keyword argument before any existing keyword arguments like category or filename, preserving other arguments and their order.
10 hazards
- If stacklevel was already provided as a positional argument after message (e.g., warnings.warn(msg, 1)), adding another stacklevel=2 creates a duplicate keyword argument, causing a TypeError.
- If the call uses *args to pass arguments (e.g., warnings.warn(*args)), inserting stacklevel=2 breaks argument unpacking and may misalign parameters.
- If the call is inside a lambda or comprehension where stacklevel affects outer scope lookup, forcing stacklevel=2 may alter which warning is suppressed by filters.
- If warnings.warn is monkey-patched or overridden locally, the fix assumes the original signature and may pass an unexpected keyword argument.
- If the code relies on the default stacklevel=1 behavior to show the warning origin at the warn site, changing it to 2 shifts blame to the caller, altering diagnostic intent.
- If the call includes skip_file_prefixes in Python <3.12, the fix incorrectly adds stacklevel=2 despite skip_file_prefixes being ignored, potentially conflicting with user intent.
- If the message argument is an expression with side effects (e.g., warn(f(x))), reordering arguments to insert stacklevel=2 could change evaluation order if the fix incorrectly places it before the message.
- If the call uses keyword-only arguments via *, such as warnings.warn(msg, *, category=Error), inserting stacklevel=2 before * causes a syntax error.
- If the code depends on the warning being filtered based on stackline matching, changing stacklevel alters which frames are considered and may unexpectedly show or hide warnings.
- If the call is in a stub (.pyi) file or conditional typing block, adding runtime arguments may violate type checker expectations or cause overload mismatches.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fired, no fix | Bytes vs Str Encoding Hazard | bytes vs str, encoding and newline handling, text vs binary modes |
| r1-p002 | fired, no fix | Monkey-Patch Signature Hazard | If warnings.warn is monkey-patched or overridden locally, the fix assumes the original signature and may pass an unexpected keyword argument. |
| r1-p003 | fired, no fix | Exception Handling Hazard | exceptions raised inside the rewritten code, finally/else clauses, exception chaining |
| r1-p004 | fired, no fix | Async Await Ordering Hazard | async def/await ordering, async generators |
| r1-p005 | fired, no fix | Mutable Default Aliasing Hazard | mutable default arguments and aliasing after a rewrite |
| r1-p006 | fired, no fix | Stacklevel Filtering Hazard | If the code depends on the warning being filtered based on stackline matching, changing stacklevel alters which frames are considered and may unexpectedly show or hide warnings. |
| r1-p007 | silent prediction off | Skip File Prefixes <3.12 Hazard | If the call includes skip_file_prefixes in Python <3.12, the fix incorrectly adds stacklevel=2 despite skip_file_prefixes being ignored, potentially conflicting with user intent. |
| r1-p008 | fired, no fix prediction off | Stub File Overload Hazard | If the call is in a stub (.pyi) file or conditional typing block, adding runtime arguments may violate type checker expectations or cause overload mismatches. |
| r2-p001 | fired, no fix | Mutable default argument mutation affects behavior | mutable default arguments and aliasing after a rewrite |
| r2-p002 | fired, no fix | Message expression side effect evaluation order changed | If the message argument is an expression with side effects (e.g., warn(f(x))), reordering arguments to insert stacklevel=2 could change evaluation order if the fix incorrectly places it before the mes |
| r2-p003 | silent prediction off | *args forwarding misaligned by inserted stacklevel | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p004 | silent prediction off | Star-import and __all__ interaction with rewritten call | star-imports, module-level side effects, __all__ |
| r2-p005 | fired, no fix | Stacklevel change alters warning origin reporting | If the code relies on the default stacklevel=1 behavior to show the warning origin at the warn site, changing it to 2 shifts blame to the caller, altering diagnostic intent. |
| r2-p006 | fired, no fix prediction off | Stub file conditional typing block gets invalid runtime arg | If the call is in a stub (.pyi) file or conditional typing block, adding runtime arguments may violate type checker expectations or cause overload mismatches. |
| r2-p007 | silent prediction off | *args unpacking broken by inserted stacklevel argument | If the call uses *args to pass arguments (e.g., warnings.warn(*args)), inserting stacklevel=2 breaks argument unpacking and may misalign parameters. |
| r2-p008 | fired, no fix | Expression coercion and evaluation order affected | int/float/bool coercion, Decimal, division and rounding |
Sources
r1-p001 · Bytes vs Str Encoding Hazard
1import warnings
2with open('test.txt', 'wb') as f:
3 f.write(b'data\n')
4with open('test.txt', 'r', encoding='utf-8') as f:
5 content = f.read().strip()
6warnings.warn(content)
7print(f'Warned with: {repr(content)}')
Warned with: 'data'
r1-p002 · Monkey-Patch Signature Hazard
1import warnings
2original_warn = warnings.warn
3def patched_warn(message, *, category=None):
4 print(f'Patched warn called with: {message}, category={category}')
5 return None
6warnings.warn = patched_warn
7try:
8 warnings.warn('test')
9except TypeError as e:
10 print(f'TypeError: {e}')
Patched warn called with: test, category=None
r1-p003 · Exception Handling Hazard
1import warnings
2try:
3 warnings.warn('error ahead')
4 raise ValueError('failed')
5except ValueError as e:
6 print(f'Caught: {e}')
7finally:
8 print('Finally block executed')
Caught: failed Finally block executed
r1-p004 · Async Await Ordering Hazard
1import warnings
2async def warn_async():
3 warnings.warn('async msg')
4 await asyncio.sleep(0)
5async def main():
6 task = asyncio.create_task(warn_async())
7 await task
8import asyncio
9asyncio.run(main())
10print('Async warn completed')
Async warn completed
r1-p005 · Mutable Default Aliasing Hazard
1import warnings
2def log_warn(msg, stack=[]):
3 stack.append(msg)
4 warnings.warn(msg)
5 return stack
6log_warn('first')
7log_warn('second')
8print(f'Stack after two warns: {log_warn([])}')
r1-p006 · Stacklevel Filtering Hazard
1import warnings
2warnings.filterwarnings('ignore', lineno=15)
3def inner():
4 warnings.warn('filtered?') # Line 15
5inner()
6print('No warning printed if filtered')
No warning printed if filtered
r1-p007 · Skip File Prefixes <3.12 Hazard
1import warnings
2import sys
3if sys.version_info < (3, 12):
4 warnings.warn('test', skip_file_prefixes=['ignore_me'])
5 print('skip_file_prefixes used (ignored in <3.12)')
6else:
7 print('skip_file_prefixes respected')
skip_file_prefixes respected
r1-p008 · Stub File Overload Hazard
1import warnings
2if False:
3 # This block is not executed but may appear in stubs
4 warnings.warn('stub-only', category=RuntimeWarning)
5print('No runtime effect from conditional block')
No runtime effect from conditional block
r2-p001 · Mutable default argument mutation affects behavior
1import warnings
2
3def f(lst=None):
4 if lst is None:
5 lst = []
6 lst.append(99)
7 return lst
8
9lst = []
10warnings.warn(str(f(lst)))
11print('lst after:', lst)
lst after: [99]
r2-p002 · Message expression side effect evaluation order changed
1import warnings
2
3counter = [0]
4def msg():
5 counter[0] += 1
6 return f'message-{counter[0]}'
7
8warnings.warn(msg(), category=UserWarning)
9print('counter:', counter[0])
counter: 1
r2-p003 · *args forwarding misaligned by inserted stacklevel
1import warnings
2
3def wrapper(*args):
4 warnings.warn(*args)
5
6wrapper('test', category=DeprecationWarning)
7print('warning issued')
r2-p004 · Star-import and __all__ interaction with rewritten call
1import warnings
2
3from warnings import *
4warn('test')
5print('warn called via star-import')
warn called via star-import
r2-p005 · Stacklevel change alters warning origin reporting
1import warnings
2
3def inner():
4 warnings.warn('alert')
5
6def outer():
7 inner()
8
9outer()
r2-p006 · Stub file conditional typing block gets invalid runtime arg
1import warnings
2import typing
3if typing.TYPE_CHECKING:
4 warnings.warn('test')
5print('TYPE_CHECKING block skipped at runtime')
TYPE_CHECKING block skipped at runtime
r2-p007 · *args unpacking broken by inserted stacklevel argument
1import warnings
2
3args = ('dynamic message',)
4warnings.warn(*args)
5print('warning issued with *args')
warning issued with *args
r2-p008 · Expression coercion and evaluation order affected
1import warnings
2
3x = [10]
4def get_val():
5 x[0] -= 1
6 return x[0] / 2
7
8warnings.warn(get_val(), category=RuntimeWarning)
9print('x:', x)
x: [9]