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

thrift.protocol.TProtocol   F

Complexity

Total Complexity 103

Size/Duplication

Total Lines 407
Duplicated Lines 89.68 %

Importance

Changes 0
Metric Value
wmc 103
eloc 302
dl 365
loc 407
rs 2
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.TProtocol 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 thrift.Thrift import *
21
22
23
class TProtocolException(TException):
24
  """Custom Protocol Exception class"""
25
26
  UNKNOWN = 0
27
  INVALID_DATA = 1
28
  NEGATIVE_SIZE = 2
29
  SIZE_LIMIT = 3
30
  BAD_VERSION = 4
31
32
  def __init__(self, type=UNKNOWN, message=None):
33
    TException.__init__(self, message)
34
    self.type = type
35
36
37
class TProtocolBase:
38
  """Base class for Thrift protocol driver."""
39
40
  def __init__(self, trans):
41
    self.trans = trans
42
43
  def writeMessageBegin(self, name, type, seqid):
44
    pass
45
46
  def writeMessageEnd(self):
47
    pass
48
49
  def writeStructBegin(self, name):
50
    pass
51
52
  def writeStructEnd(self):
53
    pass
54
55
  def writeFieldBegin(self, name, type, id):
56
    pass
57
58
  def writeFieldEnd(self):
59
    pass
60
61
  def writeFieldStop(self):
62
    pass
63
64
  def writeMapBegin(self, ktype, vtype, size):
65
    pass
66
67
  def writeMapEnd(self):
68
    pass
69
70
  def writeListBegin(self, etype, size):
71
    pass
72
73
  def writeListEnd(self):
74
    pass
75
76
  def writeSetBegin(self, etype, size):
77
    pass
78
79
  def writeSetEnd(self):
80
    pass
81
82
  def writeBool(self, bool):
83
    pass
84
85
  def writeByte(self, byte):
86
    pass
87
88
  def writeI16(self, i16):
89
    pass
90
91
  def writeI32(self, i32):
92
    pass
93
94
  def writeI64(self, i64):
95
    pass
96
97
  def writeDouble(self, dub):
98
    pass
99
100
  def writeString(self, str):
101
    pass
102
103
  def readMessageBegin(self):
104
    pass
105
106
  def readMessageEnd(self):
107
    pass
108
109
  def readStructBegin(self):
110
    pass
111
112
  def readStructEnd(self):
113
    pass
114
115
  def readFieldBegin(self):
116
    pass
117
118
  def readFieldEnd(self):
119
    pass
120
121
  def readMapBegin(self):
122
    pass
123
124
  def readMapEnd(self):
125
    pass
126
127
  def readListBegin(self):
128
    pass
129
130
  def readListEnd(self):
131
    pass
132
133
  def readSetBegin(self):
134
    pass
135
136
  def readSetEnd(self):
137
    pass
138
139
  def readBool(self):
140
    pass
141
142
  def readByte(self):
143
    pass
144
145
  def readI16(self):
146
    pass
147
148
  def readI32(self):
149
    pass
150
151
  def readI64(self):
152
    pass
153
154
  def readDouble(self):
155
    pass
156
157
  def readString(self):
158
    pass
159
160
  def skip(self, type):
161
    if type == TType.STOP:
162
      return
163
    elif type == TType.BOOL:
164
      self.readBool()
165
    elif type == TType.BYTE:
166
      self.readByte()
167
    elif type == TType.I16:
168
      self.readI16()
169
    elif type == TType.I32:
170
      self.readI32()
171
    elif type == TType.I64:
172
      self.readI64()
173
    elif type == TType.DOUBLE:
174
      self.readDouble()
175
    elif type == TType.STRING:
176
      self.readString()
177
    elif type == TType.STRUCT:
178
      name = self.readStructBegin()
179
      while True:
180
        (name, type, id) = self.readFieldBegin()
181
        if type == TType.STOP:
182
          break
183
        self.skip(type)
184
        self.readFieldEnd()
185
      self.readStructEnd()
186
    elif type == TType.MAP:
187
      (ktype, vtype, size) = self.readMapBegin()
188
      for i in range(size):
189
        self.skip(ktype)
190
        self.skip(vtype)
191
      self.readMapEnd()
192
    elif type == TType.SET:
193
      (etype, size) = self.readSetBegin()
194
      for i in range(size):
195
        self.skip(etype)
