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