1"""
2Tests for the future.standard_library module
3"""
4
5from __future__ import absolute_import, print_function
6from future import standard_library
7from future import utils
8from future.tests.base import unittest, CodeHandler, expectedFailurePY2
9
10import sys
11import tempfile
12import os
13import copy
14import textwrap
15from subprocess import CalledProcessError
16
17
18class TestStandardLibraryReorganization(CodeHandler):
19
20    def setUp(self):
21        self.interpreter = sys.executable
22        standard_library.install_aliases()
23        super(TestStandardLibraryReorganization, self).setUp()
24
25    def tearDown(self):
26        # standard_library.remove_hooks()
27        pass
28
29    def test_can_import_several(self):
30        """
31        This test failed in v0.12-pre if e.g.
32        future/standard_library/email/header.py contained:
33
34            from future import standard_library
35            standard_library.remove_hooks()
36        """
37
38        import future.moves.urllib.parse as urllib_parse
39        import future.moves.urllib.request as urllib_request
40
41        import http.server
42        for m in [urllib_parse, urllib_request, http.server]:
43            self.assertTrue(m is not None)
44
45    def test_is_py2_stdlib_module(self):
46        """
47        Tests whether the internal is_py2_stdlib_module function (called by the
48        sys.modules scrubbing functions) is reliable.
49        """
50        externalmodules = [standard_library, utils]
51        self.assertTrue(not any([standard_library.is_py2_stdlib_module(module)
52                             for module in externalmodules]))
53
54        py2modules = [sys, tempfile, copy, textwrap]
55        if utils.PY2:
56            # Debugging:
57            for module in py2modules:
58                if hasattr(module, '__file__'):
59                    print(module.__file__, file=sys.stderr)
60            self.assertTrue(all([standard_library.is_py2_stdlib_module(module)
61                                 for module in py2modules]))
62        else:
63            self.assertTrue(
64                    not any ([standard_library.is_py2_stdlib_module(module)
65                              for module in py2modules]))
66
67    # @unittest.skip("No longer relevant")
68    # def test_all_modules_identical(self):
69    #     """
70    #     Tests whether all of the old imports in RENAMES are accessible
71    #     under their new names.
72    #     """
73    #     for (oldname, newname) in standard_library.RENAMES.items():
74    #         if newname == 'winreg' and sys.platform not in ['win32', 'win64']:
75    #             continue
76    #         if newname in standard_library.REPLACED_MODULES:
77    #             # Skip this check for e.g. the stdlib's ``test`` module,
78    #             # which we have replaced completely.
79    #             continue
80    #         oldmod = __import__(oldname)
81    #         newmod = __import__(newname)
82    #         if '.' not in oldname:
83    #             self.assertEqual(oldmod, newmod)
84
85    @expectedFailurePY2
86    def test_suspend_hooks(self):
87        """
88        Code like the try/except block here appears in Pyflakes v0.6.1. This
89        method tests whether suspend_hooks() works as advertised.
90        """
91        example_PY2_check = False
92        with standard_library.suspend_hooks():
93            # An example of fragile import code that we don't want to break:
94            try:
95                import builtins
96            except ImportError:
97                example_PY2_check = True
98        if utils.PY2:
99            self.assertTrue(example_PY2_check)
100        else:
101            self.assertFalse(example_PY2_check)
102        # The import should succeed again now:
103        import builtins
104
105    @expectedFailurePY2
106    def test_disable_hooks(self):
107        """
108        Tests the old (deprecated) names. These deprecated aliases should be
109        removed by version 1.0
110        """
111        example_PY2_check = False
112
113        standard_library.enable_hooks()   # deprecated name
114        old_meta_path = copy.copy(sys.meta_path)
115
116        standard_library.disable_hooks()
117        standard_library.scrub_future_sys_modules()
118        if utils.PY2:
119            self.assertTrue(len(old_meta_path) == len(sys.meta_path) + 1)
120        else:
121            self.assertTrue(len(old_meta_path) == len(sys.meta_path))
122
123        # An example of fragile import code that we don't want to break:
124        try:
125            import builtins
126        except ImportError:
127            example_PY2_check = True
128        if utils.PY2:
129            self.assertTrue(example_PY2_check)
130        else:
131            self.assertFalse(example_PY2_check)
132
133        standard_library.install_hooks()
134
135        # Imports should succeed again now:
136        import builtins
137        import html
138        if utils.PY2:
139            self.assertTrue(standard_library.detect_hooks())
140            self.assertTrue(len(old_meta_path) == len(sys.meta_path))
141
142    @expectedFailurePY2
143    def test_remove_hooks2(self):
144        """
145        As above, but with the new names
146        """
147        example_PY2_check = False
148
149        standard_library.install_hooks()
150        old_meta_path = copy.copy(sys.meta_path)
151
152        standard_library.remove_hooks()
153        standard_library.scrub_future_sys_modules()
154        if utils.PY2:
155            self.assertTrue(len(old_meta_path) == len(sys.meta_path) + 1)
156        else:
157            self.assertTrue(len(old_meta_path) == len(sys.meta_path))
158
159        # An example of fragile import code that we don't want to break:
160        try:
161            import builtins
162        except ImportError:
163            example_PY2_check = True
164        if utils.PY2:
165            self.assertTrue(example_PY2_check)
166        else:
167            self.assertFalse(example_PY2_check)
168        standard_library.install_hooks()
169        # The import should succeed again now:
170        import builtins
171        self.assertTrue(len(old_meta_path) == len(sys.meta_path))
172
173    def test_detect_hooks(self):
174        """
175        Tests whether the future.standard_library.detect_hooks is doing
176        its job.
177        """
178        standard_library.install_hooks()
179        if utils.PY2:
180            self.assertTrue(standard_library.detect_hooks())
181
182        meta_path = copy.copy(sys.meta_path)
183
184        standard_library.remove_hooks()
185        if utils.PY2:
186            self.assertEqual(len(meta_path), len(sys.meta_path) + 1)
187            self.assertFalse(standard_library.detect_hooks())
188
189    @unittest.skipIf(utils.PY3, 'not testing for old urllib on Py3')
190    def test_old_urllib_import(self):
191        """
192        Tests whether an imported module can import the old urllib package.
193        Importing future.standard_library in a script should be possible and
194        not disrupt any uses of the old Py2 standard library names in modules
195        imported by that script.
196        """
197        code1 = '''
198                from future import standard_library
199                with standard_library.suspend_hooks():
200                    import module_importing_old_urllib
201                '''
202        self._write_test_script(code1, 'runme.py')
203        code2 = '''
204                import urllib
205                assert 'urlopen' in dir(urllib)
206                print('Import succeeded!')
207                '''
208        self._write_test_script(code2, 'module_importing_old_urllib.py')
209        output = self._run_test_script('runme.py')
210        print(output)
211        self.assertTrue(True)
212
213    def test_sys_intern(self):
214        """
215        Py2's builtin intern() has been moved to the sys module. Tests
216        whether sys.intern is available.
217        """
218        from sys import intern
219        if utils.PY3:
220            self.assertEqual(intern('hello'), 'hello')
221        else:
222            # intern() requires byte-strings on Py2:
223            self.assertEqual(intern(b'hello'), b'hello')
224
225    def test_sys_maxsize(self):
226        """
227        Tests whether sys.maxsize is available.
228        """
229        from sys import maxsize
230        self.assertTrue(maxsize > 0)
231
232    def test_itertools_filterfalse(self):
233        """
234        Tests whether itertools.filterfalse is available.
235        """
236        from itertools import filterfalse
237        not_div_by_3 = filterfalse(lambda x: x % 3 == 0, range(8))
238        self.assertEqual(list(not_div_by_3), [1, 2, 4, 5, 7])
239
240    def test_itertools_zip_longest(self):
241        """
242        Tests whether itertools.zip_longest is available.
243        """
244        from itertools import zip_longest
245        a = (1, 2)
246        b = [2, 4, 6]
247        self.assertEqual(list(zip_longest(a, b)),
248                         [(1, 2), (2, 4), (None, 6)])
249
250    def test_ChainMap(self):
251        """
252        Tests whether collections.ChainMap is available.
253        """
254        from collections import ChainMap
255        cm = ChainMap()
256
257    @unittest.expectedFailure
258    @unittest.skipIf(utils.PY3, 'generic import tests are for Py2 only')
259    def test_import_failure_from_module(self):
260        """
261        Tests whether e.g. "import socketserver" succeeds in a module
262        imported by another module that has used and removed the stdlib hooks.
263        We want this to fail; the stdlib hooks should not bleed to imported
264        modules too without their explicitly invoking them.
265        """
266        code1 = '''
267                from future import standard_library
268                standard_library.install_hooks()
269                standard_library.remove_hooks()
270                import importme2
271                '''
272        code2 = '''
273                import socketserver
274                print('Uh oh. importme2 should have raised an ImportError.')
275                '''
276        self._write_test_script(code1, 'importme1.py')
277        self._write_test_script(code2, 'importme2.py')
278        with self.assertRaises(CalledProcessError):
279            output = self._run_test_script('importme1.py')
280
281    # Disabled since v0.16.0:
282    # def test_configparser(self):
283    #     import configparser
284
285    def test_copyreg(self):
286        import copyreg
287
288    def test_pickle(self):
289        import pickle
290
291    def test_profile(self):
292        import profile
293
294    def test_stringio(self):
295        from io import StringIO
296        s = StringIO(u'test')
297        for method in ['tell', 'read', 'seek', 'close', 'flush']:
298            self.assertTrue(hasattr(s, method))
299
300    def test_bytesio(self):
301        from io import BytesIO
302        s = BytesIO(b'test')
303        for method in ['tell', 'read', 'seek', 'close', 'flush', 'getvalue']:
304            self.assertTrue(hasattr(s, method))
305
306    def test_queue(self):
307        import queue
308        q = queue.Queue()
309        q.put('thing')
310        self.assertFalse(q.empty())
311
312    def test_reprlib(self):
313        import reprlib
314        self.assertTrue(True)
315
316    def test_socketserver(self):
317        import socketserver
318        self.assertTrue(True)
319
320    @unittest.skip("Not testing tkinter import (it may be installed separately from Python)")
321    def test_tkinter(self):
322        import tkinter
323        self.assertTrue(True)
324
325    def test_builtins(self):
326        import builtins
327        self.assertTrue(hasattr(builtins, 'tuple'))
328
329    @unittest.skip("ssl redirect support on pypi isn't working as expected for now ...")
330    def test_urllib_request_ssl_redirect(self):
331        """
332        This site redirects to https://...
333        It therefore requires ssl support.
334        """
335        import future.moves.urllib.request as urllib_request
336        from pprint import pprint
337        URL = 'http://pypi.python.org/pypi/{0}/json'
338        package = 'future'
339        r = urllib_request.urlopen(URL.format(package))
340        # pprint(r.read().decode('utf-8'))
341        self.assertTrue(True)
342
343    def test_moves_urllib_request_http(self):
344        """
345        This site (python-future.org) uses plain http (as of 2014-09-23).
346        """
347        import future.moves.urllib.request as urllib_request
348        from pprint import pprint
349        URL = 'http://python-future.org'
350        r = urllib_request.urlopen(URL)
351        data = r.read()
352        self.assertTrue(b'</html>' in data)
353
354    def test_urllib_request_http(self):
355        """
356        This site (python-future.org) uses plain http (as of 2014-09-23).
357        """
358        import urllib.request as urllib_request
359        from pprint import pprint
360        URL = 'http://python-future.org'
361        r = urllib_request.urlopen(URL)
362        data = r.read()
363        self.assertTrue(b'</html>' in data)
364
365    def test_html_import(self):
366        import html
367        import html.entities
368        import html.parser
369        self.assertTrue(True)
370
371    def test_http_client_import(self):
372        import http.client
373        self.assertTrue(True)
374
375    def test_other_http_imports(self):
376        import http
377        import http.server
378        import http.cookies
379        import http.cookiejar
380        self.assertTrue(True)
381
382    def test_urllib_imports_moves(self):
383        import future.moves.urllib
384        import future.moves.urllib.parse
385        import future.moves.urllib.request
386        import future.moves.urllib.robotparser
387        import future.moves.urllib.error
388        import future.moves.urllib.response
389        self.assertTrue(True)
390
391    def test_urllib_imports_install_aliases(self):
392        with standard_library.suspend_hooks():
393            standard_library.install_aliases()
394            import urllib
395            import urllib.parse
396            import urllib.request
397            import urllib.robotparser
398            import urllib.error
399            import urllib.response
400            self.assertTrue(True)
401
402    def test_urllib_imports_cm(self):
403        with standard_library.hooks():
404            import urllib
405            import urllib.parse
406            import urllib.request
407            import urllib.robotparser
408            import urllib.error
409            import urllib.response
410        self.assertTrue(True)
411
412    def test_urllib_imports_install_hooks(self):
413        standard_library.remove_hooks()
414        standard_library.install_hooks()
415        import urllib
416        import urllib.parse
417        import urllib.request
418        import urllib.robotparser
419        import urllib.error
420        import urllib.response
421        self.assertTrue(True)
422
423    def test_underscore_prefixed_modules(self):
424        import _thread
425        import _dummy_thread
426        import _markupbase
427        self.assertTrue(True)
428
429    def test_reduce(self):
430        """
431        reduce has been moved to the functools module
432        """
433        import functools
434        self.assertEqual(functools.reduce(lambda x, y: x+y, range(1, 6)), 15)
435
436    def test_collections_userstuff(self):
437        """
438        UserDict, UserList, and UserString have been moved to the
439        collections module.
440        """
441        from collections import UserDict
442        from collections import UserList
443        from collections import UserString
444        self.assertTrue(True)
445
446    def test_reload(self):
447        """
448        reload has been moved to the imp module
449        """
450        import imp
451        imp.reload(imp)
452        self.assertTrue(True)
453
454    def test_install_aliases(self):
455        """
456        Does the install_aliases() interface monkey-patch urllib etc. successfully?
457        """
458        from future.standard_library import remove_hooks, install_aliases
459        remove_hooks()
460        install_aliases()
461
462        from collections import Counter, OrderedDict   # backported to Py2.6
463        from collections import UserDict, UserList, UserString
464
465        # Requires Python dbm support:
466        # import dbm
467        # import dbm.dumb
468        # import dbm.gnu
469        # import dbm.ndbm
470
471        from itertools import filterfalse, zip_longest
472
473        from subprocess import check_output    # backported to Py2.6
474        from subprocess import getoutput, getstatusoutput
475
476        from sys import intern
477
478        # test_support may not be available (e.g. on Anaconda Py2.6):
479        # import test.support
480
481        import urllib.error
482        import urllib.parse
483        import urllib.request
484        import urllib.response
485        import urllib.robotparser
486
487        self.assertTrue('urlopen' in dir(urllib.request))
488
489
490class TestFutureMoves(CodeHandler):
491    def test_future_moves_urllib_request(self):
492        from future.moves.urllib import request as urllib_request
493        functions = ['getproxies',
494                     'pathname2url',
495                     'proxy_bypass',
496                     'quote',
497                     'request_host',
498                     'splitattr',
499                     'splithost',
500                     'splitpasswd',
501                     'splitport',
502                     'splitquery',
503                     'splittag',
504                     'splittype',
505                     'splituser',
506                     'splitvalue',
507                     'thishost',
508                     'to_bytes',
509                     'unquote',
510                     # 'unquote_to_bytes',   # Is there an equivalent in the Py2 stdlib?
511                     'unwrap',
512                     'url2pathname',
513                     'urlcleanup',
514                     'urljoin',
515                     'urlopen',
516                     'urlparse',
517                     'urlretrieve',
518                     'urlsplit',
519                     'urlunparse']
520        self.assertTrue(all(fn in dir(urllib_request) for fn in functions))
521
522    def test_future_moves(self):
523        """
524        Ensure everything is available from the future.moves interface that we
525        claim and expect. (Issue #104).
526        """
527        from future.moves.collections import Counter, OrderedDict   # backported to Py2.6
528        from future.moves.collections import UserDict, UserList, UserString
529
530        from future.moves import configparser
531        from future.moves import copyreg
532
533        from future.moves.itertools import filterfalse, zip_longest
534
535        from future.moves import html
536        import future.moves.html.entities
537        import future.moves.html.parser
538
539        from future.moves import http
540        import future.moves.http.client
541        import future.moves.http.cookies
542        import future.moves.http.cookiejar
543        import future.moves.http.server
544
545        from future.moves import queue
546
547        from future.moves import socketserver
548
549        from future.moves.subprocess import check_output              # even on Py2.6
550        from future.moves.subprocess import getoutput, getstatusoutput
551
552        from future.moves.sys import intern
553
554        from future.moves import urllib
555        import future.moves.urllib.error
556        import future.moves.urllib.parse
557        import future.moves.urllib.request
558        import future.moves.urllib.response
559        import future.moves.urllib.robotparser
560
561        try:
562            # Is _winreg available on Py2? If so, ensure future.moves._winreg is available too:
563            import _winreg
564        except ImportError:
565            pass
566        else:
567            from future.moves import winreg
568
569        from future.moves import xmlrpc
570        import future.moves.xmlrpc.client
571        import future.moves.xmlrpc.server
572
573        from future.moves import _dummy_thread
574        from future.moves import _markupbase
575        from future.moves import _thread
576
577    def test_future_moves_dbm(self):
578        """
579        Do the dbm imports work?
580        """
581        from future.moves import dbm
582        dbm.ndbm
583        from future.moves.dbm import dumb
584        try:
585            # Is gdbm available on Py2? If so, ensure dbm.gnu is available too:
586            import gdbm
587        except ImportError:
588            pass
589        else:
590            from future.moves.dbm import gnu
591        from future.moves.dbm import ndbm
592
593
594# Running the following tkinter test causes the following bizzare test failure:
595#
596# ======================================================================
597# FAIL: test_open_default_encoding (future.tests.test_builtins.BuiltinTest)
598# ----------------------------------------------------------------------
599# Traceback (most recent call last):
600#   File "/home/user/Install/BleedingEdge/python-future/future/tests/test_builtins.py", line 1219, in test_open_default_encoding
601#     self.assertEqual(fp.encoding, current_locale_encoding)
602# AssertionError: 'ANSI_X3.4-1968' != 'ISO-8859-1'
603#
604# ----------------------------------------------------------------------
605#
606#     def test_future_moves_tkinter(self):
607#         """
608#         Do the tkinter imports work?
609#         """
610#         from future.moves import tkinter
611#         from future.moves.tkinter import dialog
612#         from future.moves.tkinter import filedialog
613#         from future.moves.tkinter import scrolledtext
614#         from future.moves.tkinter import simpledialog
615#         from future.moves.tkinter import tix
616#         from future.moves.tkinter import constants
617#         from future.moves.tkinter import dnd
618#         from future.moves.tkinter import colorchooser
619#         from future.moves.tkinter import commondialog
620#         from future.moves.tkinter import font
621#         from future.moves.tkinter import messagebox
622
623if __name__ == '__main__':
624    unittest.main()
625