Skip to content

Commit 9d8740d

Browse files
committed
Remove RecordBase to speedup processing
Fix #55
1 parent 490e885 commit 9d8740d

File tree

1 file changed

+120
-35
lines changed

1 file changed

+120
-35
lines changed

fitparse/records.py

+120-35
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,18 @@
1414

1515
from fitparse.utils import FitParseError
1616

17-
1817
DEV_TYPES = {}
1918

2019

21-
class RecordBase(object):
22-
# namedtuple-like base class. Subclasses should must __slots__
23-
__slots__ = ()
24-
25-
# TODO: switch back to namedtuple, and don't use default arguments as None
26-
# and see if that gives us any performance improvements
27-
28-
def __init__(self, *args, **kwargs):
29-
for slot_name, value in zip_longest(self.__slots__, args, fillvalue=None):
30-
setattr(self, slot_name, value)
31-
for slot_name, value in kwargs.items():
32-
setattr(self, slot_name, value)
33-
34-
35-
class MessageHeader(RecordBase):
20+
class MessageHeader(object):
3621
__slots__ = ('is_definition', 'is_developer_data', 'local_mesg_num', 'time_offset')
3722

23+
def __init__(self, is_definition, is_developer_data, local_mesg_num, time_offset):
24+
self.is_definition = is_definition
25+
self.is_developer_data = is_developer_data
26+
self.local_mesg_num = local_mesg_num
27+
self.time_offset = time_offset
28+
3829
def __repr__(self):
3930
return '<MessageHeader: %s%s -- local mesg: #%d%s>' % (
4031
'definition' if self.is_definition else 'data',
@@ -44,10 +35,18 @@ def __repr__(self):
4435
)
4536

4637

47-
class DefinitionMessage(RecordBase):
38+
class DefinitionMessage(object):
4839
__slots__ = ('header', 'endian', 'mesg_type', 'mesg_num', 'field_defs', 'dev_field_defs')
4940
type = 'definition'
5041

42+
def __init__(self, header, endian, mesg_type, mesg_num, field_defs, dev_field_defs):
43+
self.header = header
44+
self.endian = endian
45+
self.mesg_type = mesg_type
46+
self.mesg_num = mesg_num
47+
self.field_defs = field_defs
48+
self.dev_field_defs = dev_field_defs
49+
5150
@property
5251
def name(self):
5352
return self.mesg_type.name if self.mesg_type else 'unknown_%d' % self.mesg_num
@@ -62,9 +61,15 @@ def __repr__(self):
6261
)
6362

6463

65-
class FieldDefinition(RecordBase):
64+
class FieldDefinition(object):
6665
__slots__ = ('field', 'def_num', 'base_type', 'size')
6766

67+
def __init__(self, field, def_num, base_type, size):
68+
self.field = field
69+
self.def_num = def_num
70+
self.base_type = base_type
71+
self.size = size
72+
6873
@property
6974
def name(self):
7075
return self.field.name if self.field else 'unknown_%d' % self.def_num
@@ -82,11 +87,14 @@ def __repr__(self):
8287
)
8388

8489

85-
class DevFieldDefinition(RecordBase):
90+
class DevFieldDefinition(object):
8691
__slots__ = ('field', 'dev_data_index', 'base_type', 'def_num', 'size')
8792

88-
def __init__(self, **kwargs):
89-
super(DevFieldDefinition, self).__init__(**kwargs)
93+
def __init__(self, field, dev_data_index, def_num, size):
94+
self.field = field
95+
self.def_num = def_num
96+
self.dev_data_index = dev_data_index
97+
self.size = size
9098
# For dev fields, the base_type and type are always the same.
9199
self.base_type = self.type
92100

@@ -108,10 +116,15 @@ def __repr__(self):
108116
)
109117

110118

111-
class DataMessage(RecordBase):
119+
class DataMessage(object):
112120
__slots__ = ('header', 'def_mesg', 'fields')
113121
type = 'data'
114122

123+
def __init__(self, header, def_mesg, fields):
124+
self.header = header
125+
self.def_mesg = def_mesg
126+
self.fields = fields
127+
115128
def get(self, field_name, as_dict=False):
116129
# SIMPLIFY: get rid of as_dict
117130
for field_data in self.fields:
@@ -164,11 +177,16 @@ def __str__(self):
164177
return '%s (#%d)' % (self.name, self.mesg_num)
165178

166179

167-
class FieldData(RecordBase):
180+
class FieldData(object):
168181
__slots__ = ('field_def', 'field', 'parent_field', 'value', 'raw_value', 'units')
169182

170-
def __init__(self, *args, **kwargs):
171-
super(FieldData, self).__init__(self, *args, **kwargs)
183+
def __init__(self, field_def, field, parent_field, value, raw_value, units=None):
184+
self.field_def = field_def
185+
self.field = field
186+
self.parent_field = parent_field
187+
self.value = value
188+
self.raw_value = raw_value
189+
self.units = units
172190
if not self.units and self.field:
173191
# Default to units on field, otherwise None.
174192
# NOTE:Not a property since you may want to override this in a data processor
@@ -235,10 +253,16 @@ def __str__(self):
235253
)
236254

237255

