ruff C405
labelled unknown
Analysis Nemotron 3 Super
Flags set() constructor called with a single list or tuple literal argument.
Fix: Rewrites set(L) where L is a list or tuple literal to {*L} if non-empty, otherwise set().
8 hazards
- The rewrite drops inline or trailing comments attached to the set() call or its argument, as the autofix may not preserve comment nodes during AST transformation.
- If the list or tuple literal contains mutable elements that are later modified, the resulting set may capture different object identities due to reconstruction via set literal, though values remain equal.
- In rare cases involving custom __eq__ or __hash__ implementations, the order of element insertion during set literal construction could theoretically affect hash collision resolution, though final set equality is preserved.
- If the argument is a tuple literal used elsewhere in the code (e.g., assigned to a variable), rewriting to a set literal severs that shared reference, potentially breaking aliasing expectations.
- The autofix may incorrectly apply to set() calls generated via macros or code-generation tools where the list/tuple appears literal but is semantically dynamic, leading to incorrect static rewrites.
- If the set() call is part of a larger expression where the original call's formatting or line breaks are significant (e.g., for diff tools or readability), the rewrite may alter whitespace in a way that breaks team formatting rules.
- When the list or tuple literal contains duplicate elements, the set literal rewrite behaves identically, but intermediate steps in evaluation (like list creation) are skipped, which could matter in tracing or debugging contexts.
- If the code relies on the set() constructor for its type (e.g., isinstance(x, set) after assignment), the rewrite still produces a set, so no behavioral change occurs—this hazard is included to emphasize that type preservation holds, unlike in unsafe cases.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Mutable Default Arguments Aliasing | Rewriting `set([])` to `set()` removes explicit empty list creation, causing shared state across function calls when used as a mutable default. |
| r1-p002 | fired, no fix | Custom __eq__ and Hash Collision Resolution | Set literal `{*L}` may insert elements in different order than `set(L)`, affecting internal hash table probing sequence even if final equality holds; this can surface in debugging or custom `__repr__` |
| r1-p003 | silent | Macro-Generated Code Misinterpretation | Code generation tools may produce `set([x for x in ...])` where the list comprehension looks literal but is semantically dynamic; rewriting to `{*[x for x in ...]}` is invalid syntax, causing parse fa |
| r1-p004 | silent prediction off | Duplicate Elements and Intermediate Evaluation Skipped | Rewriting `set([1,1,2])` skips list creation, removing a potential breakpoint or trace point in debugging where the list's construction had side effects. |
| r1-p005 | silent | Generators Consumed Once | Rewriting `set(generator)` is not attempted by the rule (correctly), but if mistakenly applied, `{*gen}` would consume the generator eagerly, whereas `set(gen)` does so lazily; here we show the rule c |
| r1-p006 | silent prediction off | Bytes vs Str Encoding and Newlines | Rewriting `set([b'a', b'b'])` to `{*[b'a', b'b']}` is safe for bytes, but if the list were decoded strings with encoding-sensitive content, the rewrite doesn't change semantics—yet tracing list creati |
| r1-p007 | silent prediction off | Type Annotations Evaluated at Runtime | If a list literal in a set() call is used in a forward reference resolved at runtime via `typing.get_type_hints()`, rewriting it to a set literal doesn't change the value, but the intermediate list mi |
| r1-p008 | invalid | Non-File Context Managers with write() | Rewriting `set([log_stream])` where `log_stream` is a context manager with `write()` but no `close()` doesn't affect resource safety, but if the list literal were part of a larger expression with side |
| r2-p001 | silent prediction off | Mutable List Literal Elements Modified After Set Construction | If the list or tuple literal contains mutable elements that are later modified, the resulting set may capture different object identities due to reconstruction via set literal, though values remain eq |
| r2-p002 | silent prediction off | Type Annotation Evaluated at Runtime Using Forward Reference | type annotations evaluated at runtime, typing-only imports |
| r2-p003 | silent prediction off | Tuple Literal Shared Reference Severed by Rewrite | If the argument is a tuple literal used elsewhere in the code (e.g., assigned to a variable), rewriting to a set literal severs that shared reference, potentially breaking aliasing expectations. |
| r2-p004 | silent prediction off | Dict Ordering and Duplicate Keys in Set Construction via List | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r2-p005 | silent prediction off | Async Generator Consumption Affected by Set Literal Rewrite | async def/await ordering, async generators |
| r2-p006 | silent prediction off | Custom __eq__/__hash__ and Insertion Order in Set Literal | In rare cases involving custom __eq__ or __hash__ implementations, the order of element insertion during set literal construction could theoretically affect hash collision resolution, though final set |
| r2-p007 | invalid | Bytes vs Str Encoding and Newline Handling in Set Literal | bytes vs str, encoding and newline handling, text vs binary modes |
| r2-p008 | silent prediction off | Evaluation Order and Side Effects in Set Argument Expression | evaluation order and side effects when expressions are merged, duplicated or deleted |
Sources
r1-p001 · Mutable Default Arguments Aliasing
1def f(x=None):
2 if x is None:
3 x = []
4 s = set(x)
5 s.add(len(s))
6 return s
7print(f(), f())
{0} {0}r1-p002 · Custom __eq__ and Hash Collision Resolution
1class A:
2 def __init__(self, v): self.v = v
3 def __hash__(self): return hash(self.v)
4 def __eq__(self, other): return isinstance(other, A) and self.v == other.v
5 def __repr__(self): return f'A({self.v})'
6a1, a2 = A(1), A(2)
7s = set([a1, a2])
8print(repr(s))
{A(1), A(2)}r1-p003 · Macro-Generated Code Misinterpretation
1try:
2 exec("s = {[x for x in [1,2]]}")
3 print('no error')
4except SyntaxError as e:
5 print(type(e).__name__, str(e))
r1-p004 · Duplicate Elements and Intermediate Evaluation Skipped
1trace = []
2def make_list():
3 trace.append('list made')
4 return [1,1,2]
5s = set(make_list())
6print(''.join(trace), len(s))
list made 2
r1-p005 · Generators Consumed Once
1def gen():
2 yield 1
3 yield 2
4s = set(gen())
5print(''.join(str(x) for x in s))
12
r1-p006 · Bytes vs Str Encoding and Newlines
1data = [b'hello\n', b'world\n']
2trace = []
3class TrackedBytes(bytes):
4 def __new__(cls, b): trace.append(b); return super().__new__(cls, b)
5s = set(TrackedBytes(b) for b in data)
6print(''.join(trace), sorted(s))
r1-p007 · Type Annotations Evaluated at Runtime
1import typing
2T = list[int]
3def f() -> T:
4 return [1,2]
5s = set(f())
6print(type(s), s)
<class 'set'> {1, 2}r1-p008 · Non-File Context Managers with write() (generated program does not parse: Traceback (most recent call last):)
1class LogStream:
2 def __init__(self): self.buf = []
3 def write(self, s): self.buf.append(s)
4 def __enter__(self): return self
5 def __exit__(self, *_:): pass
6with LogStream() as ls:
7 ls.write('x')
8 s = set([ls])
9 print(id(s), len(s))
r2-p001 · Mutable List Literal Elements Modified After Set Construction
1outer_list = []
2for i in range(2):
3 lst = [i]
4 outer_list.append(lst)
5 s = set(lst)
6 lst[0] = 99
7 print(f'i={i}, set={s}, lst={lst}')
i=0, set={0}, lst=[99]
i=1, set={1}, lst=[99]r2-p002 · Type Annotation Evaluated at Runtime Using Forward Reference
1from __future__ import annotations
2def f() -> 'List[int]':
3 return [1, 2]
4s = set(f())
5print(f'set from annotation-resolved list: {s}')
6if hasattr(f.__annotations__['return'], '__class__'):
7 print('Annotation type:', f.__annotations__['return'].__class__)
set from annotation-resolved list: {1, 2}
Annotation type: <class 'str'>r2-p003 · Tuple Literal Shared Reference Severed by Rewrite
1t = (1, 2)
2s = set(t)
3t = (3, 4) # reassign t
4print(f'set from original t: {s}')
5print(f't after reassignment: {t}')
6# s should still reflect (1,2), not (3,4)
set from original t: {1, 2}
t after reassignment: (3, 4)r2-p004 · Dict Ordering and Duplicate Keys in Set Construction via List
1class BadDict:
2 def __init__(self, v):
3 self.v = v
4 def __hash__(self):
5 return hash(self.v)
6 def __eq__(self, other):
7 return isinstance(other, BadDict) and self.v == other.v
8l = [BadDict(1), BadDict(1)]
9s = set(l)
10print(f'Set size from duplicate BadDict: {len(s)}')
11print(f'Elements: {[x.v for x in s]}')
Set size from duplicate BadDict: 1 Elements: [1]
r2-p005 · Async Generator Consumption Affected by Set Literal Rewrite
1async def gen():
2 yield 1
3 yield 2
4async def main():
5 g = gen()
6 lst = [x async for x in g]
7 s = set(lst)
8 print(f'Set from async gen: {s}')
9import asyncio
10asyncio.run(main())
Set from async gen: {1, 2}r2-p006 · Custom __eq__/__hash__ and Insertion Order in Set Literal
1class OrderSensitive:
2 def __init__(self, val, name):
3 self.val = val
4 self.name = name
5 def __hash__(self):
6 return hash(self.val)
7 def __eq__(self, other):
8 return isinstance(other, OrderSensitive) and self.val == other.val
9 def __repr__(self):
10 return f'OS({self.val},{self.name})'
11l = [OrderSensitive(1, 'a'), OrderSensitive(1, 'b')]
12s = set(l)
13print(f'Set contents: {s}')
14print(f'Length: {len(s)}')
Set contents: {OS(1,a)}
Length: 1r2-p007 · Bytes vs Str Encoding and Newline Handling in Set Literal (generated program does not parse: Traceback (most recent call last):)
1l = [b'hello
2', b'world\r
3']
4s = set(l)
5print(f'Set of byte strings: {s}')
6for b in s:
7 print(f'Bytes: {b!r}, Decoded: {b.decode()}')
r2-p008 · Evaluation Order and Side Effects in Set Argument Expression
1side_effects = []
2def f():
3 side_effects.append(len(side_effects))
4 return [side_effects[-1]]
5s = set(f())
6print(f'Side effects log: {side_effects}')
7print(f'Set from f(): {s}')
8# If f() called twice due to rewrite, log would be [0,1]
Side effects log: [0]
Set from f(): {0}