File: garmintools.py

package info (click to toggle)
pytrainer 2.0.0~rc1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 4,916 kB
  • sloc: python: 15,815; perl: 6,084; xml: 195; sql: 151; makefile: 84; sh: 46
file content (136 lines) | stat: -rw-r--r-- 4,771 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# -*- coding: iso-8859-1 -*-

#Copyright (C) Fiz Vazquez vud1@sindominio.net
# Modified by dgranda

#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.

#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

# Added to support python installations older than 2.6
from __future__ import with_statement

import logging
import os
from io import BytesIO
from lxml import etree

from pytrainer.lib.xmlUtils import XMLParser
from pytrainer.gui.dialogs import fileChooserDialog, guiFlush
from pytrainer.core.activity import Activity
from sqlalchemy.orm import exc

class garmintools():
	def __init__(self, parent = None, validate=False):
		self.parent = parent
		self.pytrainer_main = parent.pytrainer_main
		self.tmpdir = self.pytrainer_main.profile.tmpdir
		self.data_path = os.path.dirname(__file__)
		self.validate = validate
		self.sport = self.getConfValue("Force_sport_to")

	def getConfValue(self, confVar):
		info = XMLParser(self.data_path+"/conf.xml")
		code = info.getValue("pytrainer-plugin","plugincode")
		plugindir = self.pytrainer_main.profile.plugindir
		if not os.path.isfile(plugindir+"/"+code+"/conf.xml"):
			value = None
		else:
			info = XMLParser(plugindir+"/"+code+"/conf.xml")
			value = info.getValue("pytrainer-plugin",confVar)
		return value

	def run(self):
		logging.debug(">>")
		# able to select multiple files....
		selectedFiles = fileChooserDialog(title="Choose a garmintools dump file (or files) to import", multiple=True).getFiles()
		guiFlush()
		importfiles = []
		if not selectedFiles: #Nothing selected
			return importfiles
		for filename in selectedFiles:
			if self.valid_input_file(filename):
				#Garmin dump files are not valid xml - need to load into a xmltree
				#read file into string
				with open(filename, 'r') as f:
					xmlString = f.read()
				fileString = BytesIO(b"<root>" + xmlString + b"</root>")
				#parse string as xml
				tree = etree.parse(fileString)
				if not self.inDatabase(tree):
					sport = self.getSport(tree)
					gpxfile = "%s/garmintools-%d.gpx" % (self.tmpdir, len(importfiles))
					self.createGPXfile(gpxfile, tree)
					importfiles.append((gpxfile, sport))
				else:
					logging.debug("%s already in database. Skipping import." % (filename,) )
			else:
				logging.info("File %s failed validation" % (filename))
		logging.debug("<<")
		return importfiles

	def valid_input_file(self, filename):
		""" Function to validate input file if requested"""
		if not self.validate:  #not asked to validate
			logging.debug("Not validating %s" % (filename) )
			return True
		else:
			print "Cannot validate garmintools dump files yet"
			logging.debug("Cannot validate garmintools dump files yet")
			return True
			'''xslfile = os.path.realpath(self.parent.parent.data_path)+ "/schemas/GarminTrainingCenterDatabase_v2.xsd"
			from lib.xmlValidation import xmlValidator
			validator = xmlValidator()
			return validator.validateXSL(filename, xslfile)'''

	def inDatabase(self, tree):
		#comparing date and start time (sport may have been changed in DB after import)
		time = self.detailsFromFile(tree)
		try:
			self.pytrainer_main.ddbb.session.query(Activity).filter(Activity.date_time_utc == time).one()
			return True
		except exc.NoResultFound:
			return False

	def getSport(self, tree):
		#return sport from file or overide if present
		if self.sport:
			return self.sport
		root = tree.getroot()
		sportElement = root.find(".//run")
		try:
			sport = sportElement.get("sport")
			sport = sport.capitalize()
		except:
			sport = "import"
		return sport

	def detailsFromFile(self, tree):
		root = tree.getroot()
		#Find first point
		pointElement = root.find(".//point")
		if pointElement is not None:
			#Try to get time from point
			time = pointElement.get("time")
			print "#TODO first time is different from time used by gpsbabel and has locale embedded: " + time
			return time
		return None

	def createGPXfile(self, gpxfile, tree):
		""" Function to transform a Garmintools dump file to a valid GPX+ file
		"""
		xslt_doc = etree.parse(self.data_path+"/translate.xsl")
		transform = etree.XSLT(xslt_doc)
		result_tree = transform(tree)
		result_tree.write(gpxfile, xml_declaration=True, encoding='UTF-8')