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