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