Completed
Branch master (477316)
by Michael
08:56
created

thrift.protocol.TCompactProtocol   F

Complexity

Total Complexity 70

Size/Duplication

Total Lines 404
Duplicated Lines 74.26 %

Importance

Changes 0
Metric Value
wmc 70
eloc 309
dl 300
loc 404
rs 2.8
c 0
b 0
f 0

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like thrift.protocol.TCompactProtocol often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#
2
# Licensed to the Apache Software Foundation (ASF) under one
3
# or more contributor license agreements. See the NOTICE file
4
# distributed with this work for additional information
5
# regarding copyright ownership. The ASF licenses this file
6
# to you under the Apache License, Version 2.0 (the
7
# "License"); you may not use this file except in compliance
8
# with the License. You may obtain a copy of the License at
9
#
10
#   http://www.apache.org/licenses/LICENSE-2.0
11
#
12
# Unless required by applicable law or agreed to in writing,
13
# software distributed under the License is distributed on an
14
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
# KIND, either express or implied. See the License for the
16
# specific language governing permissions and limitations
17
# under the License.
18
#
19
20
from .TProtocol import *
21
from struct import pack, unpack
22
23
__all__ = ['TCompactProtocol', 'TCompactProtocolFactory']
24
25
CLEAR = 0
26
FIELD_WRITE = 1
27
VALUE_WRITE = 2
28
CONTAINER_WRITE = 3
29
BOOL_WRITE = 4
30
FIELD_READ = 5
31
CONTAINER_READ = 6
32
VALUE_READ = 7
33
BOOL_READ = 8
34
35
36
def make_helper(v_from, container):
37
  def helper(func):
38
    def nested(self, *args, **kwargs):
39
      assert self.state in (v_from, container), (self.state, v_from, container)
40
      return func(self, *args, **kwargs)
41
    return nested
42
  return helper
43
writer = make_helper(VALUE_WRITE, CONTAINER_WRITE)
44
reader = make_helper(VALUE_READ, CONTAINER_READ)
45
46
47
def makeZigZag(n, bits):
48
  return (n << 1) ^ (n >> (bits - 1))
49
50
51
def fromZigZag(n):
52
  return (n >> 1) ^ -(n & 1)
53
54
55
def writeVarint(trans, n):
56
  out = []
57
  while True:
58
    if n & ~0x7f == 0:
59
      out.append(n)
60
      break
61
    else:
62
      out.append((n & 0xff) | 0x80)
63
      n = n >> 7
64
  trans.write(''.join(map(chr, out)))
65
66
67
def readVarint(trans):
68
  result = 0
69
  shift = 0
70
  while True:
71
    x = trans.readAll(1)
72
    byte = ord(x)
73
    result |= (byte & 0x7f) << shift
74
    if byte >> 7 == 0:
75
      return result
76
    shift += 7
77
78
79
class CompactType:
80
  STOP = 0x00
81
  TRUE = 0x01
82
  FALSE = 0x02
83
  BYTE = 0x03
84
  I16 = 0x04
85
  I32 = 0x05
86
  I64 = 0x06
87
  DOUBLE = 0x07
88
  BINARY = 0x08
89
  LIST = 0x09
90
  SET = 0x0A
91
  MAP = 0x0B
92
  STRUCT = 0x0C
93
94
CTYPES = {TType.STOP: CompactType.STOP,
95
          TType.BOOL: CompactType.TRUE,  # used for collection
96
          TType.BYTE: CompactType.BYTE,
97
          TType.I16: CompactType.I16,
98
          TType.I32: CompactType.I32,
99
          TType.I64: CompactType.I64,
100
          TType.DOUBLE: CompactType.DOUBLE,
101
          TType.STRING: CompactType.BINARY,
102
          TType.STRUCT: CompactType.STRUCT,
103
          TType.LIST: CompactType.LIST,
104
          TType.SET: CompactType.SET,
105
          TType.MAP: CompactType.MAP
106
          }
107
108
TTYPES = {}
109
for k, v in list(CTYPES.items()):
110
  TTYPES[v] = k
111
TTYPES[CompactType.FALSE] = TType.BOOL
112
del k
113
del v
114
115
116
class TCompactProtocol(TProtocolBase):
117
  """Compact implementation of the Thrift protocol driver."""
118
119
  PROTOCOL_ID = 0x82
120
  VERSION = 1
121
  VERSION_MASK = 0x1f
122
  TYPE_MASK = 0xe0
123
  TYPE_SHIFT_AMOUNT = 5
124
125
  def __init__(self, trans):
126
    TProtocolBase.__init__(self, trans)
127
    self.state = CLEAR
128
    self.__last_fid = 0
129
    self.__bool_fid = None
130
    self.__bool_value = None
131
    self.__structs = []
132
    self.__containers = []
