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