aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2023-02-15 23:36:55 +0100
committerDaniel Schadt <kingdread@gmx.de>2023-02-15 23:36:55 +0100
commit4a3ebb1a0a71c02c1057b6fd6c6054afe3bfa876 (patch)
tree75fce89e2df7d0dde0efcdba5db4ce91a1d62df9
parent413ac5ca31dcc3ccb84484748337b815599fe314 (diff)
downloadfietsboek-4a3ebb1a0a71c02c1057b6fd6c6054afe3bfa876.tar.gz
fietsboek-4a3ebb1a0a71c02c1057b6fd6c6054afe3bfa876.tar.bz2
fietsboek-4a3ebb1a0a71c02c1057b6fd6c6054afe3bfa876.zip
try to avoid parsing the GPX more than once
-rw-r--r--fietsboek/actions.py16
-rw-r--r--fietsboek/data.py12
-rw-r--r--fietsboek/models/track.py3
-rw-r--r--fietsboek/util.py9
-rw-r--r--fietsboek/views/edit.py3
5 files changed, 31 insertions, 12 deletions
diff --git a/fietsboek/actions.py b/fietsboek/actions.py
index 4974a2c..2058f4d 100644
--- a/fietsboek/actions.py
+++ b/fietsboek/actions.py
@@ -8,7 +8,7 @@ the test functions.
import datetime
import logging
import re
-from typing import List
+from typing import List, Optional
import brotli
import gpxpy
@@ -97,7 +97,7 @@ def add_track(
# Best time to build the cache is right after the upload, but *after* the
# transformers have been applied!
- track.ensure_cache(manager.decompress_gpx())
+ track.ensure_cache(gpx)
dbsession.add(track.cache)
manager.engrave_metadata(
@@ -105,6 +105,7 @@ def add_track(
description=track.description,
author_name=track.owner.name,
time=track.date,
+ gpx=gpx,
)
return track
@@ -170,14 +171,18 @@ def edit_images(request: Request, track: models.Track):
request.dbsession.add(image_meta)
-def execute_transformers(request: Request, track: models.Track):
+def execute_transformers(request: Request, track: models.Track) -> Optional[gpxpy.gpx.GPX]:
"""Execute the transformers for the given track.
Note that this function "short circuits" if the saved transformer settings
already match the settings given in the request.
+ This function saves the modified data, but does also return it in case you
+ need to do further processing (unless no transformations have taken place).
+
:param request: The request.
:param track: The track.
+ :return: The transformed track.
"""
# pylint: disable=too-many-locals
LOGGER.debug("Executing transformers for %d", track.id)
@@ -187,7 +192,7 @@ def execute_transformers(request: Request, track: models.Track):
serialized = [[tfm.identifier(), tfm.parameters.dict()] for tfm in settings]
if serialized == track.transformers:
LOGGER.debug("Applied transformations mach on %d, skipping", track.id)
- return
+ return None
# We always start with the backup, that way we don't get "deepfried GPX"
# files by having the same filters run multiple times on the same input.
@@ -210,5 +215,6 @@ def execute_transformers(request: Request, track: models.Track):
LOGGER.debug("Rebuilding cache for %d", track.id)
request.dbsession.delete(track.cache)
track.cache = None
- track.ensure_cache(manager.decompress_gpx())
+ track.ensure_cache(gpx)
request.dbsession.add(track.cache)
+ return gpx
diff --git a/fietsboek/data.py b/fietsboek/data.py
index 1a1b66b..6906c84 100644
--- a/fietsboek/data.py
+++ b/fietsboek/data.py
@@ -158,7 +158,13 @@ class TrackDataDir:
return brotli.decompress(self.gpx_path().read_bytes())
def engrave_metadata(
- self, title: str, description: str, author_name: str, time: datetime.datetime
+ self,
+ title: str,
+ description: str,
+ author_name: str,
+ time: datetime.datetime,
+ *,
+ gpx: Optional[gpxpy.gpx.GPX] = None,
):
"""Engrave the given metadata into the GPX file.
@@ -168,8 +174,10 @@ class TrackDataDir:
:param description: The description of the track.
:param creator: Name of the track's creator.
:param time: Time of the track.
+ :param gpx: The pre-parsed GPX track, to save time if it is already parsed.
"""
- gpx = gpxpy.parse(self.decompress_gpx())
+ if gpx is None:
+ gpx = gpxpy.parse(self.decompress_gpx())
# First we delete the existing metadata
for track in gpx.tracks:
track.name = None
diff --git a/fietsboek/models/track.py b/fietsboek/models/track.py
index 9342cff..e0d2820 100644
--- a/fietsboek/models/track.py
+++ b/fietsboek/models/track.py
@@ -18,6 +18,7 @@ import logging
from itertools import chain
from typing import TYPE_CHECKING, List, Optional, Set, Union
+import gpxpy
from babel.numbers import format_decimal
from markupsafe import Markup
from pyramid.authorization import (
@@ -330,7 +331,7 @@ class Track(Base):
result = ACLHelper().permits(self, principals, "track.view")
return isinstance(result, ACLAllowed)
- def ensure_cache(self, gpx_data: Union[str, bytes]):
+ def ensure_cache(self, gpx_data: Union[str, bytes, gpxpy.gpx.GPX]):
"""Ensure that a cached version of this track's metadata exists.
:param gpx_data: GPX data (uncompressed) from which to build the cache.
diff --git a/fietsboek/util.py b/fietsboek/util.py
index c741550..68ba769 100644
--- a/fietsboek/util.py
+++ b/fietsboek/util.py
@@ -152,19 +152,22 @@ def guess_gpx_timezone(gpx: gpxpy.gpx.GPX) -> datetime.tzinfo:
return datetime.timezone.utc
-def tour_metadata(gpx_data: Union[str, bytes]) -> dict:
+def tour_metadata(gpx_data: Union[str, bytes, gpxpy.gpx.GPX]) -> dict:
"""Calculate the metadata of the tour.
Returns a dict with ``length``, ``uphill``, ``downhill``, ``moving_time``,
``stopped_time``, ``max_speed``, ``avg_speed``, ``start_time`` and
``end_time``.
- :param gpx_data: The GPX data of the tour.
+ :param gpx_data: The GPX data of the tour. Can be pre-parsed to save time.
:return: A dictionary with the computed values.
"""
if isinstance(gpx_data, bytes):
gpx_data = gpx_data.decode("utf-8")
- gpx = gpxpy.parse(gpx_data)
+ if isinstance(gpx_data, gpxpy.gpx.GPX):
+ gpx = gpx_data
+ else:
+ gpx = gpxpy.parse(gpx_data)
timezone = guess_gpx_timezone(gpx)
uphill, downhill = gpx.get_uphill_downhill()
moving_data = gpx.get_moving_data()
diff --git a/fietsboek/views/edit.py b/fietsboek/views/edit.py
index d60cced..9cc666f 100644
--- a/fietsboek/views/edit.py
+++ b/fietsboek/views/edit.py
@@ -95,12 +95,13 @@ def do_edit(request):
track.sync_tags(tags)
actions.edit_images(request, request.context)
- actions.execute_transformers(request, request.context)
+ gpx = actions.execute_transformers(request, request.context)
data.engrave_metadata(
title=track.title,
description=track.description,
author_name=track.owner.name,
time=track.date,
+ gpx=gpx,
)
return HTTPFound(request.route_url("details", track_id=track.id))