133
134
  def __writeVarint(self, n):
135
    writeVarint(self.trans, n)
136
137
  def writeMessageBegin(self, name, type, seqid):
138
    assert self.state == CLEAR
139
    self.__writeUByte(self.PROTOCOL_ID)
140
    self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT))
141
    self.__writeVarint(seqid)
142
    self.__writeString(name)
143
    self.state = VALUE_WRITE
144
145
  def writeMessageEnd(self):
146
    assert self.state == VALUE_WRITE
147
    self.state = CLEAR
148
149
  def writeStructBegin(self, name):
150
    assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state
151
    self.__structs.append((self.state, self.__last_fid))
152
    self.state = FIELD_WRITE
153
    self.__last_fid = 0
154
155
  def writeStructEnd(self):
156
    assert self.state == FIELD_WRITE
157
    self.state, self.__last_fid = self.__structs.pop()
158
159
  def writeFieldStop(self):
160
    self.__writeByte(0)
161
162
  def __writeFieldHeader(self, type, fid):
163
    delta = fid - self.__last_fid
164
    if 0 < delta <= 15:
165
      self.__writeUByte(delta << 4 | type)
166
    else:
167
      self.__writeByte(type)
168
      self.__writeI16(fid)
169
    self.__last_fid = fid
170
171
  def writeFieldBegin(self, name, type, fid):
172
    assert self.state == FIELD_WRITE, self.state
173
    if type == TType.BOOL:
174
      self.state = BOOL_WRITE
175
      self.__bool_fid = fid
176
    else:
177
      self.state = VALUE_WRITE
178
      self.__writeFieldHeader(CTYPES[type], fid)
179
180
  def writeFieldEnd(self):
181
    assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state
182
    self.state = FIELD_WRITE
183
184
  def __writeUByte(self, byte):
185
    self.trans.write(pack('!B', byte))
186
187
  def __writeByte(self, byte):
188
    self.trans.write(pack('!b', byte))
189
190
  def __writeI16(self, i16):
191
    self.__writeVarint(makeZigZag(i16, 16))
192
193
  def __writeSize(self, i32):
194
    self.__writeVarint(i32)
195
196
  def writeCollectionBegin(self, etype, size):
197
    assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
198
    if size <= 14:
199
      self.__writeUByte(size << 4 | CTYPES[etype])
200
    else:
201
      self.__writeUByte(0xf0 | CTYPES[etype])
202
      self.__writeSize(size)
203
    self.__containers.append(self.state)
204
    self.state = CONTAINER_WRITE
205
  writeSetBegin = writeCollectionBegin
206
  writeListBegin = writeCollectionBegin
207
208
  def writeMapBegin(self, ktype, vtype, size):
209
    assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
210
    if size == 0:
211
      self.__writeByte(0)
212
    else:
213
      self.__writeSize(size)
214
      self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype])
215
    self.__containers.append(self.state)
216
    self.state = CONTAINER_WRITE
217
218
  def writeCollectionEnd(self):
219
    assert self.state == CONTAINER_WRITE, self.state
220
    self.state = self.__containers.pop()
221
  writeMapEnd = writeCollectionEnd
222
  writeSetEnd = writeCollectionEnd
223
  writeListEnd = writeCollectionEnd
224
225
  def writeBool(self, bool):
226
    if self.state == BOOL_WRITE:
227
      if bool:
228
        ctype = CompactType.TRUE
229
      else:
230
        ctype = CompactType.FALSE
231
      self.__writeFieldHeader(ctype, self.__bool_fid)
232
    elif self.state == CONTAINER_WRITE:
233
      if bool:
234
        self.__writeByte(CompactType.TRUE)
235
      else:
236
        self.__writeByte(CompactType.FALSE)
237
    else:
238
      raise AssertionError("Invalid state in compact protocol")
239
240
  writeByte = writer(__writeByte)
241
  writeI16 = writer(__writeI16)
242
243
  @writer
244
  def writeI32(self, i32):
245
    self.__writeVarint(makeZigZag(i32, 32))
246
247
  @writer
248
  def writeI64(self, i64):
249
    self.__writeVarint(makeZigZag(i64, 64))
250
251
  @writer
252
  def writeDouble(self, dub):
253
    self.trans.write(pack('!d', dub))
254
255
  def __writeString(self, s):
256
    self.__writeSize(len(s))
257
    self.trans.write(s)
258
  writeString = writer(__writeString)
259
260
  def readFieldBegin(self):
261
    assert self.state == FIELD_READ, self.state
262
    type = self.__readUByte()
263
    if type & 0x0f == TType.STOP:
264
      return (None, 0, 0)
265
    delta = type >> 4
266
    if delta == 0:
267
      fid = self.__readI16()
268
    else:
