ruff PIE794
labelled unknown
Analysis Nemotron 3 Super
The rule flags duplicate field assignments within a class body where the same attribute name is assigned more than once.
Fix: The autofix removes all but the first occurrence of the duplicated field assignment in the class body, preserving the first definition and deleting subsequent duplicate lines.
12 hazards
- Removing a duplicate assignment that had a side-effect (e.g., function call, I/O) changes program behavior by omitting that side-effect.
- Deleting a duplicate assignment that mutated an object (e.g., list.append, dict.update) may leave the object in an unintended state if the mutation was meaningful.
- Removing a duplicate assignment that relied on the prior value of the same variable (e.g., x = x + 1) alters the computation by using an outdated or undefined value.
- Deleting a duplicate assignment that was intended to rebind a variable after a del statement may cause a NameError if the variable is used later.
- Removing a duplicate assignment in a conditional block (if/while/for) may be incorrect if the indentation was misleading and the line was actually meant to be at class level.
- Deleting a duplicate assignment that occurred after a comment may cause the comment to be orphaned or misattributed if the fix does not preserve comment placement.
- Removing a duplicate assignment that was part of a chained assignment (e.g., a = b = expr) breaks the binding for the other target in the chain.
- Deleting a duplicate assignment that was followed by a deletion (del) may cause the variable to be unbound when later code expects it to be defined.
- Removing a duplicate assignment that was meant to override a parent class field may inadvertently preserve the parent's value, changing inheritance behavior.
- Deleting a duplicate assignment that was syntactically valid but semantically dead (no further use) may still be hazardous if the line contained a macro-like side effect via import or decorator.
- Removing a duplicate assignment that occurs before a try/except block may affect control flow if the assignment was guarding a variable used in the except clause.
- Deleting a duplicate assignment that was the only source of a variable used in a nested function or lambda may cause a closure to capture an undefined variable.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Chained Assignment Broken | Removing a duplicate assignment that was part of a chained assignment (e.g., a = b = expr) breaks the binding for the other target in the chain. |
| r1-p002 | fired, no fix | Rebind After Del Causes NameError | Deleting a duplicate assignment that was intended to rebind a variable after a del statement may cause a NameError if the variable is used later. |
| r1-p003 | fired, no fix | Dict Mutation Lost | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r1-p004 | fired, no fix | Non-file Context Manager | context managers that are not files, objects with write() but no close() |
| r1-p005 | fired, no fix | List Append Lost | Deleting a duplicate assignment that mutated an object (e.g., list.append, dict.update) may leave the object in an unintended state if the mutation was meaningful. |
| r1-p006 | silent prediction off | Exception in Finally | exceptions raised inside the rewritten code, finally/else clauses, exception chaining |
| r1-p007 | fired, no fix | Comment Orphaned | Deleting a duplicate assignment that occurred after a comment may cause the comment to be orphaned or misattributed if the fix does not preserve comment placement. |
| r1-p008 | fired, no fix | Bytes vs Str Encoding | bytes vs str, encoding and newline handling, text vs binary modes |
| r2-p001 | silent prediction off | Hazard 1: Duplicate assignment relies on prior value | Removing a duplicate assignment that relied on the prior value of the same variable (e.g., x = x + 1) |
| r2-p002 | fired, no fix | Hazard 2: Misleading indentation suggests conditional block | Removing a duplicate assignment in a conditional block if the indentation was misleading and the line was actually meant to be at class level |
| r2-p003 | fired, no fix | Hazard 3: Class vs instance attributes, descriptors | class attributes vs instance attributes, descriptors, properties with side effects |
| r2-p004 | silent prediction off | Hazard 4: Generators vs lists, iterators consumed once | generators vs lists, iterators consumed once, lazy vs eager evaluation |
| r2-p005 | silent prediction off | Hazard 5: Bytes vs str, encoding | bytes vs str, encoding and newline handling, text vs binary modes |
| r2-p006 | fired, no fix | Hazard 6: Mutation via duplicate assignment | Deleting a duplicate assignment that mutated an object (e.g., list.append, dict.update) may leave the object in an unintended state |
| r2-p007 | fired, no fix | Hazard 7: Assignment before try/except affecting except clause | Removing a duplicate assignment that occurs before a try/except block may affect control flow if the assignment was guarding a variable used in the except clause |
| r2-p008 | fired, no fix | Hazard 8: Overriding parent class field | Removing a duplicate assignment that was meant to override a parent class field may inadvertently preserve the parent's value |
Sources
r1-p001 · Chained Assignment Broken
1class C:
2 a = b = 5
3 a = 6
4 print(f'a={a}, b={b}')
a=6, b=5
r1-p002 · Rebind After Del Causes NameError
1class C:
2 x = 1
3 del x
4 x = 2
5 try:
6 print(x)
7 except NameError as e:
8 print(f'NameError: {e}')
2
r1-p003 · Dict Mutation Lost
1class C:
2 d = {'a': 1}
3 d['b'] = 2
4 d = {}
5 print(len(d))
0
r1-p004 · Non-file Context Manager
1from contextlib import suppress
2class C:
3 cm = suppress(ValueError)
4 cm.__enter__()
5 cm = None
6 try:
7 cm.__exit__(None, None, None)
8 except AttributeError as e:
9 print(f'AttributeError: {e}')
AttributeError: 'NoneType' object has no attribute '__exit__'
r1-p005 · List Append Lost
1class C:
2 lst = [1]
3 lst.append(2)
4 lst = [3]
5 print(lst)
[3]
r1-p006 · Exception in Finally
1class C:
2 x = 1
3 try:
4 if x == 1:
5 raise ValueError('bad')
6 except ValueError as e:
7 pass
8 finally:
9 x = 2
10 print(x)
2
r1-p007 · Comment Orphaned
1class C:
2 x = 1 # important
3 x = 2
4 print(x)
2
r1-p008 · Bytes vs Str Encoding
1class C:
2 data = b'hello'
3 data = 'world'
4 print(type(data), len(data))
<class 'str'> 5
r2-p001 · Hazard 1: Duplicate assignment relies on prior value
1class Counter:
2 x = 0
3 x = x + 1
4Counter.x
r2-p002 · Hazard 2: Misleading indentation suggests conditional block
1class Confused:
2 flag = False
3 if flag:
4 pass
5 flag = True
6print(Confused.flag)
True
r2-p003 · Hazard 3: Class vs instance attributes, descriptors
1class Descriptor:
2 def __get__(self, obj, owner):
3 return 'got'
4 def __set__(self, obj, value):
5 self.value = value
6class WithDescriptor:
7 attr = Descriptor()
8 attr = 'overridden'
9print(WithDescriptor.attr)
overridden
r2-p004 · Hazard 4: Generators vs lists, iterators consumed once
1class GenTest:
2 gen = (x for x in range(2))
3 gen = list(gen)
4print(list(GenTest.gen))
[0, 1]
r2-p005 · Hazard 5: Bytes vs str, encoding
1class TextBinary:
2 data = b'hello'
3 data = data.decode()
4print(type(TextBinary.data), repr(TextBinary.data))
<class 'str'> 'hello'
r2-p006 · Hazard 6: Mutation via duplicate assignment
1class Mutator:
2 lst = [1, 2]
3 lst.append(3)
4 lst = [4]
5print(Mutator.lst)
[4]
r2-p007 · Hazard 7: Assignment before try/except affecting except clause
1class Guarded:
2 error = None
3 try:
4 raise ValueError('bad')
5 except ValueError as e:
6 error = e
7 error = 'caught'
8print(Guarded.error)
caught
r2-p008 · Hazard 8: Overriding parent class field
1class Parent:
2 attr = 'parent'
3class Child(Parent):
4 attr = 'child'
5 attr = 'overridden'
6print(Child.attr)
overridden