196
      self.readSetEnd()
197
    elif type == TType.LIST:
198
      (etype, size) = self.readListBegin()
199
      for i in range(size):
200
        self.skip(etype)
201
      self.readListEnd()
202
203
  # tuple of: ( 'reader method' name, is_container bool, 'writer_method' name )
204
  _TTYPE_HANDLERS = (
205
       (None, None, False),  # 0 TType.STOP
206
       (None, None, False),  # 1 TType.VOID # TODO: handle void?
207
       ('readBool', 'writeBool', False),  # 2 TType.BOOL
208
       ('readByte',  'writeByte', False),  # 3 TType.BYTE and I08
209
       ('readDouble', 'writeDouble', False),  # 4 TType.DOUBLE
210
       (None, None, False),  # 5 undefined
211
       ('readI16', 'writeI16', False),  # 6 TType.I16
212
       (None, None, False),  # 7 undefined
213
       ('readI32', 'writeI32', False),  # 8 TType.I32
214
       (None, None, False),  # 9 undefined
215
       ('readI64', 'writeI64', False),  # 10 TType.I64
216
       ('readString', 'writeString', False),  # 11 TType.STRING and UTF7
217
       ('readContainerStruct', 'writeContainerStruct', True),  # 12 *.STRUCT
218
       ('readContainerMap', 'writeContainerMap', True),  # 13 TType.MAP
219
       ('readContainerSet', 'writeContainerSet', True),  # 14 TType.SET
220
       ('readContainerList', 'writeContainerList', True),  # 15 TType.LIST
221
       (None, None, False),  # 16 TType.UTF8 # TODO: handle utf8 types?
222
       (None, None, False)  # 17 TType.UTF16 # TODO: handle utf16 types?
223
      )
224
225
  def readFieldByTType(self, ttype, spec):
226
    try:
227
      (r_handler, w_handler, is_container) = self._TTYPE_HANDLERS[ttype]
228
    except IndexError:
229
      raise TProtocolException(type=TProtocolException.INVALID_DATA,
230
                               message='Invalid field type %d' % (ttype))
231
    if r_handler is None:
232
      raise TProtocolException(type=TProtocolException.INVALID_DATA,
233
                               message='Invalid field type %d' % (ttype))
234
    reader = getattr(self, r_handler)
235
    if not is_container:
236
      return reader()
237
    return reader(spec)
238
239
  def readContainerList(self, spec):
240
    results = []
241
    ttype, tspec = spec[0], spec[1]
242
    r_handler = self._TTYPE_HANDLERS[ttype][0]
243
    reader = getattr(self, r_handler)
244
    (list_type, list_len) = self.readListBegin()
245
    if tspec is None:
246
      # list values are simple types
247
      for idx in range(list_len):
248
        results.append(reader())
249
    else:
250
      # this is like an inlined readFieldByTType
251
      container_reader = self._TTYPE_HANDLERS[list_type][0]
252
      val_reader = getattr(self, container_reader)
253
      for idx in range(list_len):
254
        val = val_reader(tspec)
255
        results.append(val)
256
    self.readListEnd()
257
    return results
258
259
  def readContainerSet(self, spec):
260
    results = set()
261
    ttype, tspec = spec[0], spec[1]
262
    r_handler = self._TTYPE_HANDLERS[ttype][0]
263
    reader = getattr(self, r_handler)
264
    (set_type, set_len) = self.readSetBegin()
265
    if tspec is None:
266
      # set members are simple types
267
      for idx in range(set_len):
268
        results.add(reader())
269
    else:
270
      container_reader = self._TTYPE_HANDLERS[set_type][0]
271
      val_reader = getattr(self, container_reader)
272
      for idx in range(set_len):
273
        results.add(val_reader(tspec))
274
    self.readSetEnd()
275
    return results
276
277
  def readContainerStruct(self, spec):
278
    (obj_class, obj_spec) = spec
279
    obj = obj_class()
280
    obj.read(self)
281
    return obj
282
283
  def readContainerMap(self, spec):
284
    results = dict()
285
    key_ttype, key_spec = spec[0], spec[1]
286
    val_ttype, val_spec = spec[2], spec[3]
287
    (map_ktype, map_vtype, map_len) = self.readMapBegin()
288
    # TODO: compare types we just decoded with thrift_spec and
289
    # abort/skip if types disagree
