Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update #1

Merged
merged 10 commits into from
Sep 13, 2020
Merged
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MIT License

Copyright (c) 2011-2019, David Cooper <david@dtcooper.com>
Copyright (c) 2017-2019, Carey Metcalfe <carey@cmetcalfe.ca>
Copyright (c) 2011-2020, David Cooper <david@dtcooper.com>
Copyright (c) 2017-2020, Carey Metcalfe <carey@cmetcalfe.ca>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,58 @@ FIT files
by [ANT](http://www.thisisant.com/).
- The SDK, code examples, and detailed documentation can be found in the
[ANT FIT SDK](http://www.thisisant.com/resources/fit).



Usage
-----
A simple example of printing records from a fit file:

```python
import fitparse

# Load the FIT file
fitfile = fitparse.FitFile("my_activity.fit")

# Iterate over all messages of type "record"
# (other types include "device_info", "file_creator", "event", etc)
for record in fitfile.get_messages("record"):

# Records can contain multiple pieces of data (ex: timestamp, latitude, longitude, etc)
for data in record:

# Print the name and value of the data (and the units if it has any)
if data.units:
print(" * {}: {} ({})".format(data.name, data.value, data.units))
else:
print(" * {}: {}".format(data.name, data.value))

print("---")
```

The library also provides a `fitdump` script for command line usage:
```
$ fitdump --help
usage: fitdump [-h] [-v] [-o OUTPUT] [-t {readable,json}] [-n NAME] [--ignore-crc] FITFILE

Dump .FIT files to various formats

positional arguments:
FITFILE Input .FIT file (Use - for stdin)

optional arguments:
-h, --help show this help message and exit
-v, --verbose
-o OUTPUT, --output OUTPUT
File to output data into (defaults to stdout)
-t {readable,json}, --type {readable,json}
File type to output. (DEFAULT: readable)
-n NAME, --name NAME Message name (or number) to filter
--ignore-crc Some devices can write invalid crc's, ignore these.
```

See the documentation for more: http://dtcooper.github.com/python-fitparse


Major Changes From Original Version
-----------------------------------

Expand Down
2 changes: 1 addition & 1 deletion fitparse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from fitparse.processors import FitFileDataProcessor, StandardUnitsDataProcessor


__version__ = '1.1.0'
__version__ = '1.2.0'
__all__ = [
'FitFileDataProcessor', 'FitFile', 'FitParseError',
'StandardUnitsDataProcessor', 'DataMessage'
Expand Down
10 changes: 8 additions & 2 deletions fitparse/processors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import datetime
from fitparse.utils import scrub_method_name
from fitparse.utils import scrub_method_name, is_iterable

# Datetimes (uint32) represent seconds since this UTC_REFERENCE
UTC_REFERENCE = 631065600 # timestamp for UTC 00:00 Dec 31 1989
Expand Down Expand Up @@ -107,7 +107,13 @@ def process_field_distance(self, field_data):

def process_field_speed(self, field_data):
if field_data.value is not None:
field_data.value *= 60.0 * 60.0 / 1000.0
factor = 60.0 * 60.0 / 1000.0

# record.enhanced_speed field can be a tuple
if is_iterable(field_data.value):
field_data.value = tuple(x * factor for x in field_data.value)
else:
field_data.value *= factor
field_data.units = 'km/h'

def process_units_semicircles(self, field_data):
Expand Down
28 changes: 14 additions & 14 deletions fitparse/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ def get(self, field_name, as_dict=False):
if field_data.is_named(field_name):
return field_data.as_dict() if as_dict else field_data

def get_raw_value(self, field_name):
field_data = self.get(field_name)
if field_data:
return field_data.raw_value
return None

def get_value(self, field_name):
# SIMPLIFY: get rid of this completely
field_data = self.get(field_name)
Expand Down Expand Up @@ -433,11 +439,8 @@ def parse_string(string):

def add_dev_data_id(message):
global DEV_TYPES
dev_data_index = message.get('developer_data_index').raw_value
if message.get('application_id'):
application_id = message.get('application_id').raw_value
else:
application_id = None
dev_data_index = message.get_raw_value('developer_data_index')
application_id = message.get_raw_value('application_id')

# Note that nothing in the spec says overwriting an existing type is invalid
DEV_TYPES[dev_data_index] = {'dev_data_index': dev_data_index, 'application_id': application_id, 'fields': {}}
Expand All @@ -446,15 +449,12 @@ def add_dev_data_id(message):
def add_dev_field_description(message):
global DEV_TYPES

dev_data_index = message.get('developer_data_index').raw_value
field_def_num = message.get('field_definition_number').raw_value
base_type_id = message.get('fit_base_type_id').raw_value
field_name = message.get('field_name').raw_value
units = message.get('units').raw_value

native_field_num = message.get('native_field_num')
if native_field_num is not None:
native_field_num = native_field_num.raw_value
dev_data_index = message.get_raw_value('developer_data_index')
field_def_num = message.get_raw_value('field_definition_number')
base_type_id = message.get_raw_value('fit_base_type_id')
field_name = message.get_raw_value('field_name') or "unnamed_dev_field_%s" % field_def_num
units = message.get_raw_value("units")
native_field_num = message.get_raw_value('native_field_num')

if dev_data_index not in DEV_TYPES:
raise FitParseError("No such dev_data_index=%s found" % (dev_data_index))
Expand Down
5 changes: 4 additions & 1 deletion fitparse/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import io
import re
from collections import Iterable
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable


class FitParseError(ValueError):
Expand Down
19 changes: 12 additions & 7 deletions scripts/fitdump
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class RecordJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, types.GeneratorType):
return list(obj)
if isinstance(obj, datetime.datetime):
if isinstance(obj, (datetime.datetime, datetime.time)):
return obj.isoformat()
if isinstance(obj, fitparse.DataMessage):
return {
Expand All @@ -107,12 +107,17 @@ def main(args=None):
as_dict=options.as_dict
)

if options.type == "json":
json.dump(records, fp=options.output, cls=RecordJSONEncoder)
elif options.type == "readable":
options.output.writelines(format_message(n, record, options)
for n, record in enumerate(records, 1))

try:
if options.type == "json":
json.dump(records, fp=options.output, cls=RecordJSONEncoder)
elif options.type == "readable":
options.output.writelines(format_message(n, record, options)
for n, record in enumerate(records, 1))
finally:
try:
options.output.close()
except IOError:
pass

if __name__ == '__main__':
try:
Expand Down