From: <nc...@us...> - 2011-07-29 10:02:11
|
Revision: 826 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=826&view=rev Author: ncjones Date: 2011-07-29 10:02:05 +0000 (Fri, 29 Jul 2011) Log Message: ----------- Fix loading legacy version. Modified Paths: -------------- pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/upgrade/data.py Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-07-29 10:01:41 UTC (rev 825) +++ pytrainer/trunk/pytrainer/main.py 2011-07-29 10:02:05 UTC (rev 826) @@ -76,7 +76,7 @@ logging.debug('connecting to DDBB') self.ddbb.connect() - initialize_data(self.ddbb, self.profile, self.environment.conf_dir) + initialize_data(self.ddbb, self.environment.conf_dir) if self.startup_options.check: logging.debug("Checking DB as per user's request") self.sanityCheck() Modified: pytrainer/trunk/pytrainer/upgrade/data.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/data.py 2011-07-29 10:01:41 UTC (rev 825) +++ pytrainer/trunk/pytrainer/upgrade/data.py 2011-07-29 10:02:05 UTC (rev 826) @@ -17,27 +17,27 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import logging +from lxml import etree import pytrainer from pytrainer.upgrade.context import UpgradeContext from pytrainer.upgrade.migratedb import MigratableDb MIGRATE_REPOSITORY_PATH = "pytrainer/upgrade" -def initialize_data(ddbb, profile, conf_dir): +def initialize_data(ddbb, conf_dir): """Initializes the installation's data.""" db_url = ddbb.get_connection_url() migratable_db = MigratableDb(MIGRATE_REPOSITORY_PATH, db_url) - InstalledData(migratable_db, ddbb, profile, conf_dir).update_to_current() + InstalledData(migratable_db, ddbb, conf_dir).update_to_current() class InstalledData(object): """Encapsulates an installation's existing data and provides means to check version state and upgrade.""" - def __init__(self, migratable_db, ddbb, profile, conf_dir): + def __init__(self, migratable_db, ddbb, conf_dir): self._migratable_db = migratable_db self._ddbb = ddbb - self._profile = profile self._conf_dir = conf_dir def update_to_current(self): @@ -83,10 +83,8 @@ return self._migratable_db.get_version() else: # Calculate data version in older version that does not use the - # current data versioning scheme. Versions earlier than 1.7 are not - # supported for upgrades. In versions 1.7 and 1.8 the database - # version was stored as a property in the profile config file. - legacy_version = self._profile.getValue("pytraining", "DB_version") + # current data versioning scheme. + legacy_version = self._get_legacy_version() if legacy_version is not None: legacy_version = int(legacy_version) if legacy_version <= 6: @@ -99,6 +97,16 @@ return 10 return -1 + def _get_legacy_version(self): + # In versions 1.7 and 1.8 the database version was stored as a property + # in the config file. Versions earlier than 1.7 are not supported for + # upgrades. + config_file = self._conf_dir + "/conf.xml" + parser = etree.XMLParser(encoding="UTF8", recover=True) + xml_tree = etree.parse(config_file, parser=parser) + config_element = xml_tree.getroot() + return config_element.get("DB_version") + def get_available_version(self): return self._migratable_db.get_upgrade_version() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-04 13:05:10
|
Revision: 832 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=832&view=rev Author: ncjones Date: 2011-08-04 13:05:04 +0000 (Thu, 04 Aug 2011) Log Message: ----------- Add logging when initializing environment. Modified Paths: -------------- pytrainer/trunk/pytrainer/environment.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/environment.py =================================================================== --- pytrainer/trunk/pytrainer/environment.py 2011-08-04 13:04:27 UTC (rev 831) +++ pytrainer/trunk/pytrainer/environment.py 2011-08-04 13:05:04 UTC (rev 832) @@ -32,6 +32,7 @@ """ self.conf_dir = conf_dir if conf_dir is not None else platform.get_default_conf_dir() + logging.info("Initializing environment. Conf dir is: '{0}'.".format(self.conf_dir)) self.conf_file = self.conf_dir + "/conf.xml" self.log_file = self.conf_dir + "/log.out" self.temp_dir = self.conf_dir + "/tmp" Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-08-04 13:04:27 UTC (rev 831) +++ pytrainer/trunk/pytrainer/main.py 2011-08-04 13:05:04 UTC (rev 832) @@ -58,10 +58,10 @@ self.version ="1.9.0-dev" #Process command line options self.startup_options = self.get_options() + #Setup logging + self.set_logging(self.startup_options.log_level, self.startup_options.log_type) self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir) self.environment.create_directories() - #Setup logging - self.set_logging(self.startup_options.log_level, self.startup_options.log_type) logging.debug('>>') logging.debug("PyTrainer version %s" % (self.version)) self.data_path = data_path This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-06 13:13:41
|
Revision: 836 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=836&view=rev Author: ncjones Date: 2011-08-06 13:13:35 +0000 (Sat, 06 Aug 2011) Log Message: ----------- Remove unused build_db method. Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/lib/ddbb.py pytrainer/trunk/pytrainer/profile.py Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2011-08-06 11:14:27 UTC (rev 835) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2011-08-06 13:13:35 UTC (rev 836) @@ -196,7 +196,6 @@ ) self.sportTreeView.set_model(store) self.sportTreeView.set_cursor(0) - #self.sportlistbutton.hide() self.sportlist.show() elif frame == 5: #Startup Parameters page selected self.init_params_tab() @@ -277,14 +276,6 @@ logging.debug("NewGraph deactivated") self.pytrainer_main.startup_options.newgraph = False - def on_sportlistbutton_clicked(self,widget): - sport_list = self.parent.getSportList() - if sport_list == 0: - self.parent.build_ddbb() - self.sportlistbutton.hide() - self.sportlist.show() - - def on_accept_clicked(self,widget): self.saveOptions() self.close_window() Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2011-08-06 11:14:27 UTC (rev 835) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2011-08-06 13:13:35 UTC (rev 836) @@ -139,12 +139,6 @@ def disconnect(self): self.ddbbObject.disconnect() - def build_ddbb(self): #TODO Is this needed? - self.ddbbObject.createDDBB() - self.ddbbObject.connect() - self.ddbbObject.createTables() - self.ddbbObject.createTableVersion() - def select(self,table,cells,condition=None, mod=None): return self.ddbbObject.select(table,cells,condition,mod) Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2011-08-06 11:14:27 UTC (rev 835) +++ pytrainer/trunk/pytrainer/profile.py 2011-08-06 13:13:35 UTC (rev 836) @@ -261,10 +261,6 @@ logging.debug("--") return self.pytrainer_main.ddbb.select("sports","name,met,weight,max_pace,color","name=\"%s\""%namesport)[0] - def build_ddbb(self): - logging.debug("--") - self.pytrainer_main.ddbb.build_ddbb() - def editProfile(self): logging.debug(">>") from gui.windowprofile import WindowProfile This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-13 08:26:16
|
Revision: 841 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=841&view=rev Author: ncjones Date: 2011-08-13 08:26:10 +0000 (Sat, 13 Aug 2011) Log Message: ----------- Add sport entity class. ticket:138 Added Paths: ----------- pytrainer/trunk/pytrainer/lib/color.py pytrainer/trunk/pytrainer/sport.py pytrainer/trunk/pytrainer/test/lib/ pytrainer/trunk/pytrainer/test/lib/__init__.py pytrainer/trunk/pytrainer/test/lib/color_test.py pytrainer/trunk/pytrainer/test/sport_test.py Added: pytrainer/trunk/pytrainer/lib/color.py =================================================================== --- pytrainer/trunk/pytrainer/lib/color.py (rev 0) +++ pytrainer/trunk/pytrainer/lib/color.py 2011-08-13 08:26:10 UTC (rev 841) @@ -0,0 +1,45 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +class Color(object): + + """A color represented as a 24-bit RGB value.""" + + def __init__(self, rgb_val=0): + rgb_val_int = int(rgb_val) + if rgb_val_int < 0: + raise ValueError("RGB value must not be negative.") + if rgb_val_int > 0xffffff: + raise ValueError("RGB value must not be greater than 0xffffff.") + self._rgb_val = rgb_val_int + + def _get_rgb_val(self): + return self._rgb_val + + rgb_val = property(_get_rgb_val) + + def _get_rgba_val(self): + return self._rgb_val << 8 + + rgba_val = property(_get_rgba_val) + + def to_hex_string(self): + return "{0:06x}".format(self._rgb_val) + +def color_from_hex_string(hex_string): + return Color(int(hex_string, 16)) Added: pytrainer/trunk/pytrainer/sport.py =================================================================== --- pytrainer/trunk/pytrainer/sport.py (rev 0) +++ pytrainer/trunk/pytrainer/sport.py 2011-08-13 08:26:10 UTC (rev 841) @@ -0,0 +1,92 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +from pytrainer.lib.color import Color + +class Sport(object): + + """A type of exercise. For example: "running" or "cycling".""" + + def __init__(self): + self._id = None + self.name = u"" + self.weight = 0.0 + self.met = None + self.max_pace = None + self.color = Color(0x0000ff) + + def _get_id(self): + return self._id + + def _set_id(self, id): + self._id = int(id) + + id = property(_get_id, _set_id) + + def _get_name(self): + return self._name + + def _set_name(self, name): + if not isinstance(name, unicode): + raise TypeError("Name must be unicode string, not {0}.".format(type(name).__name__)) + self._name = name + + name = property(_get_name, _set_name) + + def _get_weight(self): + return self._weight + + def _set_weight(self, weight): + weight_float = float(weight) + if weight_float < 0: + raise ValueError("Weight must not be negative.") + self._weight = weight_float + + weight = property(_get_weight, _set_weight) + + def _get_met(self): + return self._met + + def _set_met(self, met): + met_float = float(met) if met is not None else None + if met_float is not None and met_float < 0: + raise ValueError("MET must not be negative.") + self._met = met_float + + met = property(_get_met, _set_met) + + def _get_max_pace(self): + return self._max_pace + + def _set_max_pace(self, max_pace): + max_pace_int = int(max_pace) if max_pace is not None else None + if max_pace_int is not None and max_pace_int < 0: + raise ValueError("Max pace must not be negative.") + self._max_pace = max_pace_int + + max_pace = property(_get_max_pace, _set_max_pace) + + def _get_color(self): + return self._color + + def _set_color(self, color): + if color is None: + raise ValueError("Color must be valued.") + self._color = color + + color = property(_get_color, _set_color) Added: pytrainer/trunk/pytrainer/test/lib/__init__.py =================================================================== Added: pytrainer/trunk/pytrainer/test/lib/color_test.py =================================================================== --- pytrainer/trunk/pytrainer/test/lib/color_test.py (rev 0) +++ pytrainer/trunk/pytrainer/test/lib/color_test.py 2011-08-13 08:26:10 UTC (rev 841) @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +from pytrainer.lib.color import Color, color_from_hex_string +import unittest + +class ColorTest(unittest.TestCase): + + def test_constructor_should_accept_integer(self): + color = Color(12345) + self.assertEqual(12345, color.rgb_val) + + def test_constructor_should_accept_integer_string(self): + color = Color("12345") + self.assertEqual(12345, color.rgb_val) + + def test_constructor_should_not_accept_non_integer_string(self): + try: + Color("ff00ff") + except(ValueError): + pass + else: + self.fail() + + def test_constructor_should_not_accept_none(self): + try: + Color(None) + except(TypeError): + pass + else: + self.fail() + + def test_constructor_should_not_accept_negative_value(self): + try: + Color(-1) + except(ValueError): + pass + else: + self.fail() + + def test_constructor_should_not_accept_value_over_24_bit(self): + try: + Color(2 ** 24) + except(ValueError): + pass + else: + self.fail() + + def test_rgb_value_should_default_to_0(self): + color = Color() + self.assertEqual(0, color.rgb_val) + + def test_rgb_value_should_be_read_only(self): + color = Color() + try: + color.rgb_val = 1 + except(AttributeError): + pass + else: + self.fail() + + def test_rgba_value_should_be_rgb_value_with_two_trailing_zero_hex_digits(self): + color = Color(0x1177ff) + self.assertEquals(0x1177ff00, color.rgba_val) + + def test_to_hex_string_should_create_six_digit_hex_value(self): + color = Color(0xfab) + self.assertEquals("000fab", color.to_hex_string()) + + def test_color_from_hex_string_should_correctly_decode_hex_value(self): + color = color_from_hex_string("fab") + self.assertEquals(0xfab, color.rgb_val) Added: pytrainer/trunk/pytrainer/test/sport_test.py =================================================================== --- pytrainer/trunk/pytrainer/test/sport_test.py (rev 0) +++ pytrainer/trunk/pytrainer/test/sport_test.py 2011-08-13 08:26:10 UTC (rev 841) @@ -0,0 +1,214 @@ +# -*- coding: utf-8 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +import unittest +from pytrainer.sport import Sport + +class SportTest(unittest.TestCase): + + def test_id_should_default_to_none(self): + sport = Sport() + self.assertEquals(None, sport.id) + + def test_id_should_accept_integer(self): + sport = Sport() + sport.id = 1 + self.assertEquals(1, sport.id) + + def test_id_should_accept_integer_string(self): + sport = Sport() + sport.id = "1" + self.assertEquals(1, sport.id) + + def test_id_should_not_accept_non_integer_string(self): + sport = Sport() + try: + sport.id = "1.1" + except(ValueError): + pass + else: + self.fail() + + def test_id_should_not_accept_none(self): + sport = Sport() + try: + sport.id = None + except(TypeError): + pass + else: + self.fail() + + def test_name_should_default_to_empty_string(self): + sport = Sport() + self.assertEquals(u"", sport.name) + + def test_name_should_accept_unicode_string(self): + sport = Sport() + sport.name = u"Unicycling" + self.assertEquals(u"Unicycling", sport.name) + + def test_name_should_not_accept_non_unicode_string(self): + sport = Sport() + try: + sport.name = "Juggling" + except(TypeError): + pass + else: + self.fail() + + def test_name_should_not_accept_none(self): + sport = Sport() + try: + sport.name = None + except(TypeError): + pass + else: + self.fail() + + def test_met_should_default_to_None(self): + sport = Sport() + self.assertEquals(None, sport.met) + + def test_met_should_accept_float(self): + sport = Sport() + sport.met = 22.5 + self.assertEquals(22.5, sport.met) + + def test_met_should_accept_float_string(self): + sport = Sport() + sport.met = "22.5" + self.assertEquals(22.5, sport.met) + + def test_met_should_not_accept_non_float_string(self): + sport = Sport() + try: + sport.met = "22.5kg" + except(ValueError): + pass + else: + self.fail() + + def test_met_should_not_accept_negative_value(self): + sport = Sport() + try: + sport.met = -1 + except(ValueError): + pass + else: + self.fail() + + def test_met_should_accept_none(self): + sport = Sport() + sport.met = None + self.assertEquals(None, sport.met) + + def test_weight_should_default_to_zero(self): + sport = Sport() + self.assertEquals(0, sport.weight) + + def test_weight_should_accept_float(self): + sport = Sport() + sport.weight = 22.5 + self.assertEquals(22.5, sport.weight) + + def test_weight_should_accept_float_string(self): + sport = Sport() + sport.weight = "22.5" + self.assertEquals(22.5, sport.weight) + + def test_weight_should_not_accept_non_float_string(self): + sport = Sport() + try: + sport.weight = "22.5kg" + except(ValueError): + pass + else: + self.fail() + + def test_weight_should_not_accept_negative_value(self): + sport = Sport() + try: + sport.weight = -1 + except(ValueError): + pass + else: + self.fail() + + def test_weight_should_not_accept_none(self): + sport = Sport() + try: + sport.weight = None + except(TypeError): + pass + else: + self.fail() + + def test_max_pace_should_default_to_none(self): + sport = Sport() + self.assertEquals(None, sport.max_pace) + + def test_max_pace_should_accept_integer(self): + sport = Sport() + sport.max_pace = 220 + self.assertEquals(220, sport.max_pace) + + def test_max_pace_should_accept_integer_string(self): + sport = Sport() + sport.max_pace = "220" + self.assertEquals(220, sport.max_pace) + + def test_max_pace_should_not_accept_non_integer_string(self): + sport = Sport() + try: + sport.max_pace = "225s" + except(ValueError): + pass + else: + self.fail() + + def test_max_pace_should_take_floor_of_float(self): + sport = Sport() + sport.max_pace = 220.6 + self.assertEquals(220, sport.max_pace) + + def test_max_pace_should_not_accept_negative_value(self): + sport = Sport() + try: + sport.max_pace = -1 + except(ValueError): + pass + else: + self.fail() + + def test_max_pace_should_accept_none(self): + sport = Sport() + sport.max_pace = None + self.assertEquals(None, sport.max_pace) + + def test_color_should_default_to_blue(self): + sport = Sport() + self.assertEquals(0x0000ff, sport.color.rgb_val) + + def test_color_should_not_accept_none(self): + sport = Sport() + try: + sport.color = None + except(ValueError): + pass + else: + self.fail() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-13 08:27:03
|
Revision: 842 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=842&view=rev Author: ncjones Date: 2011-08-13 08:26:55 +0000 (Sat, 13 Aug 2011) Log Message: ----------- Add sport service. ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/sport.py pytrainer/trunk/pytrainer/test/sport_test.py Modified: pytrainer/trunk/pytrainer/sport.py =================================================================== --- pytrainer/trunk/pytrainer/sport.py 2011-08-13 08:26:10 UTC (rev 841) +++ pytrainer/trunk/pytrainer/sport.py 2011-08-13 08:26:55 UTC (rev 842) @@ -16,7 +16,8 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from pytrainer.lib.color import Color +from pytrainer.lib.color import Color, color_from_hex_string +import logging class Sport(object): @@ -90,3 +91,130 @@ self._color = color color = property(_get_color, _set_color) + +class SportServiceException(Exception): + + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + +_TABLE = "sports" + +_ID_COLUMN = "id_sports" + +_NAME_COLUMN = "name" + +_UPDATE_COLUMNS = _NAME_COLUMN + ",weight,met,max_pace,color" + +_SELECT_COLUMNS = _ID_COLUMN + "," + _UPDATE_COLUMNS + +class SportService(object): + + """Provides access to stored sports.""" + + def __init__(self, ddbb): + self._ddbb = ddbb + + def _create_sport(self, row): + sport = Sport() + sport.id = row[0] + sport.name = unicode(row[1]) + sport.weight = row[2] + sport.met = row[3] + sport.max_pace = row[4] + sport.color = color_from_hex_string(row[5]) + return sport + + def _create_row(self, sport): + return [sport.name, + sport.weight, + sport.met, + sport.max_pace, + sport.color.to_hex_string()] + + def _create_id_where_clause(self, sport_id): + return _ID_COLUMN + "=" + str(sport_id) + + def _create_name_where_clause(self, sport_name): + return _NAME_COLUMN + "=\"{0}\"".format(sport_name) + + def get_sport(self, sport_id): + """Get the sport with the specified id. + + If no sport with the given id exists then None is returned.""" + resultSet = self._ddbb.select(_TABLE, _SELECT_COLUMNS, self._create_id_where_clause(sport_id)) + if len(resultSet) == 0: + return None + else: + return self._create_sport(resultSet[0]) + + def get_sport_by_name(self, name): + """Get the sport with the specified name. + + If no sport with the given name exists then None is returned.""" + sport_id = self._get_sport_id_from_name(name) + return self.get_sport(sport_id) + + def _get_sport_id_from_name(self, name): + result_set = self._ddbb.select(_TABLE, _ID_COLUMN, self._create_name_where_clause(name)) + if len(result_set) > 0: + return result_set[0][0] + return None + + def get_all_sports(self): + """Get all stored sports.""" + result_set = self._ddbb.select(_TABLE, _SELECT_COLUMNS) + logging.debug("Retrieved all sports ({0} results).".format(len(result_set))) + sports = [] + for row in result_set: + sport = self._create_sport(row) + sports.append(sport) + return sports + + def store_sport(self, sport): + """Store a new or update an existing sport. + + The stored object is returned.""" + if (sport.id is None): + sport_id = self._store_new_sport(sport) + else: + sport_id = self._update_existing_sport(sport) + return self.get_sport(sport_id) + + def _store_new_sport(self, sport): + self._assert_unique(sport) + self._ddbb.insert(_TABLE, _UPDATE_COLUMNS, self._create_row(sport)) + logging.debug("Stored new sport: '{0}'.".format(sport.name)) + return self._get_sport_id_from_name(sport.name) + + def _update_existing_sport(self, sport): + self._assert_exists(sport) + self._assert_unique(sport) + self._ddbb.update(_TABLE, _UPDATE_COLUMNS, self._create_row(sport), self._create_id_where_clause(sport.id)) + logging.debug("Updated sport: '{0}'.".format(sport.name)) + return sport.id + + def _assert_unique(self, sport): + id = self._get_sport_id_from_name(sport.name) + if id is not None and id != sport.id: + raise SportServiceException("A sport already exists with name '{0}'".format(sport.name)) + logging.debug("Asserted sport name is unique: '{0}'.".format(sport.name)) + + def _assert_exists(self, sport): + result_set = self._ddbb.select(_TABLE, _ID_COLUMN, self._create_id_where_clause(sport.id)) + if (result_set == []): + raise SportServiceException("Sport does not exist with id: '{0}'.".format(sport.id)) + logging.debug("Asserted sport exists with id: '{0}'.".format(sport.id)) + + def remove_sport(self, sport): + """Delete a stored sport. + + All records associated with the sport will also be deleted.""" + if (sport.id is None): + raise SportServiceException("Cannot remove sport which has not been stored: '{0}'.".format(sport.name)) + self._assert_exists(sport) + self._ddbb.delete("records", "sport=" + str(sport.id)) + self._ddbb.delete(_TABLE, self._create_id_where_clause(sport.id)) + logging.debug("Deleted sport: '{0}'.".format(sport.name)) Modified: pytrainer/trunk/pytrainer/test/sport_test.py =================================================================== --- pytrainer/trunk/pytrainer/test/sport_test.py 2011-08-13 08:26:10 UTC (rev 841) +++ pytrainer/trunk/pytrainer/test/sport_test.py 2011-08-13 08:26:55 UTC (rev 842) @@ -17,7 +17,10 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import unittest -from pytrainer.sport import Sport +from pytrainer.sport import Sport, SportService, SportServiceException +import mock +from pytrainer.lib.sqliteUtils import Sql +import pytrainer class SportTest(unittest.TestCase): @@ -212,3 +215,164 @@ pass else: self.fail() + + +class SportServiceTest(unittest.TestCase): + + def setUp(self): + self.mock_ddbb = mock.Mock(spec=Sql) + self.sport_service = SportService(self.mock_ddbb) + + def test_store_sport_should_insert_row_when_sport_has_no_id(self): + self.mock_ddbb.select.return_value = [] + sport = Sport() + sport.name = u"Test name" + self.sport_service.store_sport(sport) + self.mock_ddbb.insert.assert_called_with("sports", "name,weight,met,max_pace,color", + [u"Test name", 0.0, None, None, "0000ff"]) + + def test_store_sport_should_update_row_when_sport_has_id(self): + def mock_select(table, columns, where): + if columns == "id_sports": + return [[1]] + else: + return [(1, u"", 0, 0, 0, "0")] + self.mock_ddbb.select = mock.Mock(wraps=mock_select) + sport = Sport() + sport.id = 1 + sport.name = u"New name" + self.sport_service.store_sport(sport) + self.mock_ddbb.update.assert_called_with("sports", "name,weight,met,max_pace,color", + [u"New name", 0.0, None, None, "0000ff"], "id_sports=1") + + def test_store_sport_should_return_stored_sport(self): + sport_ids = [] + def update_sport_ids(*args): + sport_ids.append([1]) + self.mock_ddbb.insert.side_effect = update_sport_ids + def mock_select(table, columns, where): + if columns == "id_sports": + return sport_ids + else: + return [(2, u"", 0, 0, 0, "0")] + self.mock_ddbb.select = mock.Mock(wraps=mock_select) + sport = Sport() + stored_sport = self.sport_service.store_sport(sport) + self.assertEquals(2, stored_sport.id) + + def test_store_sport_should_error_when_sport_has_unknown_id(self): + self.mock_ddbb.select.return_value = [] + sport = Sport() + sport.id = 100 + try: + self.sport_service.store_sport(sport) + except(SportServiceException): + pass + else: + self.fail() + + def test_store_sport_should_error_when_new_sport_has_duplicate_name(self): + self.mock_ddbb.select.return_value = [(1, u"Test name", 150, 12.5, 200, "0")] + sport = Sport() + sport.name = u"Test name" + try: + self.sport_service.store_sport(sport) + except(SportServiceException): + pass + else: + self.fail() + + def test_store_sport_should_error_when_existing_sport_has_duplicate_name(self): + def mock_select(table, columns, where): + if columns == pytrainer.sport._ID_COLUMN: + return [[2]] + else: + return [(1, u"Test name", 0, 0.0, "0"), (2, u"New name", 0, 0.0, "0")] + self.mock_ddbb.select = mock.Mock(wraps=mock_select) + sport = Sport() + sport.id = 1 + sport.name = u"New name" + try: + self.sport_service.store_sport(sport) + except(SportServiceException): + pass + else: + self.fail() + + def test_get_sport_returns_none_for_nonexistant_sport(self): + self.mock_ddbb.select.return_value = [] + sport = self.sport_service.get_sport(1) + self.assertEquals(None, sport) + + def test_get_sport_returns_sport_with_id(self): + self.mock_ddbb.select.return_value = [(1, u"", 0, 0, 0, "0")] + sport = self.sport_service.get_sport(1) + self.assertEquals(1, sport.id) + + def test_get_sport_by_name_returns_none_for_nonexistant_sport(self): + self.mock_ddbb.select.return_value = [] + sport = self.sport_service.get_sport("no such sport") + self.assertEquals(None, sport) + + def test_get_sport_by_name_returns_sport_with_name(self): + def mock_select(table, columns, where): + if columns == "id_sport": + return [(1)] + else: + return [(1, u"rugby", 0, 0, 0, "0")] + self.mock_ddbb.select = mock.Mock(wraps=mock_select) + sport = self.sport_service.get_sport("rugby") + self.assertEquals(u"rugby", sport.name) + + def test_get_all_sports_should_return_all_sports_in_query_result(self): + self.mock_ddbb.select.return_value = [(1, u"Test name", 0, 0, 0, "0"), (2, u"Test name 2", 0, 0, 0, "0")] + sports = self.sport_service.get_all_sports() + self.assertEquals(2, len(sports)) + sport1 = sports[0] + self.assertEquals(1, sport1.id) + sport2 = sports[1] + self.assertEquals(2, sport2.id) + + def test_get_all_sports_should_return_no_sports_when_query_result_empty(self): + self.mock_ddbb.select.return_value = [] + sports = self.sport_service.get_all_sports() + self.assertEquals(0, len(sports)) + + def test_remove_sport_should_error_when_sport_has_no_id(self): + self.mock_ddbb.select.return_value = [(1, u"Test name", 150, 12.5, 200, "0")] + sport = Sport() + try: + self.sport_service.remove_sport(sport) + except(SportServiceException): + pass + else: + self.fail() + + def test_remove_sport_should_error_when_sport_has_unknown_id(self): + self.mock_ddbb.select.return_value = [] + sport = Sport() + sport.id = 100 + try: + self.sport_service.remove_sport(sport) + except(SportServiceException): + pass + else: + self.fail() + + def test_remove_sport_should_delete_sport_with_specified_id(self): + self.mock_ddbb.select.return_value = [[1]] + sport = Sport() + sport.id = 1 + self.sport_service.remove_sport(sport) + self.mock_ddbb.delete.assert_called_with("sports", "id_sports=1") + + def test_remove_sport_should_remove_associated_entries(self): + self.mock_ddbb.select.return_value = [[1]] + sport = Sport() + sport.id = 1 + delete_arguments = [] + def mock_delete(*args): + delete_arguments.append(args) + self.mock_ddbb.delete = mock.Mock(wraps=mock_delete) + self.sport_service.remove_sport(sport) + self.assertEquals(("records", "sport=1"), delete_arguments[0]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-13 08:28:12
|
Revision: 843 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=843&view=rev Author: ncjones Date: 2011-08-13 08:28:05 +0000 (Sat, 13 Aug 2011) Log Message: ----------- Use sport service for sports CRUD. ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/profile.py Added Paths: ----------- pytrainer/trunk/pytrainer/gui/color.py pytrainer/trunk/pytrainer/test/gui/color_test.py Added: pytrainer/trunk/pytrainer/gui/color.py =================================================================== --- pytrainer/trunk/pytrainer/gui/color.py (rev 0) +++ pytrainer/trunk/pytrainer/gui/color.py 2011-08-13 08:28:05 UTC (rev 843) @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +import gtk.gdk +from pytrainer.lib.color import Color + +class ColorConverter(object): + + """Converts between Pytrainer and GDK color instances.""" + + def convert_to_gdk_color(self, color): + """Convert a Pytrainer color to a GDK color.""" + color_format = "#{0:06x}".format(color.rgb_val) + return gtk.gdk.color_parse(color_format) + + def convert_to_color(self, gdk_col): + """Convert a GDK color to a Pytrainer color.""" + red = gdk_col.red >> 8 + green = gdk_col.green >> 8 + blue = gdk_col.blue >> 8 + rgb_val = (red << 16) + (green << 8) + blue + return Color(rgb_val) Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2011-08-13 08:26:55 UTC (rev 842) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2011-08-13 08:28:05 UTC (rev 843) @@ -21,9 +21,13 @@ from windowcalendar import WindowCalendar from pytrainer.equipment import EquipmentService from pytrainer.gui.equipment import EquipmentUi +from pytrainer.sport import Sport, SportService import gtk import gobject import logging +import pytrainer +import pytrainer.lib.color +from pytrainer.gui.color import ColorConverter class WindowProfile(SimpleGladeApp): def __init__(self, data_path = None, parent=None, pytrainer_main=None): @@ -35,7 +39,8 @@ self.data_path = data_path SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) self.conf_options = parent.profile_options - self.stored_color = "000000" + self.stored_color = pytrainer.lib.color.Color(0) + self._sport_service = SportService(self.pytrainer_main.ddbb) def new(self): self.gender_options = { @@ -151,52 +156,27 @@ #print widget, pointer, frame if frame==2: self.saveOptions() - sport_list = self.parent.getSportList() - logging.debug("Got sport_list: %s" % str(sport_list) ) - if sport_list == 0: - pass - elif sport_list == -1: - self.sportlistbutton.set_label("It is not possible connect to the server") - else: - store = gtk.ListStore( - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gtk.gdk.Pixbuf, - object) - for i in sport_list: - try: - met = float(i[1]) - except: - met = "" - try: - weight = float(i[2]) - except: - weight = "" - try: - max_pace = int(i[4]) - if max_pace is None or max_pace == 0: - max_pace = "" - except Exception as e: - #print type(e), e - max_pace = "" - - colorPixBuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 25, 15) - colorPixBuf.fill(0 if i[5] in (None,'') else long(i[5]+'00',16)) - - iter = store.append() - store.set ( - iter, - 0, str(i[0]), - 1, met, - 2, weight, - 3, max_pace, - 4, colorPixBuf, - ) - self.sportTreeView.set_model(store) - self.sportTreeView.set_cursor(0) - self.sportlist.show() + sport_list = self._sport_service.get_all_sports() + store = gtk.ListStore( + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gtk.gdk.Pixbuf, + object) + for sport in sport_list: + iter = store.append() + colorPixBuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 25, 15) + colorPixBuf.fill(sport.color.rgba_val) + store.set(iter, + 0, sport.name, + 1, sport.met, + 2, sport.weight, + 3, sport.max_pace, + 4, colorPixBuf) + self.sportTreeView.set_model(store) + self.sportTreeView.set_cursor(0) + self.sportlist.show() elif frame == 5: #Startup Parameters page selected self.init_params_tab() @@ -321,19 +301,21 @@ self.addsport.show() def on_newsport_accept_clicked(self,widget): - sport = self.newsportentry.get_text() - met = self.newmetentry.get_text() - weight = self.newweightentry.get_text() - maxpace = self.newmaxpace.get_text() - if sport.lower() in [s[0].lower() for s in self.parent.getSportList()]: - msg = "Sport '%s' already exists" % sport + sport = Sport() + sport.name = unicode(self.newsportentry.get_text()) + sport.met = self._trim_to_null(self.newmetentry.get_text()) + sport.weight = self.newweightentry.get_text() + sport.max_pace = self._trim_to_null(self.newmaxpace.get_text()) + sport.color = self.stored_color + if sport.name.lower() in [s.name.lower() for s in self._sport_service.get_all_sports()]: + msg = "Sport '%s' already exists" % sport.name logging.error(msg) md = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, _(msg)) md.set_title(_("Sport Creation Error")) md.run() md.destroy() return - self.parent.addNewSport(sport,met,weight,maxpace,self.stored_color) + self._sport_service.store_sport(sport) self.parent.actualize_mainsportlist() self.on_switch_page(None,None,2) self.hidesportsteps() @@ -350,8 +332,9 @@ self.deletesport.show() def on_deletesport_clicked(self,widget): - sport = self.sportnamedel.get_text() - self.parent.delSport(sport) + sport_name = self.sportnamedel.get_text() + sport = self._sport_service.get_sport_by_name(sport_name) + self._sport_service.remove_sport(sport) self.parent.actualize_mainsportlist() self.on_switch_page(None,None,2) self.hidesportsteps() @@ -362,48 +345,34 @@ selected,iter = self.sportTreeView.get_selection().get_selected() if iter: self.buttonbox.set_sensitive(0) - sport = selected.get_value(iter,0) - name,met,weight,maxpace,color = self.parent.getSportInfo(sport) - self.editsportentry.set_text(sport) - self.sportnameedit.set_text(sport) - if weight is not None: - self.editweightentry.set_text(str(weight)) - else: - self.editweightentry.set_text("") - if met is not None: - self.editmetentry.set_text(str(met)) - else: - self.editmetentry.set_text("") - if maxpace is not None: - self.editmaxpace.set_text(str(maxpace)) - else: - self.editmaxpace.set_text("") - if color == None: - color = "0000" - + sport_desc = selected.get_value(iter,0) + sport = self._sport_service.get_sport_by_name(sport_desc) + self.editsportentry.set_text(sport.name) + self.sportnameedit.set_text(sport.name) + self.editweightentry.set_text(str(sport.weight)) + met_str = "" if sport.met is None else str(sport.met) + self.editmetentry.set_text(met_str) + max_pace_str = "" if sport.max_pace is None else str(sport.max_pace) + self.editmaxpace.set_text(max_pace_str) colorPixBuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 250, 20) - colorPixBuf.fill(long("0x%s00" % color, 16)) + colorPixBuf.fill(sport.color.rgba_val) self.editcolor.set_from_pixbuf(colorPixBuf) - self.hidesportsteps() self.editsport.show() def on_editcolor_clicked(self, widget): selected,iter = self.sportTreeView.get_selection().get_selected() if iter: - sport = selected.get_value(iter,0) - name,met,weight,maxpace,color = self.parent.getSportInfo(sport) - if color==None: - color = "000000" + sport_desc = selected.get_value(iter,0) + sport = self._sport_service.get_sport_by_name(sport_desc) colorseldlg = gtk.ColorSelectionDialog("test") colorseldlg.colorsel.set_has_palette(True) - colorseldlg.colorsel.set_current_color(gtk.gdk.color_parse("#"+color)) + colorseldlg.colorsel.set_current_color(ColorConverter().convert_to_gdk_color(sport.color)) colorseldlg.run() - col = colorseldlg.colorsel.get_current_color() - self.stored_color = ("%02x" % col.red)[:2] + ("%02x" % col.green)[:2] + ("%02x" % col.blue)[:2] - + gdk_color = colorseldlg.colorsel.get_current_color() + self.stored_color = ColorConverter().convert_to_color(gdk_color) colorPixBuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 250, 20) - colorPixBuf.fill(long("0x%s00" % self.stored_color, 16)) + colorPixBuf.fill(self.stored_color.rgba_val) self.newcolor.set_from_pixbuf(colorPixBuf) self.editcolor.set_from_pixbuf(colorPixBuf) @@ -414,17 +383,23 @@ def on_editsport_accept_clicked(self,widget): oldnamesport = self.sportnameedit.get_text() - newnamesport = self.editsportentry.get_text() - newmetsport = self.editmetentry.get_text() - newweightsport = self.editweightentry.get_text() - newmaxpace = self.editmaxpace.get_text() - self.parent.updateSport(oldnamesport,newnamesport,newmetsport,newweightsport, newmaxpace, self.stored_color) + sport = self._sport_service.get_sport_by_name(oldnamesport) + sport.name = unicode(self.editsportentry.get_text()) + sport.weight = self.editweightentry.get_text() + sport.met = self._trim_to_null(self.editmetentry.get_text()) + sport.max_pace = self._trim_to_null(self.editmaxpace.get_text()) + sport.color = self.stored_color + self._sport_service.store_sport(sport) self.parent.actualize_mainsportlist() self.on_switch_page(None,None,2) self.hidesportsteps() self.buttonbox.set_sensitive(1) self.sportlist.show() + def _trim_to_null(self, string): + trimmed = string.strip() + return None if trimmed == "" else trimmed + def on_sportcancel_clicked(self,widget): self.hidesportsteps() self.buttonbox.set_sensitive(1) Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2011-08-13 08:26:55 UTC (rev 842) +++ pytrainer/trunk/pytrainer/profile.py 2011-08-13 08:28:05 UTC (rev 843) @@ -228,39 +228,6 @@ #else: # return connection - def addNewSport(self,sport,met,weight,maxpace,color): - """31.08.2008 - dgranda - It adds a new sport. - arguments: - sport: sport's name - met: - weight: - returns: id_sports from new sport""" - logging.debug(">>") - logging.debug("Adding new sport: "+sport+"|"+weight+"|"+met+"|"+maxpace+"|"+str(color)) - sport = [sport,met,weight,maxpace,color] - self.pytrainer_main.ddbb.insert("sports","name,met,weight,max_pace,color",sport) - sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %(sport)) - logging.debug("<<") - return sport_id - - def delSport(self,sport): - logging.debug(">>") - condition = "name=\"%s\"" %sport - id_sport = self.pytrainer_main.ddbb.select("sports","id_sports",condition)[0][0] - logging.debug("removing records from sport "+ sport + " (id_sport: "+str(id_sport)+")") - self.pytrainer_main.ddbb.delete("records","sport=\"%d\""%id_sport) - self.pytrainer_main.ddbb.delete("sports","id_sports=\"%d\""%id_sport) - logging.debug("<<") - - def updateSport(self,oldnamesport,newnamesport,newmetsport,newweightsport,newmaxpace=None,newcolor=None): - logging.debug("--") - self.pytrainer_main.ddbb.update("sports","name,met,weight,max_pace,color",[newnamesport,newmetsport,newweightsport, newmaxpace, newcolor],"name=\"%s\""%oldnamesport) - - def getSportInfo(self,namesport): - logging.debug("--") - return self.pytrainer_main.ddbb.select("sports","name,met,weight,max_pace,color","name=\"%s\""%namesport)[0] - def editProfile(self): logging.debug(">>") from gui.windowprofile import WindowProfile Added: pytrainer/trunk/pytrainer/test/gui/color_test.py =================================================================== --- pytrainer/trunk/pytrainer/test/gui/color_test.py (rev 0) +++ pytrainer/trunk/pytrainer/test/gui/color_test.py 2011-08-13 08:28:05 UTC (rev 843) @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +from pytrainer.gui.color import ColorConverter +from pytrainer.lib.color import Color +import gtk.gdk +import unittest + +class ColorConverterTest(unittest.TestCase): + + def setUp(self): + self._converter = ColorConverter() + + def test_convert_to_gdk_color_should_create_gdk_color_with_equivalent_rgb_values(self): + color = Color(0xaaff33) + gdk_color = self._converter.convert_to_gdk_color(color) + self.assertEquals(0x3333, gdk_color.blue) + self.assertEquals(0xffff, gdk_color.green) + self.assertEquals(0xaaaa, gdk_color.red) + + def test_convert_to_color_should_create_color_with_equivalent_rgb_values(self): + gdk_col = gtk.gdk.color_parse("#aaff33") + color = self._converter.convert_to_color(gdk_col) + self.assertEqual(0xaaff33, color.rgb_val) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2011-08-15 10:09:39
|
Revision: 847 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=847&view=rev Author: dgranda Date: 2011-08-15 10:09:33 +0000 (Mon, 15 Aug 2011) Log Message: ----------- Enabling localization for labels - ticket #99 Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/equipment.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/listview.py Modified: pytrainer/trunk/pytrainer/gui/equipment.py =================================================================== --- pytrainer/trunk/pytrainer/gui/equipment.py 2011-08-14 20:01:41 UTC (rev 846) +++ pytrainer/trunk/pytrainer/gui/equipment.py 2011-08-15 10:09:33 UTC (rev 847) @@ -95,11 +95,11 @@ def _init_tree_view(self): tree_view = self._get_tree_view() - column = gtk.TreeViewColumn("Description", gtk.CellRendererText(), text=1) + column = gtk.TreeViewColumn(_("Description"), gtk.CellRendererText(), text=1) column.set_resizable(True) tree_view.append_column(column) - tree_view.append_column(gtk.TreeViewColumn("Usage", gtk.CellRendererProgress(), value=2, text=3)) - tree_view.append_column(gtk.TreeViewColumn("Active", gtk.CellRendererToggle(), active=4)) + tree_view.append_column(gtk.TreeViewColumn(_("Usage"), gtk.CellRendererProgress(), value=2, text=3)) + tree_view.append_column(gtk.TreeViewColumn(_("Active"), gtk.CellRendererToggle(), active=4)) # add filler column tree_view.append_column(gtk.TreeViewColumn()) tree_view.set_model(self._equipment_store) Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-14 20:01:41 UTC (rev 846) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-15 10:09:33 UTC (rev 847) @@ -2207,7 +2207,7 @@ table = gtk.Table(1,2) self.entryList = [] #Add date - label = gtk.Label("<b>Date</b>") + label = gtk.Label(_("<b>Date</b>")) label.set_use_markup(True) entry = gtk.Entry() entry.set_text(data['date']) @@ -2223,7 +2223,7 @@ #table.attach(calbut,2,3,0,1) #TODO #Add weight - label = gtk.Label("<b>Weight</b>") + label = gtk.Label(_("<b>Weight</b>")) label.set_use_markup(True) entry = gtk.Entry() entry.set_text(data['weight']) @@ -2231,7 +2231,7 @@ table.attach(label,0,1,1,2) table.attach(entry,1,2,1,2) #Add Body fat - label = gtk.Label("<b>Body Fat</b>") + label = gtk.Label(_("<b>Body Fat</b>")) label.set_use_markup(True) entry = gtk.Entry() entry.set_text(data['bf']) @@ -2239,7 +2239,7 @@ table.attach(label,0,1,2,3) table.attach(entry,1,2,2,3) #Add Resting HR - label = gtk.Label("<b>Resting Heart Rate</b>") + label = gtk.Label(_("<b>Resting Heart Rate</b>")) label.set_use_markup(True) entry = gtk.Entry() entry.set_text(data['restingHR']) @@ -2247,7 +2247,7 @@ table.attach(label,0,1,3,4) table.attach(entry,1,2,3,4) #Add Max HR - label = gtk.Label("<b>Max Heart Rate</b>") + label = gtk.Label(_("<b>Max Heart Rate</b>")) label.set_use_markup(True) entry = gtk.Entry() entry.set_text(data['maxHR']) Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2011-08-14 20:01:41 UTC (rev 846) +++ pytrainer/trunk/pytrainer/lib/listview.py 2011-08-15 10:09:33 UTC (rev 847) @@ -1,13 +1,13 @@ import datetime -UC_LISTDISTANCE = {False : [['All Distances', [0.0,999999.9]], +UC_LISTDISTANCE = {False : [[_('All Distances'), [0.0,999999.9]], ['<1 km', [0.0, 1.0]], ['1-5 km', [1.0, 5.0]], ['5-20 km', [5.0, 20.0]], ['20-50 km', [20.0, 50.0]], ['50-100 km', [50.0, 100.0]], ['>100 km', [100.0, 999999.9]]] , - True : [['All Distances', [0.0,999999.9]], + True : [[_('All Distances'), [0.0,999999.9]], ['<1 mi', [0.0, 1.609344]], ['1-5 mi', [1.609344, 8.04672]], ['5-10 mi', [8.04672, 16.09344]], @@ -29,13 +29,13 @@ self.distance = 0 self.listSport = self.pytrainer_main.profile.getSportList() - self.listPast = [['All Time', -99999], ['Last 4 Weeks', -31], - ['Last 6 Months', -183], ['Last 12 Months', -366]] + self.listPast = [[_('All Time'), -99999], [_('Last 4 Weeks'), -31], + [_('Last 6 Months'), -183], [_('Last 12 Months'), -366]] - self.listDuration = [['All Durations', [0,999999]], - ['<1 Hour', [0,3600]], - ['1-2 Hours', [3600,7200]], - ['>2 Hours', [7200,999999]]] + self.listDuration = [[_('All Durations'), [0,999999]], + [_('<1 Hour'), [0,3600]], + [_('1-2 Hours'), [3600,7200]], + [_('>2 Hours'), [7200,999999]]] """ self.listDistanceUS = [['All Distances', [0.0,999999.9]], This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-18 03:12:49
|
Revision: 850 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=850&view=rev Author: ncjones Date: 2011-08-18 03:12:43 +0000 (Thu, 18 Aug 2011) Log Message: ----------- Use sport service in main. ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/gui/windowprofile.py pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/profile.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-17 11:10:47 UTC (rev 849) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-18 03:12:43 UTC (rev 850) @@ -297,8 +297,8 @@ #Re-add "All Sports" liststore.append([firstEntry]) #Re-add all sports in listSport - for i in listSport: - liststore.append([i[0]]) + for sport in listSport: + liststore.append([sport.name]) self.sportlist.set_active(0) logging.debug("<<") Modified: pytrainer/trunk/pytrainer/gui/windowprofile.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowprofile.py 2011-08-17 11:10:47 UTC (rev 849) +++ pytrainer/trunk/pytrainer/gui/windowprofile.py 2011-08-18 03:12:43 UTC (rev 850) @@ -21,7 +21,7 @@ from windowcalendar import WindowCalendar from pytrainer.equipment import EquipmentService from pytrainer.gui.equipment import EquipmentUi -from pytrainer.sport import Sport, SportService +from pytrainer.sport import Sport import gtk import gobject import logging @@ -30,7 +30,7 @@ from pytrainer.gui.color import ColorConverter class WindowProfile(SimpleGladeApp): - def __init__(self, data_path = None, parent=None, pytrainer_main=None): + def __init__(self, sport_service, data_path = None, parent=None, pytrainer_main=None): glade_path="glade/profile.glade" root = "newprofile" domain = None @@ -40,7 +40,7 @@ SimpleGladeApp.__init__(self, data_path+glade_path, root, domain) self.conf_options = parent.profile_options self.stored_color = pytrainer.lib.color.Color(0) - self._sport_service = SportService(self.pytrainer_main.ddbb) + self._sport_service = sport_service def new(self): self.gender_options = { Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2011-08-17 11:10:47 UTC (rev 849) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2011-08-18 03:12:43 UTC (rev 850) @@ -67,8 +67,8 @@ "rcd_maxvel", ] self.listSport = {} - for i in listSport: - self.listSport[i[3]] = i[0] #Create dictionary using SportID as key (may be non sequential if sports have been deleted) + for sport in listSport: + self.listSport[sport.id] = sport.name for i in self.listSport: self.rcd_sport.insert_text(i,self.listSport[i]) self.rcd_sport.set_active(0) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-08-17 11:10:47 UTC (rev 849) +++ pytrainer/trunk/pytrainer/main.py 2011-08-18 03:12:43 UTC (rev 850) @@ -41,6 +41,7 @@ from importdata import Importdata from plugins import Plugins from profile import Profile +from pytrainer.sport import SportService from athlete import Athlete from stats import Stats @@ -81,6 +82,7 @@ logging.debug("Checking DB as per user's request") self.sanityCheck() + self._sport_service = SportService(self.ddbb) self.record = Record(data_path,self) self.athlete = Athlete(data_path,self) self.stats = Stats(data_path,self) @@ -207,8 +209,8 @@ def refreshMainSportList(self): logging.debug('>>') - listSport = self.profile.getSportList() - self.windowmain.updateSportList(listSport) + sports = self._sport_service.get_all_sports() + self.windowmain.updateSportList(sports) logging.debug('<<') def refreshGraphView(self, view, sport=None): @@ -426,20 +428,17 @@ def newRecord(self,title=None,distance=None,time=None,upositive=None,unegative=None,bpm=None,calories=None,date=None,comment=None,view=None): logging.debug('>>') - list_sport = self.profile.getSportList() if date == None: date = self.date.getDate() - self.record.newRecord(list_sport, date, title, distance, time, upositive, unegative, bpm, calories, comment) + self.record.newRecord(date, title, distance, time, upositive, unegative, bpm, calories, comment) self.refreshListRecords() if view is not None: self.refreshGraphView(view) logging.debug('<<') def editRecord(self, id_record, view=None): - logging.debug('>>') - list_sport = self.profile.getSportList() - logging.debug('id_record: '+str(id_record)+' | list_sport: '+str(list_sport)) - self.record.editRecord(id_record,list_sport) + logging.debug("Editing record with id: '%s'", id_record) + self.record.editRecord(id_record) self.refreshListRecords() if view is not None: self.refreshGraphView(view) @@ -488,7 +487,7 @@ def editProfile(self): logging.debug('>>') - self.profile.editProfile() + self.profile.editProfile(self._sport_service) self.activitypool.clear_pool() self.windowmain.setup() logging.debug('<<') Modified: pytrainer/trunk/pytrainer/profile.py =================================================================== --- pytrainer/trunk/pytrainer/profile.py 2011-08-17 11:10:47 UTC (rev 849) +++ pytrainer/trunk/pytrainer/profile.py 2011-08-18 03:12:43 UTC (rev 850) @@ -228,14 +228,14 @@ #else: # return connection - def editProfile(self): + def editProfile(self, sport_service): logging.debug(">>") from gui.windowprofile import WindowProfile logging.debug("retrieving configuration data") #Refresh configuration self.configuration = self._parse_config_file(self.config_file) if self.profilewindow is None: - self.profilewindow = WindowProfile(self.data_path, self, pytrainer_main=self.pytrainer_main) + self.profilewindow = WindowProfile(sport_service, self.data_path, self, pytrainer_main=self.pytrainer_main) logging.debug("setting data values") self.profilewindow.setValues(self.configuration) self.profilewindow.run() Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-08-17 11:10:47 UTC (rev 849) +++ pytrainer/trunk/pytrainer/record.py 2011-08-18 03:12:43 UTC (rev 850) @@ -41,9 +41,10 @@ self.date = Date() logging.debug('<<') - def newRecord(self, list_sport, date, title=None, distance=None, time=None, upositive=None, unegative=None, bpm=None, calories=None, comment=None): + def newRecord(self, date, title=None, distance=None, time=None, upositive=None, unegative=None, bpm=None, calories=None, comment=None): logging.debug('>>') - self.recordwindow = WindowRecord(self._equipment_service, self.data_path, list_sport,self, date, title, distance, time, upositive, unegative, bpm, calories, comment) + sports = self._sport_service.get_all_sports() + self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, self, date, title, distance, time, upositive, unegative, bpm, calories, comment) self.recordwindow.run() logging.debug('<<') @@ -56,11 +57,12 @@ return self.recordwindow.getActivityData() logging.debug('<<') - def editRecord(self,id_record,list_sport): + def editRecord(self,id_record): logging.debug('>>') activity = self.pytrainer_main.activitypool.get_activity(id_record) record_equipment = self.get_record_equipment(id_record) - self.recordwindow = WindowRecord(self._equipment_service, self.data_path, list_sport, self, None, windowTitle=_("Edit Entry"), equipment=record_equipment) + sports = self._sport_service.get_all_sports() + self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, self, None, windowTitle=_("Edit Entry"), equipment=record_equipment) self.recordwindow.setValuesFromActivity(activity) ''' record = self.pytrainer_main.ddbb.select("records", "id_record, date, sport, distance, time, beats, average, calories, comments, gpslog, title, upositive, unegative, maxspeed, maxpace, pace, maxbeats, date_time_utc, date_time_local", "id_record=\"%s\"" %id_record) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-18 03:13:17
|
Revision: 851 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=851&view=rev Author: ncjones Date: 2011-08-18 03:13:11 +0000 (Thu, 18 Aug 2011) Log Message: ----------- Use sport service in record.py ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py pytrainer/trunk/pytrainer/sport.py pytrainer/trunk/pytrainer/test/sport_test.py Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-08-18 03:12:43 UTC (rev 850) +++ pytrainer/trunk/pytrainer/main.py 2011-08-18 03:13:11 UTC (rev 851) @@ -83,7 +83,7 @@ self.sanityCheck() self._sport_service = SportService(self.ddbb) - self.record = Record(data_path,self) + self.record = Record(self._sport_service, data_path, self) self.athlete = Athlete(data_path,self) self.stats = Stats(data_path,self) pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-08-18 03:12:43 UTC (rev 850) +++ pytrainer/trunk/pytrainer/record.py 2011-08-18 03:13:11 UTC (rev 851) @@ -29,10 +29,12 @@ from lib.date import Date from lib.gpx import Gpx from pytrainer.equipment import EquipmentService +from pytrainer.sport import Sport class Record: - def __init__(self, data_path = None, parent = None): + def __init__(self, sport_service, data_path = None, parent = None): logging.debug('>>') + self._sport_service = sport_service self.parent = parent self.pytrainer_main = parent self._equipment_service = EquipmentService(self.pytrainer_main.ddbb) @@ -92,37 +94,6 @@ logging.debug('removed gpxfile '+gpxfile) logging.debug('<<') - def _formatRecord (self, list_options): - logging.debug('>>') - time = self.date.time2second(list_options["rcd_time"]) - average = self.parseFloatRecord(list_options["rcd_average"]) - cells= "date,sport,distance,time,beats,comments,average,calories,title,upositive,unegative,maxspeed,maxpace,pace,maxbeats" - if (list_options["rcd_beats"] == ""): - list_options["rcd_beats"] = 0 - - #calculate the sport id - sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %list_options["rcd_sport"])[0][0] - - values= ( - list_options["rcd_date"], - sport_id, - self.parseFloatRecord(list_options["rcd_distance"]), - time, - self.parseFloatRecord(list_options["rcd_beats"]), - list_options["rcd_comments"], - average, - self.parseFloatRecord(list_options["rcd_calories"]), - list_options["rcd_title"], - self.parseFloatRecord(list_options["rcd_upositive"]), - self.parseFloatRecord(list_options["rcd_unegative"]), - self.parseFloatRecord(list_options["rcd_maxvel"]), - self.pace_to_float(list_options["rcd_maxpace"]), - self.pace_to_float(list_options["rcd_pace"]), - self.parseFloatRecord(list_options["rcd_maxbeats"]) - ) - logging.debug('<<') - return cells,values - def pace_to_float(self, value): '''Take a mm:ss or mm.ss and return float''' value = value.replace(':', '.') @@ -418,55 +389,41 @@ return self.pytrainer_main.ddbb.select(tables, "date,distance,time,beats,comments,average,calories,maxspeed,maxbeats,upositive,unegative", condition) + + def _get_sport(self, sport_name): + return self._sport_service.get_sport_by_name(sport_name) - def getSportMet(self,sport): + def getSportMet(self,sport_name): + """Deprecated: use sport.met""" logging.debug('--') - return self.pytrainer_main.ddbb.select("sports","met","name=\"%s\"" %(sport))[0][0] + return self._get_sport(sport_name).met - def getSportWeight(self,sport): + def getSportWeight(self,sport_name): + """Deprecated: use sport.weight""" logging.debug('--') - return self.pytrainer_main.ddbb.select("sports","weight","name=\"%s\"" %(sport))[0][0] + return self._get_sport(sport_name).weight - def getSportId(self,sport,add=None): - """31.08.2008 - dgranda - Retrieves id_sports from provided sport. If add is not set to None, sport is added to the system + def getSportId(self, sport_name, add=None): + """Deprecated: use sport_service.get_sport_by_name() + + Get the id of a sport by name, optionally adding a new sport if + none exists with the given name. arguments: - sport: sport's name to get id from - add: attribute to add or not the sport to db - returns: id_sports from provided sport""" - logging.debug('>>') - sport_id=None - if sport == "" or sport is None: - return sport_id - try: - sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %(sport))[0][0] - except: - logging.error('Error retrieving id_sports from '+ str(sport)) - #traceback.print_last() - if add is None: - logging.debug('Sport '+str(sport)+' will not be added to DB') - else: - logging.debug('Adding sport '+str(sport)+' to DB') - sport_id = self.addNewSport(sport,"0","0") - logging.debug('<<') - return sport_id + sport_name: sport's name to get id for + add: whether the sport should be added if not found + returns: id for sport with given name or None""" + if sport_name is None: + return None + sport = self._get_sport(sport_name) + if sport is None: + logging.debug("No sport with name: '%s'", str(sport_name)) + if add is not None: + logging.debug("Adding sport '%s'", str(sport)) + new_sport = Sport() + new_sport.name = sport_name + sport = self._sport_service.store_sport(new_sport) + return None if sport is None else sport.id - def addNewSport(self,sport,met,weight): - """31.08.2008 - dgranda - Copied from Profile class, adds a new sport. - arguments: - sport: sport's name - met: - weight: - returns: id_sports from new sport""" - logging.debug(">>") - logging.debug("Adding new sport: "+sport+"|"+weight+"|"+met) - sportT = [sport,met,weight] - self.pytrainer_main.ddbb.insert("sports","name,met,weight",sportT) - sport_id = self.pytrainer_main.ddbb.select("sports","id_sports","name=\"%s\"" %(sport))[0][0] - logging.debug("<<") - return sport_id - def getAllrecord(self): logging.debug('--') return self.pytrainer_main.ddbb.select("records", "date,distance,time,beats,comments,average,calories") Modified: pytrainer/trunk/pytrainer/sport.py =================================================================== --- pytrainer/trunk/pytrainer/sport.py 2011-08-18 03:12:43 UTC (rev 850) +++ pytrainer/trunk/pytrainer/sport.py 2011-08-18 03:13:11 UTC (rev 851) @@ -144,6 +144,8 @@ """Get the sport with the specified id. If no sport with the given id exists then None is returned.""" + if sport_id is None: + raise ValueError("Sport id cannot be None") resultSet = self._ddbb.select(_TABLE, _SELECT_COLUMNS, self._create_id_where_clause(sport_id)) if len(resultSet) == 0: return None @@ -154,7 +156,11 @@ """Get the sport with the specified name. If no sport with the given name exists then None is returned.""" + if name is None: + raise ValueError("Sport name cannot be None") sport_id = self._get_sport_id_from_name(name) + if sport_id is None: + return None return self.get_sport(sport_id) def _get_sport_id_from_name(self, name): Modified: pytrainer/trunk/pytrainer/test/sport_test.py =================================================================== --- pytrainer/trunk/pytrainer/test/sport_test.py 2011-08-18 03:12:43 UTC (rev 850) +++ pytrainer/trunk/pytrainer/test/sport_test.py 2011-08-18 03:13:11 UTC (rev 851) @@ -224,7 +224,12 @@ self.sport_service = SportService(self.mock_ddbb) def test_store_sport_should_insert_row_when_sport_has_no_id(self): - self.mock_ddbb.select.return_value = [] + def mock_select(table, columns, where): + call_count = self.mock_ddbb.select.call_count + if call_count == 2: + return [[1]] + return [] + self.mock_ddbb.select = mock.Mock(wraps=mock_select) sport = Sport() sport.name = u"Test name" self.sport_service.store_sport(sport) @@ -309,6 +314,14 @@ sport = self.sport_service.get_sport(1) self.assertEquals(1, sport.id) + def test_get_sport_raises_error_for_id_none(self): + try: + self.sport_service.get_sport(None) + except(ValueError): + pass + else: + self.fail() + def test_get_sport_by_name_returns_none_for_nonexistant_sport(self): self.mock_ddbb.select.return_value = [] sport = self.sport_service.get_sport("no such sport") @@ -324,6 +337,14 @@ sport = self.sport_service.get_sport("rugby") self.assertEquals(u"rugby", sport.name) + def test_get_sport_by_name_raises_error_for_none_sport_name(self): + try: + self.sport_service.get_sport_by_name(None) + except(ValueError): + pass + else: + self.fail() + def test_get_all_sports_should_return_all_sports_in_query_result(self): self.mock_ddbb.select.return_value = [(1, u"Test name", 0, 0, 0, "0"), (2, u"Test name 2", 0, 0, 0, "0")] sports = self.sport_service.get_all_sports() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-18 03:13:38
|
Revision: 852 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=852&view=rev Author: ncjones Date: 2011-08-18 03:13:32 +0000 (Thu, 18 Aug 2011) Log Message: ----------- Use sport service in stats.py ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/stats.py Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-08-18 03:13:11 UTC (rev 851) +++ pytrainer/trunk/pytrainer/main.py 2011-08-18 03:13:32 UTC (rev 852) @@ -85,7 +85,7 @@ self._sport_service = SportService(self.ddbb) self.record = Record(self._sport_service, data_path, self) self.athlete = Athlete(data_path,self) - self.stats = Stats(data_path,self) + self.stats = Stats(self._sport_service, self) pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) self.activitypool = ActivityPool(self, size=pool_size) #preparamos la ventana principal Modified: pytrainer/trunk/pytrainer/stats.py =================================================================== --- pytrainer/trunk/pytrainer/stats.py 2011-08-18 03:13:11 UTC (rev 851) +++ pytrainer/trunk/pytrainer/stats.py 2011-08-18 03:13:32 UTC (rev 852) @@ -17,17 +17,12 @@ #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import logging -import dateutil -from pytrainer.lib.ddbb import DDBB -from pytrainer.lib.graphdata import GraphData - class Stats: - def __init__(self, data_path = None, parent = None): + def __init__(self, sport_service, parent = None): logging.debug('>>') - self.parent = parent + self._sport_service = sport_service self.pytrainer_main = parent - self.data_path = data_path self.init_from_conf() self.data = self.get_stats() logging.debug('<<') @@ -54,12 +49,11 @@ for f in fields: data[f] = 0 - sports = dict([(s['id_sports'], s['name']) for s in self.pytrainer_main.ddbb.select_dict("sports", ('id_sports', 'name'))]) results = self.pytrainer_main.ddbb.select_dict("records", ('id_record', 'date', 'sport', 'distance', 'duration', 'maxbeats', 'maxspeed', 'maxpace', 'average','pace','beats')) for r in results: -# r['duration'] /= 3600 if r['sport'] not in data['sports']: - data['sports'][r['sport']] = {'name': sports[r['sport']], 'count': 0} + sport = self._sport_service.get_sport(r['sport']) + data['sports'][r['sport']] = {'name': sport.name, 'count': 0} for f in fields: data['sports'][r['sport']][f] = 0 data['sports'][r['sport']]['total_'+f] = 0 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-18 03:14:04
|
Revision: 853 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=853&view=rev Author: ncjones Date: 2011-08-18 03:13:58 +0000 (Thu, 18 Aug 2011) Log Message: ----------- Use sport service in windowimportdata.py. ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowimportdata.py pytrainer/trunk/pytrainer/importdata.py pytrainer/trunk/pytrainer/main.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/gui/windowimportdata.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowimportdata.py 2011-08-18 03:13:32 UTC (rev 852) +++ pytrainer/trunk/pytrainer/gui/windowimportdata.py 2011-08-18 03:13:58 UTC (rev 853) @@ -32,7 +32,8 @@ from pytrainer.lib.date import Date class WindowImportdata(SimpleGladeApp): - def __init__(self, data_path = None, parent=None, config=None, pytrainer_main=None): + def __init__(self, sport_service, data_path = None, parent=None, config=None, pytrainer_main=None): + self._sport_service = sport_service self.data_path = data_path self.glade_path=data_path+"glade/importdata.glade" self.root = "win_importdata" @@ -202,12 +203,12 @@ def init_csvimport_tab(self): logging.debug(">>") #Populate Force Sport to combobox - sport_list = self.pytrainer_main.profile.getSportList() + sport_list = self._sport_service.get_all_sports() #Remove placeholder item (needed to ensure correct model for combobox) self.comboCSVForceSport.remove_text(0) for sport in sport_list: - logging.debug('Adding sport: %s' % sport[0]) - self.comboCSVForceSport.append_text(sport[0]) + logging.debug('Adding sport: %s' % sport.name) + self.comboCSVForceSport.append_text(sport.name) self.comboCSVForceSport.set_active(0) logging.debug("<<") return @@ -487,11 +488,8 @@ """ Function to import selected activity """ - - #selectedActivities.append((activity_id, start_time, distance, duration, sport, gpx_file)) logging.debug( "Importing %d activities" % len(activities)) - list_sport = self.pytrainer_main.profile.getSportList() - result = self.pytrainer_main.record.newMultiRecord(activities, list_sport) + result = self.pytrainer_main.record.newMultiRecord(activities) for activity in result: if "db_id" in activity.keys() and type(activity["db_id"]) is types.IntType: #Activity imported correctly Modified: pytrainer/trunk/pytrainer/importdata.py =================================================================== --- pytrainer/trunk/pytrainer/importdata.py 2011-08-18 03:13:32 UTC (rev 852) +++ pytrainer/trunk/pytrainer/importdata.py 2011-08-18 03:13:58 UTC (rev 853) @@ -16,17 +16,16 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import os - from gui.windowimportdata import WindowImportdata class Importdata: - def __init__(self, data_path = None, parent = None, config = None): + def __init__(self, sport_service, data_path = None, parent = None, config = None): + self._sport_service = sport_service self.data_path=data_path self.parent = parent self.pytrainer_main = parent self.configuration = config def runImportdata(self): - windowImportdata = WindowImportdata(self.data_path, self, self.configuration, self.pytrainer_main) + windowImportdata = WindowImportdata(self._sport_service, self.data_path, self, self.configuration, self.pytrainer_main) windowImportdata.run() Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-08-18 03:13:32 UTC (rev 852) +++ pytrainer/trunk/pytrainer/main.py 2011-08-18 03:13:58 UTC (rev 853) @@ -45,7 +45,6 @@ from athlete import Athlete from stats import Stats -from gui.windowimportdata import WindowImportdata from gui.windowmain import Main from gui.warning import Warning from lib.date import Date @@ -94,7 +93,7 @@ self.waypoint = Waypoint(data_path,self) self.extension = Extension(data_path, self) self.plugins = Plugins(data_path, self) - self.importdata = Importdata(data_path, self, self.profile) + self.importdata = Importdata(self._sport_service, data_path, self, self.profile) self.loadPlugins() self.loadExtensions() self.windowmain.setup() Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-08-18 03:13:32 UTC (rev 852) +++ pytrainer/trunk/pytrainer/record.py 2011-08-18 03:13:58 UTC (rev 853) @@ -50,10 +50,10 @@ self.recordwindow.run() logging.debug('<<') - def newMultiRecord(self, activities, list_sport): + def newMultiRecord(self, activities): logging.debug('>>') - #activities (activity_id, start_time, distance, duration, sport, gpx_file) - self.recordwindow = WindowRecord(self._equipment_service, self.data_path, list_sport, parent=self, windowTitle="Modify details before importing") + sports = self._sport_service.get_all_sports() + self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, parent=self, windowTitle="Modify details before importing") self.recordwindow.populateMultiWindow(activities) self.recordwindow.run() return self.recordwindow.getActivityData() @@ -66,19 +66,6 @@ sports = self._sport_service.get_all_sports() self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, self, None, windowTitle=_("Edit Entry"), equipment=record_equipment) self.recordwindow.setValuesFromActivity(activity) - ''' - record = self.pytrainer_main.ddbb.select("records", "id_record, date, sport, distance, time, beats, average, calories, comments, gpslog, title, upositive, unegative, maxspeed, maxpace, pace, maxbeats, date_time_utc, date_time_local", "id_record=\"%s\"" %id_record) - logging.debug('retrieving data from DB: '+str(record)) - gpxfile = self.pytrainer_main.profile.gpxdir+"/%d.gpx"%int(id_record) - logging.debug('gpx file associated: '+gpxfile) - self.recordwindow = WindowRecord(self.data_path, list_sport,self, None, windowTitle=_("Edit Entry")) - if os.path.isfile(gpxfile): - self.recordwindow.rcd_gpxfile.set_text(gpxfile) - self.recordwindow.frameGeneral.set_sensitive(0) #Currently record values not changed if a GPX file is present - self.recordwindow.frameVelocity.set_sensitive(0) #Greying out options to indicate this to user - logging.debug('sending record info to window') - self.recordwindow.setValues(record[0]) - ''' logging.debug('launching window') self.recordwindow.run() logging.debug('<<') @@ -519,18 +506,6 @@ selectrckdialog.run() logging.debug('<<') - def newGpxRecord(self,gpxfile,list_sport): #TODO Not used? - logging.debug('>>') - logging.debug("opening a new window record "+self.data_path+'|'+gpxfile+'|'+str(list_sport)) - self.recordwindow = WindowRecord(self._equipment_service, self.data_path, list_sport,self, None) - logging.debug('setting text in window '+ gpxfile) - self.recordwindow.rcd_gpxfile.set_text(gpxfile) - logging.debug('retrieving data from gpx file') - self.actualize_fromgpx(gpxfile) - logging.debug('Launching window...') - self.recordwindow.run() - logging.debug('<<') - def importFromGPX(self, gpxFile, sport): """ Add a record from a valid pytrainer type GPX file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-18 03:14:32
|
Revision: 854 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=854&view=rev Author: ncjones Date: 2011-08-18 03:14:26 +0000 (Thu, 18 Aug 2011) Log Message: ----------- Use sport service for list view sport filter. ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/listview.py pytrainer/trunk/pytrainer/main.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-18 03:13:58 UTC (rev 853) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-18 03:14:26 UTC (rev 854) @@ -57,7 +57,7 @@ class Main(SimpleGladeApp): - def __init__(self, data_path = None, parent = None, version = None, gpxDir = None): + def __init__(self, sport_service, data_path = None, parent = None, version = None, gpxDir = None): def url_hook(dialog, url): pytrainer.lib.webUtils.open_url_in_browser(url) # Available in PyGTK 2.6 and above @@ -87,7 +87,7 @@ self.y1_color = None self.y1_linewidth = 1 # setup Search ListView - self.listsearch = ListSearch(self, self.pytrainer_main) + self.listsearch = ListSearch(sport_service, self, self.pytrainer_main) self.aboutwindow = None Modified: pytrainer/trunk/pytrainer/lib/listview.py =================================================================== --- pytrainer/trunk/pytrainer/lib/listview.py 2011-08-18 03:13:58 UTC (rev 853) +++ pytrainer/trunk/pytrainer/lib/listview.py 2011-08-18 03:14:26 UTC (rev 854) @@ -17,7 +17,7 @@ } class ListSearch(object): """ Builds SQLite condition out of search parameters""" - def __init__(self, parent = None, pytrainer_main = None): + def __init__(self, sport_service, parent = None, pytrainer_main = None): self.parent = parent self.pytrainer_main = pytrainer_main self.uc = self.pytrainer_main.uc @@ -27,7 +27,7 @@ self.past = 0 self.duration = 0 self.distance = 0 - self.listSport = self.pytrainer_main.profile.getSportList() + self.listSport = sport_service.get_all_sports() self.listPast = [[_('All Time'), -99999], [_('Last 4 Weeks'), -31], [_('Last 6 Months'), -183], [_('Last 12 Months'), -366]] @@ -70,7 +70,7 @@ _search = "title like '%" +self.title + "%'" _add_and = True if self.sport > 0: - _sport = self.listSport[self.sport-1][3] + _sport = self.listSport[self.sport-1].id _here = "sport=%s" % _sport if _add_and: _search += " and " + _here @@ -130,8 +130,8 @@ #Re-add "All Sports" liststore_lsa.append([firstEntry]) #Re-add all sports in listSport - for i in self.listSport: - liststore_lsa.append([i[0]]) + for sport in self.listSport: + liststore_lsa.append([sport.name]) self.parent.lsa_sport.set_active(0) #Add handler manually, so above changes do not trigger recursive loop self.parent.lsa_sport.connect("changed", self.parent.on_listareasearch_clicked) Modified: pytrainer/trunk/pytrainer/main.py =================================================================== --- pytrainer/trunk/pytrainer/main.py 2011-08-18 03:13:58 UTC (rev 853) +++ pytrainer/trunk/pytrainer/main.py 2011-08-18 03:14:26 UTC (rev 854) @@ -88,7 +88,7 @@ pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1) self.activitypool = ActivityPool(self, size=pool_size) #preparamos la ventana principal - self.windowmain = Main(data_path,self,self.version, gpxDir=self.profile.gpxdir) + self.windowmain = Main(self._sport_service, data_path,self,self.version, gpxDir=self.profile.gpxdir) self.date = Date(self.windowmain.calendar) self.waypoint = Waypoint(data_path,self) self.extension = Extension(data_path, self) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-08-18 03:15:05
|
Revision: 855 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=855&view=rev Author: ncjones Date: 2011-08-18 03:14:59 +0000 (Thu, 18 Aug 2011) Log Message: ----------- Use sport service to load sports for graphs. ticket:138 Modified Paths: -------------- pytrainer/trunk/pytrainer/daygraph.py pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/monthgraph.py pytrainer/trunk/pytrainer/timegraph.py pytrainer/trunk/pytrainer/totalgraph.py pytrainer/trunk/pytrainer/weekgraph.py pytrainer/trunk/pytrainer/yeargraph.py Modified: pytrainer/trunk/pytrainer/daygraph.py =================================================================== --- pytrainer/trunk/pytrainer/daygraph.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/daygraph.py 2011-08-18 03:14:59 UTC (rev 855) @@ -19,8 +19,8 @@ from timegraph import TimeGraph class DayGraph(TimeGraph): - def __init__(self, vbox = None, combovalue = None): - TimeGraph.__init__(self, vbox=vbox, window=window) + def __init__(self, sports, vbox = None, combovalue = None): + TimeGraph.__init__(self, sports, vbox=vbox) self.combovalue = combovalue def drawgraph(self,values): Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-08-18 03:14:59 UTC (rev 855) @@ -58,6 +58,7 @@ class Main(SimpleGladeApp): def __init__(self, sport_service, data_path = None, parent = None, version = None, gpxDir = None): + self._sport_service = sport_service def url_hook(dialog, url): pytrainer.lib.webUtils.open_url_in_browser(url) # Available in PyGTK 2.6 and above @@ -271,12 +272,12 @@ def createGraphs(self): self.drawarearecord = RecordGraph(self.record_graph_vbox, self.window1, self.record_combovalue, self.record_combovalue2, self.btnShowLaps, self.tableConfigY1, pytrainer_main=self.pytrainer_main) self.drawareaheartrate = HeartRateGraph(self.heartrate_vbox, self.window1, self.heartrate_vbox2, pytrainer_main=self.pytrainer_main) - #self.drawareaday = DayGraph(self.day_vbox, self.day_combovalue) self.day_vbox.hide() - self.drawareaweek = WeekGraph(self.weekview, self.window1, self.week_combovalue, self.week_combovalue2, self.pytrainer_main) - self.drawareamonth = MonthGraph(self.month_vbox, self.window1, self.month_combovalue,self.month_combovalue2, self.pytrainer_main) - self.drawareayear = YearGraph(self.year_vbox, self.window1, self.year_combovalue,self.year_combovalue2, self.pytrainer_main) - self.drawareatotal = TotalGraph(self.total_vbox, self.window1, self.total_combovalue,self.total_combovalue2, self.pytrainer_main) + sports = self._sport_service.get_all_sports() + self.drawareaweek = WeekGraph(sports, self.weekview, self.window1, self.week_combovalue, self.week_combovalue2, self.pytrainer_main) + self.drawareamonth = MonthGraph(sports, self.month_vbox, self.window1, self.month_combovalue,self.month_combovalue2, self.pytrainer_main) + self.drawareayear = YearGraph(sports, self.year_vbox, self.window1, self.year_combovalue,self.year_combovalue2, self.pytrainer_main) + self.drawareatotal = TotalGraph(sports, self.total_vbox, self.window1, self.total_combovalue,self.total_combovalue2, self.pytrainer_main) def createMap(self,MapViewer,waypoint): self.waypoint = waypoint Modified: pytrainer/trunk/pytrainer/monthgraph.py =================================================================== --- pytrainer/trunk/pytrainer/monthgraph.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/monthgraph.py 2011-08-18 03:14:59 UTC (rev 855) @@ -30,8 +30,8 @@ (_("day"),_("Calories"), _("Daily Calories"),"b"), ] - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): - TimeGraph.__init__(self, vbox=vbox, window=window, main=main) + def __init__(self, sports, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): + TimeGraph.__init__(self, sports, vbox=vbox, window=window, main=main) self.combovalue = combovalue self.combovalue2 = combovalue2 self.KEY_FORMAT = "%d" Modified: pytrainer/trunk/pytrainer/timegraph.py =================================================================== --- pytrainer/trunk/pytrainer/timegraph.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/timegraph.py 2011-08-18 03:14:59 UTC (rev 855) @@ -16,15 +16,15 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import datetime, calendar +import datetime import logging from gui.drawArea import DrawArea class TimeGraph(object): - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): + def __init__(self, sports, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): self.drawarea = DrawArea(vbox, window) self.SPORT_FIELD = 9 - self.sportlist = dict([(s[0],s[5]) for s in main.profile.getSportList()]) + self.sport_colors = dict([(sport.name, sport.color.to_hex_string()) for sport in sports]) def getFloatValue(self, value): try: @@ -124,7 +124,7 @@ xlab.append(xvalues) valsAreTime.append(valuesAreTime) #Draw chart - self.drawarea.drawStackedBars(xlab,yval,ylab,tit,valsAreTime, colors = self.sportlist) + self.drawarea.drawStackedBars(xlab,yval,ylab,tit,valsAreTime, colors = self.sport_colors) def get_value_params(self,value): return self.value_params[value] Modified: pytrainer/trunk/pytrainer/totalgraph.py =================================================================== --- pytrainer/trunk/pytrainer/totalgraph.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/totalgraph.py 2011-08-18 03:14:59 UTC (rev 855) @@ -28,8 +28,8 @@ (_("year"),_("Calories"), _("Annual Calories"),"b"), ] - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): - TimeGraph.__init__(self, vbox=vbox, window=window, main=main) + def __init__(self, sports, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): + TimeGraph.__init__(self, sports, vbox=vbox, window=window, main=main) self.combovalue = combovalue self.combovalue2 = combovalue2 self.KEY_FORMAT = "%Y" Modified: pytrainer/trunk/pytrainer/weekgraph.py =================================================================== --- pytrainer/trunk/pytrainer/weekgraph.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/weekgraph.py 2011-08-18 03:14:59 UTC (rev 855) @@ -32,8 +32,8 @@ (None, _("Calories"), _("Daily Calories"), None), ] - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): - TimeGraph.__init__(self, vbox=vbox, window=window, main=main) + def __init__(self, sports, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): + TimeGraph.__init__(self, sports, vbox=vbox, window=window, main=main) self.combovalue = combovalue self.combovalue2 = combovalue2 self.KEY_FORMAT = "%a" Modified: pytrainer/trunk/pytrainer/yeargraph.py =================================================================== --- pytrainer/trunk/pytrainer/yeargraph.py 2011-08-18 03:14:26 UTC (rev 854) +++ pytrainer/trunk/pytrainer/yeargraph.py 2011-08-18 03:14:59 UTC (rev 855) @@ -30,8 +30,8 @@ (_("month"),_("Calories"), _("Monthly Calories"),"b"), ] - def __init__(self, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): - TimeGraph.__init__(self, vbox=vbox, window=window, main=main) + def __init__(self, sports, vbox = None, window = None, combovalue = None, combovalue2 = None, main = None): + TimeGraph.__init__(self, sports, vbox=vbox, window=window, main=main) self.combovalue = combovalue self.combovalue2 = combovalue2 self.KEY_FORMAT = "%m" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2011-08-28 16:01:06
|
Revision: 867 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=867&view=rev Author: dgranda Date: 2011-08-28 16:00:59 +0000 (Sun, 28 Aug 2011) Log Message: ----------- Using normal way of import for new GPX based activities - ticket:137, ticket:105 Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/lib/gpx.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2011-08-28 11:39:59 UTC (rev 866) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2011-08-28 16:00:59 UTC (rev 867) @@ -289,9 +289,8 @@ if self.mode == "newrecord": logging.debug('Track data: '+str(list_options)) if list_options["rcd_gpxfile"] != "": - logging.info('Adding new activity based on GPX file') - trackSummary=(list_options["rcd_sport"],"","") - self.parent.insertNewRecord(list_options["rcd_gpxfile"], trackSummary) + logging.info('Adding new activity based on GPX file') + self.parent.insertRecord(list_options, None, selected_equipment_ids) else: logging.info('Adding new activity based on provided data') #Manual entry, calculate time info Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2011-08-28 11:39:59 UTC (rev 866) +++ pytrainer/trunk/pytrainer/lib/activity.py 2011-08-28 16:00:59 UTC (rev 867) @@ -219,7 +219,8 @@ self.gpx_distance = self.gpx.total_dist logging.info("GPX Distance: %s | distance (trkpts): %s | duration: %s | duration (trkpts): %s" % (self.gpx_distance, self.gpx.total_dist_trkpts, self.gpx.total_time, self.gpx.total_time_trkpts)) time_diff = self.gpx.total_time_trkpts - self.gpx.total_time - if time_diff > 10: + acceptable_lapse = 4 # number of seconds that duration calculated using lap and trkpts data can differ + if time_diff > acceptable_lapse: self.time_pause = time_diff logging.debug("Identified non active time: %s s" % self.time_pause) logging.debug("<<") Modified: pytrainer/trunk/pytrainer/lib/gpx.py =================================================================== --- pytrainer/trunk/pytrainer/lib/gpx.py 2011-08-28 11:39:59 UTC (rev 866) +++ pytrainer/trunk/pytrainer/lib/gpx.py 2011-08-28 16:00:59 UTC (rev 867) @@ -75,6 +75,7 @@ self.maxhr = 0 self.hr_average = 0 self.date = "" + self.start_time = "" #self.Date = Date() self.calories= 0 self.tree = None @@ -129,6 +130,7 @@ timeResult = trk.find(timeTag) if timeResult is not None: time_ = timeResult.text # check timezone + logging.debug("TimeResult: %s" %time_) mk_time = self.getDateTime(time_)[0] time_ = mk_time.strftime("%Y-%m-%d") else: @@ -152,6 +154,9 @@ def getCalories(self): return self.calories + def getStart_time(self): + return self.start_time + def getLaps(self): logging.debug(">>") lapInfo = [] @@ -228,7 +233,7 @@ logging.info("Lap distance: %s m | Duration: %s s | Calories: %s kcal" % (lapDistance, lapDuration, lapCalories)) self.total_dist = float(totalDistance/1000.0) # Returning km self.total_time = int(totalDuration) # Returning seconds - logging.info("Distance: %.02f km | Duration: %d s | Calories: %s kcal" % (self.total_dist, self.total_time, self.calories)) + logging.info("Laps - Distance: %.02f km | Duration: %d s | Calories: %s kcal" % (self.total_dist, self.total_time, self.calories)) else: laps = [] @@ -255,9 +260,10 @@ else: mk_time = self.getDateTime(date_)[1] #Local Date self.date = mk_time.strftime("%Y-%m-%d") + self.start_time = mk_time.strftime("%H:%M:%S") waiting_points = [] + logging.debug("date: %s | start_time: %s | mk_time: %s" % (self.date, self.start_time, mk_time)) - for i, trkpoint in enumerate(trkpoints): #Get data from trkpoint try: @@ -297,7 +303,7 @@ else: time_elapsed = time_ - self.trkpoints[i-1]['time'] if self.trkpoints[i-1]['time'] is not None else 0 self.total_time_trkpts += time_elapsed - if time_elapsed > 10: + if time_elapsed > 5: logging.debug("Adding %d seconds from last trkpt, someone took a break!" % time_elapsed) else: time_ = None @@ -403,12 +409,13 @@ self.total_dist = self.total_dist_trkpts else: dist_diff = 1000*(self.total_dist_trkpts - self.total_dist) - logging.info("Distance difference between laps and trkpts calculation: %f m" % dist_diff) + logging.debug("Distance difference between laps and trkpts calculation: %f m" % dist_diff) if self.total_time is None or self.total_time == 0: self.total_time = self.total_time_trkpts else: time_diff = self.total_time_trkpts - self.total_time - logging.info("Duration difference between laps and trkpts calculation: %d s" % time_diff) + logging.debug("Duration difference between laps and trkpts calculation: %d s" % time_diff) + logging.info("Values - Distance: %.02f km | Duration: %d s | Calories: %s kcal" % (self.total_dist, self.total_time, self.calories)) logging.debug("<<") return retorno Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-08-28 11:39:59 UTC (rev 866) +++ pytrainer/trunk/pytrainer/record.py 2011-08-28 16:00:59 UTC (rev 867) @@ -53,7 +53,7 @@ def newMultiRecord(self, activities): logging.debug('>>') sports = self._sport_service.get_all_sports() - self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, parent=self, windowTitle="Modify details before importing") + self.recordwindow = WindowRecord(self._equipment_service, self.data_path, sports, parent=self, windowTitle=_("Modify details before importing")) self.recordwindow.populateMultiWindow(activities) self.recordwindow.run() return self.recordwindow.getActivityData() @@ -476,8 +476,10 @@ heartrate = gpx.getHeartRateAverage() date = gpx.getDate() calories = gpx.getCalories() + start_time = gpx.getStart_time() self.recordwindow.rcd_date.set_text(date) + self.recordwindow.rcd_starttime.set_text(start_time) self.recordwindow.rcd_upositive.set_text(str(upositive)) self.recordwindow.rcd_unegative.set_text(str(unegative)) self.recordwindow.rcd_beats.set_text(str(heartrate)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-09-07 14:21:06
|
Revision: 881 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=881&view=rev Author: ncjones Date: 2011-09-07 14:20:53 +0000 (Wed, 07 Sep 2011) Log Message: ----------- Allow records with null sport reference to be edited. ticket:147 Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/activity.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/lib/activity.py =================================================================== --- pytrainer/trunk/pytrainer/lib/activity.py 2011-09-07 13:42:02 UTC (rev 880) +++ pytrainer/trunk/pytrainer/lib/activity.py 2011-09-07 14:20:53 UTC (rev 881) @@ -231,35 +231,39 @@ ''' logging.debug(">>") #Get base information - db_result = self.pytrainer_main.ddbb.select_dict("records,sports", - ("sports.name","id_sports", "date","distance","time","beats","comments", + cols = ("sports.name","id_sports", "date","distance","time","beats","comments", "average","calories","id_record","title","upositive","unegative", - "maxspeed","maxpace","pace","maxbeats","date_time_utc","date_time_local", "sports.max_pace"), - "id_record=\"%s\" and records.sport=sports.id_sports" %self.id) + "maxspeed","maxpace","pace","maxbeats","date_time_utc","date_time_local", "sports.max_pace") + # outer join on sport id to workaround bug where sport reference is null on records from GPX import + db_result = self.pytrainer_main.ddbb.select("records left outer join sports on records.sport=sports.id_sports", + ", ".join(cols), + "id_record=\"%s\" " %self.id) if len(db_result) == 1: - _dict = db_result[0] - self.sport_name = _dict['sports.name'] - self.sport_id = _dict['id_sports'] - self.pace_limit = _dict['sports.max_pace'] + row = db_result[0] + self.sport_name = row[cols.index('sports.name')] + if self.sport_name == None: + self.sport_name = "" + self.sport_id = row[cols.index('id_sports')] + self.pace_limit = row[cols.index('sports.max_pace')] if self.pace_limit == 0 or self.pace_limit == "": self.pace_limit = None - self.title = _dict['title'] + self.title = row[cols.index('title')] if self.title is None: self.title = "" - self.date = _dict['date'] - self.time = self._int(_dict['time']) + self.date = row[cols.index('date')] + self.time = self._int(row[cols.index('time')]) self.time_tuple = Date().second2time(self.time) - self.beats = self._int(_dict['beats']) - self.comments = _dict['comments'] + self.beats = self._int(row[cols.index('beats')]) + self.comments = row[cols.index('comments')] if self.comments is None: self.comments = "" - self.calories = self._int(_dict['calories']) - self.id_record = _dict['id_record'] - self.maxbeats = self._int(_dict['maxbeats']) + self.calories = self._int(row[cols.index('calories')]) + self.id_record = row[cols.index('id_record')] + self.maxbeats = self._int(row[cols.index('maxbeats')]) #Sort time.... # ... use local time if available otherwise use date_time_utc and create a local datetime... - self.date_time_local = _dict['date_time_local'] - self.date_time_utc = _dict['date_time_utc'] + self.date_time_local = row[cols.index('date_time_local')] + self.date_time_utc = row[cols.index('date_time_utc')] if self.date_time_local is not None: #Have a local time stored in DB self.date_time = dateutil.parser.parse(self.date_time_local) self.starttime = self.date_time.strftime("%X") @@ -269,23 +273,23 @@ self.starttime = self.date_time.strftime("%X") #Sort data that changes for the US etc #if self.us_system: - # self.distance = km2miles(self._float(_dict['distance'])) - # self.average = km2miles(self._float(_dict['average'])) - # self.upositive = m2feet(self._float(_dict['upositive'])) - # self.unegative = m2feet(self._float(_dict['unegative'])) - # self.maxspeed = km2miles(self._float(_dict['maxspeed'])) - # self.maxpace = pacekm2miles(self._float(_dict['maxpace'])) - # self.pace = pacekm2miles(self._float(_dict['pace'])) + # self.distance = km2miles(self._float(row[cols.index('distance')])) + # self.average = km2miles(self._float(row[cols.index('average')])) + # self.upositive = m2feet(self._float(row[cols.index('upositive')])) + # self.unegative = m2feet(self._float(row[cols.index('unegative')])) + # self.maxspeed = km2miles(self._float(row[cols.index('maxspeed')])) + # self.maxpace = pacekm2miles(self._float(row[cols.index('maxpace')])) + # self.pace = pacekm2miles(self._float(row[cols.index('pace')])) #else: - self.distance = self._float(_dict['distance']) + self.distance = self._float(row[cols.index('distance')]) if not self.distance: self.distance = self.gpx_distance - self.average = self._float(_dict['average']) - self.upositive = self._float(_dict['upositive']) - self.unegative = self._float(_dict['unegative']) - self.maxspeed = self._float(_dict['maxspeed']) - self.maxpace = self._float(_dict['maxpace']) - self.pace = self._float(_dict['pace']) + self.average = self._float(row[cols.index('average')]) + self.upositive = self._float(row[cols.index('upositive')]) + self.unegative = self._float(row[cols.index('unegative')]) + self.maxspeed = self._float(row[cols.index('maxspeed')]) + self.maxpace = self._float(row[cols.index('maxpace')]) + self.pace = self._float(row[cols.index('pace')]) self.has_data = True else: raise Exception( "Error - multiple results from DB for id: %s" % self.id ) Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-09-07 13:42:02 UTC (rev 880) +++ pytrainer/trunk/pytrainer/record.py 2011-09-07 14:20:53 UTC (rev 881) @@ -301,9 +301,10 @@ def getrecordList(self,date, id_sport=None): logging.debug('--') if not id_sport: - return self.pytrainer_main.ddbb.select("records,sports", + # outer join on sport id to workaround bug where sport reference is null on records from GPX import + return self.pytrainer_main.ddbb.select("records left outer join sports on records.sport=sports.id_sports", "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local,upositive,unegative", - "date=\"%s\" and records.sport=sports.id_sports" %date) + "date=\"%s\" " %date) else: return self.pytrainer_main.ddbb.select("records,sports", "sports.name,date,distance,time,beats,comments,average,calories,id_record,maxspeed,maxbeats,date_time_utc,date_time_local,upositive,unegative", This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-10-22 07:41:41
|
Revision: 899 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=899&view=rev Author: ncjones Date: 2011-10-22 07:41:34 +0000 (Sat, 22 Oct 2011) Log Message: ----------- Fix data migration from 1.7.1 - 1.7.2 ticket:132 Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py Added Paths: ----------- pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py Removed Paths: ------------- pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2011-10-21 17:09:03 UTC (rev 898) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2011-10-22 07:41:34 UTC (rev 899) @@ -344,7 +344,6 @@ #Run any functions to update or correct data #These functions _must_ be safe to run at any time (i.e. not be version specfic or only safe to run once) self.populate_date_time_local() - self.populate_duration_from_time() self.add_lap_metadata() logging.debug('<<') @@ -355,55 +354,6 @@ for table in tablesList.keys(): pass - def populate_duration_from_time(self): - ''' - Populate duration from time field - only for time can be parsed as an int - - also check pace value - ''' - logging.debug('--') - #listOfRecords = self.select_dict("records",('id_record','time'), "duration is NULL") - #logging.debug("Found %d records in DB without date_time_local field populated" % (len(listOfRecords) ) ) - listOfRecords = self.select_dict("records",('id_record','time', 'duration', 'pace', 'average', 'maxspeed', 'maxpace')) - logging.debug("Found %d records in DB" % (len(listOfRecords) ) ) - for record in listOfRecords: - data = {} - try: - duration = int(record['time']) - except Exception as e: - logging.info( "Error parsing time (%s) as int for record_id: %s" % (record['time'], record['id_record'])) - continue - if duration != record['duration']: - logging.debug("setting record %s duration to %d" % (record['id_record'], duration)) - data['duration'] = duration - #Check pace - try: - db_avg_speed = float(record['average']) #km/hr - db_pace = float(record['pace']) #min/km - db_max_speed = float(record['maxspeed']) - db_max_pace = float(record['maxpace']) - calc_pace = 60 / db_avg_speed - calc_max_pace = 60 / db_max_speed - #Update DB if db_pace != calc_pace - if "%.2f" % db_pace != "%.2f" % calc_pace: - print "DB Pace: %.2f, Calc: %.2f" % (db_pace, calc_pace) - #data['pace'] = calc_pace - else: - print "Pace ok: %.2f" % db_pace - #Update DB if db_max_pace != calc_max_pace - if "%.2f" % db_max_pace != "%.2f" % calc_max_pace: - print "DB Max Pace: %.2f, Calc: %.2f" % (db_max_pace, calc_max_pace) - #data['max_pace'] = calc_max_pace - else: - print "Max pace ok: %.2f" % db_max_pace - except Exception as e: - #print type(e), e - logging.debug("Error with converting pace (%s), average speed(%s), max speed (%s), max pace(%s)" % (record['pace'], record['average'], record['maxspeed'], record['maxpace'])) - #Update DB if any changes - if len(data) > 0: - self.update_dict("records",data ,"id_record = %d"%record['id_record']) - def populate_date_time_local(self): ''' Populate date_time_local and date from date_time_utc only access records that date_time_local is NULL Added: pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py 2011-10-22 07:41:34 UTC (rev 899) @@ -0,0 +1,40 @@ +from sqlalchemy import MetaData, Table, Column, Integer +from sqlalchemy.sql.expression import text +import logging + +# record duration added in version 1.7.2 + +def upgrade(migrate_engine): + add_duration_column(migrate_engine) + populate_duration_values(migrate_engine) + +def add_duration_column(migrate_engine): + logging.info("Adding records.duration column") + meta = MetaData(migrate_engine) + records_table = Table("records", meta, autoload=True) + duration_column = Column("duration", Integer) + duration_column.create(records_table) + logging.info("Created records.duration column") + +def populate_duration_values(migrate_engine): + logging.info("Populating records.duration column") + records = migrate_engine.execute("select id_record, time from records where duration is null") + for record in records: + record_id = record["id_record"] + record_time = record["time"] + try: + duration = int(record_time) + except: + logging.info("Error parsing time (%s) as int for record_id: %s" % (record_time, record_id)) + duration = 0 + logging.debug("setting record %s duration to %d" , record_id, duration) + migrate_engine.execute(text("update records set duration=:duration where id_record=:record_id"), duration=duration, record_id=record_id) + records.close() + +# work around a migrate bug +try: + import migrate.versioning.exceptions as ex1 + import migrate.changeset.exceptions as ex2 + ex1.MigrateDeprecationWarning = ex2.MigrateDeprecationWarning +except ImportError: + pass Deleted: pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql 2011-10-21 17:09:03 UTC (rev 898) +++ pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql 2011-10-22 07:41:34 UTC (rev 899) @@ -1,2 +0,0 @@ --- record duration added in version 1.7.2 -alter table records add duration integer; \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-10-23 11:09:44
|
Revision: 902 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=902&view=rev Author: ncjones Date: 2011-10-23 11:09:38 +0000 (Sun, 23 Oct 2011) Log Message: ----------- Incorporate lap data migration into upgrade script. ticket:132 Modified Paths: -------------- pytrainer/trunk/pytrainer/lib/ddbb.py Added Paths: ----------- pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py Removed Paths: ------------- pytrainer/trunk/pytrainer/upgrade/versions/009_default_upgrade.sql Modified: pytrainer/trunk/pytrainer/lib/ddbb.py =================================================================== --- pytrainer/trunk/pytrainer/lib/ddbb.py 2011-10-23 11:09:12 UTC (rev 901) +++ pytrainer/trunk/pytrainer/lib/ddbb.py 2011-10-23 11:09:38 UTC (rev 902) @@ -23,7 +23,6 @@ import traceback import commands, os import dateutil -import gpx from pytrainer.lib.date import Date #Define the tables and their columns that should be in the database @@ -344,7 +343,6 @@ #Run any functions to update or correct data #These functions _must_ be safe to run at any time (i.e. not be version specfic or only safe to run once) self.populate_date_time_local() - self.add_lap_metadata() logging.debug('<<') def checkDBDataValues(self): @@ -390,21 +388,3 @@ print e logging.debug("Error updating record: " + str(record)) logging.debug(str(e)) - - def add_lap_metadata(self): - logging.debug('--') - record_ids = set([r[0] for r in self.select("laps","record")]) - for record in record_ids: - try: - laps = self.select("laps","id_lap, intensity, avg_hr, max_hr, max_speed, laptrigger", "record = %s" % record) - gpxfile = self.configuration.gpxdir+"/%s.gpx"%(record) - if not laps[0][1] and os.path.isfile(gpxfile) : #GPX file exists for this record - probably not a manual record - gpxrecord = gpx.Gpx(filename=gpxfile) - for lap, gpxlap in zip(laps, gpxrecord.getLaps()): - self.ddbbObject.update("laps", "intensity, avg_hr, max_hr, max_speed, laptrigger", (gpxlap[7], gpxlap[8], gpxlap[9], gpxlap[10], "%s" % gpxlap[11]), "id_lap = %d" % lap[0]) - except Exception as e: - print "Error updating record: " + str(record) - print e - logging.debug("Error updating record: " + str(record)) - logging.debug(str(e)) - Added: pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py 2011-10-23 11:09:38 UTC (rev 902) @@ -0,0 +1,77 @@ +from pytrainer.upgrade.context import UPGRADE_CONTEXT +from pytrainer.lib import gpx +from sqlalchemy import MetaData, Table, Column +from sqlalchemy.types import Integer, Text, Float, String +from sqlalchemy.sql.expression import text +import logging +import os.path + +# lap info added in version 1.9.0 +def upgrade(migrate_engine): + add_lap_details_columns(migrate_engine) + populate_lap_details_values(migrate_engine) + +def add_lap_details_columns(migrate_engine): + logging.info("Adding laps details columns") + meta = MetaData(migrate_engine) + laps_table = Table("laps", meta, autoload=True) + create_laps_column(laps_table, "intensity", String(7)) + create_laps_column(laps_table, "laptrigger", String(9)) + create_laps_column(laps_table, "max_speed", Float) + create_laps_column(laps_table, "avg_hr" , Integer) + create_laps_column(laps_table, "max_hr", Integer) + create_laps_column(laps_table, "comments", Text) + logging.info("Created laps details columns") + +def create_laps_column(laps_table, column_name, column_type): + logging.info("Adding column laps.%s" , column_name) + column = Column(column_name, column_type) + laps_table.create(column) + +def populate_lap_details_values(migrate_engine): + logging.info("Populating laps details columns") + resultset = migrate_engine.execute(text("select distinct record from laps where intensity is null")) + record_ids = [] + for row in resultset: + record_ids.append(row["record"]) + resultset.close() + for record_id in record_ids: + gpx_file = UPGRADE_CONTEXT.conf_dir + "/gpx/{0}.gpx".format(record_id) + if os.path.isfile(gpx_file): + gpx_record = gpx.Gpx(filename=gpx_file) + populate_laps_from_gpx(migrate_engine, record_id, gpx_record) + +def populate_laps_from_gpx(migrate_engine, record_id, gpx_record): + resultset = migrate_engine.execute(text("select id_lap from laps where record=:record_id" ), record_id=record_id) + lap_ids = [] + for row in resultset: + lap_ids.append(row["id_lap"]) + resultset.close() + if(len(lap_ids) > 0): + logging.info("Populating laps from GPX for record %s" , record_id) + for lap_id, gpx_lap in zip(lap_ids, gpx_record.getLaps()): + populate_lap_from_gpx(migrate_engine, lap_id, gpx_lap) + +def populate_lap_from_gpx(migrate_engine, lap_id, gpx_lap): + logging.info("Populating lap details from GPX for lap %s" , lap_id) + migrate_engine.execute(text("""update laps set + intensity=:intensity, + avg_hr=:avg_heart_rate, + max_hr=:max_heart_rate, + max_speed=:max_speed, + laptrigger=:lap_trigger + where id_lap=:lap_id"""), + intensity=gpx_lap[7], + avg_heart_rate=gpx_lap[8], + max_heart_rate=gpx_lap[9], + max_speed=float(gpx_lap[10]), + lap_trigger=gpx_lap[11], + lap_id=lap_id) + +# work around a migrate bug +try: + import migrate.versioning.exceptions as ex1 + import migrate.changeset.exceptions as ex2 + ex1.MigrateDeprecationWarning = ex2.MigrateDeprecationWarning +except ImportError: + pass Deleted: pytrainer/trunk/pytrainer/upgrade/versions/009_default_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/009_default_upgrade.sql 2011-10-23 11:09:12 UTC (rev 901) +++ pytrainer/trunk/pytrainer/upgrade/versions/009_default_upgrade.sql 2011-10-23 11:09:38 UTC (rev 902) @@ -1,7 +0,0 @@ --- lap info added in version 1.9.0 -alter table laps add intensity varchar(7); -alter table laps add laptrigger varchar(9); -alter table laps add max_speed float; -alter table laps add avg_hr int; -alter table laps add max_hr int; -alter table laps add comments text; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nc...@us...> - 2011-10-23 12:17:29
|
Revision: 906 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=906&view=rev Author: ncjones Date: 2011-10-23 12:17:22 +0000 (Sun, 23 Oct 2011) Log Message: ----------- Split "add" and "populate" upgrade operations into separate scripts. ticket:132 Modified Paths: -------------- pytrainer/trunk/pytrainer/upgrade/data.py pytrainer/trunk/pytrainer/upgrade/versions/008_mysql_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/008_sqlite_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/010_default_upgrade.sql Added Paths: ----------- pytrainer/trunk/pytrainer/test/upgrade/versions/version014_test.py pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/007_populate_record_duration.py pytrainer/trunk/pytrainer/upgrade/versions/009_mysql_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/009_sqlite_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/011_populate_lap_details.py pytrainer/trunk/pytrainer/upgrade/versions/012_default_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/013_remove_db_version.py pytrainer/trunk/pytrainer/upgrade/versions/014_clean_sport_data.py pytrainer/trunk/pytrainer/upgrade/versions/version014.py Removed Paths: ------------- pytrainer/trunk/pytrainer/test/upgrade/versions/version012_test.py pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py pytrainer/trunk/pytrainer/upgrade/versions/007_mysql_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/007_sqlite_upgrade.sql pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py pytrainer/trunk/pytrainer/upgrade/versions/011_remove_db_version.py pytrainer/trunk/pytrainer/upgrade/versions/012_clean_sport_data.py pytrainer/trunk/pytrainer/upgrade/versions/version012.py Deleted: pytrainer/trunk/pytrainer/test/upgrade/versions/version012_test.py =================================================================== --- pytrainer/trunk/pytrainer/test/upgrade/versions/version012_test.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/test/upgrade/versions/version012_test.py 2011-10-23 12:17:22 UTC (rev 906) @@ -1,81 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -#Copyright (C) Nathan Jones nc...@us... - -#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. - -import unittest -import sqlalchemy -import pytrainer.upgrade.versions.version012 as version012 - -class UpgradeTest(unittest.TestCase): - - def setUp(self): - self._engine = sqlalchemy.create_engine("sqlite:///:memory:") - self._metadata = sqlalchemy.MetaData() - self._metadata.bind = self._engine - self._sports_table = sqlalchemy.Table("sports", self._metadata, - sqlalchemy.Column("id_sports", sqlalchemy.Integer, primary_key=True), - sqlalchemy.Column("name", sqlalchemy.String(100)), - sqlalchemy.Column("weight", sqlalchemy.Float), - sqlalchemy.Column("color", sqlalchemy.String(6)), - sqlalchemy.Column("met", sqlalchemy.Float), - sqlalchemy.Column("max_pace", sqlalchemy.Integer) - ) - self._metadata.drop_all() - self._metadata.create_all() - - def upgradeAndAssert(self, original, expected): - self._engine.execute(sqlalchemy.text("insert into sports (id_sports, name, weight, color, met, max_pace)" - " values (:id, :name, :weight, :color, :met, :max_pace)"), - id= 1, - name= "Test Sport", - weight= original["weight"], - color= original["color"], - met= original["met"], - max_pace= original["max_pace"]) - version012.upgrade(self._engine) - result = self._engine.execute(self._sports_table.select(self._sports_table.c.id_sports==1)) - (_, _, weight, color, met, max_pace) = result.fetchone() - result.close() - self.assertEqual(expected["weight"], weight) - self.assertEqual(expected["color"], color) - self.assertEqual(expected["met"], met) - self.assertEqual(expected["max_pace"], max_pace) - - def testUpgradeFromNullValues(self): - original = { "weight": None, "color": None, "met": None, "max_pace": None } - expected = { "weight": 0.0, "color": "0000ff", "met": None, "max_pace": None } - self.upgradeAndAssert(original, expected) - - def testUpgradeFromZeroValues(self): - original = { "weight": 0, "color": 0, "met": 0, "max_pace": 0 } - expected = { "weight": 0.0, "color": "0", "met": 0, "max_pace": None } - self.upgradeAndAssert(original, expected) - - def testUpgradeFromEmptyValues(self): - original = { "weight": "", "color": "", "met": "", "max_pace": "" } - expected = { "weight": 0.0, "color": "0000ff", "met": None, "max_pace": None } - self.upgradeAndAssert(original, expected) - - def testUpgradeFromNegativeValues(self): - original = { "weight": -1, "color": -1, "met": -1, "max_pace": -1 } - expected = { "weight": 0.0, "color": "-1", "met": None, "max_pace": None } - self.upgradeAndAssert(original, expected) - - def testUpgradeFromValidValues(self): - original = { "weight": 3.4, "color": "abc123", "met": 45.6, "max_pace": 123 } - expected = { "weight": 3.4, "color": "abc123", "met": 45.6, "max_pace": 123 } - self.upgradeAndAssert(original, expected) Copied: pytrainer/trunk/pytrainer/test/upgrade/versions/version014_test.py (from rev 905, pytrainer/trunk/pytrainer/test/upgrade/versions/version012_test.py) =================================================================== --- pytrainer/trunk/pytrainer/test/upgrade/versions/version014_test.py (rev 0) +++ pytrainer/trunk/pytrainer/test/upgrade/versions/version014_test.py 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,81 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +import unittest +import sqlalchemy +import pytrainer.upgrade.versions.version014 as version014 + +class UpgradeTest(unittest.TestCase): + + def setUp(self): + self._engine = sqlalchemy.create_engine("sqlite:///:memory:") + self._metadata = sqlalchemy.MetaData() + self._metadata.bind = self._engine + self._sports_table = sqlalchemy.Table("sports", self._metadata, + sqlalchemy.Column("id_sports", sqlalchemy.Integer, primary_key=True), + sqlalchemy.Column("name", sqlalchemy.String(100)), + sqlalchemy.Column("weight", sqlalchemy.Float), + sqlalchemy.Column("color", sqlalchemy.String(6)), + sqlalchemy.Column("met", sqlalchemy.Float), + sqlalchemy.Column("max_pace", sqlalchemy.Integer) + ) + self._metadata.drop_all() + self._metadata.create_all() + + def upgradeAndAssert(self, original, expected): + self._engine.execute(sqlalchemy.text("insert into sports (id_sports, name, weight, color, met, max_pace)" + " values (:id, :name, :weight, :color, :met, :max_pace)"), + id= 1, + name= "Test Sport", + weight= original["weight"], + color= original["color"], + met= original["met"], + max_pace= original["max_pace"]) + version014.upgrade(self._engine) + result = self._engine.execute(self._sports_table.select(self._sports_table.c.id_sports==1)) + (_, _, weight, color, met, max_pace) = result.fetchone() + result.close() + self.assertEqual(expected["weight"], weight) + self.assertEqual(expected["color"], color) + self.assertEqual(expected["met"], met) + self.assertEqual(expected["max_pace"], max_pace) + + def testUpgradeFromNullValues(self): + original = { "weight": None, "color": None, "met": None, "max_pace": None } + expected = { "weight": 0.0, "color": "0000ff", "met": None, "max_pace": None } + self.upgradeAndAssert(original, expected) + + def testUpgradeFromZeroValues(self): + original = { "weight": 0, "color": 0, "met": 0, "max_pace": 0 } + expected = { "weight": 0.0, "color": "0", "met": 0, "max_pace": None } + self.upgradeAndAssert(original, expected) + + def testUpgradeFromEmptyValues(self): + original = { "weight": "", "color": "", "met": "", "max_pace": "" } + expected = { "weight": 0.0, "color": "0000ff", "met": None, "max_pace": None } + self.upgradeAndAssert(original, expected) + + def testUpgradeFromNegativeValues(self): + original = { "weight": -1, "color": -1, "met": -1, "max_pace": -1 } + expected = { "weight": 0.0, "color": "-1", "met": None, "max_pace": None } + self.upgradeAndAssert(original, expected) + + def testUpgradeFromValidValues(self): + original = { "weight": 3.4, "color": "abc123", "met": 45.6, "max_pace": 123 } + expected = { "weight": 3.4, "color": "abc123", "met": 45.6, "max_pace": 123 } + self.upgradeAndAssert(original, expected) Modified: pytrainer/trunk/pytrainer/upgrade/data.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/data.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/data.py 2011-10-23 12:17:22 UTC (rev 906) @@ -115,13 +115,13 @@ elif legacy_version == 5: # 1.8.0-dev return 5 elif legacy_version == 6: # 1.8.0 - return 8 + return 9 elif legacy_version == 7: # 1.9.0-dev - return 9 + return 10 elif legacy_version == 8: # 1.9.0-dev - return 10 + return 12 elif legacy_version == 9: # 1.9.0-dev - return 10 + return 12 return None def get_available_version(self): Deleted: pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py 2011-10-23 12:17:22 UTC (rev 906) @@ -1,40 +0,0 @@ -from sqlalchemy import MetaData, Table, Column, Integer -from sqlalchemy.sql.expression import text -import logging - -# record duration added in version 1.8.0 - -def upgrade(migrate_engine): - add_duration_column(migrate_engine) - populate_duration_values(migrate_engine) - -def add_duration_column(migrate_engine): - logging.info("Adding records.duration column") - meta = MetaData(migrate_engine) - records_table = Table("records", meta, autoload=True) - duration_column = Column("duration", Integer) - duration_column.create(records_table) - logging.info("Created records.duration column") - -def populate_duration_values(migrate_engine): - logging.info("Populating records.duration column") - records = migrate_engine.execute("select id_record, time from records where duration is null") - for record in records: - record_id = record["id_record"] - record_time = record["time"] - try: - duration = int(record_time) - except: - logging.info("Error parsing time (%s) as int for record_id: %s" % (record_time, record_id)) - duration = 0 - logging.debug("setting record %s duration to %d" , record_id, duration) - migrate_engine.execute(text("update records set duration=:duration where id_record=:record_id"), duration=duration, record_id=record_id) - records.close() - -# work around a migrate bug -try: - import migrate.versioning.exceptions as ex1 - import migrate.changeset.exceptions as ex2 - ex1.MigrateDeprecationWarning = ex2.MigrateDeprecationWarning -except ImportError: - pass Added: pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/006_default_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,2 @@ +-- record duration added in version 1.8.0 +alter table records add duration integer; \ No newline at end of file Deleted: pytrainer/trunk/pytrainer/upgrade/versions/007_mysql_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/007_mysql_upgrade.sql 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/007_mysql_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -1,4 +0,0 @@ --- record date_time data type changed in version 1.8.0 -alter table records - modify date_time_local varchar(40), - modify date_time_utc varchar(40); \ No newline at end of file Copied: pytrainer/trunk/pytrainer/upgrade/versions/007_populate_record_duration.py (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/006_add_record_duration.py) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/007_populate_record_duration.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/007_populate_record_duration.py 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,27 @@ +from sqlalchemy.sql.expression import text +import logging + +# record duration added in version 1.8.0 + +def upgrade(migrate_engine): + logging.info("Populating records.duration column") + records = migrate_engine.execute("select id_record, time from records where duration is null") + for record in records: + record_id = record["id_record"] + record_time = record["time"] + try: + duration = int(record_time) + except: + logging.info("Error parsing time (%s) as int for record_id: %s" % (record_time, record_id)) + duration = 0 + logging.debug("setting record %s duration to %d" , record_id, duration) + migrate_engine.execute(text("update records set duration=:duration where id_record=:record_id"), duration=duration, record_id=record_id) + records.close() + +# work around a migrate bug +try: + import migrate.versioning.exceptions as ex1 + import migrate.changeset.exceptions as ex2 + ex1.MigrateDeprecationWarning = ex2.MigrateDeprecationWarning +except ImportError: + pass Deleted: pytrainer/trunk/pytrainer/upgrade/versions/007_sqlite_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/007_sqlite_upgrade.sql 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/007_sqlite_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -1 +0,0 @@ --- data type change does not affect sqlite schema \ No newline at end of file Modified: pytrainer/trunk/pytrainer/upgrade/versions/008_mysql_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/008_mysql_upgrade.sql 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/008_mysql_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -1,16 +1,4 @@ --- equipment management added in version 1.8.0 - -create table equipment ( - id integer primary key auto_increment , - description varchar(200), - active boolean, - life_expectancy int, - prior_usage int, - notes text -); - -create table record_equipment ( - id integer primary key auto_increment, - record_id int, - equipment_id int -); +-- record date_time data type changed in version 1.8.0 +alter table records + modify date_time_local varchar(40), + modify date_time_utc varchar(40); \ No newline at end of file Modified: pytrainer/trunk/pytrainer/upgrade/versions/008_sqlite_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/008_sqlite_upgrade.sql 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/008_sqlite_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -1,16 +1 @@ --- equipment management added in version 1.8.0 - -create table equipment ( - id integer primary key autoincrement , - description varchar(200), - active boolean, - life_expectancy int, - prior_usage int, - notes text -); - -create table record_equipment ( - id integer primary key autoincrement, - record_id int, - equipment_id int -); +-- data type change does not affect sqlite schema \ No newline at end of file Deleted: pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py 2011-10-23 12:17:22 UTC (rev 906) @@ -1,77 +0,0 @@ -from pytrainer.upgrade.context import UPGRADE_CONTEXT -from pytrainer.lib import gpx -from sqlalchemy import MetaData, Table, Column -from sqlalchemy.types import Integer, Text, Float, String -from sqlalchemy.sql.expression import text -import logging -import os.path - -# lap info added in version 1.9.0 -def upgrade(migrate_engine): - add_lap_details_columns(migrate_engine) - populate_lap_details_values(migrate_engine) - -def add_lap_details_columns(migrate_engine): - logging.info("Adding laps details columns") - meta = MetaData(migrate_engine) - laps_table = Table("laps", meta, autoload=True) - create_laps_column(laps_table, "intensity", String(7)) - create_laps_column(laps_table, "laptrigger", String(9)) - create_laps_column(laps_table, "max_speed", Float) - create_laps_column(laps_table, "avg_hr" , Integer) - create_laps_column(laps_table, "max_hr", Integer) - create_laps_column(laps_table, "comments", Text) - logging.info("Created laps details columns") - -def create_laps_column(laps_table, column_name, column_type): - logging.info("Adding column laps.%s" , column_name) - column = Column(column_name, column_type) - laps_table.create(column) - -def populate_lap_details_values(migrate_engine): - logging.info("Populating laps details columns") - resultset = migrate_engine.execute(text("select distinct record from laps where intensity is null")) - record_ids = [] - for row in resultset: - record_ids.append(row["record"]) - resultset.close() - for record_id in record_ids: - gpx_file = UPGRADE_CONTEXT.conf_dir + "/gpx/{0}.gpx".format(record_id) - if os.path.isfile(gpx_file): - gpx_record = gpx.Gpx(filename=gpx_file) - populate_laps_from_gpx(migrate_engine, record_id, gpx_record) - -def populate_laps_from_gpx(migrate_engine, record_id, gpx_record): - resultset = migrate_engine.execute(text("select id_lap from laps where record=:record_id" ), record_id=record_id) - lap_ids = [] - for row in resultset: - lap_ids.append(row["id_lap"]) - resultset.close() - if(len(lap_ids) > 0): - logging.info("Populating laps from GPX for record %s" , record_id) - for lap_id, gpx_lap in zip(lap_ids, gpx_record.getLaps()): - populate_lap_from_gpx(migrate_engine, lap_id, gpx_lap) - -def populate_lap_from_gpx(migrate_engine, lap_id, gpx_lap): - logging.info("Populating lap details from GPX for lap %s" , lap_id) - migrate_engine.execute(text("""update laps set - intensity=:intensity, - avg_hr=:avg_heart_rate, - max_hr=:max_heart_rate, - max_speed=:max_speed, - laptrigger=:lap_trigger - where id_lap=:lap_id"""), - intensity=gpx_lap[7], - avg_heart_rate=gpx_lap[8], - max_heart_rate=gpx_lap[9], - max_speed=float(gpx_lap[10]), - lap_trigger=gpx_lap[11], - lap_id=lap_id) - -# work around a migrate bug -try: - import migrate.versioning.exceptions as ex1 - import migrate.changeset.exceptions as ex2 - ex1.MigrateDeprecationWarning = ex2.MigrateDeprecationWarning -except ImportError: - pass Copied: pytrainer/trunk/pytrainer/upgrade/versions/009_mysql_upgrade.sql (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/008_mysql_upgrade.sql) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/009_mysql_upgrade.sql (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/009_mysql_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,16 @@ +-- equipment management added in version 1.8.0 + +create table equipment ( + id integer primary key auto_increment , + description varchar(200), + active boolean, + life_expectancy int, + prior_usage int, + notes text +); + +create table record_equipment ( + id integer primary key auto_increment, + record_id int, + equipment_id int +); Copied: pytrainer/trunk/pytrainer/upgrade/versions/009_sqlite_upgrade.sql (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/008_sqlite_upgrade.sql) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/009_sqlite_upgrade.sql (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/009_sqlite_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,16 @@ +-- equipment management added in version 1.8.0 + +create table equipment ( + id integer primary key autoincrement , + description varchar(200), + active boolean, + life_expectancy int, + prior_usage int, + notes text +); + +create table record_equipment ( + id integer primary key autoincrement, + record_id int, + equipment_id int +); Modified: pytrainer/trunk/pytrainer/upgrade/versions/010_default_upgrade.sql =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/010_default_upgrade.sql 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/010_default_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -1,2 +1,7 @@ --- sport color added in version 1.9.0 -alter table sports add color char(6); \ No newline at end of file +-- lap info added in version 1.9.0 +alter table laps add intensity varchar(7); +alter table laps add laptrigger varchar(9); +alter table laps add max_speed float; +alter table laps add avg_hr int; +alter table laps add max_hr int; +alter table laps add comments text; Copied: pytrainer/trunk/pytrainer/upgrade/versions/011_populate_lap_details.py (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/009_add_lap_details.py) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/011_populate_lap_details.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/011_populate_lap_details.py 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,54 @@ +from pytrainer.upgrade.context import UPGRADE_CONTEXT +from pytrainer.lib import gpx +from sqlalchemy.sql.expression import text +import logging +import os.path + +# lap info added in version 1.9.0 +def upgrade(migrate_engine): + logging.info("Populating laps details columns") + resultset = migrate_engine.execute(text("select distinct record from laps where intensity is null")) + record_ids = [] + for row in resultset: + record_ids.append(row["record"]) + resultset.close() + for record_id in record_ids: + gpx_file = UPGRADE_CONTEXT.conf_dir + "/gpx/{0}.gpx".format(record_id) + if os.path.isfile(gpx_file): + gpx_record = gpx.Gpx(filename=gpx_file) + populate_laps_from_gpx(migrate_engine, record_id, gpx_record) + +def populate_laps_from_gpx(migrate_engine, record_id, gpx_record): + resultset = migrate_engine.execute(text("select id_lap from laps where record=:record_id" ), record_id=record_id) + lap_ids = [] + for row in resultset: + lap_ids.append(row["id_lap"]) + resultset.close() + if(len(lap_ids) > 0): + logging.info("Populating laps from GPX for record %s" , record_id) + for lap_id, gpx_lap in zip(lap_ids, gpx_record.getLaps()): + populate_lap_from_gpx(migrate_engine, lap_id, gpx_lap) + +def populate_lap_from_gpx(migrate_engine, lap_id, gpx_lap): + logging.info("Populating lap details from GPX for lap %s" , lap_id) + migrate_engine.execute(text("""update laps set + intensity=:intensity, + avg_hr=:avg_heart_rate, + max_hr=:max_heart_rate, + max_speed=:max_speed, + laptrigger=:lap_trigger + where id_lap=:lap_id"""), + intensity=gpx_lap[7], + avg_heart_rate=gpx_lap[8], + max_heart_rate=gpx_lap[9], + max_speed=float(gpx_lap[10]), + lap_trigger=gpx_lap[11], + lap_id=lap_id) + +# work around a migrate bug +try: + import migrate.versioning.exceptions as ex1 + import migrate.changeset.exceptions as ex2 + ex1.MigrateDeprecationWarning = ex2.MigrateDeprecationWarning +except ImportError: + pass Deleted: pytrainer/trunk/pytrainer/upgrade/versions/011_remove_db_version.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/011_remove_db_version.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/011_remove_db_version.py 2011-10-23 12:17:22 UTC (rev 906) @@ -1,10 +0,0 @@ -from lxml import etree -from pytrainer.upgrade.context import UPGRADE_CONTEXT - -def upgrade(migrate_engine): - config_file = UPGRADE_CONTEXT.conf_dir + "/conf.xml" - parser = etree.XMLParser(encoding="UTF8", recover=True) - xml_tree = etree.parse(config_file, parser=parser) - config_element = xml_tree.getroot() - del config_element.attrib["DB_version"] - xml_tree.write(config_file, xml_declaration=True, encoding="UTF-8") Deleted: pytrainer/trunk/pytrainer/upgrade/versions/012_clean_sport_data.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/012_clean_sport_data.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/012_clean_sport_data.py 2011-10-23 12:17:22 UTC (rev 906) @@ -1,4 +0,0 @@ -import pytrainer.upgrade.versions.version012 as version12 - -def upgrade(migrate_engine): - version12.upgrade(migrate_engine) \ No newline at end of file Copied: pytrainer/trunk/pytrainer/upgrade/versions/012_default_upgrade.sql (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/010_default_upgrade.sql) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/012_default_upgrade.sql (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/012_default_upgrade.sql 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,2 @@ +-- sport color added in version 1.9.0 +alter table sports add color char(6); \ No newline at end of file Copied: pytrainer/trunk/pytrainer/upgrade/versions/013_remove_db_version.py (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/011_remove_db_version.py) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/013_remove_db_version.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/013_remove_db_version.py 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,10 @@ +from lxml import etree +from pytrainer.upgrade.context import UPGRADE_CONTEXT + +def upgrade(migrate_engine): + config_file = UPGRADE_CONTEXT.conf_dir + "/conf.xml" + parser = etree.XMLParser(encoding="UTF8", recover=True) + xml_tree = etree.parse(config_file, parser=parser) + config_element = xml_tree.getroot() + del config_element.attrib["DB_version"] + xml_tree.write(config_file, xml_declaration=True, encoding="UTF-8") Added: pytrainer/trunk/pytrainer/upgrade/versions/014_clean_sport_data.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/014_clean_sport_data.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/014_clean_sport_data.py 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,4 @@ +import pytrainer.upgrade.versions.version014 as version14 + +def upgrade(migrate_engine): + version14.upgrade(migrate_engine) \ No newline at end of file Deleted: pytrainer/trunk/pytrainer/upgrade/versions/version012.py =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/version012.py 2011-10-23 12:15:59 UTC (rev 905) +++ pytrainer/trunk/pytrainer/upgrade/versions/version012.py 2011-10-23 12:17:22 UTC (rev 906) @@ -1,91 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -#Copyright (C) Nathan Jones nc...@us... - -#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. - -from sqlalchemy.sql.expression import text -import logging - -class _SportNormalizer(object): - - """A row from the sport DB table that can be "normalized" to have invalid - values replaced with valid defaults.""" - - def __init__(self, id, weight, color, met, max_pace): - self._id = id - self._weight = weight - self._color = color - self._met = met - self._max_pace = max_pace - - def normalize(self, migrate_engine): - self._normalize_weight(migrate_engine) - self._normalize_color(migrate_engine) - self._normalize_met(migrate_engine) - self._normalize_max_pace(migrate_engine) - - def _normalize_weight(self, migrate_engine): - valid = True - try: - weight = float(self._weight) - if weight < 0: - valid = False - except: - valid = False - if not valid: - logging.debug("Sport with id '%s' has invalid weight: '%s'. Replacing with default.", self._id, self._weight) - migrate_engine.execute(text("update sports set weight=:weight where id_sports=:id"), id=self._id, weight=0.0) - - def _normalize_color(self, migrate_engine): - try: - # colors that do not have exactly 6 hexadecimal digits should also - # be invalid, but we do not expect such invalid values to exist. - int(self._color, 16) - except: - logging.debug("Sport with id '%s' has invalid color: '%s'. Replacing with default.", self._id, self._color) - migrate_engine.execute(text("update sports set color=:color where id_sports=:id"), id=self._id, color="0000ff") - - def _normalize_met(self, migrate_engine): - valid = True - if self._met is not None: - try: - met = float(self._met) - if met < 0: - valid = False - except: - valid = False - if not valid: - logging.debug("Sport with id '%s' has invalid MET: '%s'. Replacing with default.", self._id, self._met) - migrate_engine.execute(text("update sports set met=:met where id_sports=:id"), id=self._id, met=None) - - def _normalize_max_pace(self, migrate_engine): - valid = True - if self._max_pace is not None: - try: - max_pace = int(self._max_pace) - if max_pace <= 0: - valid = False - except: - valid = False - if not valid: - logging.debug("Sport with id '%s' has invalid max pace: '%s'. Replacing with default.", self._id, self._max_pace) - migrate_engine.execute(text("update sports set max_pace=:max_pace where id_sports=:id"), id=self._id, max_pace=None) - -def upgrade(migrate_engine): - sport_rows = migrate_engine.execute("select id_sports, weight, color, met, max_pace from sports") - for (id, weight, color, met, max_pace) in sport_rows: - _SportNormalizer(id, weight, color, met, max_pace).normalize(migrate_engine) - sport_rows.close() Copied: pytrainer/trunk/pytrainer/upgrade/versions/version014.py (from rev 905, pytrainer/trunk/pytrainer/upgrade/versions/version012.py) =================================================================== --- pytrainer/trunk/pytrainer/upgrade/versions/version014.py (rev 0) +++ pytrainer/trunk/pytrainer/upgrade/versions/version014.py 2011-10-23 12:17:22 UTC (rev 906) @@ -0,0 +1,91 @@ +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Nathan Jones nc...@us... + +#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. + +from sqlalchemy.sql.expression import text +import logging + +class _SportNormalizer(object): + + """A row from the sport DB table that can be "normalized" to have invalid + values replaced with valid defaults.""" + + def __init__(self, id, weight, color, met, max_pace): + self._id = id + self._weight = weight + self._color = color + self._met = met + self._max_pace = max_pace + + def normalize(self, migrate_engine): + self._normalize_weight(migrate_engine) + self._normalize_color(migrate_engine) + self._normalize_met(migrate_engine) + self._normalize_max_pace(migrate_engine) + + def _normalize_weight(self, migrate_engine): + valid = True + try: + weight = float(self._weight) + if weight < 0: + valid = False + except: + valid = False + if not valid: + logging.debug("Sport with id '%s' has invalid weight: '%s'. Replacing with default.", self._id, self._weight) + migrate_engine.execute(text("update sports set weight=:weight where id_sports=:id"), id=self._id, weight=0.0) + + def _normalize_color(self, migrate_engine): + try: + # colors that do not have exactly 6 hexadecimal digits should also + # be invalid, but we do not expect such invalid values to exist. + int(self._color, 16) + except: + logging.debug("Sport with id '%s' has invalid color: '%s'. Replacing with default.", self._id, self._color) + migrate_engine.execute(text("update sports set color=:color where id_sports=:id"), id=self._id, color="0000ff") + + def _normalize_met(self, migrate_engine): + valid = True + if self._met is not None: + try: + met = float(self._met) + if met < 0: + valid = False + except: + valid = False + if not valid: + logging.debug("Sport with id '%s' has invalid MET: '%s'. Replacing with default.", self._id, self._met) + migrate_engine.execute(text("update sports set met=:met where id_sports=:id"), id=self._id, met=None) + + def _normalize_max_pace(self, migrate_engine): + valid = True + if self._max_pace is not None: + try: + max_pace = int(self._max_pace) + if max_pace <= 0: + valid = False + except: + valid = False + if not valid: + logging.debug("Sport with id '%s' has invalid max pace: '%s'. Replacing with default.", self._id, self._max_pace) + migrate_engine.execute(text("update sports set max_pace=:max_pace where id_sports=:id"), id=self._id, max_pace=None) + +def upgrade(migrate_engine): + sport_rows = migrate_engine.execute("select id_sports, weight, color, met, max_pace from sports") + for (id, weight, color, met, max_pace) in sport_rows: + _SportNormalizer(id, weight, color, met, max_pace).normalize(migrate_engine) + sport_rows.close() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2011-10-24 19:05:55
|
Revision: 907 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=907&view=rev Author: dgranda Date: 2011-10-24 19:05:49 +0000 (Mon, 24 Oct 2011) Log Message: ----------- Overcome scenario when no lap max_speed value is found, especially for TCXv2 files Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowmain.py pytrainer/trunk/pytrainer/lib/gpx.py Modified: pytrainer/trunk/pytrainer/gui/windowmain.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowmain.py 2011-10-23 12:17:22 UTC (rev 906) +++ pytrainer/trunk/pytrainer/gui/windowmain.py 2011-10-24 19:05:49 UTC (rev 907) @@ -454,7 +454,10 @@ max_speed = lap['max_speed'] * 3.6 if s > 0: pace = "%d:%02d" %((3600/s)/60,(3600/s)%60) - max_pace = "%d:%02d" %((3600/max_speed)/60,(3600/max_speed)%60) + if max_speed >0: + max_pace = "%d:%02d" %((3600/max_speed)/60,(3600/max_speed)%60) + else: + max_pace = "0:00" color = { 'active' : '#000000', Modified: pytrainer/trunk/pytrainer/lib/gpx.py =================================================================== --- pytrainer/trunk/pytrainer/lib/gpx.py 2011-10-23 12:17:22 UTC (rev 906) +++ pytrainer/trunk/pytrainer/lib/gpx.py 2011-10-24 19:05:49 UTC (rev 907) @@ -196,6 +196,9 @@ trigger = lap.findtext(triggerTag).lower() summary = lap.find(summaryTag) max_speed = summary.findtext(mainNS.substitute(tag="MaximumSpeed")) + if not max_speed: + max_speed = 0 + logging.info("No max speed found in lap info. Default setting to 0") avg_hr = summary.findtext(mainNS.substitute(tag="AverageHeartRateBpm")) max_hr = summary.findtext(mainNS.substitute(tag="MaximumHeartRateBpm")) logging.debug("Found time: %s, lat: %s lon: %s cal: %s dist: %s " % (elapsedTime, lat, lon, calories, distance)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2011-10-31 17:35:53
|
Revision: 912 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=912&view=rev Author: dgranda Date: 2011-10-31 17:35:47 +0000 (Mon, 31 Oct 2011) Log Message: ----------- Fixed issue that made pytrainer quit when exporting activities in csv format Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/filechooser.py pytrainer/trunk/pytrainer/lib/fileUtils.py pytrainer/trunk/pytrainer/save.py Modified: pytrainer/trunk/pytrainer/gui/filechooser.py =================================================================== --- pytrainer/trunk/pytrainer/gui/filechooser.py 2011-10-31 13:12:25 UTC (rev 911) +++ pytrainer/trunk/pytrainer/gui/filechooser.py 2011-10-31 17:35:47 UTC (rev 912) @@ -20,9 +20,11 @@ from SimpleGladeApp import SimpleGladeApp import gtk +import logging class FileChooser(SimpleGladeApp): def __init__(self,data_path = None, parent = None, method = None, action = None): + logging.debug('>>') self.data_path = data_path self.filename = None self.parent = parent @@ -36,26 +38,35 @@ filter.add_pattern("*.gpx") self.filechooserdialog.set_filter(filter) else: - self.button14.set_label("Save") + self.button14.set_label(_("Save")) self.filechooserdialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) - print self.filechooserdialog.get_action() self.filechooserdialog.set_current_name("*.csv") + logging.debug('<<') def on_accept_clicked(self,widget): + logging.debug('>>') try: self.filename = self.filechooserdialog.get_filename() + logging.debug("Filename chosen: %s" % self.filename) except AttributeError: if self.filename is None: + logging.debug("No valid filename has been chosen. Exiting") self.quit() return + logging.debug("Parent: %s | Method: %s" %(self.parent, self.method)) parentmethod = getattr(self.parent,self.method) parentmethod() + logging.debug("Closing current window") self.closewindow() + logging.debug('<<') def on_cancel_clicked(self,widget): + logging.debug(">>") self.closewindow() + logging.debug('<<') def closewindow(self): - #self.filechooserdialog.hide() - self.filechooserdialog = None - self.quit() + if self.filechooserdialog is not None: + self.filechooserdialog.hide() + else: + logging.debug('GTK Dialog no longer exists, nothing to do') Modified: pytrainer/trunk/pytrainer/lib/fileUtils.py =================================================================== --- pytrainer/trunk/pytrainer/lib/fileUtils.py 2011-10-31 13:12:25 UTC (rev 911) +++ pytrainer/trunk/pytrainer/lib/fileUtils.py 2011-10-31 17:35:47 UTC (rev 912) @@ -16,14 +16,22 @@ #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +import logging + class fileUtils: - def __init__(self, filename, data): - self.filename = filename - self.data = data + def __init__(self, filename, data): + self.filename = filename + self.data = data - def run(self): - out = open(self.filename, 'w') - out.write(self.data) - out.close() + def run(self): + logging.debug('>>') + if self.data is not None: + logging.debug("Writing in %s " % self.filename) + out = open(self.filename, 'w') + out.write(self.data) + out.close() + else: + logging.error("Nothing to write in %s" % self.filename) + logging.debug('<<') Modified: pytrainer/trunk/pytrainer/save.py =================================================================== --- pytrainer/trunk/pytrainer/save.py 2011-10-31 13:12:25 UTC (rev 911) +++ pytrainer/trunk/pytrainer/save.py 2011-10-31 17:35:47 UTC (rev 912) @@ -18,6 +18,8 @@ from lib.fileUtils import fileUtils from gui.filechooser import FileChooser +import logging +import traceback class Save: def __init__(self, data_path = None, record = None): @@ -25,33 +27,39 @@ self.data_path = data_path def run(self): + logging.debug('>>') self.filewindow = FileChooser(self.data_path, self, "savecsvfile") - self.filewindow.run() + #self.filewindow.run() + logging.debug('<<') def savecsvfile(self): + logging.debug('>>') filename = self.filewindow.filename records = self.record.getAllrecord() # CSV Header content = "date,distance,time,beats,comments,average,calories\n" - for record in records: - line = "" - for i, data in enumerate(record): - if i in [1, 3, 5]: - try: - data = round(data, 2) - except: - pass - data = "%s" %data - data = data.replace(",", " ") - data = data.replace("\n", " ") - data = data.replace("\r", " ") - if i>0: - line += ",%s" %data - else: - line += "%s" %data - content += "%s\n" %line - file = fileUtils(filename,content) - file.run() - + try: + for record in records: + line = "" + for i, data in enumerate(record): + if i in [1, 3, 5]: + try: + data = round(data, 2) + except: + pass + data = "%s" %data + data = data.replace(",", " ") + data = data.replace("\n", " ") + data = data.replace("\r", " ") + if i>0: + line += ",%s" %data + else: + line += "%s" %data + content += "%s\n" %line + logging.info("Record data successfully retrieved. Choosing file to save it") + file = fileUtils(filename,content) + file.run() + except: + logging.debug("Traceback: %s" % traceback.format_exc()) + logging.debug('<<') - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dg...@us...> - 2011-11-12 20:46:35
|
Revision: 928 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=928&view=rev Author: dgranda Date: 2011-11-12 20:46:28 +0000 (Sat, 12 Nov 2011) Log Message: ----------- Fixed pace format issue when retrieving values from DB Modified Paths: -------------- pytrainer/trunk/pytrainer/gui/windowrecord.py pytrainer/trunk/pytrainer/record.py Modified: pytrainer/trunk/pytrainer/gui/windowrecord.py =================================================================== --- pytrainer/trunk/pytrainer/gui/windowrecord.py 2011-11-12 16:04:26 UTC (rev 927) +++ pytrainer/trunk/pytrainer/gui/windowrecord.py 2011-11-12 20:46:28 UTC (rev 928) @@ -371,8 +371,8 @@ self.rcd_upositive.set_text("%.2f" %self.uc.height(activity.upositive)) self.rcd_unegative.set_text("%.2f" %self.uc.height(activity.unegative)) self.rcd_maxvel.set_text("%.2f" %self.uc.speed(activity.maxspeed)) - self.rcd_maxpace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.maxpace))) - self.rcd_pace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.pace))) + self.rcd_maxpace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.maxpace),True)) # value coming from DB + self.rcd_pace.set_text("%s" %self.parent.pace_from_float(self.uc.pace(activity.pace),True)) # value coming from DB self.rcd_maxbeats.set_text("%s"%activity.maxbeats) self.rcd_title.set_text(activity.title) Modified: pytrainer/trunk/pytrainer/record.py =================================================================== --- pytrainer/trunk/pytrainer/record.py 2011-11-12 16:04:26 UTC (rev 927) +++ pytrainer/trunk/pytrainer/record.py 2011-11-12 20:46:28 UTC (rev 928) @@ -96,15 +96,18 @@ value = None return value - def pace_from_float(self, value): + def pace_from_float(self, value, fromDB=False): '''Helper to generate mm:ss from float representation mm.ss (or mm,ss?)''' #Check that value supplied is a float try: _value = "%0.2f" % float(value) except ValueError: _value = str(value) - mins, sec_dec = _value.split(".") - pace = mins + ":" + "%02d" %round(int(sec_dec)*3/5) + if fromDB: # paces in DB are stored in mixed format -> 4:30 as 4.3 (NOT as 4.5 aka 'decimal') + pace = _value + else: + mins, sec_dec = _value.split(".") + pace = mins + ":" + "%02d" %round(int(sec_dec)*3/5) return pace def _formatRecordNew (self, list_options): @@ -268,7 +271,7 @@ logging.debug('<<') return summaryRecord, laps - def updateRecord(self, list_options, id_record, equipment=None): + def updateRecord(self, list_options, id_record, equipment=None): # ToDo: update only fields that can change if GPX file is present logging.debug('>>') #Remove activity from pool so data is updated self.pytrainer_main.activitypool.remove_activity(id_record) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |