ruff UP005
labelled unknown
Analysis Nemotron 3 Super
Flags usage of deprecated unittest method aliases like assertEquals, assertNotEquals, etc.
Fix: Replaces deprecated unittest method aliases with their non-deprecated counterparts (e.g., assertEquals → assertEqual, assertNotEquals → assertNotEqual, failUnless → assertTrue, failIf → assertFalse, assertRaisesRegexp → assertRaisesRegex, assertRegexpMatches → assertRegex).
12 hazards
- Rewriting self.assertEquals to self.assertEqual changes behavior if a subclass overrides assertEquals but not assertEqual, breaking polymorphism.
- If 'self' is not a TestCase instance (e.g., a mock or wrapper), the rewritten method may not exist, causing AttributeError.
- Comments attached to the deprecated method name (e.g., self.assertEquals # TODO) are lost during token replacement.
- In dynamically generated code via exec() or eval(), the string 'assertEquals' may be referenced elsewhere, and rewriting breaks string-based lookups.
- If a variable named 'assertEquals' exists in local scope (e.g., assertEquals = 5), the rewrite incorrectly modifies it to 'assertEqual', causing a NameError.
- When using getattr(self, 'assertEquals') dynamically, the rewrite does not update the string argument, causing a mismatch.
- In code that inspects method names via __dict__ or dir(), the renamed method alters introspection results, affecting frameworks that rely on deprecated names.
- If the code runs under Python <3.12 where deprecated aliases still exist, the fix is unnecessary but harmless; however, in rare cases of custom unittest subclasses that deliberately shadow the deprecated name, the rewrite may bypass intended overrides.
- Rewriting assertRaisesRegexp to assertRaisesRegex fails if the test framework or monkey-patched version expects the old name for plugin compatibility.
- In code that uses functools.partial or methodcaller with the deprecated name as a string, the fix does not update those references, leading to runtime errors.
- If the deprecated method is accessed via a class variable alias (e.g., eq = self.assertEquals), the rewrite does not propagate to the alias, leaving stale references.
- In IPython notebooks or interactive environments where unittest is reloaded, the fix may misfire due to delayed module state.
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p001 | fix-changes-behavior | labelled safe | real · high | related | The fix replaces the deprecated alias `assertEquals` with `assertEqual`, but the original code relied on the `AttributeError` from the missing alias to short-c… |
| r1-p004 | fix-changes-behavior | labelled safe | real · high | no match | The rule rewrites self.assertEquals to self.assertEqual assuming it only replaces a deprecated alias, but the program defines a custom assertEquals method in a… |
| r1-p007 | fix-changes-behavior | labelled safe | intended-change · high | no match | The rule replaces the deprecated alias assertEquals with assertEqual, which is exactly the semantic change the rule documents. The before-run fails with Attrib… |
| r1-p006 | fix-changes-behavior | labelled safe | program-bug · high | no match | The original program already fails with an AttributeError because 'assertAlmostEquals' does not exist on the TestCase class in the execution environment (likel… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix-changes-behavior | Walrus and comprehension scoping interaction | UP005 replacement inside list comprehension with walrus operator alters variable scope capture, causing incorrect value retention after loop. |
| r1-p002 | fix ok | Runtime-evaluated type annotation with forward reference | UP005 rewrites assertEquals in a string annotation evaluated at runtime via typing.get_type_hints, breaking if the method no longer exists. |
| r1-p003 | silent prediction off | Dynamic getattr with string name not updated by fix | UP005 does not rewrite the string argument in getattr(self, 'assertEquals'), so after fix, the method no longer exists causing AttributeError. |
| r1-p004 | fix-changes-behavior | Custom subclass shadowing deprecated alias intentionally | UP005 rewrites self.assertEquals to self.assertEqual, bypassing a deliberate override in a subclass that defines assertEquals for custom behavior. |
| r1-p005 | silent prediction off | functools.partial with deprecated method name as string | UP005 does not update the string in functools.partial(self, 'assertEquals'), so partial fails after rewrite when method renamed. |
| r1-p006 | fix-changes-behavior | Float division and rounding in assertion arguments | UP005 rewrite occurs in assertAlmostEquals with float division arguments; precision-sensitive output shows if fix alters evaluation timing or value. |
| r1-p007 | fix-changes-behavior | Comments attached to deprecated method line | UP005 removal of self.assertAlsoEqually (typo) leaves orphan comment; but we use correct shape: comment on assertEquals line persists after fix, but if line is changed, comment may misattach. |
| r1-p008 | fix ok prediction off | IPython-like reload simulation: module state delay | Simulates delayed unittest state: after rewriting assertEquals to assertEqual, if unittest module is reloaded and old alias restored, call fails. |
Sources
r1-p001 · Walrus and comprehension scoping interaction
1import unittest
2class Test(unittest.TestCase):
3 def test(self):
4 data = [1, 2, 3]
5 results = [(x := i) for i in data if self.assertEquals(x, i)]
6 print('results:', results)
7 print('final x:', x)
8Test().test()
--- orig.py 2026-10-17 17:11:31.333194520 -0400 +++ fixed.py 2026-10-17 17:11:31.786199166 -0400 @@ -2,7 +2,7 @@ class Test(unittest.TestCase): def test(self): data = [1, 2, 3] - results = [(x := i) for i in data if self.assertEquals(x, i)] + results = [(x := i) for i in data if self.assertEqual(x, i)] print('results:', results) print('final x:', x) Test().test()
r1-p002 · Runtime-evaluated type annotation with forward reference
1import unittest
2from typing import get_type_hints
3class Test(unittest.TestCase):
4 def method(self) -> 'assertEquals(1, 1)':
5 pass
6class TestSub(Test):
7 def test(self):
8 hints = get_type_hints(self.method, include_extras=True)
9 print('hints:', hints)
10 try:
11 self.assertEquals(1, 1)
12 except AttributeError as e:
13 print('AttributeError:', type(e).__name__, str(e))
14TestSub().test()
--- orig.py 2026-10-17 17:11:32.014201505 -0400 +++ fixed.py 2026-10-17 17:11:32.443205905 -0400 @@ -8,7 +8,7 @@ hints = get_type_hints(self.method, include_extras=True) print('hints:', hints) try: - self.assertEquals(1, 1) + self.assertEqual(1, 1) except AttributeError as e: print('AttributeError:', type(e).__name__, str(e)) TestSub().test()
r1-p003 · Dynamic getattr with string name not updated by fix
1import unittest
2class Test(unittest.TestCase):
3 def test(self):
4 method_name = 'assertEquals'
5 method = getattr(self, method_name)
6 try:
7 method(1, 1)
8 print('Success')
9 except AttributeError as e:
10 print('AttributeError:', type(e).__name__, str(e))
11Test().test()
r1-p004 · Custom subclass shadowing deprecated alias intentionally
1import unittest
2class CustomTestCase(unittest.TestCase):
3 def assertEquals(self, a, b):
4 print('Custom assertEquals called with', a, b)
5 return super().assertEqual(a, b)
6class Test(CustomTestCase):
7 def test(self):
8 self.assertEquals(1, 1)
9 self.assertEqual(2, 2)
10Test().test()
--- orig.py 2026-10-17 17:11:33.054212171 -0400 +++ fixed.py 2026-10-17 17:11:33.289214581 -0400 @@ -5,6 +5,6 @@ return super().assertEqual(a, b) class Test(CustomTestCase): def test(self): - self.assertEquals(1, 1) + self.assertEqual(1, 1) self.assertEqual(2, 2) Test().test()
Custom assertEquals called with 1 1
r1-p005 · functools.partial with deprecated method name as string
1import unittest
2import functools
3class Test(unittest.TestCase):
4 def test(self):
5 func = functools.partial(getattr(self, 'assertEquals'), 1)
6 try:
7 func(1)
8 print('Success')
9 except AttributeError as e:
10 print('AttributeError:', type(e).__name__, str(e))
11Test().test()
r1-p006 · Float division and rounding in assertion arguments
1import unittest
2class Test(unittest.TestCase):
3 def test(self):
4 val = 1.0 / 3.0
5 try:
6 self.assertAlmostEquals(val, 0.333, places=5)
7 print('assertAlmostEquals passed')
8 except AssertionError as e:
9 print('AssertionError:', type(e).__name__, str(e))
10 self.assertAlmostEqual(val, 0.333, places=5)
11 print('assertEqual passed')
12Test().test()
--- orig.py 2026-10-17 17:11:33.814219965 -0400 +++ fixed.py 2026-10-17 17:11:34.214224066 -0400 @@ -3,7 +3,7 @@ def test(self): val = 1.0 / 3.0 try: - self.assertAlmostEquals(val, 0.333, places=5) + self.assertAlmostEqual(val, 0.333, places=5) print('assertAlmostEquals passed') except AssertionError as e: print('AssertionError:', type(e).__name__, str(e))
r1-p007 · Comments attached to deprecated method line
1import unittest
2class Test(unittest.TestCase):
3 def test(self):
4 # This check validates user input equivalence
5 self.assertEquals('hello', 'hello') # inline: critical
6 print('Comment preserved and check passed')
7Test().test()
--- orig.py 2026-10-17 17:11:34.442226404 -0400 +++ fixed.py 2026-10-17 17:11:34.851230597 -0400 @@ -2,6 +2,6 @@ class Test(unittest.TestCase): def test(self): # This check validates user input equivalence - self.assertEquals('hello', 'hello') # inline: critical + self.assertEqual('hello', 'hello') # inline: critical print('Comment preserved and check passed') Test().test()
r1-p008 · IPython-like reload simulation: module state delay
1import unittest
2import sys
3# Simulate IPython reload: restore deprecated alias after import
4if 'unittest' in sys.modules:
5 unittest.TestCase.assertEquals = lambda self, a, b: self.assertEqual(a, b)
6class Test(unittest.TestCase):
7 def test(self):
8 try:
9 self.assertEquals(1, 1)
10 print('Success via restored alias')
11 except AttributeError as e:
12 print('AttributeError:', type(e).__name__, str(e))
13Test().test()
--- orig.py 2026-10-17 17:11:34.995232074 -0400 +++ fixed.py 2026-10-17 17:11:35.246234647 -0400 @@ -6,7 +6,7 @@ class Test(unittest.TestCase): def test(self): try: - self.assertEquals(1, 1) + self.assertEqual(1, 1) print('Success via restored alias') except AttributeError as e: print('AttributeError:', type(e).__name__, str(e))
Success via restored alias