Skip to content

Commit 490e885

Browse files
pR0PsDavid Cooper
authored and
David Cooper
committedMar 4, 2018
Add JSON output option to fitdump script (#45)
Other minor things: - Removed non-implemented output formats - Removed the restrction on dumping non-readable formats to stdout - Allow Python to buffer the output for faster execution Fixes #41
1 parent 03e2961 commit 490e885

File tree

2 files changed

+53
-25
lines changed

2 files changed

+53
-25
lines changed
 

‎fitparse/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from fitparse.base import FitFile, FitParseError
2+
from fitparse.records import DataMessage
23
from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor
34

45

56
__version__ = '1.0.1'
67
__all__ = [
78
'FitFileDataProcessor', 'FitFile', 'FitParseError',
8-
'StandardUnitsDataProcessor',
9+
'StandardUnitsDataProcessor', 'DataMessage'
910
]

‎scripts/fitdump

+51-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
#!/usr/bin/env python
2+
from __future__ import print_function
23

34
import argparse
5+
import codecs
6+
import datetime
7+
import json
48
import sys
9+
import types
510

611
# Python 2 compat
712
try:
@@ -13,20 +18,21 @@ except NameError:
1318
import fitparse
1419

1520

16-
def format_message(message, options):
17-
s = message.name
21+
def format_message(num, message, options):
22+
s = ["{}. {}".format(num, message.name)]
1823
if options.with_defs:
19-
s += ' [%s]' % message.type
20-
s += '\n'
24+
s.append(' [{}]'.format(message.type))
25+
s.append('\n')
2126

2227
if message.type == 'data':
2328
for field_data in message:
24-
s += ' * %s: %s' % (field_data.name, field_data.value)
29+
s.append(' * {}: {}'.format(field_data.name, field_data.value))
2530
if field_data.units:
26-
s += ' [%s]' % field_data.units
27-
s += '\n'
31+
s.append(' [{}]'.format(field_data.units))
32+
s.append('\n')
2833

29-
return s
34+
s.append('\n')
35+
return "".join(s)
3036

3137

3238
def parse_args(args=None):
@@ -36,11 +42,12 @@ def parse_args(args=None):
3642
)
3743
parser.add_argument('-v', '--verbose', action='count', default=0)
3844
parser.add_argument(
39-
'-o', '--output', type=argparse.FileType(mode='wb'),
40-
help='File to output to.',
45+
'-o', '--output', type=argparse.FileType(mode='w'), default="-",
46+
help='File to output data into (defaults to stdout)',
4147
)
4248
parser.add_argument(
43-
'-t', '--type', choices=('csv', 'excel', 'readable'), default='readable',
49+
# TODO: csv
50+
'-t', '--type', choices=('readable', 'json'), default='readable',
4451
help='File type to output. (DEFAULT: %(default)s)',
4552
)
4653
parser.add_argument(
@@ -56,20 +63,36 @@ def parse_args(args=None):
5663

5764
options = parser.parse_args(args)
5865

59-
if (options.type != 'readable') and not options.output:
60-
parser.error('Please specify an output file (-o) or set --type readable')
66+
# Work around argparse.FileType not accepting an `encoding` kwarg in
67+
# Python < 3.4 by closing and reopening the file (unless it's stdout)
68+
if options.output is not sys.stdout:
69+
options.output.close()
70+
options.output = codecs.open(options.output.name, 'w', encoding='UTF-8')
6171

62-
options.with_defs = (options.verbose >= 1)
63-
options.print_messages = (options.type == 'readable')
64-
options.print_stream = (options.output or sys.stdout)
65-
66-
if not options.print_messages and (options.verbose >= 1):
67-
options.print_messages = True
68-
options.print_stream = sys.stdout
72+
options.verbose = options.verbose >= 1
73+
options.with_defs = (options.type == "readable" and options.verbose)
74+
options.as_dict = (options.type != "readable" and options.verbose)
6975

7076
return options
7177

7278

79+
class RecordJSONEncoder(json.JSONEncoder):
80+
def default(self, obj):
81+
if isinstance(obj, types.GeneratorType):
82+
return list(obj)
83+
if isinstance(obj, datetime.datetime):
84+
return obj.isoformat()
85+
if isinstance(obj, fitparse.DataMessage):
86+
return {
87+
"type": obj.name,
88+
"data": {
89+
data.name: data.value for data in obj
90+
}
91+
}
92+
# Fall back to original to raise a TypeError
93+
return super(RecordJSONEncoder, self).default(obj)
94+
95+
7396
def main(args=None):
7497
options = parse_args(args)
7598

@@ -78,14 +101,18 @@ def main(args=None):
78101
data_processor=fitparse.StandardUnitsDataProcessor(),
79102
check_crc = not(options.ignore_crc),
80103
)
81-
messages = fitfile.get_messages(
104+
records = fitfile.get_messages(
82105
name=options.name,
83106
with_definitions=options.with_defs,
107+
as_dict=options.as_dict
84108
)
85109

86-
for n, message in enumerate(messages, 1):
87-
if options.print_messages:
88-
print('{}. {}'.format(n, format_message(message, options), file=options.print_stream))
110+
if options.type == "json":
111+
json.dump(records, fp=options.output, cls=RecordJSONEncoder)
112+
elif options.type == "readable":
113+
options.output.writelines(format_message(n, record, options)
114+
for n, record in enumerate(records, 1))
115+
89116

90117
if __name__ == '__main__':
91118
try:

0 commit comments

Comments
 (0)
Please sign in to comment.