1
1
#!/usr/bin/env python
2
+ from __future__ import print_function
2
3
3
4
import argparse
5
+ import codecs
6
+ import datetime
7
+ import json
4
8
import sys
9
+ import types
5
10
6
11
# Python 2 compat
7
12
try :
@@ -13,20 +18,21 @@ except NameError:
13
18
import fitparse
14
19
15
20
16
- def format_message (message , options ):
17
- s = message .name
21
+ def format_message (num , message , options ):
22
+ s = [ "{}. {}" . format ( num , message .name )]
18
23
if options .with_defs :
19
- s += ' [%s]' % message .type
20
- s += '\n '
24
+ s . append ( ' [{}]' . format ( message .type ))
25
+ s . append ( '\n ' )
21
26
22
27
if message .type == 'data' :
23
28
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 ) )
25
30
if field_data .units :
26
- s += ' [%s]' % field_data .units
27
- s += '\n '
31
+ s . append ( ' [{}]' . format ( field_data .units ))
32
+ s . append ( '\n ' )
28
33
29
- return s
34
+ s .append ('\n ' )
35
+ return "" .join (s )
30
36
31
37
32
38
def parse_args (args = None ):
@@ -36,11 +42,12 @@ def parse_args(args=None):
36
42
)
37
43
parser .add_argument ('-v' , '--verbose' , action = 'count' , default = 0 )
38
44
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) ' ,
41
47
)
42
48
parser .add_argument (
43
- '-t' , '--type' , choices = ('csv' , 'excel' , 'readable' ), default = 'readable' ,
49
+ # TODO: csv
50
+ '-t' , '--type' , choices = ('readable' , 'json' ), default = 'readable' ,
44
51
help = 'File type to output. (DEFAULT: %(default)s)' ,
45
52
)
46
53
parser .add_argument (
@@ -56,20 +63,36 @@ def parse_args(args=None):
56
63
57
64
options = parser .parse_args (args )
58
65
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' )
61
71
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 )
69
75
70
76
return options
71
77
72
78
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
+
73
96
def main (args = None ):
74
97
options = parse_args (args )
75
98
@@ -78,14 +101,18 @@ def main(args=None):
78
101
data_processor = fitparse .StandardUnitsDataProcessor (),
79
102
check_crc = not (options .ignore_crc ),
80
103
)
81
- messages = fitfile .get_messages (
104
+ records = fitfile .get_messages (
82
105
name = options .name ,
83
106
with_definitions = options .with_defs ,
107
+ as_dict = options .as_dict
84
108
)
85
109
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
+
89
116
90
117
if __name__ == '__main__' :
91
118
try :
0 commit comments