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