1import unittest 2import sys 3from test.test_support import check_py3k_warnings, CleanImport, run_unittest 4import warnings 5from test import test_support 6 7if not sys.py3kwarning: 8 raise unittest.SkipTest('%s must be run with the -3 flag' % __name__) 9 10try: 11 from test.test_support import __warningregistry__ as _registry 12except ImportError: 13 def check_deprecated_module(module_name): 14 return False 15else: 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 27def reset_module_registry(module): 28 try: 29 registry = module.__warningregistry__ 30 except AttributeError: 31 pass 32 else: 33 registry.clear() 34 35class 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 317class 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 442def test_main(): 443 run_unittest(TestPy3KWarnings, 444 TestStdlibRemovals) 445 446if __name__ == '__main__': 447 test_main() 448