Skip to content

Commit

Permalink
FitVersion support to handle issue dtcooper#56
Browse files Browse the repository at this point in the history
  • Loading branch information
fundthmcalculus committed Nov 1, 2021
1 parent 3225b94 commit fc8bee8
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 2 deletions.
64 changes: 62 additions & 2 deletions fitparse/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import io
import logging
import os
import struct
import warnings
Expand Down Expand Up @@ -217,8 +218,8 @@ def _parse_file_header(self):
header_size, protocol_ver_enc, profile_ver_enc, data_size = self._read_struct('2BHI4x', data=header_data)

# Decode the same way the SDK does
self.protocol_version = float("%d.%d" % (protocol_ver_enc >> 4, protocol_ver_enc & ((1 << 4) - 1)))
self.profile_version = float("%d.%d" % (profile_ver_enc / 100, profile_ver_enc % 100))
self.protocol_version = FitVersion("%d.%d" % (protocol_ver_enc >> 4, protocol_ver_enc & ((1 << 4) - 1)))
self.profile_version = FitVersion("%d.%d" % (profile_ver_enc / 100, profile_ver_enc % 100))

# Consume extra header information
extra_header_size = header_size - 12
Expand Down Expand Up @@ -626,6 +627,65 @@ class FitFile(CacheMixin, UncachedFitFile):
pass


class FitVersion():
def __init__(self, version=None):
self._major = 0
self._minor = 0
if isinstance(version, float):
# Legacy match
logging.warning("Legacy matching with float versions, provide a string or FitVersion object for precision")
# Cast to a string and fall through
version = str(version)
if isinstance(version, str):
version_fields = version.split('.')
self._major = int(version_fields[0])
self._minor = int(version_fields[1])
else:
raise ValueError(f"Unknown quantity {version} cannot be parsed as a version string/float.")

@property
def major(self):
return self._major

@property
def minor(self):
return self._minor

def __str__(self):
return f"{self.major}.{self.minor}"

def __eq__(self, other):
if isinstance(other, FitVersion):
return self.major == other.major and self.minor == other.minor
else:
return self == FitVersion(other)

def __gt__(self, other):
if isinstance(other, FitVersion):
return self.major > other.major or self.major == other.major and self.minor > other.minor
else:
return self > FitVersion(other)

def __lt__(self, other):
if isinstance(other, FitVersion):
return self.major < other.major or self.major == other.major and self.minor < other.minor
else:
return self > FitVersion(other)

def __ge__(self, other):
if isinstance(other, FitVersion):
return self.major > other.major or self.major == other.major and self.minor >= other.minor
else:
return self > FitVersion(other)

def __le__(self, other):
if isinstance(other, FitVersion):
return self.major < other.major or self.major == other.major and self.minor <= other.minor
else:
return self > FitVersion(other)




# TODO: Create subclasses like Activity and do per-value monkey patching
# for example local_timestamp to adjust timestamp on a per-file basis
45 changes: 45 additions & 0 deletions tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import warnings

from fitparse import FitFile
from fitparse.base import FitVersion
from fitparse.processors import UTC_REFERENCE, StandardUnitsDataProcessor
from fitparse.records import BASE_TYPES, Crc
from fitparse.utils import FitEOFError, FitCRCError, FitHeaderError, FitParseError
Expand Down Expand Up @@ -77,6 +78,50 @@ def testfile(filename):
return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'files', filename)


class FitVersionTestCase(unittest.TestCase):
def test_version_parse(self):
v10 = FitVersion("1.0")
v11 = FitVersion("1.1")
v12 = FitVersion(1.2)

self.assertEqual(v10, "1.0")
self.assertEqual(v11, "1.1")
self.assertEqual(v12, "1.2")

def test_version_parse_errors(self):
with self.assertRaises(ValueError):
FitVersion(1)
with self.assertRaises(ValueError):
FitVersion([1, 2])

def test_version_equality(self):
v10 = FitVersion("1.0")
v10_ = FitVersion("1.0")
v11 = FitVersion("1.1")

self.assertEqual(v10, v10_)
self.assertEqual(v10_, v10)
self.assertNotEqual(v10, v11)

self.assertGreaterEqual(v10, v10_)
self.assertLessEqual(v10, v10_)

def test_version_inequality(self):
v10 = FitVersion("1.0")
v11 = FitVersion("1.1")
v20 = FitVersion("2.0")

self.assertGreater(v11, v10)
self.assertGreater(v20, v11)
self.assertGreaterEqual(v11, v10)
self.assertGreaterEqual(v20, v11)

self.assertLess(v10, v11)
self.assertLess(v11, v20)
self.assertLessEqual(v10, v11)
self.assertLessEqual(v11, v20)


class FitFileTestCase(unittest.TestCase):
def test_basic_file_with_one_record(self, endian='<'):
f = FitFile(generate_fitfile(endian=endian))
Expand Down

0 comments on commit fc8bee8

Please sign in to comment.