Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/future/standard_library/__init__.py: 28%
270 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:53 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:53 +0000
1"""
2Python 3 reorganized the standard library (PEP 3108). This module exposes
3several standard library modules to Python 2 under their new Python 3
4names.
6It is designed to be used as follows::
8 from future import standard_library
9 standard_library.install_aliases()
11And then these normal Py3 imports work on both Py3 and Py2::
13 import builtins
14 import copyreg
15 import queue
16 import reprlib
17 import socketserver
18 import winreg # on Windows only
19 import test.support
20 import html, html.parser, html.entites
21 import http, http.client, http.server
22 import http.cookies, http.cookiejar
23 import urllib.parse, urllib.request, urllib.response, urllib.error, urllib.robotparser
24 import xmlrpc.client, xmlrpc.server
26 import _thread
27 import _dummy_thread
28 import _markupbase
30 from itertools import filterfalse, zip_longest
31 from sys import intern
32 from collections import UserDict, UserList, UserString
33 from collections import OrderedDict, Counter, ChainMap # even on Py2.6
34 from subprocess import getoutput, getstatusoutput
35 from subprocess import check_output # even on Py2.6
37(The renamed modules and functions are still available under their old
38names on Python 2.)
40This is a cleaner alternative to this idiom (see
41http://docs.pythonsprints.com/python3_porting/py-porting.html)::
43 try:
44 import queue
45 except ImportError:
46 import Queue as queue
49Limitations
50-----------
51We don't currently support these modules, but would like to::
53 import dbm
54 import dbm.dumb
55 import dbm.gnu
56 import collections.abc # on Py33
57 import pickle # should (optionally) bring in cPickle on Python 2
59"""
61from __future__ import absolute_import, division, print_function
63import sys
64import logging
65import imp
66import contextlib
67import types
68import copy
69import os
71# Make a dedicated logger; leave the root logger to be configured
72# by the application.
73flog = logging.getLogger('future_stdlib')
74_formatter = logging.Formatter(logging.BASIC_FORMAT)
75_handler = logging.StreamHandler()
76_handler.setFormatter(_formatter)
77flog.addHandler(_handler)
78flog.setLevel(logging.WARN)
80from future.utils import PY2, PY3
82# The modules that are defined under the same names on Py3 but with
83# different contents in a significant way (e.g. submodules) are:
84# pickle (fast one)
85# dbm
86# urllib
87# test
88# email
90REPLACED_MODULES = set(['test', 'urllib', 'pickle', 'dbm']) # add email and dbm when we support it
92# The following module names are not present in Python 2.x, so they cause no
93# potential clashes between the old and new names:
94# http
95# html
96# tkinter
97# xmlrpc
98# Keys: Py2 / real module names
99# Values: Py3 / simulated module names
100RENAMES = {
101 # 'cStringIO': 'io', # there's a new io module in Python 2.6
102 # that provides StringIO and BytesIO
103 # 'StringIO': 'io', # ditto
104 # 'cPickle': 'pickle',
105 '__builtin__': 'builtins',
106 'copy_reg': 'copyreg',
107 'Queue': 'queue',
108 'future.moves.socketserver': 'socketserver',
109 'ConfigParser': 'configparser',
110 'repr': 'reprlib',
111 # 'FileDialog': 'tkinter.filedialog',
112 # 'tkFileDialog': 'tkinter.filedialog',
113 # 'SimpleDialog': 'tkinter.simpledialog',
114 # 'tkSimpleDialog': 'tkinter.simpledialog',
115 # 'tkColorChooser': 'tkinter.colorchooser',
116 # 'tkCommonDialog': 'tkinter.commondialog',
117 # 'Dialog': 'tkinter.dialog',
118 # 'Tkdnd': 'tkinter.dnd',
119 # 'tkFont': 'tkinter.font',
120 # 'tkMessageBox': 'tkinter.messagebox',
121 # 'ScrolledText': 'tkinter.scrolledtext',
122 # 'Tkconstants': 'tkinter.constants',
123 # 'Tix': 'tkinter.tix',
124 # 'ttk': 'tkinter.ttk',
125 # 'Tkinter': 'tkinter',
126 '_winreg': 'winreg',
127 'thread': '_thread',
128 'dummy_thread': '_dummy_thread',
129 # 'anydbm': 'dbm', # causes infinite import loop
130 # 'whichdb': 'dbm', # causes infinite import loop
131 # anydbm and whichdb are handled by fix_imports2
132 # 'dbhash': 'dbm.bsd',
133 # 'dumbdbm': 'dbm.dumb',
134 # 'dbm': 'dbm.ndbm',
135 # 'gdbm': 'dbm.gnu',
136 'future.moves.xmlrpc': 'xmlrpc',
137 # 'future.backports.email': 'email', # for use by urllib
138 # 'DocXMLRPCServer': 'xmlrpc.server',
139 # 'SimpleXMLRPCServer': 'xmlrpc.server',
140 # 'httplib': 'http.client',
141 # 'htmlentitydefs' : 'html.entities',
142 # 'HTMLParser' : 'html.parser',
143 # 'Cookie': 'http.cookies',
144 # 'cookielib': 'http.cookiejar',
145 # 'BaseHTTPServer': 'http.server',
146 # 'SimpleHTTPServer': 'http.server',
147 # 'CGIHTTPServer': 'http.server',
148 # 'future.backports.test': 'test', # primarily for renaming test_support to support
149 # 'commands': 'subprocess',
150 # 'urlparse' : 'urllib.parse',
151 # 'robotparser' : 'urllib.robotparser',
152 # 'abc': 'collections.abc', # for Py33
153 # 'future.utils.six.moves.html': 'html',
154 # 'future.utils.six.moves.http': 'http',
155 'future.moves.html': 'html',
156 'future.moves.http': 'http',
157 # 'future.backports.urllib': 'urllib',
158 # 'future.utils.six.moves.urllib': 'urllib',
159 'future.moves._markupbase': '_markupbase',
160 }
163# It is complicated and apparently brittle to mess around with the
164# ``sys.modules`` cache in order to support "import urllib" meaning two
165# different things (Py2.7 urllib and backported Py3.3-like urllib) in different
166# contexts. So we require explicit imports for these modules.
167assert len(set(RENAMES.values()) & set(REPLACED_MODULES)) == 0
170# Harmless renames that we can insert.
171# These modules need names from elsewhere being added to them:
172# subprocess: should provide getoutput and other fns from commands
173# module but these fns are missing: getstatus, mk2arg,
174# mkarg
175# re: needs an ASCII constant that works compatibly with Py3
177# etc: see lib2to3/fixes/fix_imports.py
179# (New module name, new object name, old module name, old object name)
180MOVES = [('collections', 'UserList', 'UserList', 'UserList'),
181 ('collections', 'UserDict', 'UserDict', 'UserDict'),
182 ('collections', 'UserString','UserString', 'UserString'),
183 ('collections', 'ChainMap', 'future.backports.misc', 'ChainMap'),
184 ('itertools', 'filterfalse','itertools', 'ifilterfalse'),
185 ('itertools', 'zip_longest','itertools', 'izip_longest'),
186 ('sys', 'intern','__builtin__', 'intern'),
187 # The re module has no ASCII flag in Py2, but this is the default.
188 # Set re.ASCII to a zero constant. stat.ST_MODE just happens to be one
189 # (and it exists on Py2.6+).
190 ('re', 'ASCII','stat', 'ST_MODE'),
191 ('base64', 'encodebytes','base64', 'encodestring'),
192 ('base64', 'decodebytes','base64', 'decodestring'),
193 ('subprocess', 'getoutput', 'commands', 'getoutput'),
194 ('subprocess', 'getstatusoutput', 'commands', 'getstatusoutput'),
195 ('subprocess', 'check_output', 'future.backports.misc', 'check_output'),
196 ('math', 'ceil', 'future.backports.misc', 'ceil'),
197 ('collections', 'OrderedDict', 'future.backports.misc', 'OrderedDict'),
198 ('collections', 'Counter', 'future.backports.misc', 'Counter'),
199 ('collections', 'ChainMap', 'future.backports.misc', 'ChainMap'),
200 ('itertools', 'count', 'future.backports.misc', 'count'),
201 ('reprlib', 'recursive_repr', 'future.backports.misc', 'recursive_repr'),
202 ('functools', 'cmp_to_key', 'future.backports.misc', 'cmp_to_key'),
204# This is no use, since "import urllib.request" etc. still fails:
205# ('urllib', 'error', 'future.moves.urllib', 'error'),
206# ('urllib', 'parse', 'future.moves.urllib', 'parse'),
207# ('urllib', 'request', 'future.moves.urllib', 'request'),
208# ('urllib', 'response', 'future.moves.urllib', 'response'),
209# ('urllib', 'robotparser', 'future.moves.urllib', 'robotparser'),
210 ]
213# A minimal example of an import hook:
214# class WarnOnImport(object):
215# def __init__(self, *args):
216# self.module_names = args
217#
218# def find_module(self, fullname, path=None):
219# if fullname in self.module_names:
220# self.path = path
221# return self
222# return None
223#
224# def load_module(self, name):
225# if name in sys.modules:
226# return sys.modules[name]
227# module_info = imp.find_module(name, self.path)
228# module = imp.load_module(name, *module_info)
229# sys.modules[name] = module
230# flog.warning("Imported deprecated module %s", name)
231# return module
234class RenameImport(object):
235 """
236 A class for import hooks mapping Py3 module names etc. to the Py2 equivalents.
237 """
238 # Different RenameImport classes are created when importing this module from
239 # different source files. This causes isinstance(hook, RenameImport) checks
240 # to produce inconsistent results. We add this RENAMER attribute here so
241 # remove_hooks() and install_hooks() can find instances of these classes
242 # easily:
243 RENAMER = True
245 def __init__(self, old_to_new):
246 '''
247 Pass in a dictionary-like object mapping from old names to new
248 names. E.g. {'ConfigParser': 'configparser', 'cPickle': 'pickle'}
249 '''
250 self.old_to_new = old_to_new
251 both = set(old_to_new.keys()) & set(old_to_new.values())
252 assert (len(both) == 0 and
253 len(set(old_to_new.values())) == len(old_to_new.values())), \
254 'Ambiguity in renaming (handler not implemented)'
255 self.new_to_old = dict((new, old) for (old, new) in old_to_new.items())
257 def find_module(self, fullname, path=None):
258 # Handles hierarchical importing: package.module.module2
259 new_base_names = set([s.split('.')[0] for s in self.new_to_old])
260 # Before v0.12: Was: if fullname in set(self.old_to_new) | new_base_names:
261 if fullname in new_base_names:
262 return self
263 return None
265 def load_module(self, name):
266 path = None
267 if name in sys.modules:
268 return sys.modules[name]
269 elif name in self.new_to_old:
270 # New name. Look up the corresponding old (Py2) name:
271 oldname = self.new_to_old[name]
272 module = self._find_and_load_module(oldname)
273 # module.__future_module__ = True
274 else:
275 module = self._find_and_load_module(name)
276 # In any case, make it available under the requested (Py3) name
277 sys.modules[name] = module
278 return module
280 def _find_and_load_module(self, name, path=None):
281 """
282 Finds and loads it. But if there's a . in the name, handles it
283 properly.
284 """
285 bits = name.split('.')
286 while len(bits) > 1:
287 # Treat the first bit as a package
288 packagename = bits.pop(0)
289 package = self._find_and_load_module(packagename, path)
290 try:
291 path = package.__path__
292 except AttributeError:
293 # This could be e.g. moves.
294 flog.debug('Package {0} has no __path__.'.format(package))
295 if name in sys.modules:
296 return sys.modules[name]
297 flog.debug('What to do here?')
299 name = bits[0]
300 module_info = imp.find_module(name, path)
301 return imp.load_module(name, *module_info)
304class hooks(object):
305 """
306 Acts as a context manager. Saves the state of sys.modules and restores it
307 after the 'with' block.
309 Use like this:
311 >>> from future import standard_library
312 >>> with standard_library.hooks():
313 ... import http.client
314 >>> import requests
316 For this to work, http.client will be scrubbed from sys.modules after the
317 'with' block. That way the modules imported in the 'with' block will
318 continue to be accessible in the current namespace but not from any
319 imported modules (like requests).
320 """
321 def __enter__(self):
322 # flog.debug('Entering hooks context manager')
323 self.old_sys_modules = copy.copy(sys.modules)
324 self.hooks_were_installed = detect_hooks()
325 # self.scrubbed = scrub_py2_sys_modules()
326 install_hooks()
327 return self
329 def __exit__(self, *args):
330 # flog.debug('Exiting hooks context manager')
331 # restore_sys_modules(self.scrubbed)
332 if not self.hooks_were_installed:
333 remove_hooks()
334 # scrub_future_sys_modules()
336# Sanity check for is_py2_stdlib_module(): We aren't replacing any
337# builtin modules names:
338if PY2:
339 assert len(set(RENAMES.values()) & set(sys.builtin_module_names)) == 0
342def is_py2_stdlib_module(m):
343 """
344 Tries to infer whether the module m is from the Python 2 standard library.
345 This may not be reliable on all systems.
346 """
347 if PY3:
348 return False
349 if not 'stdlib_path' in is_py2_stdlib_module.__dict__:
350 stdlib_files = [contextlib.__file__, os.__file__, copy.__file__]
351 stdlib_paths = [os.path.split(f)[0] for f in stdlib_files]
352 if not len(set(stdlib_paths)) == 1:
353 # This seems to happen on travis-ci.org. Very strange. We'll try to
354 # ignore it.
355 flog.warn('Multiple locations found for the Python standard '
356 'library: %s' % stdlib_paths)
357 # Choose the first one arbitrarily
358 is_py2_stdlib_module.stdlib_path = stdlib_paths[0]
360 if m.__name__ in sys.builtin_module_names:
361 return True
363 if hasattr(m, '__file__'):
364 modpath = os.path.split(m.__file__)
365 if (modpath[0].startswith(is_py2_stdlib_module.stdlib_path) and
366 'site-packages' not in modpath[0]):
367 return True
369 return False
372def scrub_py2_sys_modules():
373 """
374 Removes any Python 2 standard library modules from ``sys.modules`` that
375 would interfere with Py3-style imports using import hooks. Examples are
376 modules with the same names (like urllib or email).
378 (Note that currently import hooks are disabled for modules like these
379 with ambiguous names anyway ...)
380 """
381 if PY3:
382 return {}
383 scrubbed = {}
384 for modulename in REPLACED_MODULES & set(RENAMES.keys()):
385 if not modulename in sys.modules:
386 continue
388 module = sys.modules[modulename]
390 if is_py2_stdlib_module(module):
391 flog.debug('Deleting (Py2) {} from sys.modules'.format(modulename))
392 scrubbed[modulename] = sys.modules[modulename]
393 del sys.modules[modulename]
394 return scrubbed
397def scrub_future_sys_modules():
398 """
399 Deprecated.
400 """
401 return {}
403class suspend_hooks(object):
404 """
405 Acts as a context manager. Use like this:
407 >>> from future import standard_library
408 >>> standard_library.install_hooks()
409 >>> import http.client
410 >>> # ...
411 >>> with standard_library.suspend_hooks():
412 >>> import requests # incompatible with ``future``'s standard library hooks
414 If the hooks were disabled before the context, they are not installed when
415 the context is left.
416 """
417 def __enter__(self):
418 self.hooks_were_installed = detect_hooks()
419 remove_hooks()
420 # self.scrubbed = scrub_future_sys_modules()
421 return self
423 def __exit__(self, *args):
424 if self.hooks_were_installed:
425 install_hooks()
426 # restore_sys_modules(self.scrubbed)
429def restore_sys_modules(scrubbed):
430 """
431 Add any previously scrubbed modules back to the sys.modules cache,
432 but only if it's safe to do so.
433 """
434 clash = set(sys.modules) & set(scrubbed)
435 if len(clash) != 0:
436 # If several, choose one arbitrarily to raise an exception about
437 first = list(clash)[0]
438 raise ImportError('future module {} clashes with Py2 module'
439 .format(first))
440 sys.modules.update(scrubbed)
443def install_aliases():
444 """
445 Monkey-patches the standard library in Py2.6/7 to provide
446 aliases for better Py3 compatibility.
447 """
448 if PY3:
449 return
450 # if hasattr(install_aliases, 'run_already'):
451 # return
452 for (newmodname, newobjname, oldmodname, oldobjname) in MOVES:
453 __import__(newmodname)
454 # We look up the module in sys.modules because __import__ just returns the
455 # top-level package:
456 newmod = sys.modules[newmodname]
457 # newmod.__future_module__ = True
459 __import__(oldmodname)
460 oldmod = sys.modules[oldmodname]
462 obj = getattr(oldmod, oldobjname)
463 setattr(newmod, newobjname, obj)
465 # Hack for urllib so it appears to have the same structure on Py2 as on Py3
466 import urllib
467 from future.backports.urllib import request
468 from future.backports.urllib import response
469 from future.backports.urllib import parse
470 from future.backports.urllib import error
471 from future.backports.urllib import robotparser
472 urllib.request = request
473 urllib.response = response
474 urllib.parse = parse
475 urllib.error = error
476 urllib.robotparser = robotparser
477 sys.modules['urllib.request'] = request
478 sys.modules['urllib.response'] = response
479 sys.modules['urllib.parse'] = parse
480 sys.modules['urllib.error'] = error
481 sys.modules['urllib.robotparser'] = robotparser
483 # Patch the test module so it appears to have the same structure on Py2 as on Py3
484 try:
485 import test
486 except ImportError:
487 pass
488 try:
489 from future.moves.test import support
490 except ImportError:
491 pass
492 else:
493 test.support = support
494 sys.modules['test.support'] = support
496 # Patch the dbm module so it appears to have the same structure on Py2 as on Py3
497 try:
498 import dbm
499 except ImportError:
500 pass
501 else:
502 from future.moves.dbm import dumb
503 dbm.dumb = dumb
504 sys.modules['dbm.dumb'] = dumb
505 try:
506 from future.moves.dbm import gnu
507 except ImportError:
508 pass
509 else:
510 dbm.gnu = gnu
511 sys.modules['dbm.gnu'] = gnu
512 try:
513 from future.moves.dbm import ndbm
514 except ImportError:
515 pass
516 else:
517 dbm.ndbm = ndbm
518 sys.modules['dbm.ndbm'] = ndbm
520 # install_aliases.run_already = True
523def install_hooks():
524 """
525 This function installs the future.standard_library import hook into
526 sys.meta_path.
527 """
528 if PY3:
529 return
531 install_aliases()
533 flog.debug('sys.meta_path was: {0}'.format(sys.meta_path))
534 flog.debug('Installing hooks ...')
536 # Add it unless it's there already
537 newhook = RenameImport(RENAMES)
538 if not detect_hooks():
539 sys.meta_path.append(newhook)
540 flog.debug('sys.meta_path is now: {0}'.format(sys.meta_path))
543def enable_hooks():
544 """
545 Deprecated. Use install_hooks() instead. This will be removed by
546 ``future`` v1.0.
547 """
548 install_hooks()
551def remove_hooks(scrub_sys_modules=False):
552 """
553 This function removes the import hook from sys.meta_path.
554 """
555 if PY3:
556 return
557 flog.debug('Uninstalling hooks ...')
558 # Loop backwards, so deleting items keeps the ordering:
559 for i, hook in list(enumerate(sys.meta_path))[::-1]:
560 if hasattr(hook, 'RENAMER'):
561 del sys.meta_path[i]
563 # Explicit is better than implicit. In the future the interface should
564 # probably change so that scrubbing the import hooks requires a separate
565 # function call. Left as is for now for backward compatibility with
566 # v0.11.x.
567 if scrub_sys_modules:
568 scrub_future_sys_modules()
571def disable_hooks():
572 """
573 Deprecated. Use remove_hooks() instead. This will be removed by
574 ``future`` v1.0.
575 """
576 remove_hooks()
579def detect_hooks():
580 """
581 Returns True if the import hooks are installed, False if not.
582 """
583 flog.debug('Detecting hooks ...')
584 present = any([hasattr(hook, 'RENAMER') for hook in sys.meta_path])
585 if present:
586 flog.debug('Detected.')
587 else:
588 flog.debug('Not detected.')
589 return present
592# As of v0.12, this no longer happens implicitly:
593# if not PY3:
594# install_hooks()
597if not hasattr(sys, 'py2_modules'):
598 sys.py2_modules = {}
600def cache_py2_modules():
601 """
602 Currently this function is unneeded, as we are not attempting to provide import hooks
603 for modules with ambiguous names: email, urllib, pickle.
604 """
605 if len(sys.py2_modules) != 0:
606 return
607 assert not detect_hooks()
608 import urllib
609 sys.py2_modules['urllib'] = urllib
611 import email
612 sys.py2_modules['email'] = email
614 import pickle
615 sys.py2_modules['pickle'] = pickle
617 # Not all Python installations have test module. (Anaconda doesn't, for example.)
618 # try:
619 # import test
620 # except ImportError:
621 # sys.py2_modules['test'] = None
622 # sys.py2_modules['test'] = test
624 # import dbm
625 # sys.py2_modules['dbm'] = dbm
628def import_(module_name, backport=False):
629 """
630 Pass a (potentially dotted) module name of a Python 3 standard library
631 module. This function imports the module compatibly on Py2 and Py3 and
632 returns the top-level module.
634 Example use:
635 >>> http = import_('http.client')
636 >>> http = import_('http.server')
637 >>> urllib = import_('urllib.request')
639 Then:
640 >>> conn = http.client.HTTPConnection(...)
641 >>> response = urllib.request.urlopen('http://mywebsite.com')
642 >>> # etc.
644 Use as follows:
645 >>> package_name = import_(module_name)
647 On Py3, equivalent to this:
649 >>> import module_name
651 On Py2, equivalent to this if backport=False:
653 >>> from future.moves import module_name
655 or to this if backport=True:
657 >>> from future.backports import module_name
659 except that it also handles dotted module names such as ``http.client``
660 The effect then is like this:
662 >>> from future.backports import module
663 >>> from future.backports.module import submodule
664 >>> module.submodule = submodule
666 Note that this would be a SyntaxError in Python:
668 >>> from future.backports import http.client
670 """
671 # Python 2.6 doesn't have importlib in the stdlib, so it requires
672 # the backported ``importlib`` package from PyPI as a dependency to use
673 # this function:
674 import importlib
676 if PY3:
677 return __import__(module_name)
678 else:
679 # client.blah = blah
680 # Then http.client = client
681 # etc.
682 if backport:
683 prefix = 'future.backports'
684 else:
685 prefix = 'future.moves'
686 parts = prefix.split('.') + module_name.split('.')
688 modules = []
689 for i, part in enumerate(parts):
690 sofar = '.'.join(parts[:i+1])
691 modules.append(importlib.import_module(sofar))
692 for i, part in reversed(list(enumerate(parts))):
693 if i == 0:
694 break
695 setattr(modules[i-1], part, modules[i])
697 # Return the next-most top-level module after future.backports / future.moves:
698 return modules[2]
701def from_import(module_name, *symbol_names, **kwargs):
702 """
703 Example use:
704 >>> HTTPConnection = from_import('http.client', 'HTTPConnection')
705 >>> HTTPServer = from_import('http.server', 'HTTPServer')
706 >>> urlopen, urlparse = from_import('urllib.request', 'urlopen', 'urlparse')
708 Equivalent to this on Py3:
710 >>> from module_name import symbol_names[0], symbol_names[1], ...
712 and this on Py2:
714 >>> from future.moves.module_name import symbol_names[0], ...
716 or:
718 >>> from future.backports.module_name import symbol_names[0], ...
720 except that it also handles dotted module names such as ``http.client``.
721 """
723 if PY3:
724 return __import__(module_name)
725 else:
726 if 'backport' in kwargs and bool(kwargs['backport']):
727 prefix = 'future.backports'
728 else:
729 prefix = 'future.moves'
730 parts = prefix.split('.') + module_name.split('.')
731 module = importlib.import_module(prefix + '.' + module_name)
732 output = [getattr(module, name) for name in symbol_names]
733 if len(output) == 1:
734 return output[0]
735 else:
736 return output
739class exclude_local_folder_imports(object):
740 """
741 A context-manager that prevents standard library modules like configparser
742 from being imported from the local python-future source folder on Py3.
744 (This was need prior to v0.16.0 because the presence of a configparser
745 folder would otherwise have prevented setuptools from running on Py3. Maybe
746 it's not needed any more?)
747 """
748 def __init__(self, *args):
749 assert len(args) > 0
750 self.module_names = args
751 # Disallow dotted module names like http.client:
752 if any(['.' in m for m in self.module_names]):
753 raise NotImplementedError('Dotted module names are not supported')
755 def __enter__(self):
756 self.old_sys_path = copy.copy(sys.path)
757 self.old_sys_modules = copy.copy(sys.modules)
758 if sys.version_info[0] < 3:
759 return
760 # The presence of all these indicates we've found our source folder,
761 # because `builtins` won't have been installed in site-packages by setup.py:
762 FUTURE_SOURCE_SUBFOLDERS = ['future', 'past', 'libfuturize', 'libpasteurize', 'builtins']
764 # Look for the future source folder:
765 for folder in self.old_sys_path:
766 if all([os.path.exists(os.path.join(folder, subfolder))
767 for subfolder in FUTURE_SOURCE_SUBFOLDERS]):
768 # Found it. Remove it.
769 sys.path.remove(folder)
771 # Ensure we import the system module:
772 for m in self.module_names:
773 # Delete the module and any submodules from sys.modules:
774 # for key in list(sys.modules):
775 # if key == m or key.startswith(m + '.'):
776 # try:
777 # del sys.modules[key]
778 # except KeyError:
779 # pass
780 try:
781 module = __import__(m, level=0)
782 except ImportError:
783 # There's a problem importing the system module. E.g. the
784 # winreg module is not available except on Windows.
785 pass
787 def __exit__(self, *args):
788 # Restore sys.path and sys.modules:
789 sys.path = self.old_sys_path
790 for m in set(self.old_sys_modules.keys()) - set(sys.modules.keys()):
791 sys.modules[m] = self.old_sys_modules[m]
793TOP_LEVEL_MODULES = ['builtins',
794 'copyreg',
795 'html',
796 'http',
797 'queue',
798 'reprlib',
799 'socketserver',
800 'test',
801 'tkinter',
802 'winreg',
803 'xmlrpc',
804 '_dummy_thread',
805 '_markupbase',
806 '_thread',
807 ]
809def import_top_level_modules():
810 with exclude_local_folder_imports(*TOP_LEVEL_MODULES):
811 for m in TOP_LEVEL_MODULES:
812 try:
813 __import__(m)
814 except ImportError: # e.g. winreg
815 pass