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