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