##// END OF EJS Templates
pycompat: only accept a bytestring filepath in Python 2
Martijn Pieters -
r30133:f6dcda75 default
parent child Browse files
Show More
@@ -1,214 +1,196 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 sys
13 import sys
14
14
15 ispy3 = (sys.version_info[0] >= 3)
15 ispy3 = (sys.version_info[0] >= 3)
16
16
17 if not ispy3:
17 if not ispy3:
18 import cPickle as pickle
18 import cPickle as pickle
19 import cStringIO as io
19 import cStringIO as io
20 import httplib
20 import httplib
21 import Queue as _queue
21 import Queue as _queue
22 import SocketServer as socketserver
22 import SocketServer as socketserver
23 import urlparse
23 import urlparse
24 import xmlrpclib
24 import xmlrpclib
25 else:
25 else:
26 import http.client as httplib
26 import http.client as httplib
27 import io
27 import io
28 import pickle
28 import pickle
29 import queue as _queue
29 import queue as _queue
30 import socketserver
30 import socketserver
31 import urllib.parse as urlparse
31 import urllib.parse as urlparse
32 import xmlrpc.client as xmlrpclib
32 import xmlrpc.client as xmlrpclib
33
33
34 if ispy3:
34 if ispy3:
35 import builtins
35 import builtins
36 import functools
36 import functools
37 import os
37 import os
38 fsencode = os.fsencode
38 fsencode = os.fsencode
39
39
40 def sysstr(s):
40 def sysstr(s):
41 """Return a keyword str to be passed to Python functions such as
41 """Return a keyword str to be passed to Python functions such as
42 getattr() and str.encode()
42 getattr() and str.encode()
43
43
44 This never raises UnicodeDecodeError. Non-ascii characters are
44 This never raises UnicodeDecodeError. Non-ascii characters are
45 considered invalid and mapped to arbitrary but unique code points
45 considered invalid and mapped to arbitrary but unique code points
46 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
46 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
47 """
47 """
48 if isinstance(s, builtins.str):
48 if isinstance(s, builtins.str):
49 return s
49 return s
50 return s.decode(u'latin-1')
50 return s.decode(u'latin-1')
51
51
52 def _wrapattrfunc(f):
52 def _wrapattrfunc(f):
53 @functools.wraps(f)
53 @functools.wraps(f)
54 def w(object, name, *args):
54 def w(object, name, *args):
55 return f(object, sysstr(name), *args)
55 return f(object, sysstr(name), *args)
56 return w
56 return w
57
57
58 # these wrappers are automagically imported by hgloader
58 # these wrappers are automagically imported by hgloader
59 delattr = _wrapattrfunc(builtins.delattr)
59 delattr = _wrapattrfunc(builtins.delattr)
60 getattr = _wrapattrfunc(builtins.getattr)
60 getattr = _wrapattrfunc(builtins.getattr)
61 hasattr = _wrapattrfunc(builtins.hasattr)
61 hasattr = _wrapattrfunc(builtins.hasattr)
62 setattr = _wrapattrfunc(builtins.setattr)
62 setattr = _wrapattrfunc(builtins.setattr)
63 xrange = builtins.range
63 xrange = builtins.range
64
64
65 else:
65 else:
66 def sysstr(s):
66 def sysstr(s):
67 return s
67 return s
68
68
69 # Partial backport from os.py in Python 3
69 # Partial backport from os.py in Python 3, which only accepts bytes.
70 def _fscodec():
70 # In Python 2, our paths should only ever be bytes, a unicode path
71 encoding = sys.getfilesystemencoding()
71 # indicates a bug.
72 if encoding == 'mbcs':
73 errors = 'strict'
74 else:
75 errors = 'surrogateescape'
76
77 def fsencode(filename):
72 def fsencode(filename):
78 """
79 Encode filename to the filesystem encoding with 'surrogateescape'
80 error handler, return bytes unchanged. On Windows, use 'strict'
81 error handler if the file system encoding is 'mbcs' (which is the
82 default encoding).
83 """
84 if isinstance(filename, str):
73 if isinstance(filename, str):
85 return filename
74 return filename
86 elif isinstance(filename, unicode):
87 return filename.encode(encoding, errors)
88 else:
75 else:
89 raise TypeError(
76 raise TypeError(
90 "expect str or unicode, not %s" % type(filename).__name__)
77 "expect str, not %s" % type(filename).__name__)
91
92 return fsencode
93
94 fsencode = _fscodec()
95 del _fscodec
96
78
97 stringio = io.StringIO
79 stringio = io.StringIO
98 empty = _queue.Empty
80 empty = _queue.Empty
99 queue = _queue.Queue
81 queue = _queue.Queue
100
82
101 class _pycompatstub(object):
83 class _pycompatstub(object):
102 def __init__(self):
84 def __init__(self):
103 self._aliases = {}
85 self._aliases = {}
104
86
105 def _registeraliases(self, origin, items):
87 def _registeraliases(self, origin, items):
106 """Add items that will be populated at the first access"""
88 """Add items that will be populated at the first access"""
107 items = map(sysstr, items)
89 items = map(sysstr, items)
108 self._aliases.update(
90 self._aliases.update(
109 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
91 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
110 for item in items)
92 for item in items)
111
93
112 def __getattr__(self, name):
94 def __getattr__(self, name):
113 try:
95 try:
114 origin, item = self._aliases[name]
96 origin, item = self._aliases[name]
115 except KeyError:
97 except KeyError:
116 raise AttributeError(name)
98 raise AttributeError(name)
117 self.__dict__[name] = obj = getattr(origin, item)
99 self.__dict__[name] = obj = getattr(origin, item)
118 return obj
100 return obj
119
101
120 httpserver = _pycompatstub()
102 httpserver = _pycompatstub()
121 urlreq = _pycompatstub()
103 urlreq = _pycompatstub()
122 urlerr = _pycompatstub()
104 urlerr = _pycompatstub()
123 if not ispy3:
105 if not ispy3:
124 import BaseHTTPServer
106 import BaseHTTPServer
125 import CGIHTTPServer
107 import CGIHTTPServer
126 import SimpleHTTPServer
108 import SimpleHTTPServer
127 import urllib2
109 import urllib2
128 import urllib
110 import urllib
129 urlreq._registeraliases(urllib, (
111 urlreq._registeraliases(urllib, (
130 "addclosehook",
112 "addclosehook",
131 "addinfourl",
113 "addinfourl",
132 "ftpwrapper",
114 "ftpwrapper",
133 "pathname2url",
115 "pathname2url",
134 "quote",
116 "quote",
135 "splitattr",
117 "splitattr",
136 "splitpasswd",
118 "splitpasswd",
137 "splitport",
119 "splitport",
138 "splituser",
120 "splituser",
139 "unquote",
121 "unquote",
140 "url2pathname",
122 "url2pathname",
141 "urlencode",
123 "urlencode",
142 ))
124 ))
143 urlreq._registeraliases(urllib2, (
125 urlreq._registeraliases(urllib2, (
144 "AbstractHTTPHandler",
126 "AbstractHTTPHandler",
145 "BaseHandler",
127 "BaseHandler",
146 "build_opener",
128 "build_opener",
147 "FileHandler",
129 "FileHandler",
148 "FTPHandler",
130 "FTPHandler",
149 "HTTPBasicAuthHandler",
131 "HTTPBasicAuthHandler",
150 "HTTPDigestAuthHandler",
132 "HTTPDigestAuthHandler",
151 "HTTPHandler",
133 "HTTPHandler",
152 "HTTPPasswordMgrWithDefaultRealm",
134 "HTTPPasswordMgrWithDefaultRealm",
153 "HTTPSHandler",
135 "HTTPSHandler",
154 "install_opener",
136 "install_opener",
155 "ProxyHandler",
137 "ProxyHandler",
156 "Request",
138 "Request",
157 "urlopen",
139 "urlopen",
158 ))
140 ))
159 urlerr._registeraliases(urllib2, (
141 urlerr._registeraliases(urllib2, (
160 "HTTPError",
142 "HTTPError",
161 "URLError",
143 "URLError",
162 ))
144 ))
163 httpserver._registeraliases(BaseHTTPServer, (
145 httpserver._registeraliases(BaseHTTPServer, (
164 "HTTPServer",
146 "HTTPServer",
165 "BaseHTTPRequestHandler",
147 "BaseHTTPRequestHandler",
166 ))
148 ))
167 httpserver._registeraliases(SimpleHTTPServer, (
149 httpserver._registeraliases(SimpleHTTPServer, (
168 "SimpleHTTPRequestHandler",
150 "SimpleHTTPRequestHandler",
169 ))
151 ))
170 httpserver._registeraliases(CGIHTTPServer, (
152 httpserver._registeraliases(CGIHTTPServer, (
171 "CGIHTTPRequestHandler",
153 "CGIHTTPRequestHandler",
172 ))
154 ))
173
155
174 else:
156 else:
175 import urllib.request
157 import urllib.request
176 urlreq._registeraliases(urllib.request, (
158 urlreq._registeraliases(urllib.request, (
177 "AbstractHTTPHandler",
159 "AbstractHTTPHandler",
178 "addclosehook",
160 "addclosehook",
179 "addinfourl",
161 "addinfourl",
180 "BaseHandler",
162 "BaseHandler",
181 "build_opener",
163 "build_opener",
182 "FileHandler",
164 "FileHandler",
183 "FTPHandler",
165 "FTPHandler",
184 "ftpwrapper",
166 "ftpwrapper",
185 "HTTPHandler",
167 "HTTPHandler",
186 "HTTPSHandler",
168 "HTTPSHandler",
187 "install_opener",
169 "install_opener",
188 "pathname2url",
170 "pathname2url",
189 "HTTPBasicAuthHandler",
171 "HTTPBasicAuthHandler",
190 "HTTPDigestAuthHandler",
172 "HTTPDigestAuthHandler",
191 "HTTPPasswordMgrWithDefaultRealm",
173 "HTTPPasswordMgrWithDefaultRealm",
192 "ProxyHandler",
174 "ProxyHandler",
193 "quote",
175 "quote",
194 "Request",
176 "Request",
195 "splitattr",
177 "splitattr",
196 "splitpasswd",
178 "splitpasswd",
197 "splitport",
179 "splitport",
198 "splituser",
180 "splituser",
199 "unquote",
181 "unquote",
200 "url2pathname",
182 "url2pathname",
201 "urlopen",
183 "urlopen",
202 ))
184 ))
203 import urllib.error
185 import urllib.error
204 urlerr._registeraliases(urllib.error, (
186 urlerr._registeraliases(urllib.error, (
205 "HTTPError",
187 "HTTPError",
206 "URLError",
188 "URLError",
207 ))
189 ))
208 import http.server
190 import http.server
209 httpserver._registeraliases(http.server, (
191 httpserver._registeraliases(http.server, (
210 "HTTPServer",
192 "HTTPServer",
211 "BaseHTTPRequestHandler",
193 "BaseHTTPRequestHandler",
212 "SimpleHTTPRequestHandler",
194 "SimpleHTTPRequestHandler",
213 "CGIHTTPRequestHandler",
195 "CGIHTTPRequestHandler",
214 ))
196 ))
General Comments 0
You need to be logged in to leave comments. Login now