ruff UP004
labelled unknown
Analysis Nemotron 3 Super
Flags class definitions that explicitly inherit from object, which is redundant in Python 3.
Fix: Removes 'object' from the base class list; if object is the only base, the entire inheritance list is deleted leaving just 'class Name:'; if object is among multiple bases, it is stripped out while preserving order and spacing of remaining bases.
8 hazards
- Rewriting 'class C(object, Mixin): pass' to 'class C(Mixin): pass' changes the method resolution order (MRO) if Mixin defines methods also present in later bases, altering which method is called via super().
- If a class uses a metaclass via '__metaclass__' attribute (Python 2) or '__classcell__' in nested scopes, removing 'object' may affect class creation semantics in edge cases involving class cell closure capture.
- In rare cases where 'object' is used as a placeholder for a dynamically assigned base via metaprogramming (e.g., class decorators that inspect bases), removing it breaks the decorator's assumption about the base list.
- If the class definition contains a trailing comment after the colon (e.g., 'class Foo(object): # comment'), the autofix may drop the comment when reformatting the line, violating comment preservation safety.
- When 'object' is the first base and followed by a newline-indented block, removing it may cause the linter/formatter to reindent the block incorrectly if the tool does not preserve whitespace exactly, altering readability though not semantics.
- In code that relies on the string representation of the class's bases (e.g., for serialization or debugging), removing 'object' changes the output of __bases__, potentially breaking introspection-dependent logic.
- If a class is defined inside a function and uses 'object' to avoid a name conflict with a local variable named 'object', removing it could cause unintended binding (though this is extremely unlikely and non-standard).
- When using Python 2 compatibility layers like 'six' or 'future', some code may rely on explicit 'object' inheritance to trigger new-style class behavior; removing it in Py2 would break the code, but the rule only applies in Py3+ contexts—still, if the file is run under Py2 due to misconfiguration, the fix introduces a regression.
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p003 | fix-changes-behavior | labelled safe | real · high | related | The fix removes 'object' from the base class list of a class that also inherits from Mixin and Base, changing the MRO and resolving a previously unresolvable d… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Class Attributes vs Instance Attributes | Removing 'object' has no effect on attribute lookup semantics in Python 3, but this program verifies descriptor/__set_name__ behavior remains unchanged after rewrite. |
| r1-p002 | fix ok | Type Annotations Evaluated at Runtime | Ensures that removing 'object' does not affect runtime evaluation of type annotations in class body, especially when using typing-only imports. |
| r1-p003 | fix-changes-behavior | Method Resolution Order Change | Rewriting 'class C(object, Mixin)' to 'class C(Mixin)' alters MRO when Mixin and a later base define the same method, changing which method is called via super(). |
| r1-p004 | fix ok | Generators vs Lists | Tests that removing 'object' does not affect lazy evaluation in generators defined in class scope, ensuring iteration behavior is preserved. |
| r1-p005 | fix ok | Context Managers Not Files | Verifies that removing 'object' does not break context manager protocol (__enter__, __exit__) for non-file objects with custom write-like behavior. |
| r1-p006 | fix ok | Walrus and Comprehensions Scoping | Checks that removing 'object' does not affect scoping in comprehensions or walrus usage inside methods, ensuring closure capture is stable. |
| r1-p007 | fix ok | Whitespace Sensitivity After object Removal | When 'object' is first base and followed by indented block, ensuring linters/formatters do not corrupt indentation upon removal (semantics preserved, readability tested via structure). |
| r1-p008 | invalid | String Formatting Edge Cases | Ensures that removing 'object' does not interfere with string formatting methods (% , format, f-strings) or repr/str behavior in class hierarchy. |
| r2-p001 | fix ok | Star Imports and Module-Level Side Effects | star-imports, module-level side effects, __all__ |
| r2-p002 | fix ok | Runtime Type Annotations with typing-only imports | type annotations evaluated at runtime, typing-only imports |
| r2-p003 | fix ok | Custom __bool__ and Truthiness Semantics | truthiness of custom __bool__/__len__, None vs falsy, 'is' vs '==' |
| r2-p004 | fix ok | Mutable Default Arguments and Aliasing | mutable default arguments and aliasing after a rewrite |
| r2-p005 | fix ok | Dict Ordering, Hash, and Eq Overrides | dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r2-p006 | fix ok | Evaluation Order and Side Effects in Merged Expressions | evaluation order and side effects when expressions are merged, duplicated or deleted |
| r2-p007 | fix ok | Metaclass and __classcell__ Interaction | If a class uses a metaclass via '__metaclass__' attribute (Python 2) or '__classcell__' in nested scopes, removing 'object' may affect class creation semantics in edge cases involving class cell closu |
| r2-p008 | silent prediction off | Nested Class and Local Variable Name Conflict | If a class is defined inside a function and uses 'object' to avoid a name conflict with a local variable named 'object', removing it could cause unintended binding (though this is extremely unlikely a |
Sources
r1-p001 · Class Attributes vs Instance Attributes
1class Descr:
2 def __set_name__(self, owner, name):
3 self.name = name
4 def __get__(self, obj, objtype=None):
5 return getattr(obj, '_' + self.name, None)
6 def __set__(self, obj, value):
7 setattr(obj, '_' + self.name, value * 2)
8
9class A(object):
10 x = Descr()
11 def __init__(self):
12 self.x = 5
13
14a = A()
15print(a.x)
--- orig.py 2026-10-17 17:10:22.461483987 -0400 +++ fixed.py 2026-10-17 17:10:22.627485710 -0400 @@ -6,7 +6,7 @@ def __set__(self, obj, value): setattr(obj, '_' + self.name, value * 2) -class A(object): +class A: x = Descr() def __init__(self): self.x = 5
10
r1-p002 · Type Annotations Evaluated at Runtime
1from typing import List, TYPE_CHECKING
2if TYPE_CHECKING:
3 class _Tmp: pass
4
5class B(object):
6 attr: 'List[int]' = [1, 2, 3]
7 def method(self) -> int:
8 return len(self.attr)
9
10b = B()
11print(b.method())
--- orig.py 2026-10-17 17:10:22.733486810 -0400 +++ fixed.py 2026-10-17 17:10:22.918488730 -0400 @@ -2,7 +2,7 @@ if TYPE_CHECKING: class _Tmp: pass -class B(object): +class B: attr: 'List[int]' = [1, 2, 3] def method(self) -> int: return len(self.attr)
3
r1-p003 · Method Resolution Order Change
1class Mixin:
2 def ping(self):
3 return 'from Mixin'
4
5class Base:
6 def ping(self):
7 return 'from Base'
8
9class C(object, Mixin, Base):
10 def ping(self):
11 return super().ping()
12
13c = C()
14print(c.ping())
--- orig.py 2026-10-17 17:10:23.023489820 -0400 +++ fixed.py 2026-10-17 17:10:23.444494188 -0400 @@ -6,7 +6,7 @@ def ping(self): return 'from Base' -class C(object, Mixin, Base): +class C(Mixin, Base): def ping(self): return super().ping()
r1-p004 · Generators vs Lists
1class D(object):
2 def gen(self):
3 yield 1
4 yield 2
5
6 @property
7 def values(self):
8 return list(self.gen())
9
10d = D()
11print(d.values)
--- orig.py 2026-10-17 17:10:23.542495205 -0400 +++ fixed.py 2026-10-17 17:10:23.700496845 -0400 @@ -1,4 +1,4 @@ -class D(object): +class D: def gen(self): yield 1 yield 2
[1, 2]
r1-p005 · Context Managers Not Files
1class Echo:
2 def __enter__(self):
3 self.buffer = []
4 return self
5 def __exit__(self, *exc):
6 return False
7 def write(self, data):
8 self.buffer.append(data)
9
10class F(object):
11 def log(self):
12 with Echo() as e:
13 e.write('test')
14 return ''.join(e.buffer)
15
16f = F()
17print(f.log())
--- orig.py 2026-10-17 17:10:23.806497945 -0400 +++ fixed.py 2026-10-17 17:10:23.974499688 -0400 @@ -7,7 +7,7 @@ def write(self, data): self.buffer.append(data) -class F(object): +class F: def log(self): with Echo() as e: e.write('test')
test
r1-p006 · Walrus and Comprehensions Scoping
1class G(object):
2 def process(self, data):
3 return [(y := x * 2) for x in data if (y := x * 2) > 4]
4
5g = G()
6print(g.process([1, 2, 3]))
--- orig.py 2026-10-17 17:10:24.072500705 -0400 +++ fixed.py 2026-10-17 17:10:24.231502354 -0400 @@ -1,4 +1,4 @@ -class G(object): +class G: def process(self, data): return [(y := x * 2) for x in data if (y := x * 2) > 4]
[6]
r1-p007 · Whitespace Sensitivity After object Removal
1class H(object):
2 x = 1
3 def get_x(self):
4 return self.x
5
6h = H()
7print(h.get_x())
--- orig.py 2026-10-17 17:10:24.330503381 -0400 +++ fixed.py 2026-10-17 17:10:24.493505072 -0400 @@ -1,4 +1,4 @@ -class H(object): +class H: x = 1 def get_x(self): return self.x
1
r1-p008 · String Formatting Edge Cases (generated program does not parse: Traceback (most recent call last):)
1class I(object):
2 value = 42
3 def __str__(self):
4 return f'Value: {self.value}'
5 def __repr__(self):
6 return f'I({self.value!r})
7'
8
9i = I()
10print(str(i))
11print(repr(i))
r2-p001 · Star Imports and Module-Level Side Effects
1__all__ = []
2
3class _Hidden(object):
4 value = 42
5
6def init():
7 globals().update(_Hidden.__dict__)
8 __all__.append('value')
9
10init()
11print(value)
--- orig.py 2026-10-17 17:10:35.673620945 -0400 +++ fixed.py 2026-10-17 17:10:35.849622768 -0400 @@ -1,6 +1,6 @@ __all__ = [] -class _Hidden(object): +class _Hidden: value = 42 def init():
42
r2-p002 · Runtime Type Annotations with typing-only imports
1from typing import List
2
3class Parser(object):
4 def parse(self, data: List[int]) -> List[str]:
5 return [str(x) for x in data]
6
7p = Parser()
8result = p.parse([1, 2, 3])
9print(result)
--- orig.py 2026-10-17 17:10:35.950623814 -0400 +++ fixed.py 2026-10-17 17:10:36.132625698 -0400 @@ -1,6 +1,6 @@ from typing import List -class Parser(object): +class Parser: def parse(self, data: List[int]) -> List[str]: return [str(x) for x in data]
['1', '2', '3']
r2-p003 · Custom __bool__ and Truthiness Semantics
1class Flag(object):
2 def __init__(self, v):
3 self.v = v
4 def __bool__(self):
5 return self.v is not None
6
7f = Flag(None)
8print(bool(f))
9f.v = 0
10print(bool(f))
--- orig.py 2026-10-17 17:10:36.251626930 -0400 +++ fixed.py 2026-10-17 17:10:36.415628627 -0400 @@ -1,4 +1,4 @@ -class Flag(object): +class Flag: def __init__(self, v): self.v = v def __bool__(self):
False True
r2-p004 · Mutable Default Arguments and Aliasing
1class Container(object):
2 def __init__(self, items=None):
3 self.items = items or []
4 self.items.append(len(self.items))
5
6c1 = Container()
7c2 = Container()
8print(c1.items, c2.items)
--- orig.py 2026-10-17 17:10:36.517629684 -0400 +++ fixed.py 2026-10-17 17:10:36.679631361 -0400 @@ -1,4 +1,4 @@ -class Container(object): +class Container: def __init__(self, items=None): self.items = items or [] self.items.append(len(self.items))
[0] [0]
r2-p005 · Dict Ordering, Hash, and Eq Overrides
1class Key(object):
2 def __init__(self, val):
3 self.val = val
4 def __hash__(self):
5 return hash(self.val)
6 def __eq__(self, other):
7 return isinstance(other, Key) and self.val == other.val
8
9k1 = Key(1)
10k2 = Key(1)
11d = {k1: 'first', k2: 'second'}
12print(len(d), d[k1])
--- orig.py 2026-10-17 17:10:36.785632458 -0400 +++ fixed.py 2026-10-17 17:10:36.952634187 -0400 @@ -1,4 +1,4 @@ -class Key(object): +class Key: def __init__(self, val): self.val = val def __hash__(self):
1 second
r2-p006 · Evaluation Order and Side Effects in Merged Expressions
1counter = 0
2
3def inc():
4 global counter
5 counter += 1
6 return counter
7
8class Test(object):
9 x = inc()
10 y = inc()
11
12print(Test.x, Test.y, counter)
--- orig.py 2026-10-17 17:10:37.053635232 -0400 +++ fixed.py 2026-10-17 17:10:37.227637034 -0400 @@ -5,7 +5,7 @@ counter += 1 return counter -class Test(object): +class Test: x = inc() y = inc()
1 2 2
r2-p007 · Metaclass and __classcell__ Interaction
1def outer():
2 class_cell = None
3
4 class Meta(type):
5 def __new__(mcls, name, bases, namespace, **kw):
6 if '__classcell__' in namespace:
7 namespace['__classcell__'] = namespace.pop('__classcell__')
8 return super().__new__(mcls, name, bases, namespace, **kw)
9
10 class Base(object, metaclass=Meta):
11 pass
12
13 class Derived(Base):
14 x = 1
15
16 return Derived.x
17
18print(outer())
--- orig.py 2026-10-17 17:10:37.318637975 -0400 +++ fixed.py 2026-10-17 17:10:37.484639694 -0400 @@ -7,7 +7,7 @@ namespace['__classcell__'] = namespace.pop('__classcell__') return super().__new__(mcls, name, bases, namespace, **kw) - class Base(object, metaclass=Meta): + class Base(metaclass=Meta): pass class Derived(Base):
1
r2-p008 · Nested Class and Local Variable Name Conflict
1def make_class():
2 object = 42 # local variable named 'object'
3 class Local(object): # inherits from built-in object, not the local var
4 def get(self):
5 return object # refers to local var due to scoping
6 return Local()
7
8inst = make_class()
9print(inst.get())