Home | History | Annotate | Download | only in test
      1 import unittest
      2 import sys
      3 from test.test_support import check_py3k_warnings, CleanImport, run_unittest
      4 import warnings
      5 from test import test_support
      6 
      7 if not sys.py3kwarning:
      8     raise unittest.SkipTest('%s must be run with the -3 flag' % __name__)
      9 
     10 try:
     11     from test.test_support import __warningregistry__ as _registry
     12 except ImportError:
     13     def check_deprecated_module(module_name):
     14         return False
     15 else:
     16     past_warnings = _registry.keys()
     17     del _registry
     18     def check_deprecated_module(module_name):
     19         """Lookup the past warnings for module already loaded using
     20         test_support.import_module(..., deprecated=True)
     21         """
     22         return any(module_name in msg and ' removed' in msg
     23                    and issubclass(cls, DeprecationWarning)
     24                    and (' module' in msg or ' package' in msg)
     25                    for (msg, cls, line) in past_warnings)
     26 
     27 def reset_module_registry(module):
     28     try:
     29         registry = module.__warningregistry__
     30     except AttributeError:
     31         pass
     32     else:
     33         registry.clear()
     34 
     35 class TestPy3KWarnings(unittest.TestCase):
     36 
     37     def assertWarning(self, _, warning, expected_message):
     38         self.assertEqual(str(warning.message), expected_message)
     39 
     40     def assertNoWarning(self, _, recorder):
     41         self.assertEqual(len(recorder.warnings), 0)
     42 
     43     def test_backquote(self):
     44         expected = 'backquote not supported in 3.x; use repr()'
     45         with check_py3k_warnings((expected, SyntaxWarning)):
     46             exec "`2`" in {}
     47 
     48     def test_paren_arg_names(self):
     49         expected = 'parenthesized argument names are invalid in 3.x'
     50         def check(s):
     51             with check_py3k_warnings((expected, SyntaxWarning)):
     52                 exec s in {}
     53         check("def f((x)): pass")
     54         check("def f((((x))), (y)): pass")
     55         check("def f((x), (((y))), m=32): pass")
     56         # Something like def f((a, (b))): pass will raise the tuple
     57         # unpacking warning.
     58 
     59     def test_forbidden_names(self):
     60         # So we don't screw up our globals
     61         def safe_exec(expr):
     62             def f(**kwargs): pass
     63             exec expr in {'f' : f}
     64 
     65         tests = [("True", "assignment to True or False is forbidden in 3.x"),
     66                  ("False", "assignment to True or False is forbidden in 3.x"),
     67                  ("nonlocal", "nonlocal is a keyword in 3.x")]
     68         with check_py3k_warnings(('', SyntaxWarning)) as w:
     69             for keyword, expected in tests:
     70                 safe_exec("{0} = False".format(keyword))
     71                 self.assertWarning(None, w, expected)
     72                 w.reset()
     73                 try:
     74                     safe_exec("obj.{0} = True".format(keyword))
     75                 except NameError:
     76                     pass
     77                 self.assertWarning(None, w, expected)
     78                 w.reset()
     79                 safe_exec("def {0}(): pass".format(keyword))
     80                 self.assertWarning(None, w, expected)
     81                 w.reset()
     82                 safe_exec("class {0}: pass".format(keyword))
     83                 self.assertWarning(None, w, expected)
     84                 w.reset()
     85                 safe_exec("def f({0}=43): pass".format(keyword))
     86                 self.assertWarning(None, w, expected)
     87                 w.reset()
     88 
     89 
     90     def test_type_inequality_comparisons(self):
     91         expected = 'type inequality comparisons not supported in 3.x'
     92         with check_py3k_warnings() as w:
     93             self.assertWarning(int < str, w, expected)
     94             w.reset()
     95             self.assertWarning(type < object, w, expected)
     96 
     97     def test_object_inequality_comparisons(self):
     98         expected = 'comparing unequal types not supported in 3.x'
     99         with check_py3k_warnings() as w:
    100             self.assertWarning(str < [], w, expected)
    101             w.reset()
    102             self.assertWarning(object() < (1, 2), w, expected)
    103 
    104     def test_dict_inequality_comparisons(self):
    105         expected = 'dict inequality comparisons not supported in 3.x'
    106         with check_py3k_warnings() as w:
    107             self.assertWarning({} < {2:3}, w, expected)
    108             w.reset()
    109             self.assertWarning({} <= {}, w, expected)
    110             w.reset()
    111             self.assertWarning({} > {2:3}, w, expected)
    112             w.reset()
    113             self.assertWarning({2:3} >= {}, w, expected)
    114 
    115     def test_cell_inequality_comparisons(self):
    116         expected = 'cell comparisons not supported in 3.x'
    117         def f(x):
    118             def g():
    119                 return x
    120             return g
    121         cell0, = f(0).func_closure
    122         cell1, = f(1).func_closure
    123         with check_py3k_warnings() as w:
    124             self.assertWarning(cell0 == cell1, w, expected)
    125             w.reset()
    126             self.assertWarning(cell0 < cell1, w, expected)
    127 
    128     def test_code_inequality_comparisons(self):
    129         expected = 'code inequality comparisons not supported in 3.x'
    130         def f(x):
    131             pass
    132         def g(x):
    133             pass
    134         with check_py3k_warnings() as w:
    135             self.assertWarning(f.func_code < g.func_code, w, expected)
    136             w.reset()
    137             self.assertWarning(f.func_code <= g.func_code, w, expected)
    138             w.reset()
    139             self.assertWarning(f.func_code >= g.func_code, w, expected)
    140             w.reset()
    141             self.assertWarning(f.func_code > g.func_code, w, expected)
    142 
    143     def test_builtin_function_or_method_comparisons(self):
    144         expected = ('builtin_function_or_method '
    145                     'order comparisons not supported in 3.x')
    146         func = eval
    147         meth = {}.get
    148         with check_py3k_warnings() as w:
    149             self.assertWarning(func < meth, w, expected)
    150             w.reset()
    151             self.assertWarning(func > meth, w, expected)
    152             w.reset()
    153             self.assertWarning(meth <= func, w, expected)
    154             w.reset()
    155             self.assertWarning(meth >= func, w, expected)
    156             w.reset()
    157             self.assertNoWarning(meth == func, w)
    158             self.assertNoWarning(meth != func, w)
    159             lam = lambda x: x
    160             self.assertNoWarning(lam == func, w)
    161             self.assertNoWarning(lam != func, w)
    162 
    163     def test_frame_attributes(self):
    164         template = "%s has been removed in 3.x"
    165         f = sys._getframe(0)
    166         for attr in ("f_exc_traceback", "f_exc_value", "f_exc_type"):
    167             expected = template % attr
    168             with check_py3k_warnings() as w:
    169                 self.assertWarning(getattr(f, attr), w, expected)
    170                 w.reset()
    171                 self.assertWarning(setattr(f, attr, None), w, expected)
    172 
    173     def test_sort_cmp_arg(self):
    174         expected = "the cmp argument is not supported in 3.x"
    175         lst = range(5)
    176         cmp = lambda x,y: -1
    177 
    178         with check_py3k_warnings() as w:
    179             self.assertWarning(lst.sort(cmp=cmp), w, expected)
    180             w.reset()
    181             self.assertWarning(sorted(lst, cmp=cmp), w, expected)
    182             w.reset()
    183             self.assertWarning(lst.sort(cmp), w, expected)
    184             w.reset()
    185             self.assertWarning(sorted(lst, cmp), w, expected)
    186 
    187     def test_sys_exc_clear(self):
    188         expected = 'sys.exc_clear() not supported in 3.x; use except clauses'
    189         with check_py3k_warnings() as w:
    190             self.assertWarning(sys.exc_clear(), w, expected)
    191 
    192     def test_methods_members(self):
    193         expected = '__members__ and __methods__ not supported in 3.x'
    194         class C:
    195             __methods__ = ['a']
    196             __members__ = ['b']
    197         c = C()
    198         with check_py3k_warnings() as w:
    199             self.assertWarning(dir(c), w, expected)
    200 
    201     def test_softspace(self):
    202         expected = 'file.softspace not supported in 3.x'
    203         with file(__file__) as f:
    204             with check_py3k_warnings() as w:
    205                 self.assertWarning(f.softspace, w, expected)
    206             def set():
    207                 f.softspace = 0
    208             with check_py3k_warnings() as w:
    209                 self.assertWarning(set(), w, expected)
    210 
    211     def test_slice_methods(self):
    212         class Spam(object):
    213             def __getslice__(self, i, j): pass
    214             def __setslice__(self, i, j, what): pass
    215             def __delslice__(self, i, j): pass
    216         class Egg:
    217             def __getslice__(self, i, h): pass
    218             def __setslice__(self, i, j, what): pass
    219             def __delslice__(self, i, j): pass
    220 
    221         expected = "in 3.x, __{0}slice__ has been removed; use __{0}item__"
    222 
    223         for obj in (Spam(), Egg()):
    224             with check_py3k_warnings() as w:
    225                 self.assertWarning(obj[1:2], w, expected.format('get'))
    226                 w.reset()
    227                 del obj[3:4]
    228                 self.assertWarning(None, w, expected.format('del'))
    229                 w.reset()
    230                 obj[4:5] = "eggs"
    231                 self.assertWarning(None, w, expected.format('set'))
    232 
    233     def test_tuple_parameter_unpacking(self):
    234         expected = "tuple parameter unpacking has been removed in 3.x"
    235         with check_py3k_warnings((expected, SyntaxWarning)):
    236             exec "def f((a, b)): pass"
    237 
    238     def test_buffer(self):
    239         expected = 'buffer() not supported in 3.x'
    240         with check_py3k_warnings() as w:
    241             self.assertWarning(buffer('a'), w, expected)
    242 
    243     def test_file_xreadlines(self):
    244         expected = ("f.xreadlines() not supported in 3.x, "
    245                     "try 'for line in f' instead")
    246         with file(__file__) as f:
    247             with check_py3k_warnings() as w:
    248                 self.assertWarning(f.xreadlines(), w, expected)
    249 
    250     def test_hash_inheritance(self):
    251         with check_py3k_warnings() as w:
    252             # With object as the base class
    253             class WarnOnlyCmp(object):
    254                 def __cmp__(self, other): pass
    255             self.assertEqual(len(w.warnings), 0)
    256             w.reset()
    257             class WarnOnlyEq(object):
    258                 def __eq__(self, other): pass
    259             self.assertEqual(len(w.warnings), 1)
    260             self.assertWarning(None, w,
    261                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
    262             w.reset()
    263             class WarnCmpAndEq(object):
    264                 def __cmp__(self, other): pass
    265                 def __eq__(self, other): pass
    266             self.assertEqual(len(w.warnings), 1)
    267             self.assertWarning(None, w,
    268                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
    269             w.reset()
    270             class NoWarningOnlyHash(object):
    271                 def __hash__(self): pass
    272             self.assertEqual(len(w.warnings), 0)
    273             # With an intermediate class in the hierarchy
    274             class DefinesAllThree(object):
    275                 def __cmp__(self, other): pass
    276                 def __eq__(self, other): pass
    277                 def __hash__(self): pass
    278             class WarnOnlyCmp(DefinesAllThree):
    279                 def __cmp__(self, other): pass
    280             self.assertEqual(len(w.warnings), 0)
    281             w.reset()
    282             class WarnOnlyEq(DefinesAllThree):
    283                 def __eq__(self, other): pass
    284             self.assertEqual(len(w.warnings), 1)
    285             self.assertWarning(None, w,
    286                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
    287             w.reset()
    288             class WarnCmpAndEq(DefinesAllThree):
    289                 def __cmp__(self, other): pass
    290                 def __eq__(self, other): pass
    291             self.assertEqual(len(w.warnings), 1)
    292             self.assertWarning(None, w,
    293                  "Overriding __eq__ blocks inheritance of __hash__ in 3.x")
    294             w.reset()
    295             class NoWarningOnlyHash(DefinesAllThree):
    296                 def __hash__(self): pass
    297             self.assertEqual(len(w.warnings), 0)
    298 
    299     def test_operator(self):
    300         from operator import isCallable, sequenceIncludes
    301 
    302         callable_warn = ("operator.isCallable() is not supported in 3.x. "
    303                          "Use hasattr(obj, '__call__').")
    304         seq_warn = ("operator.sequenceIncludes() is not supported "
    305                     "in 3.x. Use operator.contains().")
    306         with check_py3k_warnings() as w:
    307             self.assertWarning(isCallable(self), w, callable_warn)
    308             w.reset()
    309             self.assertWarning(sequenceIncludes(range(3), 2), w, seq_warn)
    310 
    311     def test_nonascii_bytes_literals(self):
    312         expected = "non-ascii bytes literals not supported in 3.x"
    313         with check_py3k_warnings((expected, SyntaxWarning)):
    314             exec "b'\xbd'"
    315 
    316 
    317 class TestStdlibRemovals(unittest.TestCase):
    318 
    319     # test.testall not tested as it executes all unit tests as an
    320     # import side-effect.
    321     all_platforms = ('audiodev', 'imputil', 'mutex', 'user', 'new', 'rexec',
    322                         'Bastion', 'compiler', 'dircache', 'mimetools',
    323                         'fpformat', 'ihooks', 'mhlib', 'statvfs', 'htmllib',
    324                         'sgmllib', 'rfc822', 'sunaudio')
    325     inclusive_platforms = {'irix' : ('pure', 'AL', 'al', 'CD', 'cd', 'cddb',
    326                                      'cdplayer', 'CL', 'cl', 'DEVICE', 'GL',
    327                                      'gl', 'ERRNO', 'FILE', 'FL', 'flp', 'fl',
    328                                      'fm', 'GET', 'GLWS', 'imgfile', 'IN',
    329                                      'IOCTL', 'jpeg', 'panel', 'panelparser',
    330                                      'readcd', 'SV', 'torgb', 'WAIT'),
    331                           'darwin' : ('autoGIL', 'Carbon', 'OSATerminology',
    332                                       'icglue', 'Nav',
    333                                       # MacOS should (and does) give a Py3kWarning, but one of the
    334                                       # earlier tests already imports the MacOS extension which causes
    335                                       # this test to fail. Disabling the test for 'MacOS' avoids this
    336                                       # spurious test failure.
    337                                       #'MacOS',
    338                                       'aepack',
    339                                       'aetools', 'aetypes', 'applesingle',
    340                                       'appletrawmain', 'appletrunner',
    341                                       'argvemulator', 'bgenlocations',
    342                                       'EasyDialogs', 'macerrors', 'macostools',
    343                                       'findertools', 'FrameWork', 'ic',
    344                                       'gensuitemodule', 'icopen', 'macresource',
    345                                       'MiniAEFrame', 'pimp', 'PixMapWrapper',
    346                                       'terminalcommand', 'videoreader',
    347                                       '_builtinSuites', 'CodeWarrior',
    348                                       'Explorer', 'Finder', 'Netscape',
    349                                       'StdSuites', 'SystemEvents', 'Terminal',
    350                                       'cfmfile', 'bundlebuilder', 'buildtools',
    351                                       'ColorPicker', 'Audio_mac'),
    352                            'sunos5' : ('sunaudiodev', 'SUNAUDIODEV'),
    353                           }
    354     optional_modules = ('bsddb185', 'Canvas', 'dl', 'linuxaudiodev', 'imageop',
    355                         'sv', 'bsddb', 'dbhash')
    356 
    357     def check_removal(self, module_name, optional=False):
    358         """Make sure the specified module, when imported, raises a
    359         DeprecationWarning and specifies itself in the message."""
    360         if module_name in sys.modules:
    361             mod = sys.modules[module_name]
    362             filename = getattr(mod, '__file__', '')
    363             mod = None
    364             # the module is not implemented in C?
    365             if not filename.endswith(('.py', '.pyc', '.pyo')):
    366                 # Issue #23375: If the module was already loaded, reimporting
    367                 # the module will not emit again the warning. The warning is
    368                 # emited when the module is loaded, but C modules cannot
    369                 # unloaded.
    370                 if test_support.verbose:
    371                     print("Cannot test the Python 3 DeprecationWarning of the "
    372                           "%s module, the C module is already loaded"
    373                           % module_name)
    374                 return
    375         with CleanImport(module_name), warnings.catch_warnings():
    376             warnings.filterwarnings("error", ".+ (module|package) .+ removed",
    377                                     DeprecationWarning, __name__)
    378             warnings.filterwarnings("error", ".+ removed .+ (module|package)",
    379                                     DeprecationWarning, __name__)
    380             try:
    381                 __import__(module_name, level=0)
    382             except DeprecationWarning as exc:
    383                 self.assertIn(module_name, exc.args[0],
    384                               "%s warning didn't contain module name"
    385                               % module_name)
    386             except ImportError:
    387                 if not optional:
    388                     self.fail("Non-optional module {0} raised an "
    389                               "ImportError.".format(module_name))
    390             else:
    391                 # For extension modules, check the __warningregistry__.
    392                 # They won't rerun their init code even with CleanImport.
    393                 if not check_deprecated_module(module_name):
    394                     self.fail("DeprecationWarning not raised for {0}"
    395                               .format(module_name))
    396 
    397     def test_platform_independent_removals(self):
    398         # Make sure that the modules that are available on all platforms raise
    399         # the proper DeprecationWarning.
    400         for module_name in self.all_platforms:
    401             self.check_removal(module_name)
    402 
    403     def test_platform_specific_removals(self):
    404         # Test the removal of platform-specific modules.
    405         for module_name in self.inclusive_platforms.get(sys.platform, []):
    406             self.check_removal(module_name, optional=True)
    407 
    408     def test_optional_module_removals(self):
    409         # Test the removal of modules that may or may not be built.
    410         for module_name in self.optional_modules:
    411             self.check_removal(module_name, optional=True)
    412 
    413     def test_os_path_walk(self):
    414         msg = "In 3.x, os.path.walk is removed in favor of os.walk."
    415         def dumbo(where, names, args): pass
    416         for path_mod in ("ntpath", "macpath", "os2emxpath", "posixpath"):
    417             mod = __import__(path_mod)
    418             reset_module_registry(mod)
    419             with check_py3k_warnings() as w:
    420                 mod.walk("crashers", dumbo, None)
    421             self.assertEqual(str(w.message), msg)
    422 
    423     def test_reduce_move(self):
    424         from operator import add
    425         # reduce tests may have already triggered this warning
    426         reset_module_registry(unittest.case)
    427         with warnings.catch_warnings():
    428             warnings.filterwarnings("error", "reduce")
    429             self.assertRaises(DeprecationWarning, reduce, add, range(10))
    430 
    431     def test_mutablestring_removal(self):
    432         # UserString.MutableString has been removed in 3.0.
    433         import UserString
    434         # UserString tests may have already triggered this warning
    435         reset_module_registry(UserString)
    436         with warnings.catch_warnings():
    437             warnings.filterwarnings("error", ".*MutableString",
    438                                     DeprecationWarning)
    439             self.assertRaises(DeprecationWarning, UserString.MutableString)
    440 
    441 
    442 def test_main():
    443     run_unittest(TestPy3KWarnings,
    444                  TestStdlibRemovals)
    445 
    446 if __name__ == '__main__':
    447     test_main()
    448