##// END OF EJS Templates
watchman: drop some py2 compat code...
Matt Harbison -
r50743:139f7130 default
parent child Browse files
Show More
@@ -1,68 +1,53
1 # Copyright 2016-present Facebook, Inc.
1 # Copyright 2016-present Facebook, Inc.
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Redistribution and use in source and binary forms, with or without
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
5 # modification, are permitted provided that the following conditions are met:
6 #
6 #
7 # * Redistributions of source code must retain the above copyright notice,
7 # * Redistributions of source code must retain the above copyright notice,
8 # this list of conditions and the following disclaimer.
8 # this list of conditions and the following disclaimer.
9 #
9 #
10 # * Redistributions in binary form must reproduce the above copyright notice,
10 # * Redistributions in binary form must reproduce the above copyright notice,
11 # this list of conditions and the following disclaimer in the documentation
11 # this list of conditions and the following disclaimer in the documentation
12 # and/or other materials provided with the distribution.
12 # and/or other materials provided with the distribution.
13 #
13 #
14 # * Neither the name Facebook nor the names of its contributors may be used to
14 # * Neither the name Facebook nor the names of its contributors may be used to
15 # endorse or promote products derived from this software without specific
15 # endorse or promote products derived from this software without specific
16 # prior written permission.
16 # prior written permission.
17 #
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 import sys
29 import sys
30
30
31
31
32 """Compatibility module across Python 2 and 3."""
32 """Compatibility module across Python 2 and 3."""
33
33
34
34
35 PYTHON2 = sys.version_info < (3, 0)
36 PYTHON3 = sys.version_info >= (3, 0)
35 PYTHON3 = sys.version_info >= (3, 0)
37
36
38 # This is adapted from https://bitbucket.org/gutworth/six, and used under the
37 # This is adapted from https://bitbucket.org/gutworth/six, and used under the
39 # MIT license. See LICENSE for a full copyright notice.
38 # MIT license. See LICENSE for a full copyright notice.
40 if PYTHON3:
41
42 def reraise(tp, value, tb=None):
43 try:
44 if value is None:
45 value = tp()
46 if value.__traceback__ is not tb:
47 raise value.with_traceback(tb)
48 raise value
49 finally:
50 value = None
51 tb = None
52
39
53
40
54 else:
55 exec(
56 """
57 def reraise(tp, value, tb=None):
41 def reraise(tp, value, tb=None):
58 try:
42 try:
59 raise tp, value, tb
43 if value is None:
44 value = tp()
45 if value.__traceback__ is not tb:
46 raise value.with_traceback(tb)
47 raise value
60 finally:
48 finally:
49 value = None
61 tb = None
50 tb = None
62 """.strip()
51
63 )
64
52
65 if PYTHON3:
53 UNICODE = str
66 UNICODE = str
67 else:
68 UNICODE = unicode # noqa: F821 We handled versioning above
@@ -1,569 +1,564
1 # Copyright 2015 Facebook, Inc.
1 # Copyright 2015 Facebook, Inc.
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Redistribution and use in source and binary forms, with or without
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
5 # modification, are permitted provided that the following conditions are met:
6 #
6 #
7 # * Redistributions of source code must retain the above copyright notice,
7 # * Redistributions of source code must retain the above copyright notice,
8 # this list of conditions and the following disclaimer.
8 # this list of conditions and the following disclaimer.
9 #
9 #
10 # * Redistributions in binary form must reproduce the above copyright notice,
10 # * Redistributions in binary form must reproduce the above copyright notice,
11 # this list of conditions and the following disclaimer in the documentation
11 # this list of conditions and the following disclaimer in the documentation
12 # and/or other materials provided with the distribution.
12 # and/or other materials provided with the distribution.
13 #
13 #
14 # * Neither the name Facebook nor the names of its contributors may be used to
14 # * Neither the name Facebook nor the names of its contributors may be used to
15 # endorse or promote products derived from this software without specific
15 # endorse or promote products derived from this software without specific
16 # prior written permission.
16 # prior written permission.
17 #
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
29 import binascii
29 import binascii
30 import collections
30 import collections
31 import ctypes
31 import ctypes
32 import struct
32 import struct
33 import sys
33 import sys
34
34
35 from . import compat
35 from . import compat
36
36
37 abc = collections.abc
37 abc = collections.abc
38
38
39 BSER_ARRAY = b"\x00"
39 BSER_ARRAY = b"\x00"
40 BSER_OBJECT = b"\x01"
40 BSER_OBJECT = b"\x01"
41 BSER_BYTESTRING = b"\x02"
41 BSER_BYTESTRING = b"\x02"
42 BSER_INT8 = b"\x03"
42 BSER_INT8 = b"\x03"
43 BSER_INT16 = b"\x04"
43 BSER_INT16 = b"\x04"
44 BSER_INT32 = b"\x05"
44 BSER_INT32 = b"\x05"
45 BSER_INT64 = b"\x06"
45 BSER_INT64 = b"\x06"
46 BSER_REAL = b"\x07"
46 BSER_REAL = b"\x07"
47 BSER_TRUE = b"\x08"
47 BSER_TRUE = b"\x08"
48 BSER_FALSE = b"\x09"
48 BSER_FALSE = b"\x09"
49 BSER_NULL = b"\x0a"
49 BSER_NULL = b"\x0a"
50 BSER_TEMPLATE = b"\x0b"
50 BSER_TEMPLATE = b"\x0b"
51 BSER_SKIP = b"\x0c"
51 BSER_SKIP = b"\x0c"
52 BSER_UTF8STRING = b"\x0d"
52 BSER_UTF8STRING = b"\x0d"
53
53
54 if compat.PYTHON3:
54 STRING_TYPES = (str, bytes)
55 STRING_TYPES = (str, bytes)
55 unicode = str
56 unicode = str
56
57
57
58 def tobytes(i):
58 def tobytes(i):
59 return str(i).encode("ascii")
59 return str(i).encode("ascii")
60
60
61 long = int
61
62 else:
62 long = int
63 STRING_TYPES = (unicode, str)
64 tobytes = bytes
65
63
66 # Leave room for the serialization header, which includes
64 # Leave room for the serialization header, which includes
67 # our overall length. To make things simpler, we'll use an
65 # our overall length. To make things simpler, we'll use an
68 # int32 for the header
66 # int32 for the header
69 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
67 EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00"
70 EMPTY_HEADER_V2 = b"\x00\x02\x00\x00\x00\x00\x05\x00\x00\x00\x00"
68 EMPTY_HEADER_V2 = b"\x00\x02\x00\x00\x00\x00\x05\x00\x00\x00\x00"
71
69
72
70
73 def _int_size(x):
71 def _int_size(x):
74 """Return the smallest size int that can store the value"""
72 """Return the smallest size int that can store the value"""
75 if -0x80 <= x <= 0x7F:
73 if -0x80 <= x <= 0x7F:
76 return 1
74 return 1
77 elif -0x8000 <= x <= 0x7FFF:
75 elif -0x8000 <= x <= 0x7FFF:
78 return 2
76 return 2
79 elif -0x80000000 <= x <= 0x7FFFFFFF:
77 elif -0x80000000 <= x <= 0x7FFFFFFF:
80 return 4
78 return 4
81 elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF):
79 elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF):
82 return 8
80 return 8
83 else:
81 else:
84 raise RuntimeError("Cannot represent value: " + str(x))
82 raise RuntimeError("Cannot represent value: " + str(x))
85
83
86
84
87 def _buf_pos(buf, pos):
85 def _buf_pos(buf, pos):
88 ret = buf[pos]
86 ret = buf[pos]
89 # Normalize the return type to bytes
87 # Normalize the return type to bytes
90 if compat.PYTHON3 and not isinstance(ret, bytes):
88 if not isinstance(ret, bytes):
91 ret = bytes((ret,))
89 ret = bytes((ret,))
92 return ret
90 return ret
93
91
94
92
95 class _bser_buffer:
93 class _bser_buffer:
96 def __init__(self, version):
94 def __init__(self, version):
97 self.bser_version = version
95 self.bser_version = version
98 self.buf = ctypes.create_string_buffer(8192)
96 self.buf = ctypes.create_string_buffer(8192)
99 if self.bser_version == 1:
97 if self.bser_version == 1:
100 struct.pack_into(
98 struct.pack_into(
101 tobytes(len(EMPTY_HEADER)) + b"s", self.buf, 0, EMPTY_HEADER
99 tobytes(len(EMPTY_HEADER)) + b"s", self.buf, 0, EMPTY_HEADER
102 )
100 )
103 self.wpos = len(EMPTY_HEADER)
101 self.wpos = len(EMPTY_HEADER)
104 else:
102 else:
105 assert self.bser_version == 2
103 assert self.bser_version == 2
106 struct.pack_into(
104 struct.pack_into(
107 tobytes(len(EMPTY_HEADER_V2)) + b"s",
105 tobytes(len(EMPTY_HEADER_V2)) + b"s",
108 self.buf,
106 self.buf,
109 0,
107 0,
110 EMPTY_HEADER_V2,
108 EMPTY_HEADER_V2,
111 )
109 )
112 self.wpos = len(EMPTY_HEADER_V2)
110 self.wpos = len(EMPTY_HEADER_V2)
113
111
114 def ensure_size(self, size):
112 def ensure_size(self, size):
115 while ctypes.sizeof(self.buf) - self.wpos < size:
113 while ctypes.sizeof(self.buf) - self.wpos < size:
116 ctypes.resize(self.buf, ctypes.sizeof(self.buf) * 2)
114 ctypes.resize(self.buf, ctypes.sizeof(self.buf) * 2)
117
115
118 def append_long(self, val):
116 def append_long(self, val):
119 size = _int_size(val)
117 size = _int_size(val)
120 to_write = size + 1
118 to_write = size + 1
121 self.ensure_size(to_write)
119 self.ensure_size(to_write)
122 if size == 1:
120 if size == 1:
123 struct.pack_into(b"=cb", self.buf, self.wpos, BSER_INT8, val)
121 struct.pack_into(b"=cb", self.buf, self.wpos, BSER_INT8, val)
124 elif size == 2:
122 elif size == 2:
125 struct.pack_into(b"=ch", self.buf, self.wpos, BSER_INT16, val)
123 struct.pack_into(b"=ch", self.buf, self.wpos, BSER_INT16, val)
126 elif size == 4:
124 elif size == 4:
127 struct.pack_into(b"=ci", self.buf, self.wpos, BSER_INT32, val)
125 struct.pack_into(b"=ci", self.buf, self.wpos, BSER_INT32, val)
128 elif size == 8:
126 elif size == 8:
129 struct.pack_into(b"=cq", self.buf, self.wpos, BSER_INT64, val)
127 struct.pack_into(b"=cq", self.buf, self.wpos, BSER_INT64, val)
130 else:
128 else:
131 raise RuntimeError("Cannot represent this long value")
129 raise RuntimeError("Cannot represent this long value")
132 self.wpos += to_write
130 self.wpos += to_write
133
131
134 def append_string(self, s):
132 def append_string(self, s):
135 if isinstance(s, unicode):
133 if isinstance(s, unicode):
136 s = s.encode("utf-8")
134 s = s.encode("utf-8")
137 s_len = len(s)
135 s_len = len(s)
138 size = _int_size(s_len)
136 size = _int_size(s_len)
139 to_write = 2 + size + s_len
137 to_write = 2 + size + s_len
140 self.ensure_size(to_write)
138 self.ensure_size(to_write)
141 if size == 1:
139 if size == 1:
142 struct.pack_into(
140 struct.pack_into(
143 b"=ccb" + tobytes(s_len) + b"s",
141 b"=ccb" + tobytes(s_len) + b"s",
144 self.buf,
142 self.buf,
145 self.wpos,
143 self.wpos,
146 BSER_BYTESTRING,
144 BSER_BYTESTRING,
147 BSER_INT8,
145 BSER_INT8,
148 s_len,
146 s_len,
149 s,
147 s,
150 )
148 )
151 elif size == 2:
149 elif size == 2:
152 struct.pack_into(
150 struct.pack_into(
153 b"=cch" + tobytes(s_len) + b"s",
151 b"=cch" + tobytes(s_len) + b"s",
154 self.buf,
152 self.buf,
155 self.wpos,
153 self.wpos,
156 BSER_BYTESTRING,
154 BSER_BYTESTRING,
157 BSER_INT16,
155 BSER_INT16,
158 s_len,
156 s_len,
159 s,
157 s,
160 )
158 )
161 elif size == 4:
159 elif size == 4:
162 struct.pack_into(
160 struct.pack_into(
163 b"=cci" + tobytes(s_len) + b"s",
161 b"=cci" + tobytes(s_len) + b"s",
164 self.buf,
162 self.buf,
165 self.wpos,
163 self.wpos,
166 BSER_BYTESTRING,
164 BSER_BYTESTRING,
167 BSER_INT32,
165 BSER_INT32,
168 s_len,
166 s_len,
169 s,
167 s,
170 )
168 )
171 elif size == 8:
169 elif size == 8:
172 struct.pack_into(
170 struct.pack_into(
173 b"=ccq" + tobytes(s_len) + b"s",
171 b"=ccq" + tobytes(s_len) + b"s",
174 self.buf,
172 self.buf,
175 self.wpos,
173 self.wpos,
176 BSER_BYTESTRING,
174 BSER_BYTESTRING,
177 BSER_INT64,
175 BSER_INT64,
178 s_len,
176 s_len,
179 s,
177 s,
180 )
178 )
181 else:
179 else:
182 raise RuntimeError("Cannot represent this string value")
180 raise RuntimeError("Cannot represent this string value")
183 self.wpos += to_write
181 self.wpos += to_write
184
182
185 def append_recursive(self, val):
183 def append_recursive(self, val):
186 if isinstance(val, bool):
184 if isinstance(val, bool):
187 needed = 1
185 needed = 1
188 self.ensure_size(needed)
186 self.ensure_size(needed)
189 if val:
187 if val:
190 to_encode = BSER_TRUE
188 to_encode = BSER_TRUE
191 else:
189 else:
192 to_encode = BSER_FALSE
190 to_encode = BSER_FALSE
193 struct.pack_into(b"=c", self.buf, self.wpos, to_encode)
191 struct.pack_into(b"=c", self.buf, self.wpos, to_encode)
194 self.wpos += needed
192 self.wpos += needed
195 elif val is None:
193 elif val is None:
196 needed = 1
194 needed = 1
197 self.ensure_size(needed)
195 self.ensure_size(needed)
198 struct.pack_into(b"=c", self.buf, self.wpos, BSER_NULL)
196 struct.pack_into(b"=c", self.buf, self.wpos, BSER_NULL)
199 self.wpos += needed
197 self.wpos += needed
200 elif isinstance(val, (int, long)):
198 elif isinstance(val, (int, long)):
201 self.append_long(val)
199 self.append_long(val)
202 elif isinstance(val, STRING_TYPES):
200 elif isinstance(val, STRING_TYPES):
203 self.append_string(val)
201 self.append_string(val)
204 elif isinstance(val, float):
202 elif isinstance(val, float):
205 needed = 9
203 needed = 9
206 self.ensure_size(needed)
204 self.ensure_size(needed)
207 struct.pack_into(b"=cd", self.buf, self.wpos, BSER_REAL, val)
205 struct.pack_into(b"=cd", self.buf, self.wpos, BSER_REAL, val)
208 self.wpos += needed
206 self.wpos += needed
209 elif isinstance(val, abc.Mapping) and isinstance(val, abc.Sized):
207 elif isinstance(val, abc.Mapping) and isinstance(val, abc.Sized):
210 val_len = len(val)
208 val_len = len(val)
211 size = _int_size(val_len)
209 size = _int_size(val_len)
212 needed = 2 + size
210 needed = 2 + size
213 self.ensure_size(needed)
211 self.ensure_size(needed)
214 if size == 1:
212 if size == 1:
215 struct.pack_into(
213 struct.pack_into(
216 b"=ccb",
214 b"=ccb",
217 self.buf,
215 self.buf,
218 self.wpos,
216 self.wpos,
219 BSER_OBJECT,
217 BSER_OBJECT,
220 BSER_INT8,
218 BSER_INT8,
221 val_len,
219 val_len,
222 )
220 )
223 elif size == 2:
221 elif size == 2:
224 struct.pack_into(
222 struct.pack_into(
225 b"=cch",
223 b"=cch",
226 self.buf,
224 self.buf,
227 self.wpos,
225 self.wpos,
228 BSER_OBJECT,
226 BSER_OBJECT,
229 BSER_INT16,
227 BSER_INT16,
230 val_len,
228 val_len,
231 )
229 )
232 elif size == 4:
230 elif size == 4:
233 struct.pack_into(
231 struct.pack_into(
234 b"=cci",
232 b"=cci",
235 self.buf,
233 self.buf,
236 self.wpos,
234 self.wpos,
237 BSER_OBJECT,
235 BSER_OBJECT,
238 BSER_INT32,
236 BSER_INT32,
239 val_len,
237 val_len,
240 )
238 )
241 elif size == 8:
239 elif size == 8:
242 struct.pack_into(
240 struct.pack_into(
243 b"=ccq",
241 b"=ccq",
244 self.buf,
242 self.buf,
245 self.wpos,
243 self.wpos,
246 BSER_OBJECT,
244 BSER_OBJECT,
247 BSER_INT64,
245 BSER_INT64,
248 val_len,
246 val_len,
249 )
247 )
250 else:
248 else:
251 raise RuntimeError("Cannot represent this mapping value")
249 raise RuntimeError("Cannot represent this mapping value")
252 self.wpos += needed
250 self.wpos += needed
253 if compat.PYTHON3:
251 iteritems = val.items()
254 iteritems = val.items()
255 else:
256 iteritems = val.iteritems() # noqa: B301 Checked version above
257 for k, v in iteritems:
252 for k, v in iteritems:
258 self.append_string(k)
253 self.append_string(k)
259 self.append_recursive(v)
254 self.append_recursive(v)
260 elif isinstance(val, abc.Iterable) and isinstance(val, abc.Sized):
255 elif isinstance(val, abc.Iterable) and isinstance(val, abc.Sized):
261 val_len = len(val)
256 val_len = len(val)
262 size = _int_size(val_len)
257 size = _int_size(val_len)
263 needed = 2 + size
258 needed = 2 + size
264 self.ensure_size(needed)
259 self.ensure_size(needed)
265 if size == 1:
260 if size == 1:
266 struct.pack_into(
261 struct.pack_into(
267 b"=ccb", self.buf, self.wpos, BSER_ARRAY, BSER_INT8, val_len
262 b"=ccb", self.buf, self.wpos, BSER_ARRAY, BSER_INT8, val_len
268 )
263 )
269 elif size == 2:
264 elif size == 2:
270 struct.pack_into(
265 struct.pack_into(
271 b"=cch",
266 b"=cch",
272 self.buf,
267 self.buf,
273 self.wpos,
268 self.wpos,
274 BSER_ARRAY,
269 BSER_ARRAY,
275 BSER_INT16,
270 BSER_INT16,
276 val_len,
271 val_len,
277 )
272 )
278 elif size == 4:
273 elif size == 4:
279 struct.pack_into(
274 struct.pack_into(
280 b"=cci",
275 b"=cci",
281 self.buf,
276 self.buf,
282 self.wpos,
277 self.wpos,
283 BSER_ARRAY,
278 BSER_ARRAY,
284 BSER_INT32,
279 BSER_INT32,
285 val_len,
280 val_len,
286 )
281 )
287 elif size == 8:
282 elif size == 8:
288 struct.pack_into(
283 struct.pack_into(
289 b"=ccq",
284 b"=ccq",
290 self.buf,
285 self.buf,
291 self.wpos,
286 self.wpos,
292 BSER_ARRAY,
287 BSER_ARRAY,
293 BSER_INT64,
288 BSER_INT64,
294 val_len,
289 val_len,
295 )
290 )
296 else:
291 else:
297 raise RuntimeError("Cannot represent this sequence value")
292 raise RuntimeError("Cannot represent this sequence value")
298 self.wpos += needed
293 self.wpos += needed
299 for v in val:
294 for v in val:
300 self.append_recursive(v)
295 self.append_recursive(v)
301 else:
296 else:
302 raise RuntimeError("Cannot represent unknown value type")
297 raise RuntimeError("Cannot represent unknown value type")
303
298
304
299
305 def dumps(obj, version=1, capabilities=0):
300 def dumps(obj, version=1, capabilities=0):
306 bser_buf = _bser_buffer(version=version)
301 bser_buf = _bser_buffer(version=version)
307 bser_buf.append_recursive(obj)
302 bser_buf.append_recursive(obj)
308 # Now fill in the overall length
303 # Now fill in the overall length
309 if version == 1:
304 if version == 1:
310 obj_len = bser_buf.wpos - len(EMPTY_HEADER)
305 obj_len = bser_buf.wpos - len(EMPTY_HEADER)
311 struct.pack_into(b"=i", bser_buf.buf, 3, obj_len)
306 struct.pack_into(b"=i", bser_buf.buf, 3, obj_len)
312 else:
307 else:
313 obj_len = bser_buf.wpos - len(EMPTY_HEADER_V2)
308 obj_len = bser_buf.wpos - len(EMPTY_HEADER_V2)
314 struct.pack_into(b"=i", bser_buf.buf, 2, capabilities)
309 struct.pack_into(b"=i", bser_buf.buf, 2, capabilities)
315 struct.pack_into(b"=i", bser_buf.buf, 7, obj_len)
310 struct.pack_into(b"=i", bser_buf.buf, 7, obj_len)
316 return bser_buf.buf.raw[: bser_buf.wpos]
311 return bser_buf.buf.raw[: bser_buf.wpos]
317
312
318
313
319 # This is a quack-alike with the bserObjectType in bser.c
314 # This is a quack-alike with the bserObjectType in bser.c
320 # It provides by getattr accessors and getitem for both index
315 # It provides by getattr accessors and getitem for both index
321 # and name.
316 # and name.
322 class _BunserDict:
317 class _BunserDict:
323 __slots__ = ("_keys", "_values")
318 __slots__ = ("_keys", "_values")
324
319
325 def __init__(self, keys, values):
320 def __init__(self, keys, values):
326 self._keys = keys
321 self._keys = keys
327 self._values = values
322 self._values = values
328
323
329 def __getattr__(self, name):
324 def __getattr__(self, name):
330 return self.__getitem__(name)
325 return self.__getitem__(name)
331
326
332 def __getitem__(self, key):
327 def __getitem__(self, key):
333 if isinstance(key, (int, long)):
328 if isinstance(key, (int, long)):
334 return self._values[key]
329 return self._values[key]
335 elif key.startswith("st_"):
330 elif key.startswith("st_"):
336 # hack^Wfeature to allow mercurial to use "st_size" to
331 # hack^Wfeature to allow mercurial to use "st_size" to
337 # reference "size"
332 # reference "size"
338 key = key[3:]
333 key = key[3:]
339 try:
334 try:
340 return self._values[self._keys.index(key)]
335 return self._values[self._keys.index(key)]
341 except ValueError:
336 except ValueError:
342 raise KeyError("_BunserDict has no key %s" % key)
337 raise KeyError("_BunserDict has no key %s" % key)
343
338
344 def __len__(self):
339 def __len__(self):
345 return len(self._keys)
340 return len(self._keys)
346
341
347
342
348 class Bunser:
343 class Bunser:
349 def __init__(self, mutable=True, value_encoding=None, value_errors=None):
344 def __init__(self, mutable=True, value_encoding=None, value_errors=None):
350 self.mutable = mutable
345 self.mutable = mutable
351 self.value_encoding = value_encoding
346 self.value_encoding = value_encoding
352
347
353 if value_encoding is None:
348 if value_encoding is None:
354 self.value_errors = None
349 self.value_errors = None
355 elif value_errors is None:
350 elif value_errors is None:
356 self.value_errors = "strict"
351 self.value_errors = "strict"
357 else:
352 else:
358 self.value_errors = value_errors
353 self.value_errors = value_errors
359
354
360 @staticmethod
355 @staticmethod
361 def unser_int(buf, pos):
356 def unser_int(buf, pos):
362 try:
357 try:
363 int_type = _buf_pos(buf, pos)
358 int_type = _buf_pos(buf, pos)
364 except IndexError:
359 except IndexError:
365 raise ValueError("Invalid bser int encoding, pos out of range")
360 raise ValueError("Invalid bser int encoding, pos out of range")
366 if int_type == BSER_INT8:
361 if int_type == BSER_INT8:
367 needed = 2
362 needed = 2
368 fmt = b"=b"
363 fmt = b"=b"
369 elif int_type == BSER_INT16:
364 elif int_type == BSER_INT16:
370 needed = 3
365 needed = 3
371 fmt = b"=h"
366 fmt = b"=h"
372 elif int_type == BSER_INT32:
367 elif int_type == BSER_INT32:
373 needed = 5
368 needed = 5
374 fmt = b"=i"
369 fmt = b"=i"
375 elif int_type == BSER_INT64:
370 elif int_type == BSER_INT64:
376 needed = 9
371 needed = 9
377 fmt = b"=q"
372 fmt = b"=q"
378 else:
373 else:
379 raise ValueError(
374 raise ValueError(
380 "Invalid bser int encoding 0x%s at position %s"
375 "Invalid bser int encoding 0x%s at position %s"
381 % (binascii.hexlify(int_type).decode("ascii"), pos)
376 % (binascii.hexlify(int_type).decode("ascii"), pos)
382 )
377 )
383 int_val = struct.unpack_from(fmt, buf, pos + 1)[0]
378 int_val = struct.unpack_from(fmt, buf, pos + 1)[0]
384 return (int_val, pos + needed)
379 return (int_val, pos + needed)
385
380
386 def unser_utf8_string(self, buf, pos):
381 def unser_utf8_string(self, buf, pos):
387 str_len, pos = self.unser_int(buf, pos + 1)
382 str_len, pos = self.unser_int(buf, pos + 1)
388 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
383 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
389 return (str_val.decode("utf-8"), pos + str_len)
384 return (str_val.decode("utf-8"), pos + str_len)
390
385
391 def unser_bytestring(self, buf, pos):
386 def unser_bytestring(self, buf, pos):
392 str_len, pos = self.unser_int(buf, pos + 1)
387 str_len, pos = self.unser_int(buf, pos + 1)
393 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
388 str_val = struct.unpack_from(tobytes(str_len) + b"s", buf, pos)[0]
394 if self.value_encoding is not None:
389 if self.value_encoding is not None:
395 str_val = str_val.decode(self.value_encoding, self.value_errors)
390 str_val = str_val.decode(self.value_encoding, self.value_errors)
396 # str_len stays the same because that's the length in bytes
391 # str_len stays the same because that's the length in bytes
397 return (str_val, pos + str_len)
392 return (str_val, pos + str_len)
398
393
399 def unser_array(self, buf, pos):
394 def unser_array(self, buf, pos):
400 arr_len, pos = self.unser_int(buf, pos + 1)
395 arr_len, pos = self.unser_int(buf, pos + 1)
401 arr = []
396 arr = []
402 for _ in range(arr_len):
397 for _ in range(arr_len):
403 arr_item, pos = self.loads_recursive(buf, pos)
398 arr_item, pos = self.loads_recursive(buf, pos)
404 arr.append(arr_item)
399 arr.append(arr_item)
405
400
406 if not self.mutable:
401 if not self.mutable:
407 arr = tuple(arr)
402 arr = tuple(arr)
408
403
409 return arr, pos
404 return arr, pos
410
405
411 def unser_object(self, buf, pos):
406 def unser_object(self, buf, pos):
412 obj_len, pos = self.unser_int(buf, pos + 1)
407 obj_len, pos = self.unser_int(buf, pos + 1)
413 if self.mutable:
408 if self.mutable:
414 obj = {}
409 obj = {}
415 else:
410 else:
416 keys = []
411 keys = []
417 vals = []
412 vals = []
418
413
419 for _ in range(obj_len):
414 for _ in range(obj_len):
420 key, pos = self.unser_utf8_string(buf, pos)
415 key, pos = self.unser_utf8_string(buf, pos)
421 val, pos = self.loads_recursive(buf, pos)
416 val, pos = self.loads_recursive(buf, pos)
422 if self.mutable:
417 if self.mutable:
423 obj[key] = val
418 obj[key] = val
424 else:
419 else:
425 keys.append(key)
420 keys.append(key)
426 vals.append(val)
421 vals.append(val)
427
422
428 if not self.mutable:
423 if not self.mutable:
429 obj = _BunserDict(keys, vals)
424 obj = _BunserDict(keys, vals)
430
425
431 return obj, pos
426 return obj, pos
432
427
433 def unser_template(self, buf, pos):
428 def unser_template(self, buf, pos):
434 val_type = _buf_pos(buf, pos + 1)
429 val_type = _buf_pos(buf, pos + 1)
435 if val_type != BSER_ARRAY:
430 if val_type != BSER_ARRAY:
436 raise RuntimeError("Expect ARRAY to follow TEMPLATE")
431 raise RuntimeError("Expect ARRAY to follow TEMPLATE")
437 # force UTF-8 on keys
432 # force UTF-8 on keys
438 keys_bunser = Bunser(mutable=self.mutable, value_encoding="utf-8")
433 keys_bunser = Bunser(mutable=self.mutable, value_encoding="utf-8")
439 keys, pos = keys_bunser.unser_array(buf, pos + 1)
434 keys, pos = keys_bunser.unser_array(buf, pos + 1)
440 nitems, pos = self.unser_int(buf, pos)
435 nitems, pos = self.unser_int(buf, pos)
441 arr = []
436 arr = []
442 for _ in range(nitems):
437 for _ in range(nitems):
443 if self.mutable:
438 if self.mutable:
444 obj = {}
439 obj = {}
445 else:
440 else:
446 vals = []
441 vals = []
447
442
448 for keyidx in range(len(keys)):
443 for keyidx in range(len(keys)):
449 if _buf_pos(buf, pos) == BSER_SKIP:
444 if _buf_pos(buf, pos) == BSER_SKIP:
450 pos += 1
445 pos += 1
451 ele = None
446 ele = None
452 else:
447 else:
453 ele, pos = self.loads_recursive(buf, pos)
448 ele, pos = self.loads_recursive(buf, pos)
454
449
455 if self.mutable:
450 if self.mutable:
456 key = keys[keyidx]
451 key = keys[keyidx]
457 obj[key] = ele
452 obj[key] = ele
458 else:
453 else:
459 vals.append(ele)
454 vals.append(ele)
460
455
461 if not self.mutable:
456 if not self.mutable:
462 obj = _BunserDict(keys, vals)
457 obj = _BunserDict(keys, vals)
463
458
464 arr.append(obj)
459 arr.append(obj)
465 return arr, pos
460 return arr, pos
466
461
467 def loads_recursive(self, buf, pos):
462 def loads_recursive(self, buf, pos):
468 val_type = _buf_pos(buf, pos)
463 val_type = _buf_pos(buf, pos)
469 if (
464 if (
470 val_type == BSER_INT8
465 val_type == BSER_INT8
471 or val_type == BSER_INT16
466 or val_type == BSER_INT16
472 or val_type == BSER_INT32
467 or val_type == BSER_INT32
473 or val_type == BSER_INT64
468 or val_type == BSER_INT64
474 ):
469 ):
475 return self.unser_int(buf, pos)
470 return self.unser_int(buf, pos)
476 elif val_type == BSER_REAL:
471 elif val_type == BSER_REAL:
477 val = struct.unpack_from(b"=d", buf, pos + 1)[0]
472 val = struct.unpack_from(b"=d", buf, pos + 1)[0]
478 return (val, pos + 9)
473 return (val, pos + 9)
479 elif val_type == BSER_TRUE:
474 elif val_type == BSER_TRUE:
480 return (True, pos + 1)
475 return (True, pos + 1)
481 elif val_type == BSER_FALSE:
476 elif val_type == BSER_FALSE:
482 return (False, pos + 1)
477 return (False, pos + 1)
483 elif val_type == BSER_NULL:
478 elif val_type == BSER_NULL:
484 return (None, pos + 1)
479 return (None, pos + 1)
485 elif val_type == BSER_BYTESTRING:
480 elif val_type == BSER_BYTESTRING:
486 return self.unser_bytestring(buf, pos)
481 return self.unser_bytestring(buf, pos)
487 elif val_type == BSER_UTF8STRING:
482 elif val_type == BSER_UTF8STRING:
488 return self.unser_utf8_string(buf, pos)
483 return self.unser_utf8_string(buf, pos)
489 elif val_type == BSER_ARRAY:
484 elif val_type == BSER_ARRAY:
490 return self.unser_array(buf, pos)
485 return self.unser_array(buf, pos)
491 elif val_type == BSER_OBJECT:
486 elif val_type == BSER_OBJECT:
492 return self.unser_object(buf, pos)
487 return self.unser_object(buf, pos)
493 elif val_type == BSER_TEMPLATE:
488 elif val_type == BSER_TEMPLATE:
494 return self.unser_template(buf, pos)
489 return self.unser_template(buf, pos)
495 else:
490 else:
496 raise ValueError(
491 raise ValueError(
497 "unhandled bser opcode 0x%s"
492 "unhandled bser opcode 0x%s"
498 % binascii.hexlify(val_type).decode("ascii")
493 % binascii.hexlify(val_type).decode("ascii")
499 )
494 )
500
495
501
496
502 def _pdu_info_helper(buf):
497 def _pdu_info_helper(buf):
503 if buf[0:2] == EMPTY_HEADER[0:2]:
498 if buf[0:2] == EMPTY_HEADER[0:2]:
504 bser_version = 1
499 bser_version = 1
505 bser_capabilities = 0
500 bser_capabilities = 0
506 expected_len, pos2 = Bunser.unser_int(buf, 2)
501 expected_len, pos2 = Bunser.unser_int(buf, 2)
507 elif buf[0:2] == EMPTY_HEADER_V2[0:2]:
502 elif buf[0:2] == EMPTY_HEADER_V2[0:2]:
508 if len(buf) < 8:
503 if len(buf) < 8:
509 raise ValueError("Invalid BSER header")
504 raise ValueError("Invalid BSER header")
510 bser_version = 2
505 bser_version = 2
511 bser_capabilities = struct.unpack_from("I", buf, 2)[0]
506 bser_capabilities = struct.unpack_from("I", buf, 2)[0]
512 expected_len, pos2 = Bunser.unser_int(buf, 6)
507 expected_len, pos2 = Bunser.unser_int(buf, 6)
513 else:
508 else:
514 raise ValueError("Invalid BSER header")
509 raise ValueError("Invalid BSER header")
515
510
516 return bser_version, bser_capabilities, expected_len, pos2
511 return bser_version, bser_capabilities, expected_len, pos2
517
512
518
513
519 def pdu_info(buf):
514 def pdu_info(buf):
520 info = _pdu_info_helper(buf)
515 info = _pdu_info_helper(buf)
521 return info[0], info[1], info[2] + info[3]
516 return info[0], info[1], info[2] + info[3]
522
517
523
518
524 def pdu_len(buf):
519 def pdu_len(buf):
525 info = _pdu_info_helper(buf)
520 info = _pdu_info_helper(buf)
526 return info[2] + info[3]
521 return info[2] + info[3]
527
522
528
523
529 def loads(buf, mutable=True, value_encoding=None, value_errors=None):
524 def loads(buf, mutable=True, value_encoding=None, value_errors=None):
530 """Deserialize a BSER-encoded blob.
525 """Deserialize a BSER-encoded blob.
531
526
532 @param buf: The buffer to deserialize.
527 @param buf: The buffer to deserialize.
533 @type buf: bytes
528 @type buf: bytes
534
529
535 @param mutable: Whether to return mutable results.
530 @param mutable: Whether to return mutable results.
536 @type mutable: bool
531 @type mutable: bool
537
532
538 @param value_encoding: Optional codec to use to decode values. If
533 @param value_encoding: Optional codec to use to decode values. If
539 unspecified or None, return values as bytestrings.
534 unspecified or None, return values as bytestrings.
540 @type value_encoding: str
535 @type value_encoding: str
541
536
542 @param value_errors: Optional error handler for codec. 'strict' by default.
537 @param value_errors: Optional error handler for codec. 'strict' by default.
543 The other most common argument is 'surrogateescape' on
538 The other most common argument is 'surrogateescape' on
544 Python 3. If value_encoding is None, this is ignored.
539 Python 3. If value_encoding is None, this is ignored.
545 @type value_errors: str
540 @type value_errors: str
546 """
541 """
547
542
548 info = _pdu_info_helper(buf)
543 info = _pdu_info_helper(buf)
549 expected_len = info[2]
544 expected_len = info[2]
550 pos = info[3]
545 pos = info[3]
551
546
552 if len(buf) != expected_len + pos:
547 if len(buf) != expected_len + pos:
553 raise ValueError(
548 raise ValueError(
554 "bser data len %d != header len %d" % (expected_len + pos, len(buf))
549 "bser data len %d != header len %d" % (expected_len + pos, len(buf))
555 )
550 )
556
551
557 bunser = Bunser(
552 bunser = Bunser(
558 mutable=mutable,
553 mutable=mutable,
559 value_encoding=value_encoding,
554 value_encoding=value_encoding,
560 value_errors=value_errors,
555 value_errors=value_errors,
561 )
556 )
562
557
563 return bunser.loads_recursive(buf, pos)[0]
558 return bunser.loads_recursive(buf, pos)[0]
564
559
565
560
566 def load(fp, mutable=True, value_encoding=None, value_errors=None):
561 def load(fp, mutable=True, value_encoding=None, value_errors=None):
567 from . import load
562 from . import load
568
563
569 return load.load(fp, mutable, value_encoding, value_errors)
564 return load.load(fp, mutable, value_encoding, value_errors)
General Comments 0
You need to be logged in to leave comments. Login now