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