ruff E703
labelled unknown
Analysis Nemotron 3 Super
Flags statements ending with unnecessary semicolons.
Fix: Removes the trailing semicolon at the end of the statement, leaving the preceding code unchanged.
8 hazards
- Rewriting 'x = 1;' to 'x = 1' changes nothing as the semicolon is purely syntactic and has no semantic effect in simple statements.
- In compound statements like 'if True: pass;', removing the semicolon after the suite does not alter behavior because the semicolon only terminates the simple statement 'pass'.
- For 'for i in range(10): print(i);', the semicolon after the loop body is irrelevant to execution and its removal preserves all side effects.
- In function definitions like 'def f(): return None;', the trailing semicolon after the function body is ignored by the parser and its removal does not affect the function's behavior.
- For class definitions like 'class C: x = 1;', the semicolon after the class suite is non-functional and deleting it does not alter class creation or attribute binding.
- In import statements such as 'import os;', the semicolon is redundant and its removal does not affect the import mechanism or module availability.
- For 'from sys import stdin;', the semicolon after the import statement is extraneous and deleting it preserves the imported name's availability.
- In try-except blocks like 'try: pass; except: pass;', the semicolons after each suite are meaningless and their removal does not impact exception handling or control flow.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Compound statement - if | In compound statements like 'if True: pass;', removing the semicolon after the suite does not alter behavior because the semicolon only terminates the simple statement 'pass'. |
| r1-p002 | fix ok | Class definition | For class definitions like 'class C: x = 1;', the semicolon after the class suite is non-functional and deleting it does not alter class creation or attribute binding. |
| r1-p003 | invalid | Exceptions/finally/else/chaining | exceptions raised inside the rewritten code, finally/else clauses, exception chaining |
| r1-p004 | fix ok | Async def/await/ordering, async generators | async def/await ordering, async generators |
| r1-p005 | fix ok | Int/float/bool coercion, Decimal, division and rounding | int/float/bool coercion, Decimal, division and rounding |
| r1-p006 | fix ok | Class vs instance attributes, descriptors, properties with side effects | class attributes vs instance attributes, descriptors, properties with side effects |
| r1-p007 | fix ok | Import statements | In import statements such as 'import os;', the semicolon is redundant and its removal does not affect the import mechanism or module availability. |
| r1-p008 | fix ok | Mutable default arguments and aliasing after a rewrite | mutable default arguments and aliasing after a rewrite |
| r2-p001 | fix ok | Type annotation evaluated via ForwardRef resolution | type annotations evaluated at runtime, typing-only imports |
| r2-p002 | fix ok | Keyword-only arg with default evaluated once | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p003 | fix ok | From import availability after semicolon removal | For 'from sys import stdin;', the semicolon after the import statement is extraneous and deleting it preserves the imported name's availability. |
| r2-p004 | fix ok | Float division rounding behavior | int/float/bool coercion, Decimal, division and rounding |
| r2-p005 | fix ok | Class attribute binding order | For class definitions like 'class C: x = 1;', the semicolon after the class suite is non-functional and deleting it does not alter class creation or attribute binding. |
| r2-p006 | fix ok | Pathlib vs os.path symlink resolution | pathlib vs os.path behavior on relative paths, symlinks, missing files, bytes paths |
| r2-p007 | invalid | Generator exhaustion in loop | generators vs lists, iterators consumed once, lazy vs eager evaluation |
| r2-p008 | fix ok | File write truncation with bytes | file modes and truncation, partial writes, non-str data passed to write |
Sources
r1-p001 · Compound statement - if
1x = []
2for _ in range(2):
3 if len(x) < 2:
4 x.append(len(x));
5print(x)
--- orig.py 2026-10-17 16:47:40.484134587 -0400 +++ fixed.py 2026-10-17 16:47:40.648138379 -0400 @@ -1,5 +1,5 @@ x = [] for _ in range(2): if len(x) < 2: - x.append(len(x)); + x.append(len(x)) print(x)
[0, 1]
r1-p002 · Class definition
1class C:
2 attr = [];
3def f():
4 C.attr.append(1)
5f()
6f()
7print(C.attr)
--- orig.py 2026-10-17 16:47:40.758140921 -0400 +++ fixed.py 2026-10-17 16:47:40.921144689 -0400 @@ -1,5 +1,5 @@ class C: - attr = []; + attr = [] def f(): C.attr.append(1) f()
[1, 1]
r1-p003 · Exceptions/finally/else/chaining (generated program does not parse: Traceback (most recent call last):)
1try:
2 raise ValueError('bad')
3except Exception as e:
4 try:
5 raise TypeError('worse') from e;
6except TypeError as te:
7 print(te.__cause__)
r1-p004 · Async def/await/ordering, async generators
1async def gen():
2 yield 1;
3async def main():
4 async for v in gen():
5 print(v);
6import asyncio
7asyncio.run(main())
--- orig.py 2026-10-17 16:47:41.170150440 -0400 +++ fixed.py 2026-10-17 16:47:41.459157113 -0400 @@ -1,7 +1,7 @@ async def gen(): - yield 1; + yield 1 async def main(): async for v in gen(): - print(v); + print(v) import asyncio asyncio.run(main())
1
r1-p005 · Int/float/bool coercion, Decimal, division and rounding
1from decimal import Decimal, getcontext
2getcontext().prec = 3
3x = Decimal('1') / Decimal('3');
4print(round(float(x), 2))
--- orig.py 2026-10-17 16:47:41.630161062 -0400 +++ fixed.py 2026-10-17 16:47:41.801165010 -0400 @@ -1,4 +1,4 @@ from decimal import Decimal, getcontext getcontext().prec = 3 -x = Decimal('1') / Decimal('3'); +x = Decimal('1') / Decimal('3') print(round(float(x), 2))
0.33
r1-p006 · Class vs instance attributes, descriptors, properties with side effects
1class C:
2 shared = [];
3 @property
4 def log(self):
5 self.shared.append(len(self.shared));
6 return len(self.shared)
7c = C()
8print(c.log);
9print(c.log)
--- orig.py 2026-10-17 16:47:41.905167411 -0400 +++ fixed.py 2026-10-17 16:47:42.067171150 -0400 @@ -1,9 +1,9 @@ class C: - shared = []; + shared = [] @property def log(self): - self.shared.append(len(self.shared)); + self.shared.append(len(self.shared)) return len(self.shared) c = C() -print(c.log); +print(c.log) print(c.log)
1 2
r1-p007 · Import statements
1import os;
2import sys;
3print(hasattr(os, 'path'))
4print(hasattr(sys, 'stdout'))
--- orig.py 2026-10-17 16:47:42.167173456 -0400 +++ fixed.py 2026-10-17 16:47:42.331177238 -0400 @@ -1,4 +1,4 @@ -import os; -import sys; +import os +import sys print(hasattr(os, 'path')) print(hasattr(sys, 'stdout'))
True True
r1-p008 · Mutable default arguments and aliasing after a rewrite
1def f(a=[]):
2 a.append(1);
3 return a
4print(f())
5print(f())
--- orig.py 2026-10-17 16:47:42.439179729 -0400 +++ fixed.py 2026-10-17 16:47:42.598183396 -0400 @@ -1,5 +1,5 @@ def f(a=[]): - a.append(1); + a.append(1) return a print(f()) print(f())
[1] [1, 1]
r2-p001 · Type annotation evaluated via ForwardRef resolution
1from __future__ import annotations
2T = list
3def f(x: T) -> T:
4 return x
5print(f.__annotations__) # Shows stringized annotation
6f([1]);
--- orig.py 2026-10-17 16:47:47.877304762 -0400 +++ fixed.py 2026-10-17 16:47:48.045308613 -0400 @@ -3,4 +3,4 @@ def f(x: T) -> T: return x print(f.__annotations__) # Shows stringized annotation -f([1]); +f([1])
{'x': 'T', 'return': 'T'}r2-p002 · Keyword-only arg with default evaluated once
1L = []
2def f(*, x=L.append(1) or 0):
3 return x
4print(f(), f()) # Second call sees mutated L
5f();
--- orig.py 2026-10-17 16:47:48.148310972 -0400 +++ fixed.py 2026-10-17 16:47:48.313314751 -0400 @@ -2,4 +2,4 @@ def f(*, x=L.append(1) or 0): return x print(f(), f()) # Second call sees mutated L -f(); +f()
0 0
r2-p003 · From import availability after semicolon removal
1from sys import stdin;
2print(stdin is not None)
3from sys import stdout;
4print(stdout is not None)
--- orig.py 2026-10-17 16:47:48.415317087 -0400 +++ fixed.py 2026-10-17 16:47:48.577320798 -0400 @@ -1,4 +1,4 @@ -from sys import stdin; +from sys import stdin print(stdin is not None) -from sys import stdout; +from sys import stdout print(stdout is not None)
True True
r2-p004 · Float division rounding behavior
1x = 1;
2y = 3;
3print(x / y == 0.3333333333333333); # Semicolon on x line
4print(round(x / y, 2))
--- orig.py 2026-10-17 16:47:48.687323317 -0400 +++ fixed.py 2026-10-17 16:47:48.849327027 -0400 @@ -1,4 +1,4 @@ -x = 1; -y = 3; -print(x / y == 0.3333333333333333); # Semicolon on x line +x = 1 +y = 3 +print(x / y == 0.3333333333333333) # Semicolon on x line print(round(x / y, 2))
True 0.33
r2-p005 · Class attribute binding order
1class C:
2 x = 1;
3 y = x + 1
4print(C.x, C.y)
5print(hasattr(C, 'z')) # z not defined
--- orig.py 2026-10-17 16:47:48.947329272 -0400 +++ fixed.py 2026-10-17 16:47:49.114333094 -0400 @@ -1,5 +1,5 @@ class C: - x = 1; + x = 1 y = x + 1 print(C.x, C.y) print(hasattr(C, 'z')) # z not defined
1 2 False
r2-p006 · Pathlib vs os.path symlink resolution
1import os
2import pathlib
3open('tmp.txt', 'w').write('hi')
4os.symlink('tmp.txt', 'link')
5print(os.path.exists('link')); # Semicolon on import os line
6print(pathlib.Path('link').exists())
7os.unlink('link'); os.remove('tmp.txt')
--- orig.py 2026-10-17 16:47:49.208335244 -0400 +++ fixed.py 2026-10-17 16:47:49.428340277 -0400 @@ -2,6 +2,6 @@ import pathlib open('tmp.txt', 'w').write('hi') os.symlink('tmp.txt', 'link') -print(os.path.exists('link')); # Semicolon on import os line +print(os.path.exists('link')) # Semicolon on import os line print(pathlib.Path('link').exists()) os.unlink('link'); os.remove('tmp.txt')
True True
r2-p007 · Generator exhaustion in loop (generated program does not parse: Traceback (most recent call last):)
1def gen():
2 yield 1
3 yield 2
4 g = gen();
5print(list(g)); # Semicolon on g = gen() line
6print(list(g)) # Now empty
r2-p008 · File write truncation with bytes
1with open('test.bin', 'wb') as f:
2 f.write(b'hello'); # Semicolon on write line
3 f.truncate(2)
4with open('test.bin', 'rb') as f:
5 print(f.read())
6import os
7os.remove('test.bin')
--- orig.py 2026-10-17 16:47:49.699346477 -0400 +++ fixed.py 2026-10-17 16:47:49.866350298 -0400 @@ -1,5 +1,5 @@ with open('test.bin', 'wb') as f: - f.write(b'hello'); # Semicolon on write line + f.write(b'hello') # Semicolon on write line f.truncate(2) with open('test.bin', 'rb') as f: print(f.read())
b'he'