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