fixhunt

ruff FURB167

labelled unknown
Runs / 2026-10-17T21-35-13-472Z-ehc1-ruff-FURB167ruff 0.17.12026-10-17 21:35 UTC8 programs × 2 round(s)8 programs, 6 fired, 6 fixed, 0 findings, 0 rejectedmodel cost $0.0017

Analysis Nemotron 3 Super

Flags usage of short-form regex flag constants like re.I in favor of their long-form equivalents like re.IGNORECASE.

Fix: Replaces each short-form regex flag (e.g., re.I, re.L, etc.) with its corresponding descriptive long-form constant (e.g., re.IGNORECASE, re.LOCALE, etc.) while preserving all other code structure and expressions.

12 hazards
  • Rewriting re.I inside a string literal like 're.I' would incorrectly modify code that is not executable, altering intended behavior.
  • If re is locally aliased (e.g., import re as regex), the fix may fail to match or incorrectly rewrite references, breaking flag resolution.
  • When the flag is used in a bitwise operation like re.I | re.L, rewriting only part of the expression could produce invalid syntax or incorrect flag combination.
  • If re.I is accessed via getattr(re, 'I'), the fix does not apply and may leave dynamic attribute access unchanged, missing the intent.
  • In a context where re is reassigned to a non-module object (e.g., re = 5), rewriting re.I would cause an AttributeError at runtime.
  • The fix may insert re.IGNORECASE in a position where a comment trails the short form (e.g., re.I # inline), potentially misplacing or deleting the comment due to whitespace handling.
  • If the short flag appears in a docstring or comment (e.g., "Use re.I here"), the fix could erroneously alter documentation, changing meaning without affecting execution.
  • When the flag is used as a string key in a dictionary (e.g., {'re.I': value}), rewriting it changes the key, breaking lookup logic that depends on the literal string.
  • In a lambda or comprehension where re is rebound locally (e.g., [re.I for re in range(5)]), the fix may misinterpret the loop variable as the module, leading to incorrect rewrites or errors.
  • If re.I is imported via from re import I, the fix does not trigger on the bare I and may miss the alias, leaving inconsistent usage.
  • The rewrite assumes re refers to the standard library module; if shadowed by a custom module with different attributes, the long form may not exist, causing AttributeError.
  • In Python optimizations or restricted execution modes where re.IGNORECASE is not defined (though unlikely), the fix could introduce a NameError where none existed before.

Programs

idresulttitlehazard
r1-p001fix okLocal alias mismatchIf re is locally aliased (e.g., import re as regex), the fix may fail to match or incorrectly rewrite references, breaking flag resolution.
r1-p002silentgetattr dynamic accessIf re.I is accessed via getattr(re, 'I'), the fix does not apply and may leave dynamic attribute access unchanged, missing the intent.
r1-p003silentDictionary string keyWhen the flag is used as a string key in a dictionary (e.g., {'re.I': value}), rewriting it changes the key, breaking lookup logic that depends on the literal string.
r1-p004fix okDict ordering and duplicatesdict ordering, duplicate keys, __hash__/__eq__ overrides, sets
r1-p005fix okTruthiness and identitytruthiness of custom __bool__/__len__, None vs falsy, 'is' vs '=='
r1-p006fix okBitwise operation partial rewriteWhen the flag is used in a bitwise operation like re.I | re.L, rewriting only part of the expression could produce invalid syntax or incorrect flag combination.
r1-p007fix okMutable default argumentmutable default arguments and aliasing after a rewrite
r1-p008fix okBytes vs str encodingbytes vs str, encoding and newline handling, text vs binary modes

Sources

r1-p001 · Local alias mismatch
1import re as regex
2pattern = r'hello'
3string = 'HELLO world'
4if regex.search(pattern, string, regex.I):
5 print('matched')
6else:
7 print('no match')
--- orig.py	2026-10-17 17:35:20.977019168 -0400
+++ fixed.py	2026-10-17 17:35:21.166017049 -0400
@@ -1,7 +1,7 @@
 import re as regex
 pattern = r'hello'
 string = 'HELLO world'
-if regex.search(pattern, string, regex.I):
+if regex.search(pattern, string, regex.IGNORECASE):
     print('matched')
 else:
     print('no match')
matched
r1-p002 · getattr dynamic access
1import re
2flag = getattr(re, 'I')
3pattern = r'hello'
4string = 'HELLO'
5print(bool(re.search(pattern, string, flag)))
True
r1-p003 · Dictionary string key
1import re
2d = {'re.I': 42}
3print(d.get('re.I', 0))
42
r1-p004 · Dict ordering and duplicates
1import re
2flags_dict = {re.I: 'ignore', re.L: 'locale', re.I: 'dup'}
3print(list(flags_dict.keys()))
4print(flags_dict[re.I])
--- orig.py	2026-10-17 17:35:21.562012611 -0400
+++ fixed.py	2026-10-17 17:35:21.743010582 -0400
@@ -1,4 +1,4 @@
 import re
-flags_dict = {re.I: 'ignore', re.L: 'locale', re.I: 'dup'}
+flags_dict = {re.IGNORECASE: 'ignore', re.LOCALE: 'locale', re.IGNORECASE: 'dup'}
 print(list(flags_dict.keys()))
-print(flags_dict[re.I])
+print(flags_dict[re.IGNORECASE])
[re.IGNORECASE, re.LOCALE]
dup
r1-p005 · Truthiness and identity
1import re
2class FlagWrapper:
3 def __init__(self, flag):
4 self.flag = flag
5 def __bool__(self):
6 return self.flag != 0
7fw = FlagWrapper(re.I)
8print('Truthy:', bool(fw))
9print('Is zero:', fw.flag == 0)
10print('Equals I:', fw.flag == re.I)
--- orig.py	2026-10-17 17:35:21.849009394 -0400
+++ fixed.py	2026-10-17 17:35:22.029007377 -0400
@@ -4,7 +4,7 @@
         self.flag = flag
     def __bool__(self):
         return self.flag != 0
-fw = FlagWrapper(re.I)
+fw = FlagWrapper(re.IGNORECASE)
 print('Truthy:', bool(fw))
 print('Is zero:', fw.flag == 0)
-print('Equals I:', fw.flag == re.I)
+print('Equals I:', fw.flag == re.IGNORECASE)
Truthy: True
Is zero: False
Equals I: True
r1-p006 · Bitwise operation partial rewrite
1import re
2flags = re.I | re.L
3pattern = r'\n'
4string = 'a\nb'
5print(re.findall(pattern, string, flags))
--- orig.py	2026-10-17 17:35:22.141006123 -0400
+++ fixed.py	2026-10-17 17:35:22.565001376 -0400
@@ -1,5 +1,5 @@
 import re
-flags = re.I | re.L
+flags = re.IGNORECASE | re.LOCALE
 pattern = r'\n'
 string = 'a\nb'
 print(re.findall(pattern, string, flags))
r1-p007 · Mutable default argument
1import re
2def process(p, s, f=re.I):
3 return re.search(p, s, f)
4print(bool(process(r'h', 'H')))
--- orig.py	2026-10-17 17:35:22.795998790 -0400
+++ fixed.py	2026-10-17 17:35:22.972996809 -0400
@@ -1,4 +1,4 @@
 import re
-def process(p, s, f=re.I):
+def process(p, s, f=re.IGNORECASE):
     return re.search(p, s, f)
 print(bool(process(r'h', 'H')))
True
r1-p008 · Bytes vs str encoding
1import re
2pattern = b'HELLO'
3string = b'hello world'
4print(re.findall(pattern, string, re.I))
--- orig.py	2026-10-17 17:35:23.085995545 -0400
+++ fixed.py	2026-10-17 17:35:23.270993476 -0400
@@ -1,4 +1,4 @@
 import re
 pattern = b'HELLO'
 string = b'hello world'
-print(re.findall(pattern, string, re.I))
+print(re.findall(pattern, string, re.IGNORECASE))
[b'hello']