##// END OF EJS Templates
pycompat: move imports of cStringIO/io to where they are used...
Yuya Nishihara -
r31372:06440ba0 default
parent child Browse files
Show More
@@ -1,302 +1,304
1 # pycompat.py - portability shim for python 3
1 # pycompat.py - portability shim for python 3
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 """Mercurial portability shim for python 3.
6 """Mercurial portability shim for python 3.
7
7
8 This contains aliases to hide python version-specific details from the core.
8 This contains aliases to hide python version-specific details from the core.
9 """
9 """
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12
12
13 import getopt
13 import getopt
14 import os
14 import os
15 import shlex
15 import shlex
16 import sys
16 import sys
17
17
18 ispy3 = (sys.version_info[0] >= 3)
18 ispy3 = (sys.version_info[0] >= 3)
19
19
20 if not ispy3:
20 if not ispy3:
21 import cPickle as pickle
21 import cPickle as pickle
22 import cStringIO as io
23 import httplib
22 import httplib
24 import Queue as _queue
23 import Queue as _queue
25 import SocketServer as socketserver
24 import SocketServer as socketserver
26 import urlparse
25 import urlparse
27 urlunquote = urlparse.unquote
26 urlunquote = urlparse.unquote
28 import xmlrpclib
27 import xmlrpclib
29 else:
28 else:
30 import http.client as httplib
29 import http.client as httplib
31 import io
32 import pickle
30 import pickle
33 import queue as _queue
31 import queue as _queue
34 import socketserver
32 import socketserver
35 import urllib.parse as urlparse
33 import urllib.parse as urlparse
36 urlunquote = urlparse.unquote_to_bytes
34 urlunquote = urlparse.unquote_to_bytes
37 import xmlrpc.client as xmlrpclib
35 import xmlrpc.client as xmlrpclib
38
36
39 if ispy3:
37 if ispy3:
40 import builtins
38 import builtins
41 import functools
39 import functools
40 import io
41
42 fsencode = os.fsencode
42 fsencode = os.fsencode
43 fsdecode = os.fsdecode
43 fsdecode = os.fsdecode
44 # A bytes version of os.name.
44 # A bytes version of os.name.
45 osname = os.name.encode('ascii')
45 osname = os.name.encode('ascii')
46 ospathsep = os.pathsep.encode('ascii')
46 ospathsep = os.pathsep.encode('ascii')
47 ossep = os.sep.encode('ascii')
47 ossep = os.sep.encode('ascii')
48 osaltsep = os.altsep
48 osaltsep = os.altsep
49 if osaltsep:
49 if osaltsep:
50 osaltsep = osaltsep.encode('ascii')
50 osaltsep = osaltsep.encode('ascii')
51 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
51 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
52 # returns bytes.
52 # returns bytes.
53 getcwd = os.getcwdb
53 getcwd = os.getcwdb
54 sysplatform = sys.platform.encode('ascii')
54 sysplatform = sys.platform.encode('ascii')
55 sysexecutable = sys.executable
55 sysexecutable = sys.executable
56 if sysexecutable:
56 if sysexecutable:
57 sysexecutable = os.fsencode(sysexecutable)
57 sysexecutable = os.fsencode(sysexecutable)
58 stringio = io.BytesIO
58 stringio = io.BytesIO
59
59
60 # TODO: .buffer might not exist if std streams were replaced; we'll need
60 # TODO: .buffer might not exist if std streams were replaced; we'll need
61 # a silly wrapper to make a bytes stream backed by a unicode one.
61 # a silly wrapper to make a bytes stream backed by a unicode one.
62 stdin = sys.stdin.buffer
62 stdin = sys.stdin.buffer
63 stdout = sys.stdout.buffer
63 stdout = sys.stdout.buffer
64 stderr = sys.stderr.buffer
64 stderr = sys.stderr.buffer
65
65
66 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
66 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
67 # we can use os.fsencode() to get back bytes argv.
67 # we can use os.fsencode() to get back bytes argv.
68 #
68 #
69 # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
69 # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
70 #
70 #
71 # TODO: On Windows, the native argv is wchar_t, so we'll need a different
71 # TODO: On Windows, the native argv is wchar_t, so we'll need a different
72 # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
72 # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
73 if getattr(sys, 'argv', None) is not None:
73 if getattr(sys, 'argv', None) is not None:
74 sysargv = list(map(os.fsencode, sys.argv))
74 sysargv = list(map(os.fsencode, sys.argv))
75
75
76 def bytechr(i):
76 def bytechr(i):
77 return bytes([i])
77 return bytes([i])
78
78
79 def sysstr(s):
79 def sysstr(s):
80 """Return a keyword str to be passed to Python functions such as
80 """Return a keyword str to be passed to Python functions such as
81 getattr() and str.encode()
81 getattr() and str.encode()
82
82
83 This never raises UnicodeDecodeError. Non-ascii characters are
83 This never raises UnicodeDecodeError. Non-ascii characters are
84 considered invalid and mapped to arbitrary but unique code points
84 considered invalid and mapped to arbitrary but unique code points
85 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
85 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
86 """
86 """
87 if isinstance(s, builtins.str):
87 if isinstance(s, builtins.str):
88 return s
88 return s
89 return s.decode(u'latin-1')
89 return s.decode(u'latin-1')
90
90
91 def _wrapattrfunc(f):
91 def _wrapattrfunc(f):
92 @functools.wraps(f)
92 @functools.wraps(f)
93 def w(object, name, *args):
93 def w(object, name, *args):
94 return f(object, sysstr(name), *args)
94 return f(object, sysstr(name), *args)
95 return w
95 return w
96
96
97 # these wrappers are automagically imported by hgloader
97 # these wrappers are automagically imported by hgloader
98 delattr = _wrapattrfunc(builtins.delattr)
98 delattr = _wrapattrfunc(builtins.delattr)
99 getattr = _wrapattrfunc(builtins.getattr)
99 getattr = _wrapattrfunc(builtins.getattr)
100 hasattr = _wrapattrfunc(builtins.hasattr)
100 hasattr = _wrapattrfunc(builtins.hasattr)
101 setattr = _wrapattrfunc(builtins.setattr)
101 setattr = _wrapattrfunc(builtins.setattr)
102 xrange = builtins.range
102 xrange = builtins.range
103
103
104 def open(name, mode='r', buffering=-1):
104 def open(name, mode='r', buffering=-1):
105 return builtins.open(name, sysstr(mode), buffering)
105 return builtins.open(name, sysstr(mode), buffering)
106
106
107 # getopt.getopt() on Python 3 deals with unicodes internally so we cannot
107 # getopt.getopt() on Python 3 deals with unicodes internally so we cannot
108 # pass bytes there. Passing unicodes will result in unicodes as return
108 # pass bytes there. Passing unicodes will result in unicodes as return
109 # values which we need to convert again to bytes.
109 # values which we need to convert again to bytes.
110 def getoptb(args, shortlist, namelist):
110 def getoptb(args, shortlist, namelist):
111 args = [a.decode('latin-1') for a in args]
111 args = [a.decode('latin-1') for a in args]
112 shortlist = shortlist.decode('latin-1')
112 shortlist = shortlist.decode('latin-1')
113 namelist = [a.decode('latin-1') for a in namelist]
113 namelist = [a.decode('latin-1') for a in namelist]
114 opts, args = getopt.getopt(args, shortlist, namelist)
114 opts, args = getopt.getopt(args, shortlist, namelist)
115 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
115 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
116 for a in opts]
116 for a in opts]
117 args = [a.encode('latin-1') for a in args]
117 args = [a.encode('latin-1') for a in args]
118 return opts, args
118 return opts, args
119
119
120 # keys of keyword arguments in Python need to be strings which are unicodes
120 # keys of keyword arguments in Python need to be strings which are unicodes
121 # Python 3. This function takes keyword arguments, convert the keys to str.
121 # Python 3. This function takes keyword arguments, convert the keys to str.
122 def strkwargs(dic):
122 def strkwargs(dic):
123 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
123 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
124 return dic
124 return dic
125
125
126 # keys of keyword arguments need to be unicode while passing into
126 # keys of keyword arguments need to be unicode while passing into
127 # a function. This function helps us to convert those keys back to bytes
127 # a function. This function helps us to convert those keys back to bytes
128 # again as we need to deal with bytes.
128 # again as we need to deal with bytes.
129 def byteskwargs(dic):
129 def byteskwargs(dic):
130 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
130 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
131 return dic
131 return dic
132
132
133 # shlex.split() accepts unicodes on Python 3. This function takes bytes
133 # shlex.split() accepts unicodes on Python 3. This function takes bytes
134 # argument, convert it into unicodes, pass into shlex.split(), convert the
134 # argument, convert it into unicodes, pass into shlex.split(), convert the
135 # returned value to bytes and return that.
135 # returned value to bytes and return that.
136 # TODO: handle shlex.shlex().
136 # TODO: handle shlex.shlex().
137 def shlexsplit(s):
137 def shlexsplit(s):
138 ret = shlex.split(s.decode('latin-1'))
138 ret = shlex.split(s.decode('latin-1'))
139 return [a.encode('latin-1') for a in ret]
139 return [a.encode('latin-1') for a in ret]
140
140
141 else:
141 else:
142 import cStringIO
143
142 bytechr = chr
144 bytechr = chr
143
145
144 def sysstr(s):
146 def sysstr(s):
145 return s
147 return s
146
148
147 # Partial backport from os.py in Python 3, which only accepts bytes.
149 # Partial backport from os.py in Python 3, which only accepts bytes.
148 # In Python 2, our paths should only ever be bytes, a unicode path
150 # In Python 2, our paths should only ever be bytes, a unicode path
149 # indicates a bug.
151 # indicates a bug.
150 def fsencode(filename):
152 def fsencode(filename):
151 if isinstance(filename, str):
153 if isinstance(filename, str):
152 return filename
154 return filename
153 else:
155 else:
154 raise TypeError(
156 raise TypeError(
155 "expect str, not %s" % type(filename).__name__)
157 "expect str, not %s" % type(filename).__name__)
156
158
157 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
159 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
158 # better not to touch Python 2 part as it's already working fine.
160 # better not to touch Python 2 part as it's already working fine.
159 def fsdecode(filename):
161 def fsdecode(filename):
160 return filename
162 return filename
161
163
162 def getoptb(args, shortlist, namelist):
164 def getoptb(args, shortlist, namelist):
163 return getopt.getopt(args, shortlist, namelist)
165 return getopt.getopt(args, shortlist, namelist)
164
166
165 def strkwargs(dic):
167 def strkwargs(dic):
166 return dic
168 return dic
167
169
168 def byteskwargs(dic):
170 def byteskwargs(dic):
169 return dic
171 return dic
170
172
171 osname = os.name
173 osname = os.name
172 ospathsep = os.pathsep
174 ospathsep = os.pathsep
173 ossep = os.sep
175 ossep = os.sep
174 osaltsep = os.altsep
176 osaltsep = os.altsep
175 stdin = sys.stdin
177 stdin = sys.stdin
176 stdout = sys.stdout
178 stdout = sys.stdout
177 stderr = sys.stderr
179 stderr = sys.stderr
178 if getattr(sys, 'argv', None) is not None:
180 if getattr(sys, 'argv', None) is not None:
179 sysargv = sys.argv
181 sysargv = sys.argv
180 sysplatform = sys.platform
182 sysplatform = sys.platform
181 getcwd = os.getcwd
183 getcwd = os.getcwd
182 sysexecutable = sys.executable
184 sysexecutable = sys.executable
183 shlexsplit = shlex.split
185 shlexsplit = shlex.split
184 stringio = io.StringIO
186 stringio = cStringIO.StringIO
185
187
186 empty = _queue.Empty
188 empty = _queue.Empty
187 queue = _queue.Queue
189 queue = _queue.Queue
188
190
189 class _pycompatstub(object):
191 class _pycompatstub(object):
190 def __init__(self):
192 def __init__(self):
191 self._aliases = {}
193 self._aliases = {}
192
194
193 def _registeraliases(self, origin, items):
195 def _registeraliases(self, origin, items):
194 """Add items that will be populated at the first access"""
196 """Add items that will be populated at the first access"""
195 items = map(sysstr, items)
197 items = map(sysstr, items)
196 self._aliases.update(
198 self._aliases.update(
197 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
199 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
198 for item in items)
200 for item in items)
199
201
200 def __getattr__(self, name):
202 def __getattr__(self, name):
201 try:
203 try:
202 origin, item = self._aliases[name]
204 origin, item = self._aliases[name]
203 except KeyError:
205 except KeyError:
204 raise AttributeError(name)
206 raise AttributeError(name)
205 self.__dict__[name] = obj = getattr(origin, item)
207 self.__dict__[name] = obj = getattr(origin, item)
206 return obj
208 return obj
207
209
208 httpserver = _pycompatstub()
210 httpserver = _pycompatstub()
209 urlreq = _pycompatstub()
211 urlreq = _pycompatstub()
210 urlerr = _pycompatstub()
212 urlerr = _pycompatstub()
211 if not ispy3:
213 if not ispy3:
212 import BaseHTTPServer
214 import BaseHTTPServer
213 import CGIHTTPServer
215 import CGIHTTPServer
214 import SimpleHTTPServer
216 import SimpleHTTPServer
215 import urllib2
217 import urllib2
216 import urllib
218 import urllib
217 urlreq._registeraliases(urllib, (
219 urlreq._registeraliases(urllib, (
218 "addclosehook",
220 "addclosehook",
219 "addinfourl",
221 "addinfourl",
220 "ftpwrapper",
222 "ftpwrapper",
221 "pathname2url",
223 "pathname2url",
222 "quote",
224 "quote",
223 "splitattr",
225 "splitattr",
224 "splitpasswd",
226 "splitpasswd",
225 "splitport",
227 "splitport",
226 "splituser",
228 "splituser",
227 "unquote",
229 "unquote",
228 "url2pathname",
230 "url2pathname",
229 "urlencode",
231 "urlencode",
230 ))
232 ))
231 urlreq._registeraliases(urllib2, (
233 urlreq._registeraliases(urllib2, (
232 "AbstractHTTPHandler",
234 "AbstractHTTPHandler",
233 "BaseHandler",
235 "BaseHandler",
234 "build_opener",
236 "build_opener",
235 "FileHandler",
237 "FileHandler",
236 "FTPHandler",
238 "FTPHandler",
237 "HTTPBasicAuthHandler",
239 "HTTPBasicAuthHandler",
238 "HTTPDigestAuthHandler",
240 "HTTPDigestAuthHandler",
239 "HTTPHandler",
241 "HTTPHandler",
240 "HTTPPasswordMgrWithDefaultRealm",
242 "HTTPPasswordMgrWithDefaultRealm",
241 "HTTPSHandler",
243 "HTTPSHandler",
242 "install_opener",
244 "install_opener",
243 "ProxyHandler",
245 "ProxyHandler",
244 "Request",
246 "Request",
245 "urlopen",
247 "urlopen",
246 ))
248 ))
247 urlerr._registeraliases(urllib2, (
249 urlerr._registeraliases(urllib2, (
248 "HTTPError",
250 "HTTPError",
249 "URLError",
251 "URLError",
250 ))
252 ))
251 httpserver._registeraliases(BaseHTTPServer, (
253 httpserver._registeraliases(BaseHTTPServer, (
252 "HTTPServer",
254 "HTTPServer",
253 "BaseHTTPRequestHandler",
255 "BaseHTTPRequestHandler",
254 ))
256 ))
255 httpserver._registeraliases(SimpleHTTPServer, (
257 httpserver._registeraliases(SimpleHTTPServer, (
256 "SimpleHTTPRequestHandler",
258 "SimpleHTTPRequestHandler",
257 ))
259 ))
258 httpserver._registeraliases(CGIHTTPServer, (
260 httpserver._registeraliases(CGIHTTPServer, (
259 "CGIHTTPRequestHandler",
261 "CGIHTTPRequestHandler",
260 ))
262 ))
261
263
262 else:
264 else:
263 import urllib.request
265 import urllib.request
264 urlreq._registeraliases(urllib.request, (
266 urlreq._registeraliases(urllib.request, (
265 "AbstractHTTPHandler",
267 "AbstractHTTPHandler",
266 "addclosehook",
268 "addclosehook",
267 "addinfourl",
269 "addinfourl",
268 "BaseHandler",
270 "BaseHandler",
269 "build_opener",
271 "build_opener",
270 "FileHandler",
272 "FileHandler",
271 "FTPHandler",
273 "FTPHandler",
272 "ftpwrapper",
274 "ftpwrapper",
273 "HTTPHandler",
275 "HTTPHandler",
274 "HTTPSHandler",
276 "HTTPSHandler",
275 "install_opener",
277 "install_opener",
276 "pathname2url",
278 "pathname2url",
277 "HTTPBasicAuthHandler",
279 "HTTPBasicAuthHandler",
278 "HTTPDigestAuthHandler",
280 "HTTPDigestAuthHandler",
279 "HTTPPasswordMgrWithDefaultRealm",
281 "HTTPPasswordMgrWithDefaultRealm",
280 "ProxyHandler",
282 "ProxyHandler",
281 "quote",
283 "quote",
282 "Request",
284 "Request",
283 "splitattr",
285 "splitattr",
284 "splitpasswd",
286 "splitpasswd",
285 "splitport",
287 "splitport",
286 "splituser",
288 "splituser",
287 "unquote",
289 "unquote",
288 "url2pathname",
290 "url2pathname",
289 "urlopen",
291 "urlopen",
290 ))
292 ))
291 import urllib.error
293 import urllib.error
292 urlerr._registeraliases(urllib.error, (
294 urlerr._registeraliases(urllib.error, (
293 "HTTPError",
295 "HTTPError",
294 "URLError",
296 "URLError",
295 ))
297 ))
296 import http.server
298 import http.server
297 httpserver._registeraliases(http.server, (
299 httpserver._registeraliases(http.server, (
298 "HTTPServer",
300 "HTTPServer",
299 "BaseHTTPRequestHandler",
301 "BaseHTTPRequestHandler",
300 "SimpleHTTPRequestHandler",
302 "SimpleHTTPRequestHandler",
301 "CGIHTTPRequestHandler",
303 "CGIHTTPRequestHandler",
302 ))
304 ))
General Comments 0
You need to be logged in to leave comments. Login now