-
Notifications
You must be signed in to change notification settings - Fork 292
Expand file tree
/
Copy path__init__.py
More file actions
391 lines (331 loc) · 12.8 KB
/
Copy path__init__.py
File metadata and controls
391 lines (331 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
"""
Python 3 reorganized the standard library (PEP 3108). This module exposes
several standard library modules to Python 2 under their new Python 3
names.
It is designed to be used as follows::
from future import standard_library
And then these normal Py3 imports work on both Py3 and Py2::
import builtins
import configparser
import copyreg
import queue
import reprlib
import socketserver
import winreg # on Windows only
import test.support
import html, html.parser, html.entites
import http, http.client
import _thread
import _dummythread
import _markupbase
from itertools import filterfalse, zip_longest
from sys import intern
(The renamed modules and functions are still available under their old
names on Python 2.)
To turn off the import hooks, use::
standard_library.disable_hooks()
and to turn it on again, use::
standard_library.enable_hooks()
This is a cleaner alternative to this idiom (see
http://docs.pythonsprints.com/python3_porting/py-porting.html)::
try:
import queue
except ImportError:
import Queue as queue
Limitations
-----------
We don't currently support these modules, but would like to::
import http.server, http.cookies, http.cookiejar
import dbm
import dbm.dumb
import dbm.gnu
import xmlrpc.client
import collections.abc # on Py33
import urllib.request
import urllib.parse
import urllib.error
import urllib.robotparser
import tkinter
import pickle # should (optionally) bring in cPickle on Python 2
Notes
-----
This module only supports Python 2.6 and Python 3.1+.
The following renames are already supported on Python 2.7 without any
additional work from us::
reload() -> imp.reload()
reduce() -> functools.reduce()
StringIO.StringIO -> io.StringIO
Bytes.BytesIO -> io.BytesIO
Old things that can perhaps be fixed for people by futurize.py::
string.uppercase -> string.ascii_uppercase # works on either Py2.7 or Py3+
sys.maxint -> sys.maxsize # but this isn't identical
TODO: Check out these:
Not available on Py2.6:
unittest2 -> unittest?
buffer -> memoryview?
"""
from __future__ import absolute_import, print_function
import sys
import logging
import imp
import contextlib
from future import utils
# The modules that are defined under the same names on Py3 but with
# different contents in a significant way (e.g. submodules) are:
# pickle (fast one)
# dbm
# urllib
# These ones are new (i.e. no problem)
# http
# html
# tkinter
# xmlrpc
# These modules need names from elsewhere being added to them:
# subprocess: should provide getoutput and other fns from commands
# module but these fns are missing: getstatus, mk2arg,
# mkarg
# Old to new
# etc: see lib2to3/fixes/fix_imports.py
RENAMES = {
# 'cStringIO': 'io', # there's a new io module in Python 2.6
# that provides StringIO and BytesIO
# 'StringIO': 'io', # ditto
# 'cPickle': 'pickle',
'__builtin__': 'builtins',
'copy_reg': 'copyreg',
'Queue': 'queue',
'future.standard_library.socketserver': 'socketserver',
'ConfigParser': 'configparser',
'repr': 'reprlib',
# 'FileDialog': 'tkinter.filedialog',
# 'tkFileDialog': 'tkinter.filedialog',
# 'SimpleDialog': 'tkinter.simpledialog',
# 'tkSimpleDialog': 'tkinter.simpledialog',
# 'tkColorChooser': 'tkinter.colorchooser',
# 'tkCommonDialog': 'tkinter.commondialog',
# 'Dialog': 'tkinter.dialog',
# 'Tkdnd': 'tkinter.dnd',
# 'tkFont': 'tkinter.font',
# 'tkMessageBox': 'tkinter.messagebox',
# 'ScrolledText': 'tkinter.scrolledtext',
# 'Tkconstants': 'tkinter.constants',
# 'Tix': 'tkinter.tix',
# 'ttk': 'tkinter.ttk',
# 'Tkinter': 'tkinter',
'_winreg': 'winreg',
'thread': '_thread',
'dummy_thread': '_dummy_thread',
# 'anydbm': 'dbm', # causes infinite import loop
# 'whichdb': 'dbm', # causes infinite import loop
# anydbm and whichdb are handled by fix_imports2
# 'dbhash': 'dbm.bsd',
# 'dumbdbm': 'dbm.dumb',
# 'dbm': 'dbm.ndbm',
# 'gdbm': 'dbm.gnu',
# 'xmlrpclib': 'xmlrpc.client',
# 'DocXMLRPCServer': 'xmlrpc.server',
# 'SimpleXMLRPCServer': 'xmlrpc.server',
# 'httplib': 'http.client',
# 'htmlentitydefs' : 'html.entities',
# 'HTMLParser' : 'html.parser',
# 'Cookie': 'http.cookies',
# 'cookielib': 'http.cookiejar',
# 'BaseHTTPServer': 'http.server',
# 'SimpleHTTPServer': 'http.server',
# 'CGIHTTPServer': 'http.server',
'future.standard_library.test': 'test', # primarily for renaming test_support to support
# 'commands': 'subprocess',
# 'urlparse' : 'urllib.parse',
# 'robotparser' : 'urllib.robotparser',
# 'abc': 'collections.abc', # for Py33
'future.standard_library.html': 'html',
'future.standard_library.http': 'http',
# 'future.standard_library.urllib': 'newurllib',
'future.standard_library._markupbase': '_markupbase',
}
REPLACED_MODULES = set(['test', 'urllib', 'pickle']) # add dbm when we support it
# These are entirely new to Python 2.x, so they cause no potential clashes
# xmlrpc, tkinter, http, html
class WarnOnImport(object):
def __init__(self, *args):
self.module_names = args
def find_module(self, fullname, path=None):
if fullname in self.module_names:
self.path = path
return self
return None
def load_module(self, name):
if name in sys.modules:
return sys.modules[name]
module_info = imp.find_module(name, self.path)
module = imp.load_module(name, *module_info)
sys.modules[name] = module
logging.warning("Imported deprecated module %s", name)
return module
class RenameImport(object):
def __init__(self, old_to_new):
'''
Pass in a dictionary-like object mapping from old names to new
names. E.g. {'ConfigParser': 'configparser', 'cPickle': 'pickle'}
'''
self.old_to_new = old_to_new
both = set(old_to_new.keys()) & set(old_to_new.values())
# print(both)
assert len(both) == 0, \
'Ambiguity in renaming (handler not implemented'
self.new_to_old = dict((new, old) for (old, new) in old_to_new.items())
def find_module(self, fullname, path=None):
# Handles hierarchical importing: package.module.module2
new_base_names = set([s.split('.')[0] for s in self.new_to_old])
if fullname in set(self.old_to_new) | new_base_names:
return self
return None
def load_module(self, name):
path = None
if name in sys.modules:
return sys.modules[name]
elif name in self.new_to_old:
# New name. Look up the corresponding old (Py2) name:
name = self.new_to_old[name]
module = self._find_and_load_module(name)
sys.modules[name] = module
return module
def _find_and_load_module(self, name, path=None):
"""
Finds and loads it. But if there's a . in the name, handles it
properly.
"""
bits = name.split('.')
while len(bits) > 1:
# Treat the first bit as a package
packagename = bits.pop(0)
package = self._find_and_load_module(packagename, path)
path = package.__path__
name = bits[0]
module_info = imp.find_module(name, path)
return imp.load_module(name, *module_info)
# (New module name, new object name, old module name, old object name)
MOVES = [('collections', 'UserList', 'UserList', 'UserList'),
('collections', 'UserDict', 'UserDict', 'UserDict'),
('collections', 'UserString','UserString', 'UserString'),
('itertools', 'filterfalse','itertools', 'ifilterfalse'),
('itertools', 'zip_longest','itertools', 'izip_longest'),
('sys', 'intern','__builtin__', 'intern'),
# urllib._urlopener urllib.request
# urllib.ContentTooShortError urllib.error
# urllib.FancyURLOpener urllib.request
# urllib.pathname2url urllib.request
# urllib.quote urllib.parse
# urllib.quote_plus urllib.parse
# urllib.splitattr urllib.parse
# urllib.splithost urllib.parse
# urllib.splitnport urllib.parse
# urllib.splitpasswd urllib.parse
# urllib.splitport urllib.parse
# urllib.splitquery urllib.parse
# urllib.splittag urllib.parse
# urllib.splittype urllib.parse
# urllib.splituser urllib.parse
# urllib.splitvalue urllib.parse
# urllib.unquote urllib.parse
# urllib.unquote_plus urllib.parse
# urllib.urlcleanup urllib.request
# urllib.urlencode urllib.parse
# urllib.urlopen urllib.request
# urllib.URLOpener urllib.request
# urllib.urlretrieve urllib.request
# urllib2.AbstractBasicAuthHandler urllib.request
# urllib2.AbstractDigestAuthHandler urllib.request
# urllib2.BaseHandler urllib.request
# urllib2.build_opener urllib.request
# urllib2.CacheFTPHandler urllib.request
# urllib2.FileHandler urllib.request
# urllib2.FTPHandler urllib.request
# urllib2.HTTPBasicAuthHandler urllib.request
# urllib2.HTTPCookieProcessor urllib.request
# urllib2.HTTPDefaultErrorHandler urllib.request
# urllib2.HTTPDigestAuthHandler urllib.request
# urllib2.HTTPError urllib.request
# urllib2.HTTPHandler urllib.request
# urllib2.HTTPPasswordMgr urllib.request
# urllib2.HTTPPasswordMgrWithDefaultRealm urllib.request
# urllib2.HTTPRedirectHandler urllib.request
# urllib2.HTTPSHandler urllib.request
# urllib2.install_opener urllib.request
# urllib2.OpenerDirector urllib.request
# urllib2.ProxyBasicAuthHandler urllib.request
# urllib2.ProxyDigestAuthHandler urllib.request
# urllib2.ProxyHandler urllib.request
# urllib2.Request urllib.request
# urllib2.UnknownHandler urllib.request
# urllib2.URLError urllib.request
# urllib2.urlopen urllib.request
# urlparse.parse_qs urllib.parse
# urlparse.parse_qsl urllib.parse
# urlparse.urldefrag urllib.parse
# urlparse.urljoin urllib.parse
# urlparse.urlparse urllib.parse
# urlparse.urlsplit urllib.parse
# urlparse.urlunparse urllib.parse
# urlparse.urlunsplit urllib.parse
]
_old_sys_meta_path = sys.meta_path
def enable_hooks():
if utils.PY3:
return
for (newmodname, newobjname, oldmodname, oldobjname) in MOVES:
newmod = __import__(newmodname)
oldmod = __import__(oldmodname)
obj = getattr(oldmod, oldobjname)
setattr(newmod, newobjname, obj)
sys.meta_path = [RenameImport(RENAMES)]
def disable_hooks():
if not utils.PY3:
sys.meta_path = _old_sys_meta_path
@contextlib.contextmanager
def suspend_hooks():
disable_hooks()
try:
yield
except Exception as e:
raise e
finally:
enable_hooks()
def os_path_join(a, *p):
"""
Replacement os.path.join from Python 3.3 (posixpath.py) which doesn't
add a byte-string to a unicode string as Python 2.7's does.
Join two or more pathname components, inserting '/' as needed.
If any component is an absolute path, all previous path components
will be discarded. An empty last part will result in a path that
ends with a separator."""
sep = _get_sep(a)
path = a
try:
for b in p:
if b.startswith(sep):
path = b
elif not path or path.endswith(sep):
path += b
else:
path += sep + b
except TypeError:
valid_types = all(isinstance(s, (str, bytes, bytearray))
for s in (a, ) + p)
if valid_types:
# Must have a mixture of text and binary data
raise TypeError("Can't mix strings and bytes in path "
"components.") from None
raise
return path
def monkey_patch_stdlib():
"""
Patches out some bugs, like the dodgy os.path.join in Python 2.x,
which adds the byte-string '/' to unicode paths.
"""
if not module in sys.modules:
__import__(module)
modname, module = module, sys.modules[module]
if not utils.PY3:
enable_hooks()
monkey_patch_stdlib()