ColCarroll / strava_calendar

Visualizations from Strava data in matplotlib
MIT License
83 stars 7 forks source link

FitParseError #7

Open sjwhitmore opened 4 months ago

sjwhitmore commented 4 months ago

got this FitParseError parsing my zip data -


  0%|                                                                                     | 0/1406 [00:00<?, ?it/s]
---------------------------------------------------------------------------
FitParseError                             Traceback (most recent call last)
Cell In[3], line 1
----> 1 plot_calendar(zip_path=path, year=2022)

File ~/projects/strava_calendar/strava_calendar/strava_calendar.py:55, in plot_calendar(zip_path, year, plot_size, n_cols, month_gap, col_gap, sport, label)
      9 def plot_calendar(
     10     *,
     11     zip_path,
   (...)
     18     label=None,
     19 ):
     20     """Plot a year of Strava data in a calendar layout.
     21
     22     Parameters
   (...)
     53         for further customization.
     54     """
---> 55     data = get_data(
     56         zip_path,
     57         sport,
     58         datetime.datetime(year, 1, 1),
     59         datetime.datetime(year + 1, 1, 1),
     60     )
     62     plotter = Plotter(data)
     64     fig, ax = plt.subplots(figsize=(plot_size * 5 * n_cols, plot_size * 40 / n_cols))

File ~/projects/strava_calendar/strava_calendar/data.py:191, in get_data(zip_path, sport, start_date, end_date)
    189 filters = [is_sport(sport), is_after(start_date), is_before(end_date)]
    190 data = {"activities": []}
--> 191 for strava_file in filter_files(zip_path, filters):
    192     try:
    193         data["activities"].append(strava_file.to_json())

File ~/projects/strava_calendar/strava_calendar/data.py:171, in filter_files(zip_path, filters)
    169 for data, fname in get_files(zip_path):
    170     if fname.endswith(".fit.gz"):
--> 171         strava_file = StravaFile(data)
    172     elif fname.endswith(".gpx") or fname.endswith(".gpx.gz"):
    173             strava_file = StravaGPXFile(data)

File ~/projects/strava_calendar/strava_calendar/data.py:70, in StravaFile.__init__(self, file)
     68 def __init__(self, file):
     69     super().__init__(file)
---> 70     self.session_data = self._get_session_data()

File ~/projects/strava_calendar/strava_calendar/data.py:73, in StravaFile._get_session_data(self)
     72 def _get_session_data(self):
---> 73     session_data = list(self.get_messages("session"))[:1]
     74     if len(session_data) != 1:
     75         print(f"expected only 1 session record per file, not {len(self.data.tracks)} tracks and {len(self.data.tracks[0].segments)} segments")

File ~/projects/virtualenvs/strava/lib/python3.9/site-packages/fitparse/base.py:434, in FitFile.get_messages(self, name, with_definitions, as_dict)
    432 # If there are unparsed messages, yield those too
    433 while not self._complete:
--> 434     message = self._parse_message()
    435     if message and should_yield(message):
    436         yield message.as_dict() if as_dict else message

File ~/projects/virtualenvs/strava/lib/python3.9/site-packages/fitparse/base.py:149, in FitFile._parse_message(self)
    146 header = self._parse_message_header()
    148 if header.is_definition:
--> 149     message = self._parse_definition_message(header)
    150 else:
    151     message = self._parse_data_message(header)

File ~/projects/virtualenvs/strava/lib/python3.9/site-packages/fitparse/base.py:196, in FitFile._parse_definition_message(self, header)
    191 base_type = BASE_TYPES.get(base_type_num, BASE_TYPE_BYTE)
    193 if (field_size % base_type.size) != 0:
    194     # NOTE: we could fall back to byte encoding if there's any
    195     # examples in the wild. For now, just throw an exception
--> 196     raise FitParseError("Invalid field size %d for type '%s' (expected a multiple of %d)" % (
    197         field_size, base_type.name, base_type.size))
    199 # If the field has components that are accumulators
    200 # start recording their accumulation at 0
    201 if field and field.components:

FitParseError: Invalid field size 1 for type 'uint32' (expected a multiple of 4)```

wondering if its a version mismatch issue?

here's my pip freeze output:
asttokens==2.4.1
contourpy==1.2.0
cycler==0.12.1
decorator==5.1.1
exceptiongroup==1.2.0
executing==2.0.1
fitparse==1.2.0
fonttools==4.47.2
gpxpy==1.6.2
importlib-resources==6.1.1
ipython==8.18.1
jedi==0.19.1
kiwisolver==1.4.5
matplotlib==3.8.2
matplotlib-inline==0.1.6
numpy==1.26.3
packaging==23.2
parso==0.8.3
pexpect==4.9.0
pillow==10.2.0
prompt-toolkit==3.0.43
ptyprocess==0.7.0
pure-eval==0.2.2
Pygments==2.17.2
pyparsing==3.1.1
python-dateutil==2.8.2
six==1.16.0
stack-data==0.6.3
tqdm==4.66.1
traitlets==5.14.1
typing_extensions==4.9.0
wcwidth==0.2.13
zipp==3.17.0
ColCarroll commented 4 months ago

It could be a version mismatch error. I'd guess newer watches might have different formats, too, and I'm not sure what state of the art is for parsing all these files...

I think filter_files is a generator, and it hasn't gotten past any files. If you're running this locally, you might edit ~/projects/strava_calendar/strava_calendar/data.py:171 with

try: 
  strava_file = StravaFile(data)
except:
  print(f"{fname} failed!")
  continue

and see if you get most of your data.