269
      fid = self.__last_fid + delta
270
    self.__last_fid = fid
271
    type = type & 0x0f
272
    if type == CompactType.TRUE:
273
      self.state = BOOL_READ
274
      self.__bool_value = True
275
    elif type == CompactType.FALSE:
276
      self.state = BOOL_READ
277
      self.__bool_value = False
278
    else:
279
      self.state = VALUE_READ
280
    return (None, self.__getTType(type), fid)
281
282
  def readFieldEnd(self):
283
    assert self.state in (VALUE_READ, BOOL_READ), self.state
284
    self.state = FIELD_READ
285
286
  def __readUByte(self):
287
    result, = unpack('!B', self.trans.readAll(1))
288
    return result
289
290
  def __readByte(self):
291
    result, = unpack('!b', self.trans.readAll(1))
292
    return result
293
294
  def __readVarint(self):
295
    return readVarint(self.trans)
296
297
  def __readZigZag(self):
298
    return fromZigZag(self.__readVarint())
299
300
  def __readSize(self):
301
    result = self.__readVarint()
302
    if result < 0:
303
      raise TException("Length < 0")
304
    return result
305
306
  def readMessageBegin(self):
307
    assert self.state == CLEAR
308
    proto_id = self.__readUByte()
309
    if proto_id != self.PROTOCOL_ID:
310
      raise TProtocolException(TProtocolException.BAD_VERSION,
311
          'Bad protocol id in the message: %d' % proto_id)
312
    ver_type = self.__readUByte()
313
    type = (ver_type & self.TYPE_MASK) >> self.TYPE_SHIFT_AMOUNT
314
    version = ver_type & self.VERSION_MASK
315
    if version != self.VERSION:
316
      raise TProtocolException(TProtocolException.BAD_VERSION,
317
          'Bad version: %d (expect %d)' % (version, self.VERSION))
318
    seqid = self.__readVarint()
319
    name = self.__readString()
320
    return (name, type, seqid)
321
322
  def readMessageEnd(self):
323
    assert self.state == CLEAR
324
    assert len(self.__structs) == 0
325
326
  def readStructBegin(self):
327
    assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state
328
    self.__structs.append((self.state, self.__last_fid))
329
    self.state = FIELD_READ
330
    self.__last_fid = 0
331
332
  def readStructEnd(self):
333
    assert self.state == FIELD_READ
334
    self.state, self.__last_fid = self.__structs.pop()
335
336
  def readCollectionBegin(self):
337
    assert self.state in (VALUE_READ, CONTAINER_READ), self.state
338
    size_type = self.__readUByte()
339
    size = size_type >> 4
340
    type = self.__getTType(size_type)
341
    if size == 15:
342
      size = self.__readSize()
343
    self.__containers.append(self.state)
344
    self.state = CONTAINER_READ
345
    return type, size
346
  readSetBegin = readCollectionBegin
347
  readListBegin = readCollectionBegin
348
349
  def readMapBegin(self):
350
    assert self.state in (VALUE_READ, CONTAINER_READ), self.state
351
    size = self.__readSize()
352
    types = 0
353
    if size > 0:
354
      types = self.__readUByte()
355
    vtype = self.__getTType(types)
356
    ktype = self.__getTType(types >> 4)
357
    self.__containers.append(self.state)
358
    self.state = CONTAINER_READ
359
    return (ktype, vtype, size)
360
361
  def readCollectionEnd(self):
362
    assert self.state == CONTAINER_READ, self.state
363
    self.state = self.__containers.pop()
364
  readSetEnd = readCollectionEnd
365
  readListEnd = readCollectionEnd
366
  readMapEnd = readCollectionEnd
367
368
  def readBool(self):
369
    if self.state == BOOL_READ:
370
      return self.__bool_value == CompactType.TRUE
371
    elif self.state == CONTAINER_READ:
372
      return self.__readByte() == CompactType.TRUE
373
    else:
374
      raise AssertionError("Invalid state in compact protocol: %d" %
375
                           self.state)
376
377
  readByte = reader(__readByte)
378
  __readI16 = __readZigZag
379
  readI16 = reader(__readZigZag)
380
  readI32 = reader(__readZigZag)
381
  readI64 = reader(__readZigZag)
382
383
  @reader
384
  def readDouble(self):
385
    buff = self.trans.readAll(8)
386
    val, = unpack('!d', buff)
387
    return val
388
389
  def __readString(self):
390
    len = self.__readSize()
391
    return self.trans.readAll(len)
392
  readString = reader(__readString)
393
394
  def __getTType(self, byte):
395
    return TTYPES[byte & 0x0f]
396
397
398
class TCompactProtocolFactory:
399
  def __init__(self):
400
    pass
401
402
  def getProtocol(self, trans):
403
    return TCompactProtocol(trans)
404