diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst --- a/Doc/library/2to3.rst +++ b/Doc/library/2to3.rst @@ -137,16 +137,53 @@ Each step of transforming code is encaps and off individually. They are described here in more detail. .. 2to3fixer:: apply Removes usage of :func:`apply`. For example ``apply(function, *args, **kwargs)`` is converted to ``function(*args, **kwargs)``. +.. 2to3fixer:: asserts + + Replaces deprecated :mod:`unittest` method names with the correct ones. + + ========================================= ========================================== + From To + ========================================= ========================================== + ``failUnlessEqual(a, b)`` :meth:`assertEqual(a, b) + ` + ``assertEquals(a, b)`` :meth:`assertEqual(a, b) + ` + ``failIfEqual(a, b)`` :meth:`assertNotEqual(a, b) + ` + ``assertNotEquals(a, b)`` :meth:`assertNotEqual(a, b) + ` + ``failUnless(a)`` :meth:`assertTrue(a) + ` + ``assert_(a)`` :meth:`assertTrue(a) + ` + ``failIf(a)`` :meth:`assertFalse(a) + ` + ``failUnlessRaises(exc, cal)`` :meth:`assertRaises(exc, cal) + ` + ``failUnlessAlmostEqual(a, b)`` :meth:`assertAlmostEqual(a, b) + ` + ``assertAlmostEquals(a, b)`` :meth:`assertAlmostEqual(a, b) + ` + ``failIfAlmostEqual(a, b)`` :meth:`assertNotAlmostEqual(a, b) + ` + ``assertNotAlmostEquals(a, b)`` :meth:`assertNotAlmostEqual(a, b) + ` + ``assertRegexpMatches(text, regex)`` :meth:`assertRegex(text, regex) + ` + ``assertRaisesRegexp(exc, regex, cal)`` :meth:`assertRaisesRegex(exc, regex, cal) + ` + ========================================= ========================================== + .. 2to3fixer:: basestring Converts :class:`basestring` to :class:`str`. .. 2to3fixer:: buffer Converts :class:`buffer` to :class:`memoryview`. This fixer is optional because the :class:`memoryview` API is similar but not exactly the same as diff --git a/Lib/lib2to3/fixes/fix_asserts.py b/Lib/lib2to3/fixes/fix_asserts.py new file mode 100644 --- /dev/null +++ b/Lib/lib2to3/fixes/fix_asserts.py @@ -0,0 +1,34 @@ +"""Fixer that replaces deprecated unittest method names.""" + +# Author: Ezio Melotti + +from ..fixer_base import BaseFix +from ..fixer_util import Name + +NAMES = dict( + assert_="assertTrue", + assertEquals="assertEqual", + assertNotEquals="assertNotEqual", + assertAlmostEquals="assertAlmostEqual", + assertNotAlmostEquals="assertNotAlmostEqual", + assertRegexpMatches="assertRegex", + assertRaisesRegexp="assertRaisesRegex", + failUnlessEqual="assertEqual", + failIfEqual="assertNotEqual", + failUnlessAlmostEqual="assertAlmostEqual", + failIfAlmostEqual="assertNotAlmostEqual", + failUnless="assertTrue", + failUnlessRaises="assertRaises", + failIf="assertFalse", +) + + +class FixAsserts(BaseFix): + + PATTERN = """ + power< any+ trailer< '.' meth=(%s)> any* > + """ % '|'.join(map(repr, NAMES)) + + def transform(self, node, results): + name = results["meth"][0] + name.replace(Name(NAMES[str(name)], prefix=name.prefix)) diff --git a/Lib/lib2to3/tests/test_fixers.py b/Lib/lib2to3/tests/test_fixers.py --- a/Lib/lib2to3/tests/test_fixers.py +++ b/Lib/lib2to3/tests/test_fixers.py @@ -4593,8 +4593,68 @@ class Test_exitfunc(FixerTestCase): msg = ("Can't find sys import; Please add an atexit import at the " "top of your file.") self.warns(b, a, msg) def test_unchanged(self): s = """f(sys.exitfunc)""" self.unchanged(s) + + +class Test_asserts(FixerTestCase): + + fixer = "asserts" + + def test_deprecated_names(self): + tests = (('self.assert_(True)', 'self.assertTrue(True)'), + ('self.assertEquals(2, 2)', 'self.assertEqual(2, 2)'), + ('self.assertNotEquals(2, 3)', 'self.assertNotEqual(2, 3)'), + ('self.assertAlmostEquals(2, 3)', + 'self.assertAlmostEqual(2, 3)'), + ('self.assertNotAlmostEquals(2, 8)', + 'self.assertNotAlmostEqual(2, 8)'), + ('self.failUnlessEqual(2, 2)', 'self.assertEqual(2, 2)'), + ('self.failIfEqual(2, 3)', 'self.assertNotEqual(2, 3)'), + ('self.failUnlessAlmostEqual(2, 3)', + 'self.assertAlmostEqual(2, 3)'), + ('self.failIfAlmostEqual(2, 8)', + 'self.assertNotAlmostEqual(2, 8)'), + ('self.failUnless(True)', 'self.assertTrue(True)'), + ('self.failUnlessRaises(foo)', 'self.assertRaises(foo)'), + ('self.failIf(False)', 'self.assertFalse(False)'), + ('self.assertRegexpMatches("hello", "hel*o")', + 'self.assertRegex("hello", "hel*o")'), + ('self.assertRaisesRegexp(ValueError, "invalid literal for.*XYZ$", int, "XYZ")', + 'self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ$", int, "XYZ")'),) + + for b, a in tests: + self.check(b, a) + + def test_variants(self): + b = 'eq = self.assertEquals' + a = 'eq = self.assertEqual' + self.check(b, a) + b = 'self.assertEquals(2, 3, msg="fail")' + a = 'self.assertEqual(2, 3, msg="fail")' + self.check(b, a) + b = 'self.assertEquals(2, 3, msg="fail") # foo' + a = 'self.assertEqual(2, 3, msg="fail") # foo' + self.check(b, a) + b = 'self.assertEquals (2, 3)' + a = 'self.assertEqual (2, 3)' + self.check(b, a) + b = ' self.assertEquals (2, 3)' + a = ' self.assertEqual (2, 3)' + self.check(b, a) + b = 'with self.failUnlessRaises(Explosion): explode()' + a = 'with self.assertRaises(Explosion): explode()' + self.check(b, a) + b = 'with self.failUnlessRaises(Explosion) as cm: explode()' + a = 'with self.assertRaises(Explosion) as cm: explode()' + self.check(b, a) + b = 'with self.assertRaisesRegexp(ValueError, "literal"): int("XYZ")' + a = 'with self.assertRaisesRegex(ValueError, "literal"): int("XYZ")' + self.check(b, a) + + def test_unchanged(self): + self.unchanged('self.assertEqualsOnSaturday') + self.unchanged('self.assertEqualsOnSaturday(3, 5)')