238-
class BaseType(RecordBase):
256+
class BaseType(object):
239257
__slots__ = ('name', 'identifier', 'fmt', 'parse')
240258
values = None # In case we're treated as a FieldType
241259

260+
def __init__(self, name, identifier, fmt, parse):
261+
self.name = name
262+
self.identifier = identifier
263+
self.fmt = fmt
264+
self.parse = parse
265+
242266
@property
243267
def size(self):
244268
return struct.calcsize(self.fmt)
@@ -253,21 +277,31 @@ def __repr__(self):
253277
)
254278

255279

256-
class FieldType(RecordBase):
280+
class FieldType(object):
257281
__slots__ = ('name', 'base_type', 'values')
258282

283+
def __init__(self, name, base_type, values=None):
284+
self.name = name
285+
self.base_type = base_type
286+
self.values = values
287+
259288
def __repr__(self):
260289
return '<FieldType: %s (%s)>' % (self.name, self.base_type)
261290

262291

263-
class MessageType(RecordBase):
292+
class MessageType():
264293
__slots__ = ('name', 'mesg_num', 'fields')
265294

295+
def __init__(self, name, mesg_num, fields):
296+
self.name = name
297+
self.mesg_num = mesg_num
298+
self.fields = fields
299+
266300
def __repr__(self):
267301
return '<MessageType: %s (#%d)>' % (self.name, self.mesg_num)
268302

269303

270-
class FieldAndSubFieldBase(RecordBase):
304+
class FieldAndSubFieldBase(object):
271305
__slots__ = ()
272306

273307
@property
@@ -288,27 +322,78 @@ class Field(FieldAndSubFieldBase):
288322
__slots__ = ('name', 'type', 'def_num', 'scale', 'offset', 'units', 'components', 'subfields')
289323
field_type = 'field'
290324

325+
def __init__(self, name, type, def_num, scale=None, offset=None, units=None, components=None, subfields=None):
326+
super(Field, self).__init__()
327+
self.name = name
328+
self.type = type
329+
self.def_num = def_num
330+
self.scale = scale
331+
self.offset = offset
332+
self.units = units
333+
self.components = components
334+
self.subfields = subfields
335+
291336

292337
class SubField(FieldAndSubFieldBase):
293338
__slots__ = ('name', 'def_num', 'type', 'scale', 'offset', 'units', 'components', 'ref_fields')
294339
field_type = 'subfield'
295340

341+
def __init__(self, name, def_num, type, scale=None, offset=None, units=None, components=None, ref_fields=None):
342+
super(SubField, self).__init__()
343+
self.name = name
344+
self.def_num = def_num
345+
self.type = type
346+
self.scale = scale
347+
self.offset = offset
348+
self.units = units
349+
self.components = components
350+
self.ref_fields = ref_fields
351+
296352

297353
class DevField(FieldAndSubFieldBase):
298-
__slots__ = ('dev_data_index', 'def_num', 'type', 'name', 'units', 'native_field_num',
354+
__slots__ = ('dev_data_index', 'name', 'def_num', 'type', 'units', 'native_field_num',
299355
# The rest of these are just to be compatible with Field objects. They're always None
300-
'scale', 'offset', 'components', 'subfields')
356+
'scale', 'offset', 'components', 'subfields')
301357
field_type = 'devfield'
302358

303-
304-
class ReferenceField(RecordBase):
359+
def __init__(self, dev_data_index, name, def_num, type, units, native_field_num):
360+
super(DevField, self).__init__()
361+
self.dev_data_index = dev_data_index
362+
self.name = name
363+
self.def_num = def_num
364+
self.type = type
365+
self.units = units
366+
self.native_field_num = native_field_num
367+
self.scale = None
368+
self.offset = None
369+
self.components = None
370+
self.subfields = None
371+
372+
373+
class ReferenceField(object):
305374
__slots__ = ('name', 'def_num', 'value', 'raw_value')
306375

376+
def __init__(self, name, def_num, value, raw_value):
377+
self.name = name
378+
self.def_num = def_num
379+
self.value = value
380+
self.raw_value = raw_value
381+
307382

308-
class ComponentField(RecordBase):
383+
class ComponentField(object):
309384
__slots__ = ('name', 'def_num', 'scale', 'offset', 'units', 'accumulate', 'bits', 'bit_offset')
310385
field_type = 'component'
311386

387+
def __init__(self, name, def_num, offset=None, scale=None, units=None, accumulate=None, bits=None, bit_offset=None):
388+
self.name = name
389+
self.def_num = def_num
390+
self.scale = scale
391+
self.units = units
392+
self.accumulate = accumulate
393+
self.bits = bits
394+
self.bit_offset = bit_offset
395+
self.offset = offset
396+
312397
def render(self, raw_value):
313398
if raw_value is None:
314399
return None
@@ -391,9 +476,9 @@ def add_dev_field_description(message):
391476

392477
# Note that nothing in the spec says overwriting an existing field is invalid
393478
fields[field_def_num] = DevField(dev_data_index=dev_data_index,
479+
name=field_name,
394480
def_num=field_def_num,
395481
type=BASE_TYPES[base_type_id],
396-
name=field_name,
397482
units=units,
398483
native_field_num=native_field_num)
399484

0 commit comments

Comments
 (0)