290
    key_reader = getattr(self, self._TTYPE_HANDLERS[key_ttype][0])
291
    val_reader = getattr(self, self._TTYPE_HANDLERS[val_ttype][0])
292
    # list values are simple types
293
    for idx in range(map_len):
294
      if key_spec is None:
295
        k_val = key_reader()
296
      else:
297
        k_val = self.readFieldByTType(key_ttype, key_spec)
298
      if val_spec is None:
299
        v_val = val_reader()
300
      else:
301
        v_val = self.readFieldByTType(val_ttype, val_spec)
302
      # this raises a TypeError with unhashable keys types
303
      # i.e. this fails: d=dict(); d[[0,1]] = 2
304
      results[k_val] = v_val
305
    self.readMapEnd()
306
    return results
307
308
  def readStruct(self, obj, thrift_spec):
309
    self.readStructBegin()
310
    while True:
311
      (fname, ftype, fid) = self.readFieldBegin()
312
      if ftype == TType.STOP:
313
        break
314
      try:
315
        field = thrift_spec[fid]
316
      except IndexError:
317
        self.skip(ftype)
318
      else:
319
        if field is not None and ftype == field[1]:
320
          fname = field[2]
321
          fspec = field[3]
322
          val = self.readFieldByTType(ftype, fspec)
323
          setattr(obj, fname, val)
324
        else:
325
          self.skip(ftype)
326
      self.readFieldEnd()
327
    self.readStructEnd()
328
329
  def writeContainerStruct(self, val, spec):
330
    val.write(self)
331
332
  def writeContainerList(self, val, spec):
333
    self.writeListBegin(spec[0], len(val))
334
    r_handler, w_handler, is_container = self._TTYPE_HANDLERS[spec[0]]
335
    e_writer = getattr(self, w_handler)
336
    if not is_container:
337
      for elem in val:
338
        e_writer(elem)
339
    else:
340
      for elem in val:
341
        e_writer(elem, spec[1])
342
    self.writeListEnd()
343
344
  def writeContainerSet(self, val, spec):
345
    self.writeSetBegin(spec[0], len(val))
346
    r_handler, w_handler, is_container = self._TTYPE_HANDLERS[spec[0]]
347
    e_writer = getattr(self, w_handler)
348
    if not is_container:
349
      for elem in val:
350
        e_writer(elem)
351
    else:
352
      for elem in val:
353
        e_writer(elem, spec[1])
354
    self.writeSetEnd()
355
356
  def writeContainerMap(self, val, spec):
357
    k_type = spec[0]
358
    v_type = spec[2]
359
    ignore, ktype_name, k_is_container = self._TTYPE_HANDLERS[k_type]
360
    ignore, vtype_name, v_is_container = self._TTYPE_HANDLERS[v_type]
361
    k_writer = getattr(self, ktype_name)
362
    v_writer = getattr(self, vtype_name)
363
    self.writeMapBegin(k_type, v_type, len(val))
364
    for m_key, m_val in val.items():
365
      if not k_is_container:
366
        k_writer(m_key)
367
      else:
368
        k_writer(m_key, spec[1])
369
      if not v_is_container:
370
        v_writer(m_val)
371
      else:
372
        v_writer(m_val, spec[3])
373
    self.writeMapEnd()
374
375
  def writeStruct(self, obj, thrift_spec):
376
    self.writeStructBegin(obj.__class__.__name__)
377
    for field in thrift_spec:
378
      if field is None:
379
        continue
380
      fname = field[2]
381
      val = getattr(obj, fname)
382
      if val is None:
383
        # skip writing out unset fields
384
        continue
385
      fid = field[0]
386
      ftype = field[1]
387
      fspec = field[3]
388
      # get the writer method for this value
389
      self.writeFieldBegin(fname, ftype, fid)
390
      self.writeFieldByTType(ftype, val, fspec)
391
      self.writeFieldEnd()
392
    self.writeFieldStop()
393
    self.writeStructEnd()
394
395
  def writeFieldByTType(self, ttype, val, spec):
396
    r_handler, w_handler, is_container = self._TTYPE_HANDLERS[ttype]
397
    writer = getattr(self, w_handler)
398
    if is_container:
399
      writer(val, spec)
400
    else:
401
      writer(val)
402
403
404
class TProtocolFactory:
405
  def getProtocol(self, trans):
406
    pass
407