Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: third_party/google-endpoints/future/standard_library/__init__.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 """
2 Python 3 reorganized the standard library (PEP 3108). This module exposes
3 several standard library modules to Python 2 under their new Python 3
4 names.
5
6 It is designed to be used as follows::
7
8 from future import standard_library
9 standard_library.install_aliases()
10
11 And then these normal Py3 imports work on both Py3 and Py2::
12
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.r obotparser
24 import xmlrpc.client, xmlrpc.server
25
26 import _thread
27 import _dummy_thread
28 import _markupbase
29
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 # even on Py2.6
34 from subprocess import getoutput, getstatusoutput
35 from subprocess import check_output # even on Py2.6
36
37 (The renamed modules and functions are still available under their old
38 names on Python 2.)
39
40 This is a cleaner alternative to this idiom (see
41 http://docs.pythonsprints.com/python3_porting/py-porting.html)::
42
43 try:
44 import queue
45 except ImportError:
46 import Queue as queue
47
48
49 Limitations
50 -----------
51 We don't currently support these modules, but would like to::
52
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
58
59 """
60
61 from __future__ import absolute_import, division, print_function
62
63 import sys
64 import logging
65 import imp
66 import contextlib
67 import types
68 import copy
69 import os
70
71 # Make a dedicated logger; leave the root logger to be configured
72 # by the application.
73 flog = logging.getLogger('future_stdlib')
74 _formatter = logging.Formatter(logging.BASIC_FORMAT)
75 _handler = logging.StreamHandler()
76 _handler.setFormatter(_formatter)
77 flog.addHandler(_handler)
78 flog.setLevel(logging.WARN)
79
80 from future.utils import PY2, PY3
81
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
89
90 REPLACED_MODULES = set(['test', 'urllib', 'pickle', 'dbm']) # add email and dbm when we support it
91
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
100 RENAMES = {
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_sup port 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 }
161
162
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.
167 assert len(set(RENAMES.values()) & set(REPLACED_MODULES)) == 0
168
169
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
176
177 # etc: see lib2to3/fixes/fix_imports.py
178
179 # (New module name, new object name, old module name, old object name)
180 MOVES = [('collections', 'UserList', 'UserList', 'UserList'),
181 ('collections', 'UserDict', 'UserDict', 'UserDict'),
182 ('collections', 'UserString','UserString', 'UserString'),
183 ('itertools', 'filterfalse','itertools', 'ifilterfalse'),
184 ('itertools', 'zip_longest','itertools', 'izip_longest'),
185 ('sys', 'intern','__builtin__', 'intern'),
186 # The re module has no ASCII flag in Py2, but this is the default.
187 # Set re.ASCII to a zero constant. stat.ST_MODE just happens to be one
188 # (and it exists on Py2.6+).
189 ('re', 'ASCII','stat', 'ST_MODE'),
190 ('base64', 'encodebytes','base64', 'encodestring'),
191 ('base64', 'decodebytes','base64', 'decodestring'),
192 ('subprocess', 'getoutput', 'commands', 'getoutput'),
193 ('subprocess', 'getstatusoutput', 'commands', 'getstatusoutput'),
194 ('subprocess', 'check_output', 'future.backports.misc', 'check_output') ,
195 ('math', 'ceil', 'future.backports.misc', 'ceil'),
196 ('collections', 'OrderedDict', 'future.backports.misc', 'OrderedDict'),
197 ('collections', 'Counter', 'future.backports.misc', 'Counter'),
198 ('itertools', 'count', 'future.backports.misc', 'count'),
199 ('reprlib', 'recursive_repr', 'future.backports.misc', 'recursive_repr' ),
200 ('functools', 'cmp_to_key', 'future.backports.misc', 'cmp_to_key'),
201
202 # This is no use, since "import urllib.request" etc. still fails:
203 # ('urllib', 'error', 'future.moves.urllib', 'error'),
204 # ('urllib', 'parse', 'future.moves.urllib', 'parse'),
205 # ('urllib', 'request', 'future.moves.urllib', 'request'),
206 # ('urllib', 'response', 'future.moves.urllib', 'response'),
207 # ('urllib', 'robotparser', 'future.moves.urllib', 'robotparser'),
208 ]
209
210
211 # A minimal example of an import hook:
212 # class WarnOnImport(object):
213 # def __init__(self, *args):
214 # self.module_names = args
215 #
216 # def find_module(self, fullname, path=None):
217 # if fullname in self.module_names:
218 # self.path = path
219 # return self
220 # return None
221 #
222 # def load_module(self, name):
223 # if name in sys.modules:
224 # return sys.modules[name]
225 # module_info = imp.find_module(name, self.path)
226 # module = imp.load_module(name, *module_info)
227 # sys.modules[name] = module
228 # flog.warning("Imported deprecated module %s", name)
229 # return module
230
231
232 class RenameImport(object):
233 """
234 A class for import hooks mapping Py3 module names etc. to the Py2 equivalent s.
235 """
236 # Different RenameImport classes are created when importing this module from
237 # different source files. This causes isinstance(hook, RenameImport) checks
238 # to produce inconsistent results. We add this RENAMER attribute here so
239 # remove_hooks() and install_hooks() can find instances of these classes
240 # easily:
241 RENAMER = True
242
243 def __init__(self, old_to_new):
244 '''
245 Pass in a dictionary-like object mapping from old names to new
246 names. E.g. {'ConfigParser': 'configparser', 'cPickle': 'pickle'}
247 '''
248 self.old_to_new = old_to_new
249 both = set(old_to_new.keys()) & set(old_to_new.values())
250 assert (len(both) == 0 and
251 len(set(old_to_new.values())) == len(old_to_new.values())), \
252 'Ambiguity in renaming (handler not implemented)'
253 self.new_to_old = dict((new, old) for (old, new) in old_to_new.items())
254
255 def find_module(self, fullname, path=None):
256 # Handles hierarchical importing: package.module.module2
257 new_base_names = set([s.split('.')[0] for s in self.new_to_old])
258 # Before v0.12: Was: if fullname in set(self.old_to_new) | new_base_name s:
259 if fullname in new_base_names:
260 return self
261 return None
262
263 def load_module(self, name):
264 path = None
265 if name in sys.modules:
266 return sys.modules[name]
267 elif name in self.new_to_old:
268 # New name. Look up the corresponding old (Py2) name:
269 oldname = self.new_to_old[name]
270 module = self._find_and_load_module(oldname)
271 # module.__future_module__ = True
272 else:
273 module = self._find_and_load_module(name)
274 # In any case, make it available under the requested (Py3) name
275 sys.modules[name] = module
276 return module
277
278 def _find_and_load_module(self, name, path=None):
279 """
280 Finds and loads it. But if there's a . in the name, handles it
281 properly.
282 """
283 bits = name.split('.')
284 while len(bits) > 1:
285 # Treat the first bit as a package
286 packagename = bits.pop(0)
287 package = self._find_and_load_module(packagename, path)
288 try:
289 path = package.__path__
290 except AttributeError:
291 # This could be e.g. moves.
292 flog.debug('Package {0} has no __path__.'.format(package))
293 if name in sys.modules:
294 return sys.modules[name]
295 flog.debug('What to do here?')
296
297 name = bits[0]
298 module_info = imp.find_module(name, path)
299 return imp.load_module(name, *module_info)
300
301
302 class hooks(object):
303 """
304 Acts as a context manager. Saves the state of sys.modules and restores it
305 after the 'with' block.
306
307 Use like this:
308
309 >>> from future import standard_library
310 >>> with standard_library.hooks():
311 ... import http.client
312 >>> import requests
313
314 For this to work, http.client will be scrubbed from sys.modules after the
315 'with' block. That way the modules imported in the 'with' block will
316 continue to be accessible in the current namespace but not from any
317 imported modules (like requests).
318 """
319 def __enter__(self):
320 # flog.debug('Entering hooks context manager')
321 self.old_sys_modules = copy.copy(sys.modules)
322 self.hooks_were_installed = detect_hooks()
323 # self.scrubbed = scrub_py2_sys_modules()
324 install_hooks()
325 return self
326
327 def __exit__(self, *args):
328 # flog.debug('Exiting hooks context manager')
329 # restore_sys_modules(self.scrubbed)
330 if not self.hooks_were_installed:
331 remove_hooks()
332 # scrub_future_sys_modules()
333
334 # Sanity check for is_py2_stdlib_module(): We aren't replacing any
335 # builtin modules names:
336 if PY2:
337 assert len(set(RENAMES.values()) & set(sys.builtin_module_names)) == 0
338
339
340 def is_py2_stdlib_module(m):
341 """
342 Tries to infer whether the module m is from the Python 2 standard library.
343 This may not be reliable on all systems.
344 """
345 if PY3:
346 return False
347 if not 'stdlib_path' in is_py2_stdlib_module.__dict__:
348 stdlib_files = [contextlib.__file__, os.__file__, copy.__file__]
349 stdlib_paths = [os.path.split(f)[0] for f in stdlib_files]
350 if not len(set(stdlib_paths)) == 1:
351 # This seems to happen on travis-ci.org. Very strange. We'll try to
352 # ignore it.
353 flog.warn('Multiple locations found for the Python standard '
354 'library: %s' % stdlib_paths)
355 # Choose the first one arbitrarily
356 is_py2_stdlib_module.stdlib_path = stdlib_paths[0]
357
358 if m.__name__ in sys.builtin_module_names:
359 return True
360
361 if hasattr(m, '__file__'):
362 modpath = os.path.split(m.__file__)
363 if (modpath[0].startswith(is_py2_stdlib_module.stdlib_path) and
364 'site-packages' not in modpath[0]):
365 return True
366
367 return False
368
369
370 def scrub_py2_sys_modules():
371 """
372 Removes any Python 2 standard library modules from ``sys.modules`` that
373 would interfere with Py3-style imports using import hooks. Examples are
374 modules with the same names (like urllib or email).
375
376 (Note that currently import hooks are disabled for modules like these
377 with ambiguous names anyway ...)
378 """
379 if PY3:
380 return {}
381 scrubbed = {}
382 for modulename in REPLACED_MODULES & set(RENAMES.keys()):
383 if not modulename in sys.modules:
384 continue
385
386 module = sys.modules[modulename]
387
388 if is_py2_stdlib_module(module):
389 flog.debug('Deleting (Py2) {} from sys.modules'.format(modulename))
390 scrubbed[modulename] = sys.modules[modulename]
391 del sys.modules[modulename]
392 return scrubbed
393
394
395 def scrub_future_sys_modules():
396 """
397 Deprecated.
398 """
399 return {}
400
401 class suspend_hooks(object):
402 """
403 Acts as a context manager. Use like this:
404
405 >>> from future import standard_library
406 >>> standard_library.install_hooks()
407 >>> import http.client
408 >>> # ...
409 >>> with standard_library.suspend_hooks():
410 >>> import requests # incompatible with ``future``'s standard librar y hooks
411
412 If the hooks were disabled before the context, they are not installed when
413 the context is left.
414 """
415 def __enter__(self):
416 self.hooks_were_installed = detect_hooks()
417 remove_hooks()
418 # self.scrubbed = scrub_future_sys_modules()
419 return self
420
421 def __exit__(self, *args):
422 if self.hooks_were_installed:
423 install_hooks()
424 # restore_sys_modules(self.scrubbed)
425
426
427 def restore_sys_modules(scrubbed):
428 """
429 Add any previously scrubbed modules back to the sys.modules cache,
430 but only if it's safe to do so.
431 """
432 clash = set(sys.modules) & set(scrubbed)
433 if len(clash) != 0:
434 # If several, choose one arbitrarily to raise an exception about
435 first = list(clash)[0]
436 raise ImportError('future module {} clashes with Py2 module'
437 .format(first))
438 sys.modules.update(scrubbed)
439
440
441 def install_aliases():
442 """
443 Monkey-patches the standard library in Py2.6/7 to provide
444 aliases for better Py3 compatibility.
445 """
446 if PY3:
447 return
448 # if hasattr(install_aliases, 'run_already'):
449 # return
450 for (newmodname, newobjname, oldmodname, oldobjname) in MOVES:
451 __import__(newmodname)
452 # We look up the module in sys.modules because __import__ just returns t he
453 # top-level package:
454 newmod = sys.modules[newmodname]
455 # newmod.__future_module__ = True
456
457 __import__(oldmodname)
458 oldmod = sys.modules[oldmodname]
459
460 obj = getattr(oldmod, oldobjname)
461 setattr(newmod, newobjname, obj)
462
463 # Hack for urllib so it appears to have the same structure on Py2 as on Py3
464 import urllib
465 from future.backports.urllib import request
466 from future.backports.urllib import response
467 from future.backports.urllib import parse
468 from future.backports.urllib import error
469 from future.backports.urllib import robotparser
470 urllib.request = request
471 urllib.response = response
472 urllib.parse = parse
473 urllib.error = error
474 urllib.robotparser = robotparser
475 sys.modules['urllib.request'] = request
476 sys.modules['urllib.response'] = response
477 sys.modules['urllib.parse'] = parse
478 sys.modules['urllib.error'] = error
479 sys.modules['urllib.robotparser'] = robotparser
480
481 # Patch the test module so it appears to have the same structure on Py2 as o n Py3
482 try:
483 import test
484 except ImportError:
485 pass
486 try:
487 from future.moves.test import support
488 except ImportError:
489 pass
490 else:
491 test.support = support
492 sys.modules['test.support'] = support
493
494 # Patch the dbm module so it appears to have the same structure on Py2 as on Py3
495 try:
496 import dbm
497 except ImportError:
498 pass
499 else:
500 from future.moves.dbm import dumb
501 dbm.dumb = dumb
502 sys.modules['dbm.dumb'] = dumb
503 try:
504 from future.moves.dbm import gnu
505 except ImportError:
506 pass
507 else:
508 dbm.gnu = gnu
509 sys.modules['dbm.gnu'] = gnu
510 try:
511 from future.moves.dbm import ndbm
512 except ImportError:
513 pass
514 else:
515 dbm.ndbm = ndbm
516 sys.modules['dbm.ndbm'] = ndbm
517
518 # install_aliases.run_already = True
519
520
521 def install_hooks():
522 """
523 This function installs the future.standard_library import hook into
524 sys.meta_path.
525 """
526 if PY3:
527 return
528
529 install_aliases()
530
531 flog.debug('sys.meta_path was: {0}'.format(sys.meta_path))
532 flog.debug('Installing hooks ...')
533
534 # Add it unless it's there already
535 newhook = RenameImport(RENAMES)
536 if not detect_hooks():
537 sys.meta_path.append(newhook)
538 flog.debug('sys.meta_path is now: {0}'.format(sys.meta_path))
539
540
541 def enable_hooks():
542 """
543 Deprecated. Use install_hooks() instead. This will be removed by
544 ``future`` v1.0.
545 """
546 install_hooks()
547
548
549 def remove_hooks(scrub_sys_modules=False):
550 """
551 This function removes the import hook from sys.meta_path.
552 """
553 if PY3:
554 return
555 flog.debug('Uninstalling hooks ...')
556 # Loop backwards, so deleting items keeps the ordering:
557 for i, hook in list(enumerate(sys.meta_path))[::-1]:
558 if hasattr(hook, 'RENAMER'):
559 del sys.meta_path[i]
560
561 # Explicit is better than implicit. In the future the interface should
562 # probably change so that scrubbing the import hooks requires a separate
563 # function call. Left as is for now for backward compatibility with
564 # v0.11.x.
565 if scrub_sys_modules:
566 scrub_future_sys_modules()
567
568
569 def disable_hooks():
570 """
571 Deprecated. Use remove_hooks() instead. This will be removed by
572 ``future`` v1.0.
573 """
574 remove_hooks()
575
576
577 def detect_hooks():
578 """
579 Returns True if the import hooks are installed, False if not.
580 """
581 flog.debug('Detecting hooks ...')
582 present = any([hasattr(hook, 'RENAMER') for hook in sys.meta_path])
583 if present:
584 flog.debug('Detected.')
585 else:
586 flog.debug('Not detected.')
587 return present
588
589
590 # As of v0.12, this no longer happens implicitly:
591 # if not PY3:
592 # install_hooks()
593
594
595 if not hasattr(sys, 'py2_modules'):
596 sys.py2_modules = {}
597
598 def cache_py2_modules():
599 """
600 Currently this function is unneeded, as we are not attempting to provide imp ort hooks
601 for modules with ambiguous names: email, urllib, pickle.
602 """
603 if len(sys.py2_modules) != 0:
604 return
605 assert not detect_hooks()
606 import urllib
607 sys.py2_modules['urllib'] = urllib
608
609 import email
610 sys.py2_modules['email'] = email
611
612 import pickle
613 sys.py2_modules['pickle'] = pickle
614
615 # Not all Python installations have test module. (Anaconda doesn't, for exam ple.)
616 # try:
617 # import test
618 # except ImportError:
619 # sys.py2_modules['test'] = None
620 # sys.py2_modules['test'] = test
621
622 # import dbm
623 # sys.py2_modules['dbm'] = dbm
624
625
626 def import_(module_name, backport=False):
627 """
628 Pass a (potentially dotted) module name of a Python 3 standard library
629 module. This function imports the module compatibly on Py2 and Py3 and
630 returns the top-level module.
631
632 Example use:
633 >>> http = import_('http.client')
634 >>> http = import_('http.server')
635 >>> urllib = import_('urllib.request')
636
637 Then:
638 >>> conn = http.client.HTTPConnection(...)
639 >>> response = urllib.request.urlopen('http://mywebsite.com')
640 >>> # etc.
641
642 Use as follows:
643 >>> package_name = import_(module_name)
644
645 On Py3, equivalent to this:
646
647 >>> import module_name
648
649 On Py2, equivalent to this if backport=False:
650
651 >>> from future.moves import module_name
652
653 or to this if backport=True:
654
655 >>> from future.backports import module_name
656
657 except that it also handles dotted module names such as ``http.client``
658 The effect then is like this:
659
660 >>> from future.backports import module
661 >>> from future.backports.module import submodule
662 >>> module.submodule = submodule
663
664 Note that this would be a SyntaxError in Python:
665
666 >>> from future.backports import http.client
667
668 """
669 # Python 2.6 doesn't have importlib in the stdlib, so it requires
670 # the backported ``importlib`` package from PyPI as a dependency to use
671 # this function:
672 import importlib
673
674 if PY3:
675 return __import__(module_name)
676 else:
677 # client.blah = blah
678 # Then http.client = client
679 # etc.
680 if backport:
681 prefix = 'future.backports'
682 else:
683 prefix = 'future.moves'
684 parts = prefix.split('.') + module_name.split('.')
685
686 modules = []
687 for i, part in enumerate(parts):
688 sofar = '.'.join(parts[:i+1])
689 modules.append(importlib.import_module(sofar))
690 for i, part in reversed(list(enumerate(parts))):
691 if i == 0:
692 break
693 setattr(modules[i-1], part, modules[i])
694
695 # Return the next-most top-level module after future.backports / future. moves:
696 return modules[2]
697
698
699 def from_import(module_name, *symbol_names, **kwargs):
700 """
701 Example use:
702 >>> HTTPConnection = from_import('http.client', 'HTTPConnection')
703 >>> HTTPServer = from_import('http.server', 'HTTPServer')
704 >>> urlopen, urlparse = from_import('urllib.request', 'urlopen', 'urlpar se')
705
706 Equivalent to this on Py3:
707
708 >>> from module_name import symbol_names[0], symbol_names[1], ...
709
710 and this on Py2:
711
712 >>> from future.moves.module_name import symbol_names[0], ...
713
714 or:
715
716 >>> from future.backports.module_name import symbol_names[0], ...
717
718 except that it also handles dotted module names such as ``http.client``.
719 """
720
721 if PY3:
722 return __import__(module_name)
723 else:
724 if 'backport' in kwargs and bool(kwargs['backport']):
725 prefix = 'future.backports'
726 else:
727 prefix = 'future.moves'
728 parts = prefix.split('.') + module_name.split('.')
729 module = importlib.import_module(prefix + '.' + module_name)
730 output = [getattr(module, name) for name in symbol_names]
731 if len(output) == 1:
732 return output[0]
733 else:
734 return output
735
736
737 class exclude_local_folder_imports(object):
738 """
739 A context-manager that prevents standard library modules like configparser
740 from being imported from the local python-future source folder on Py3.
741
742 (This was need prior to v0.16.0 because the presence of a configparser
743 folder would otherwise have prevented setuptools from running on Py3. Maybe
744 it's not needed any more?)
745 """
746 def __init__(self, *args):
747 assert len(args) > 0
748 self.module_names = args
749 # Disallow dotted module names like http.client:
750 if any(['.' in m for m in self.module_names]):
751 raise NotImplementedError('Dotted module names are not supported')
752
753 def __enter__(self):
754 self.old_sys_path = copy.copy(sys.path)
755 self.old_sys_modules = copy.copy(sys.modules)
756 if sys.version_info[0] < 3:
757 return
758 # The presence of all these indicates we've found our source folder,
759 # because `builtins` won't have been installed in site-packages by setup .py:
760 FUTURE_SOURCE_SUBFOLDERS = ['future', 'past', 'libfuturize', 'libpasteur ize', 'builtins']
761
762 # Look for the future source folder:
763 for folder in self.old_sys_path:
764 if all([os.path.exists(os.path.join(folder, subfolder))
765 for subfolder in FUTURE_SOURCE_SUBFOLDERS]):
766 # Found it. Remove it.
767 sys.path.remove(folder)
768
769 # Ensure we import the system module:
770 for m in self.module_names:
771 # Delete the module and any submodules from sys.modules:
772 # for key in list(sys.modules):
773 # if key == m or key.startswith(m + '.'):
774 # try:
775 # del sys.modules[key]
776 # except KeyError:
777 # pass
778 try:
779 module = __import__(m, level=0)
780 except ImportError:
781 # There's a problem importing the system module. E.g. the
782 # winreg module is not available except on Windows.
783 pass
784
785 def __exit__(self, *args):
786 # Restore sys.path and sys.modules:
787 sys.path = self.old_sys_path
788 for m in set(self.old_sys_modules.keys()) - set(sys.modules.keys()):
789 sys.modules[m] = self.old_sys_modules[m]
790
791 TOP_LEVEL_MODULES = ['builtins',
792 'copyreg',
793 'html',
794 'http',
795 'queue',
796 'reprlib',
797 'socketserver',
798 'test',
799 'tkinter',
800 'winreg',
801 'xmlrpc',
802 '_dummy_thread',
803 '_markupbase',
804 '_thread',
805 ]
806
807 def import_top_level_modules():
808 with exclude_local_folder_imports(*TOP_LEVEL_MODULES):
809 for m in TOP_LEVEL_MODULES:
810 try:
811 __import__(m)
812 except ImportError: # e.g. winreg
813 pass
OLDNEW
« no previous file with comments | « third_party/google-endpoints/future/moves/xmlrpc/server.py ('k') | third_party/google-endpoints/future/tests/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698