diff --git a/README.textile b/README.textile index 8a752edb5..ec24543c8 100644 --- a/README.textile +++ b/README.textile @@ -5,7 +5,7 @@ for everyday use. For stable versions check out "releases":https://github.com/pr h1. Requires most recent stable gtk3 (3.10) -Version of gtk required is 3.10 because of the use of HeaderBar and other bits. +Version of gtk required is 3.10 because of the use of HeaderBar and other bits. Sorry and get up to date! @@ -26,6 +26,9 @@ pre. killall hamster-service && killall hamster-windows-service Now restart your panels/dockies and you should be able to add hamster to your panel! +To allow immidiate focus on hamster window, in Ubuntu go to +CompizConfig->General->Focus & Raise Behavior and add hamster to exceprions: +!(class=Polkit-gnome-authentication-agent-1 | class=Hamster-windows-service) h1. hamster-applet -> hamster-time-tracker clean up @@ -36,4 +39,3 @@ the applet is long gone, the paths and file names have changed to pre. git checkout d140d45f105d4ca07d4e33bcec1fae30143959fe ./waf configure build --prefix=/usr sudo ./waf uninstall - diff --git a/setup.py b/setup.py index 8d0f61a4c..1c096b041 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import distutils import os from distutils.core import setup diff --git a/src/hamster-cli b/src/hamster-cli index 43e5dc605..e0b400b8f 100755 --- a/src/hamster-cli +++ b/src/hamster-cli @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # - coding: utf-8 - # Copyright (C) 2010 Matías Ribecky @@ -32,7 +32,7 @@ from hamster.lib import Fact, stuff def word_wrap(line, max_len): - """primitive word wrapper""" + """A primitive word wrapper.""" lines = [] cur_line, cur_len = "", 0 for word in line.split(): @@ -84,7 +84,7 @@ _DATETIME_PATTERN = ('^((?P-\d.+)?|(' '(?P\D.+)?$') _DATETIME_REGEX = re.compile(_DATETIME_PATTERN) def parse_datetime_range(arg): - '''Parse a date and time.''' + '''Parse a date and a time.''' match = _DATETIME_REGEX.match(arg) if not match: return None, None @@ -142,7 +142,7 @@ class HamsterClient(object): "/org/gnome/Hamster/WindowServer") getattr(server, window_name)() else: - print "Running in devel mode" + print("Running in devel mode") from gi.repository import Gtk as gtk from hamster.lib.configuration import dialogs getattr(dialogs, window_name).show() @@ -173,30 +173,29 @@ class HamsterClient(object): formats = "html tsv xml ical".split() chosen = sys.argv[-1] formats = [f for f in formats if not chosen or f.startswith(chosen)] - print "\n".join(formats) + print("\n".join(formats)) def toggle(self): self.storage.toggle() def track(self, *args): - """same as start""" + """Same as start.""" self.start(*args) def start(self, *args): '''Start a new activity.''' if not args: - print "Error: please specify activity" + print("Error: please specify an activity.") return activity = args[0] start_time, end_time = parse_datetime_range(" ".join(args[1:])) start_time = start_time or dt.datetime.now() - self.storage.add_fact(Fact(activity, - start_time = start_time, - end_time = end_time)) + self.storage.add_fact( + Fact(activity, start_time = start_time, end_time = end_time)) def stop(self, *args): @@ -216,7 +215,7 @@ class HamsterClient(object): facts = self.storage.get_facts(start_time, end_time) writer = reports.simple(facts, start_time, end_time, export_format) - print writer.export() + print(writer.export()) def _activities(self, search=""): @@ -225,24 +224,24 @@ class HamsterClient(object): activity, category = search.split("@") for cat in self.storage.get_categories(): if not category or cat['name'].lower().startswith(category.lower()): - print "%s@%s" % (activity.encode("utf8"), cat['name'].encode("utf8")) + print("%s@%s" % (activity, cat['name'])) else: for activity in self.storage.get_activities(search): - print activity['name'].encode('utf8') + print(activity['name']) if activity['category']: - print '%s@%s' % (activity['name'].encode('utf8'), activity['category'].encode('utf8')) + print('%s@%s' % (activity['name'], activity['category'])) def activities(self, *args): '''Print the names of all the activities.''' search = args[0] if args else "" for activity in self.storage.get_activities(search): - print '%s@%s' % (activity['name'].encode('utf8'), activity['category'].encode('utf8')) + print('%s@%s' % (activity['name'], activity['category'])) def categories(self, *args): '''Print the names of all the categories.''' for category in self.storage.get_categories(): - print category['name'].encode('utf8') + print(category['name']) def list(self, *times): @@ -258,10 +257,10 @@ class HamsterClient(object): """prints current activity. kinda minimal right now""" facts = self.storage.get_todays_facts() if facts and not facts[-1].end_time: - print "%s %s" % (unicode(facts[-1]).encode("utf-8").strip(), - stuff.format_duration(facts[-1].delta, human=False)) + print("%s %s" % (str(facts[-1]).strip(), + stuff.format_duration(facts[-1].delta, human=False))) else: - print _("No activity") + print(_("No activity")) def search(self, *args): @@ -309,9 +308,9 @@ class HamsterClient(object): row_width = sum([val + 3 for val in widths.values()]) - print - print fact_line.format(**headers) - print "-" * min(row_width, 80) + print() + print(fact_line.format(**headers)) + print("-" * min(row_width, 80)) by_cat = {} for fact in facts: @@ -320,26 +319,26 @@ class HamsterClient(object): by_cat[cat] += fact.delta pretty_fact = fact_dict(fact, print_with_date) - print fact_line.format(**pretty_fact) + print(fact_line.format(**pretty_fact)) if pretty_fact['description']: for line in word_wrap(pretty_fact['description'], 76): - print " %s" % line + print(" %s" % line) if pretty_fact['tags']: for line in word_wrap(pretty_fact['tags'], 76): - print " %s" % line + print(" %s" % line) - print "-" * min(row_width, 80) + print("-" * min(row_width, 80)) cats = [] - for cat, duration in sorted(by_cat.iteritems(), key=lambda x: x[1], reverse=True): + for cat, duration in sorted(by_cat.items(), key=lambda x: x[1], reverse=True): cats.append("%s: %s" % (cat, "%.1fh" % (stuff.duration_minutes(duration) / 60.0))) for line in word_wrap(", ".join(cats), 80): - print line + print(line) - print + print() @@ -362,7 +361,7 @@ Actions: * activities: List all the activities names, one per line. * categories: List all the categories names, one per line. - * overview / statistics / about: launch specific window + * overview / statistics / about / add : launch specific window Time formats: * 'YYYY-MM-DD hh:mm:ss': If date is missing, it will default to today. diff --git a/src/hamster-service b/src/hamster-service index 7e622dbe6..9bbdfd93e 100755 --- a/src/hamster-service +++ b/src/hamster-service @@ -1,19 +1,19 @@ -#!/usr/bin/python -# nicked off gwibber +#!/usr/bin/env python3 from gi.repository import GObject as gobject +from gi.repository import GLib as glib +from gi.repository import Gio as gio import dbus, dbus.service from dbus.mainloop.glib import DBusGMainLoop import datetime as dt from calendar import timegm -from gi.repository import Gio as gio DBusGMainLoop(set_as_default=True) -loop = gobject.MainLoop() +loop = glib.MainLoop() if "org.gnome.Hamster" in dbus.SessionBus().list_names(): - print "Found hamster-service already running, exiting" + print("Found hamster-service already running, exiting") quit() from hamster.lib import i18n @@ -89,7 +89,7 @@ class Storage(db.Storage, dbus.service.Object): # anyway. should make updating simpler def _on_us_change(self, monitor, gio_file, event_uri, event): if event == gio.FileMonitorEvent.CHANGES_DONE_HINT: - print "`%s` has changed. Quitting!" % __file__ + print("`%s` has changed. Quitting!" % __file__) self.Quit() @dbus.service.signal("org.gnome.Hamster") @@ -303,6 +303,6 @@ class Storage(db.Storage, dbus.service.Object): if __name__ == '__main__': - print "hamster-service up" + print("hamster-service up") storage = Storage(loop) loop.run() diff --git a/src/hamster-windows-service b/src/hamster-windows-service index 8d21c94db..b0deaf00a 100755 --- a/src/hamster-windows-service +++ b/src/hamster-windows-service @@ -1,16 +1,14 @@ -#!/usr/bin/python -# nicked off hamster-service - +#!/usr/bin/env python3 from gi.repository import GObject as gobject import dbus, dbus.service -import glib +from gi.repository import GLib as glib from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) -loop = gobject.MainLoop() +loop = glib.MainLoop() if "org.gnome.Hamster.WindowServer" in dbus.SessionBus().list_names(): - print "Found hamster-window-service already running, exiting" + print("Found hamster-window-service already running, exiting") quit() @@ -50,11 +48,11 @@ if __name__ == '__main__': from hamster.lib import i18n i18n.setup_i18n() - glib.set_prgname(unicode(_("hamster-windows-service")).encode("utf-8")) + glib.set_prgname("hamster-windows-service") from hamster.lib.configuration import runtime, dialogs, conf, load_ui_file window_server = WindowServer(loop) - print "hamster-window-service up" + print("hamster-window-service up") loop.run() diff --git a/src/hamster.bash b/src/hamster.bash index 3ab7002fd..f4a2330fc 100644 --- a/src/hamster.bash +++ b/src/hamster.bash @@ -18,7 +18,7 @@ _hamster() # # The basic options we'll complete. # - opts="activities categories current export list search start stop " + opts="activities categories current export list search start stop add overview" # diff --git a/src/hamster/about.py b/src/hamster/about.py index 6e2f29afe..0835dacc6 100644 --- a/src/hamster/about.py +++ b/src/hamster/about.py @@ -31,8 +31,8 @@ def __init__(self, parent = None): "program-name" : _("Time Tracker"), "name" : _("Time Tracker"), #this should be deprecated in gtk 2.10 "version" : runtime.version, - "comments" : _(u"Project Hamster — track your time"), - "copyright" : _(u"Copyright © 2007–2010 Toms Bauģis and others"), + "comments" : _("Project Hamster — track your time"), + "copyright" : _("Copyright © 2007–2014 Toms Bauģis and others"), "website" : "http://projecthamster.wordpress.com/", "website-label" : _("Project Hamster Website"), "title": _("About Time Tracker"), diff --git a/src/hamster/edit_activity.py b/src/hamster/edit_activity.py index 68bbf5d34..1634a8193 100644 --- a/src/hamster/edit_activity.py +++ b/src/hamster/edit_activity.py @@ -26,9 +26,9 @@ """ TODO: hook into notifications and refresh our days if some evil neighbour edit fact window has dared to edit facts """ -import widgets +from . import widgets from hamster.lib.configuration import runtime, conf, load_ui_file -from lib import Fact +from .lib import Fact class CustomFactController(gobject.GObject): __gsignals__ = { @@ -49,7 +49,7 @@ def __init__(self, parent=None, fact_date=None, fact_id=None): self.get_widget("activity_box").add(self.activity) day_start = conf.get("day_start_minutes") - self.day_start = dt.time(day_start / 60, day_start % 60) + self.day_start = dt.time(day_start // 60, day_start % 60) self.date = fact_date if not self.date: @@ -111,8 +111,7 @@ def show(self): def figure_description(self): buf = self.get_widget('description').get_buffer() - description = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0)\ - .decode("utf-8") + description = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) return description.strip() diff --git a/src/hamster/external.py b/src/hamster/external.py index bb8d007c0..cfbd6ae77 100644 --- a/src/hamster/external.py +++ b/src/hamster/external.py @@ -106,6 +106,6 @@ def get_eds_tasks(): if task.get_status() in [ecal.ICAL_STATUS_NONE, ecal.ICAL_STATUS_INPROCESS]: tasks.append({'name': task.get_summary(), 'category' : category}) return tasks - except Exception, e: + except Exception as e: logging.warn(e) return [] diff --git a/src/hamster/lib/__init__.py b/src/hamster/lib/__init__.py index bc93130a4..b9aa79abb 100644 --- a/src/hamster/lib/__init__.py +++ b/src/hamster/lib/__init__.py @@ -9,7 +9,7 @@ def figure_time(str_time): # strip everything non-numeric and consider hours to be first number # and minutes - second number numbers = re.split("\D", str_time) - numbers = filter(lambda x: x!="", numbers) + numbers = [x for x in numbers if x != ""] hours, minutes = None, None @@ -48,7 +48,7 @@ def __init__(self, activity, category = "", description = "", tags = "", self.date = date self.activity_id = activity_id - for key, val in parse_fact(activity).iteritems(): + for key, val in parse_fact(activity).items(): setattr(self, key, val) @@ -66,10 +66,10 @@ def __iter__(self): 'activity': self.activity, 'category': self.category, 'description': self.description, - 'tags': [tag.encode("utf-8").strip() for tag in self.tags], + 'tags': [tag.strip() for tag in self.tags], 'date': calendar.timegm(self.date.timetuple()) if self.date else "", - 'start_time': self.start_time if isinstance(self.start_time, basestring) else calendar.timegm(self.start_time.timetuple()), - 'end_time': self.end_time if isinstance(self.end_time, basestring) else calendar.timegm(self.end_time.timetuple()) if self.end_time else "", + 'start_time': self.start_time if isinstance(self.start_time, str) else calendar.timegm(self.start_time.timetuple()), + 'end_time': self.end_time if isinstance(self.end_time, str) else calendar.timegm(self.end_time.timetuple()) if self.end_time else "", 'delta': self.delta.seconds + self.delta.days * 24 * 60 * 60 if self.delta else "" #duration in seconds } return iter(keys.items()) diff --git a/src/hamster/lib/charting.py b/src/hamster/lib/charting.py index 60c49ed5c..279f2e615 100644 --- a/src/hamster/lib/charting.py +++ b/src/hamster/lib/charting.py @@ -22,7 +22,7 @@ from gi.repository import Pango as pango import datetime as dt import time -import graphics, stuff +from . import graphics, stuff import locale class Bar(graphics.Sprite): diff --git a/src/hamster/lib/configuration.py b/src/hamster/lib/configuration.py index e3630878b..0b003ec14 100644 --- a/src/hamster/lib/configuration.py +++ b/src/hamster/lib/configuration.py @@ -129,7 +129,7 @@ def __init__(self, get_dialog_class): self.dialog_close_handlers = {} def on_close_window(self, dialog): - for key, assoc_dialog in list(self.dialogs.iteritems()): + for key, assoc_dialog in tuple(self.dialogs.items()): if dialog == assoc_dialog: del self.dialogs[key] @@ -142,6 +142,8 @@ def show(self, parent = None, **kwargs): if params in self.dialogs: window = self.dialogs[params].window + # TODO(kazeevn) shall we remove self.dialogs altogether + # or at least fix about repeated call? self.dialogs[params].show() window.present() else: @@ -152,7 +154,8 @@ def show(self, parent = None, **kwargs): dialog.window.set_transient_for(parent.get_toplevel()) if hasattr(dialog, "connect"): - self.dialog_close_handlers[dialog] = dialog.connect("on-close", self.on_close_window) + self.dialog_close_handlers[dialog] = dialog.connect( + "on-close", self.on_close_window) else: dialog = self.get_dialog_class()(**kwargs) @@ -160,9 +163,9 @@ def show(self, parent = None, **kwargs): dialog.window.connect("destroy", lambda window, params: gtk.main_quit(), params) - self.dialogs[params] = dialog + class Dialogs(Singleton): """makes sure that we have single instance open for windows where it makes sense""" diff --git a/src/hamster/lib/desktop.py b/src/hamster/lib/desktop.py index f60905a42..3605d6ea7 100644 --- a/src/hamster/lib/desktop.py +++ b/src/hamster/lib/desktop.py @@ -20,7 +20,7 @@ import datetime as dt from calendar import timegm import logging -from gi.repository import GObject as gobject +from gi.repository import GLib as glib from hamster import idle @@ -45,7 +45,7 @@ def __init__(self, storage): self.idle_listener = idle.DbusIdleListener() self.idle_listener.connect('idle-changed', self.on_idle_changed) - gobject.timeout_add_seconds(60, self.check_hamster) + glib.timeout_add_seconds(60, self.check_hamster) def check_hamster(self): @@ -56,9 +56,11 @@ def check_hamster(self): todays_facts = self.storage._Storage__get_todays_facts() self.check_user(todays_facts) trophies.check_ongoing(todays_facts) - except Exception, e: + except Exception as e: logging.error("Error while refreshing: %s" % e) - finally: # we want to go on no matter what, so in case of any error we find out about it sooner + finally: + # we want to go on no matter what, + # so in case of any error we find out about it sooner return True @@ -79,13 +81,13 @@ def check_user(self, todays_facts): duration = delta.seconds / 60 if duration and duration % interval == 0: - message = _(u"Working on %s") % last_activity['name'] + message = _("Working on %s") % last_activity['name'] self.notify_user(message) elif self.conf_notify_on_idle: #if we have no last activity, let's just calculate duration from 00:00 if (now.minute + now.hour * 60) % interval == 0: - self.notify_user(_(u"No activity")) + self.notify_user(_("No activity")) def notify_user(self, summary="", details=""): diff --git a/src/hamster/lib/graphics.py b/src/hamster/lib/graphics.py index 0e4b684c8..799ece4ca 100644 --- a/src/hamster/lib/graphics.py +++ b/src/hamster/lib/graphics.py @@ -11,6 +11,7 @@ from gi.repository import Gtk as gtk +from gi.repository import GLib as glib from gi.repository import Gdk as gdk from gi.repository import GObject as gobject from gi.repository import Pango as pango @@ -22,7 +23,7 @@ import re try: - import pytweener + from . import pytweener except: # we can also live without tweener. Scene.animate will not work pytweener = None @@ -30,7 +31,7 @@ from collections import deque # lemme know if you know a better way how to get default font -_test_label = gtk.Label("Hello") +_test_label = gtk.Label(label="Hello") _font_desc = _test_label.get_style().font_desc.to_string() @@ -61,7 +62,7 @@ def parse(self, color): assert color is not None #parse color into rgb values - if isinstance(color, basestring): + if isinstance(color, str): match = self.hex_color_long.match(color) if match: color = [int(color, 16) / 65535.0 for color in match.groups()] @@ -123,7 +124,7 @@ def contrast(self, color, step): Colors = ColorUtils() # this is a static class, so an instance will do def get_gdk_rectangle(x, y, w, h): - rect = gdk.Rectangle() + rect = () rect.x, rect.y, rect.width, rect.height = x or 0, y or 0, w or 0, h or 0 return rect @@ -140,7 +141,7 @@ class Graphics(object): See http://cairographics.org/documentation/pycairo/2/reference/context.html for detailed description of the cairo drawing functions. """ - __slots__ = ('context', 'colors', 'extents', 'paths', '_last_matrix', + __slots__ = ('context', 'extents', 'paths', '_last_matrix', '__new_instructions', '__instruction_cache', 'cache_surface', '_cache_layout') colors = Colors # pointer to the color utilities instance @@ -510,7 +511,7 @@ def _draw_as_bitmap(self, context, opacity): # measure the path extents so we know the size of cache surface # also to save some time use the context to paint for the first time - extents = gdk.Rectangle() + extents = () for instruction, args in self.__instruction_cache: if instruction in path_end_instructions: self.paths.append((instruction, "path", context.copy_path())) @@ -605,10 +606,10 @@ def log(self, *lines): """will print out the lines in console if debug is enabled for the specific sprite""" if getattr(self, "debug", False): - print dt.datetime.now().time(), + print(dt.datetime.now().time(), end=' ') for line in lines: - print line, - print + print(line, end=' ') + print() def _add(self, sprite, index = None): """add one sprite at a time. used by add_child. split them up so that @@ -731,23 +732,23 @@ class Sprite(Parent, gobject.GObject): """ __gsignals__ = { - "on-mouse-over": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), - "on-mouse-move": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-out": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), - "on-mouse-down": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-double-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-triple-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-up": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-scroll": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-drag-start": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-drag": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-drag-finish": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-focus": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), - "on-blur": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), - "on-key-press": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-key-release": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-render": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), + "on-mouse-over": (gobject.SignalFlags.RUN_LAST, None, ()), + "on-mouse-move": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-out": (gobject.SignalFlags.RUN_LAST, None, ()), + "on-mouse-down": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-double-click": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-triple-click": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-up": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-scroll": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-click": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-drag-start": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-drag": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-drag-finish": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-focus": (gobject.SignalFlags.RUN_LAST, None, ()), + "on-blur": (gobject.SignalFlags.RUN_LAST, None, ()), + "on-key-press": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-key-release": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-render": (gobject.SignalFlags.RUN_LAST, None, ()), } transformation_attrs = set(('x', 'y', 'rotation', 'scale_x', 'scale_y', 'pivot_x', 'pivot_y')) @@ -1349,7 +1350,7 @@ def __setattr__(self, name, val): class Label(Sprite): __gsignals__ = { - "on-change": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), + "on-change": (gobject.SignalFlags.RUN_LAST, None, ()), } cache_attrs = Sprite.cache_attrs | set(("_letter_sizes", "__surface", "_ascent", "_bounds_width", "_measures")) @@ -1418,7 +1419,7 @@ def __init__(self, text = "", size = None, color = None, def __setattr__(self, name, val): if name == "font_desc": - if isinstance(val, basestring): + if isinstance(val, str): val = pango.FontDescription(val) elif isinstance(val, pango.FontDescription): val = val.copy() @@ -1648,32 +1649,32 @@ class Scene(Parent, gtk.DrawingArea): __gsignals__ = { # "draw": "override", # "configure_event": "override", - "on-enter-frame": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), - "on-finish-frame": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), - "on-resize": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), - - "on-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), - "on-drag": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), - "on-drag-start": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), - "on-drag-finish": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), - - "on-mouse-move": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-down": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-double-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-triple-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-up": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-over": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-out": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-mouse-scroll": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - - "on-key-press": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), - "on-key-release": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), + "on-enter-frame": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, )), + "on-finish-frame": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, )), + "on-resize": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, )), + + "on-click": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), + "on-drag": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), + "on-drag-start": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), + "on-drag-finish": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), + + "on-mouse-move": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-down": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-double-click": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-triple-click": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-up": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-over": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-out": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-mouse-scroll": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + + "on-key-press": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), + "on-key-release": (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), } def __init__(self, interactive = True, framerate = 60, background_color = None, scale = False, keep_aspect = True, style_class=None): - gtk.DrawingArea.__init__(self) + gobject.GObject.__init__(self) self._style = self.get_style_context() @@ -1732,7 +1733,7 @@ def __init__(self, interactive = True, framerate = 60, #: can be overidden by child sprites self.default_mouse_cursor = None - self._blank_cursor = gdk.Cursor(gdk.CursorType.BLANK_CURSOR) + self._blank_cursor = gdk.Cursor.new(gdk.CursorType.BLANK_CURSOR) self.__previous_mouse_signal_time = None @@ -1856,7 +1857,7 @@ def redraw(self): if self.__drawing_queued == False: #if we are moving, then there is a timeout somewhere already self.__drawing_queued = True self._last_frame_time = dt.datetime.now() - gobject.timeout_add(1000 / self.framerate, self.__redraw_loop) + glib.timeout_add(1000 / self.framerate, self.__redraw_loop) def __redraw_loop(self): """loop until there is nothing more to tween""" @@ -1989,7 +1990,7 @@ def __check_mouse(self, x, y): if isinstance(cursor, gdk.Cursor): self.get_window().set_cursor(cursor) else: - self.get_window().set_cursor(gdk.Cursor(cursor)) + self.get_window().set_cursor(gdk.Cursor.new(cursor)) self.__last_cursor = cursor @@ -1997,24 +1998,26 @@ def __check_mouse(self, x, y): """ mouse events """ def __on_mouse_move(self, scene, event): if self.__last_mouse_move: - gobject.source_remove(self.__last_mouse_move) + glib.source_remove(self.__last_mouse_move) + self.__last_mouse_move = None self.mouse_x, self.mouse_y = event.x, event.y # don't emit mouse move signals more often than every 0.05 seconds timeout = dt.timedelta(seconds=0.05) - if self.__previous_mouse_signal_time and dt.datetime.now() - self.__previous_mouse_signal_time < timeout: - self.__last_mouse_move = gobject.timeout_add((timeout - (dt.datetime.now() - self.__previous_mouse_signal_time)).microseconds / 1000, - self.__on_mouse_move, - scene, - event.copy()) + if self.__previous_mouse_signal_time and dt.datetime.now() - \ + self.__previous_mouse_signal_time < timeout: + + self.__last_mouse_move = glib.timeout_add( + (timeout - (dt.datetime.now() - self.__previous_mouse_signal_time)).microseconds + // 1000, self.__on_mouse_move, scene, event.copy()) return - state = event.state + state = event.get_state() if self._mouse_down_sprite and self._mouse_down_sprite.interactive \ - and self._mouse_down_sprite.draggable and gdk.ModifierType.BUTTON1_MASK & event.state: + and self._mouse_down_sprite.draggable and gdk.ModifierType.BUTTON1_MASK & event.get_state(): # dragging around if not self.__drag_started: drag_started = (self.__drag_start_x is not None and \ diff --git a/src/hamster/lib/i18n.py b/src/hamster/lib/i18n.py index 34eb91bb2..477d91e25 100644 --- a/src/hamster/lib/i18n.py +++ b/src/hamster/lib/i18n.py @@ -25,7 +25,7 @@ def setup_i18n(): module.bind_textdomain_codeset('hamster-time-tracker','utf8') - gettext.install("hamster-time-tracker", locale_dir, unicode = True) + gettext.install("hamster-time-tracker", locale_dir) else: gettext.install("hamster-time-tracker-uninstalled") diff --git a/src/hamster/lib/layout.py b/src/hamster/lib/layout.py index d2a0e360b..e128a1d83 100644 --- a/src/hamster/lib/layout.py +++ b/src/hamster/lib/layout.py @@ -12,7 +12,7 @@ from gi.repository import Pango as pango from collections import defaultdict -import graphics +from . import graphics class Widget(graphics.Sprite): diff --git a/src/hamster/lib/pytweener.py b/src/hamster/lib/pytweener.py index c2449f2b8..393f899cb 100644 --- a/src/hamster/lib/pytweener.py +++ b/src/hamster/lib/pytweener.py @@ -227,7 +227,7 @@ def color_update(fraction): self.start_value = self.decode_func(start_value) self.change = self.decode_func(target_value) - self.start_value - elif isinstance(start_value, basestring) \ + elif isinstance(start_value, str) \ and (self.hex_color_normal.match(start_value) or self.hex_color_short.match(start_value)): self.update = color_update if self.hex_color_normal.match(start_value): @@ -357,17 +357,17 @@ def __init__(self, a, b, c): total = dt.datetime.now() t = dt.datetime.now() - print "Adding %d tweens..." % object_count + print("Adding %d tweens..." % object_count) for i, o in enumerate(objects): tweener.add_tween(o, a = i, b = i, c = i, duration = 0.1 * update_times, easing=Easing.Circ.ease_in_out) - print dt.datetime.now() - t + print(dt.datetime.now() - t) t = dt.datetime.now() - print "Updating %d times......" % update_times + print("Updating %d times......" % update_times) for i in range(update_times): #update 1000 times tweener.update(0.1) - print dt.datetime.now() - t + print(dt.datetime.now() - t) diff --git a/src/hamster/lib/stuff.py b/src/hamster/lib/stuff.py index 885f11f5f..bebe60436 100644 --- a/src/hamster/lib/stuff.py +++ b/src/hamster/lib/stuff.py @@ -82,19 +82,19 @@ def format_range(start_date, end_date): # letter after prefixes (start_, end_) is the one of # standard python date formatting ones- you can use all of them # see http://docs.python.org/library/time.html#time.strftime - title = (u"%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict + title = ("%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict elif start_date.month != end_date.month: # label of date range if start and end month do not match # letter after prefixes (start_, end_) is the one of # standard python date formatting ones- you can use all of them # see http://docs.python.org/library/time.html#time.strftime - title = (u"%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict + title = ("%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict else: # label of date range for interval in same month # letter after prefixes (start_, end_) is the one of # standard python date formatting ones- you can use all of them # see http://docs.python.org/library/time.html#time.strftime - title = (u"%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict + title = ("%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict return title @@ -137,14 +137,14 @@ def zero_hour(date): # see bug 562298 def locale_from_utf8(utf8_str): try: - retval = unicode (utf8_str, "utf-8").encode(locale.getpreferredencoding()) + retval = str (utf8_str, "utf-8").encode(locale.getpreferredencoding()) except: retval = utf8_str return retval def locale_to_utf8(locale_str): try: - retval = unicode (locale_str, locale.getpreferredencoding()).encode("utf-8") + retval = str (locale_str, locale.getpreferredencoding()).encode("utf-8") except: retval = locale_str return retval diff --git a/src/hamster/lib/trophies.py b/src/hamster/lib/trophies.py index f2bd692d8..da512bb15 100644 --- a/src/hamster/lib/trophies.py +++ b/src/hamster/lib/trophies.py @@ -31,7 +31,7 @@ storage = None from hamster.lib import Fact -import stuff +from . import stuff import datetime as dt def unlock(achievement_id): diff --git a/src/hamster/overview.py b/src/hamster/overview.py index d0a3703c4..44dc29502 100755 --- a/src/hamster/overview.py +++ b/src/hamster/overview.py @@ -27,7 +27,6 @@ from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk -from gi.repository import GObject as gobject from gi.repository import PangoCairo as pangocairo from gi.repository import Pango as pango import cairo @@ -45,8 +44,8 @@ from hamster.lib.pytweener import Easing -from widgets.dates import RangePick -from widgets.facttree import FactTree +from .widgets.dates import RangePick +from .widgets.facttree import FactTree class HeaderBar(gtk.HeaderBar): @@ -237,7 +236,8 @@ class Totals(graphics.Scene): def __init__(self): graphics.Scene.__init__(self) self.set_size_request(200, 70) - self.category_totals = layout.Label(color=self._style.get_color(gtk.StateFlags.NORMAL), + # TODO(kazeevn) match colors with the style + self.category_totals = layout.Label(#color=self._style.get_color(gtk.StateFlags.NORMAL), overflow=pango.EllipsizeMode.END, x_align=0, expand=False) @@ -251,8 +251,9 @@ def __init__(self): self.totals = {} self.mouse_cursor = gdk.CursorType.HAND2 + # TODO(kazeevn) match colors with the style self.instructions_label = layout.Label("Click to see stats", - color=self._style.get_color(gtk.StateFlags.NORMAL), + #color=self._style.get_color(gtk.StateFlags.NORMAL), padding=10, expand=False) @@ -295,8 +296,8 @@ def set_facts(self, facts): totals["tag"][tag] += fact.delta - for key, group in totals.iteritems(): - totals[key] = sorted(group.iteritems(), key=lambda x: x[1], reverse=True) + for key, group in totals.items(): + totals[key] = sorted(group.items(), key=lambda x: x[1], reverse=True) self.totals = totals self.activities_chart.set_values(totals['activity']) @@ -304,7 +305,9 @@ def set_facts(self, facts): self.tag_chart.set_values(totals['tag']) self.stacked_bar.set_items([(cat, delta.total_seconds() / 60.0) for cat, delta in totals['category']]) - self.category_totals.markup = ", ".join("%s: %s" % (stuff.escape_pango(cat), stuff.format_duration(hours)) for cat, hours in totals['category']) + self.category_totals.markup = ", ".join("%s: %s" % ( + stuff.escape_pango(cat), stuff.format_duration(hours)) \ + for cat, hours in totals['category']) def on_click(self, scene, sprite, event): self.collapsed = not self.collapsed @@ -507,7 +510,7 @@ def on_report_chosen(widget, format, path): webbrowser.open_new("file://%s" % path) else: try: - gtk.show_uri(gdk.Screen(), "file://%s" % os.path.split(path)[0], 0L) + gtk.show_uri(gdk.Screen(), "file://%s" % os.path.split(path)[0], 0) except: pass # bug 626656 - no use in capturing this one i think diff --git a/src/hamster/preferences.py b/src/hamster/preferences.py index 49409fcc3..f91b109f6 100755 --- a/src/hamster/preferences.py +++ b/src/hamster/preferences.py @@ -75,8 +75,8 @@ def load(self, category_id): appearances = ["text", "icon", "both"] from hamster.lib.configuration import runtime, conf -import widgets -from lib import stuff, trophies +from . import widgets +from .lib import stuff, trophies @@ -205,7 +205,7 @@ def load_config(self, *args): self.get_widget("notify_on_idle").set_sensitive(conf.get("notify_interval") <=120) day_start = conf.get("day_start_minutes") - day_start = dt.time(day_start / 60, day_start % 60) + day_start = dt.time(day_start // 60, day_start % 60) self.day_start.set_time(day_start) self.tags = [tag["name"] for tag in runtime.storage.get_tags(only_autocomplete=True)] @@ -220,8 +220,7 @@ def load_config(self, *args): def on_autocomplete_tags_view_focus_out_event(self, view, event): buf = self.get_widget("autocomplete_tags") - updated_tags = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) \ - .decode("utf-8") + updated_tags = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) if updated_tags == self.tags: return @@ -294,7 +293,6 @@ def on_category_drop(self, treeview, context, x, y, selection, # callbacks def category_edited_cb(self, cell, path, new_text, model): - new_text = new_text.decode("utf-8") id = model[path][0] if id == -1: return False #ignoring unsorted category @@ -318,8 +316,6 @@ def category_edited_cb(self, cell, path, new_text, model): def activity_name_edited_cb(self, cell, path, new_text, model): - new_text = new_text.decode("utf-8") - id = model[path][0] category_id = model[path][2] @@ -538,7 +534,7 @@ def on_category_add_clicked(self, button): """ appends row, jumps to it and allows user to input name """ new_category = self.category_store.insert_before(self.category_store.unsorted_category, - [-2, _(u"New category")]) + [-2, _("New category")]) self.categoryCell.set_property("editable", True) self.category_tree.set_cursor_on_cell((len(self.category_tree.get_model()) - 2, ), @@ -551,7 +547,7 @@ def on_activity_add_clicked(self, button): """ appends row, jumps to it and allows user to input name """ category_id = self._get_selected_category() - new_activity = self.activity_store.append([-1, _(u"New activity"), category_id]) + new_activity = self.activity_store.append([-1, _("New activity"), category_id]) (model, iter) = self.selection.get_selected() @@ -583,7 +579,7 @@ def on_notify_interval_format_value(self, slider, value): value) % {'interval_minutes': value} else: # notify interval slider value label - label = _(u"Never") + label = _("Never") return label diff --git a/src/hamster/reports.py b/src/hamster/reports.py index 0cd917e4b..fbd09e960 100644 --- a/src/hamster/reports.py +++ b/src/hamster/reports.py @@ -41,17 +41,17 @@ from calendar import timegm -from StringIO import StringIO +from io import StringIO, IOBase -def simple(facts, start_date, end_date, format, path = None): +def simple(facts, start_date, end_date, format_, path = None): facts = copy.deepcopy(facts) # dont want to do anything bad to the input report_path = stuff.locale_from_utf8(path) - if format == "tsv": + if format_ == "tsv": writer = TSVWriter(report_path) - elif format == "xml": + elif format_ == "xml": writer = XMLWriter(report_path) - elif format == "ical": + elif format_ == "ical": writer = ICalWriter(report_path) else: #default to HTML writer = HTMLWriter(report_path, start_date, end_date) @@ -72,7 +72,7 @@ def simple(facts, start_date, end_date, format, path = None): class ReportWriter(object): - #a tiny bit better than repeating the code all the time + # a tiny bit better than repeating the code all the time def __init__(self, path = None, datetime_format = "%Y-%m-%d %H:%M:%S"): self.file = open(path, "w") if path else StringIO() self.datetime_format = datetime_format @@ -84,7 +84,7 @@ def write_report(self, facts): try: for fact in facts: fact.activity= fact.activity - fact.description = (fact.description or u"") + fact.description = (fact.description or "") fact.category = (fact.category or _("Unsorted")) if self.datetime_format: @@ -101,7 +101,7 @@ def write_report(self, facts): self._finish(facts) finally: - if isinstance(self.file, file): + if isinstance(self.file, IOBase) and not isinstance(self.file, StringIO): self.file.close() def _start(self, facts): @@ -204,13 +204,13 @@ def __init__(self, path, start_date, end_date): dates_dict.update(stuff.dateDict(end_date, "end_")) if start_date.year != end_date.year: - self.title = _(u"Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict + self.title = _("Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict elif start_date.month != end_date.month: - self.title = _(u"Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict + self.title = _("Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict elif start_date == end_date: - self.title = _(u"Activity report for %(start_B)s %(start_d)s, %(start_Y)s") % dates_dict + self.title = _("Activity report for %(start_B)s %(start_d)s, %(start_Y)s") % dates_dict else: - self.title = _(u"Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict + self.title = _("Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict # read the template, allow override @@ -333,10 +333,6 @@ def _finish(self, facts): all_activities_rows = "\n".join(self.fact_rows) ) - for key, val in data.iteritems(): - if isinstance(val, basestring): - data[key] = val.encode("utf-8") - self.file.write(Template(self.main_template).safe_substitute(data)) if self.override: diff --git a/src/hamster/storage/db.py b/src/hamster/storage/db.py index bd763b82f..52ed2979e 100644 --- a/src/hamster/storage/db.py +++ b/src/hamster/storage/db.py @@ -34,14 +34,14 @@ import os, time import datetime -import storage +from . import storage from shutil import copy as copyfile import itertools import datetime as dt try: from gi.repository import Gio as gio except ImportError: - print "Could not import gio - requires pygobject. File monitoring will be disabled" + print("Could not import gio - requires pygobject. File monitoring will be disabled") gio = None from hamster.lib import Fact @@ -80,7 +80,7 @@ def on_db_file_change(monitor, gio_file, event_uri, event): self.con = None if event in (gio.FileMonitorEvent.CHANGES_DONE_HINT, gio.FileMonitorEvent.CREATED): - print "DB file has been modified externally. Calling all stations" + print("DB file has been modified externally. Calling all stations") self.dispatch_overwrite() # plan "b" – synchronize the time tracker's database from external source while the tracker is running @@ -103,11 +103,11 @@ def __init_db_file(self, database_dir): from xdg.BaseDirectory import xdg_data_home database_dir = os.path.realpath(os.path.join(xdg_data_home, "hamster-applet")) except ImportError: - print "Could not import xdg - will store hamster.db in home folder" + print("Could not import xdg - will store hamster.db in home folder") database_dir = os.path.realpath(os.path.expanduser("~")) if not os.path.exists(database_dir): - os.makedirs(database_dir, 0744) + os.makedirs(database_dir, 0o744) # handle the move to xdg_data_home old_db_file = os.path.expanduser("~/.gnome2/hamster-applet/hamster.db") @@ -141,7 +141,7 @@ def __init_db_file(self, database_dir): copyfile(os.path.join(data_dir, 'hamster.db'), db_path) #change also permissions - sometimes they are 444 - os.chmod(db_path, 0664) + os.chmod(db_path, 0o664) return db_path @@ -637,7 +637,7 @@ def __get_todays_facts(self): day_start = conf.get("day_start_minutes") except: day_start = 5 * 60 # default day start to 5am - day_start = dt.time(day_start / 60, day_start % 60) + day_start = dt.time(day_start // 60, day_start % 60) today = (dt.datetime.now() - dt.timedelta(hours = day_start.hour, minutes = day_start.minute)).date() return self.__get_facts(today) @@ -649,7 +649,7 @@ def __get_facts(self, date, end_date = None, search_terms = "", reverse_search_t day_start = conf.get("day_start_minutes") except: day_start = 5 * 60 # default day start to 5am - day_start = dt.time(day_start / 60, day_start % 60) + day_start = dt.time(day_start // 60, day_start % 60) split_time = day_start datetime_from = dt.datetime.combine(date, split_time) @@ -775,7 +775,7 @@ def __get_activities(self, search): """ search = search.lower() search = search.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_') - activities = self.fetchall(query, (u'%s%%' % search, )) + activities = self.fetchall(query, ('%s%%' % search, )) return activities @@ -994,7 +994,7 @@ def run_fixtures(self): if version < current_version: #lock down current version self.execute("UPDATE version SET version = %d" % current_version) - print "updated database from version %d to %d" % (version, current_version) + print("updated database from version %d to %d" % (version, current_version)) # oldtimer – database version structure had been performed on startup (thus we know that user has been on at least 2 versions) if trophies: diff --git a/src/hamster/widgets/__init__.py b/src/hamster/widgets/__init__.py index 6618b7153..ffb27fa7e 100644 --- a/src/hamster/widgets/__init__.py +++ b/src/hamster/widgets/__init__.py @@ -23,21 +23,21 @@ from gi.repository import Pango as pango # import our children -from activityentry import ActivityEntry +from .activityentry import ActivityEntry -from timeinput import TimeInput +from .timeinput import TimeInput -from dayline import DayLine +from .dayline import DayLine -from tags import Tag -from tags import TagBox -from tags import TagsEntry +from .tags import Tag +from .tags import TagBox +from .tags import TagsEntry -from reportchooserdialog import ReportChooserDialog +from .reportchooserdialog import ReportChooserDialog -from facttree import FactTree +from .facttree import FactTree -from dates import RangePick +from .dates import RangePick # handy wrappers diff --git a/src/hamster/widgets/activityentry.py b/src/hamster/widgets/activityentry.py index 7a8c3f61b..317089f85 100644 --- a/src/hamster/widgets/activityentry.py +++ b/src/hamster/widgets/activityentry.py @@ -28,6 +28,7 @@ from gi.repository import PangoCairo as pangocairo from gi.repository import Pango as pango from collections import defaultdict +from gi.repository import GLib as glib from hamster import client from hamster.lib import Fact, looks_like_time @@ -35,8 +36,6 @@ from hamster.lib import graphics - - def extract_search(text): fact = Fact(text) search = fact.activity or "" @@ -86,7 +85,7 @@ class CompleteTree(graphics.Scene): __gsignals__ = { # enter or double-click, passes in current day and fact - 'on-select-row': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), + 'on-select-row': (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_PYOBJECT,)), } @@ -195,7 +194,7 @@ def on_enter_frame(self, scene, context): class ActivityEntry(gtk.Entry): def __init__(self, **kwargs): - gtk.Entry.__init__(self) + gobject.GObject.__init__(self) self.popup = gtk.Window(type = gtk.WindowType.POPUP) box = gtk.Frame() @@ -239,7 +238,7 @@ def complete(): with self.handler_block(self.checker): self.update_entry("%s%s" % (text, suffix)) self.select_region(len(text), -1) - gobject.timeout_add(0, complete) + glib.timeout_add(0, complete) def on_focus_out(self, entry, event): self.popup.hide() @@ -299,7 +298,7 @@ def load_suggestions(self): label += "@%s" % rec["category"] suggestions[label] += 0 - self.suggestions = sorted(suggestions.iteritems(), key=lambda x: x[1], reverse=True) + self.suggestions = sorted(suggestions.items(), key=lambda x: x[1], reverse=True) def complete_first(self): text = self.get_text() diff --git a/src/hamster/widgets/dates.py b/src/hamster/widgets/dates.py index 6c693aba4..8e164f844 100644 --- a/src/hamster/widgets/dates.py +++ b/src/hamster/widgets/dates.py @@ -83,7 +83,8 @@ def on_toggle(self, button): def set_range(self, start_date, end_date=None): end_date = end_date or start_date self.start_date, self.end_date = start_date, end_date - self.label.set_markup('%s' % stuff.format_range(start_date, end_date).encode("utf-8")) + self.label.set_markup('%s' % + stuff.format_range(start_date, end_date)) def get_range(self): return self.start_date, self.end_date diff --git a/src/hamster/widgets/dayline.py b/src/hamster/widgets/dayline.py index a70103cff..82cc5c50c 100644 --- a/src/hamster/widgets/dayline.py +++ b/src/hamster/widgets/dayline.py @@ -73,13 +73,13 @@ def on_render(self, sprite): duration = self.end_time - self.start_time - duration = int(duration.seconds / 60) - self.duration_label.text = "%02d:%02d" % (duration / 60, duration % 60) + duration = duration.seconds // 60 + self.duration_label.text = "%02d:%02d" % (duration // 60, duration % 60) self.duration_label.visible = self.duration_label.width < self.width if self.duration_label.visible: - self.duration_label.y = (self.height - self.duration_label.height) / 2 - self.duration_label.x = (self.width - self.duration_label.width) / 2 + self.duration_label.y = (self.height - self.duration_label.height) // 2 + self.duration_label.x = (self.width - self.duration_label.width) // 2 else: self.duration_label.visible = False @@ -91,7 +91,7 @@ def __init__(self, start_time = None): self.set_can_focus(False) # no interaction day_start = conf.get("day_start_minutes") - self.day_start = dt.time(day_start / 60, day_start % 60) + self.day_start = dt.time(day_start // 60, day_start % 60) start_time = start_time or dt.datetime.now() @@ -156,8 +156,8 @@ def on_enter_frame(self, scene, context): self.plot_area.height = self.height - 30 - vertical = min(self.plot_area.height / 5, 7) - minute_pixel = (self.scope_hours * 60.0 - 15) / self.width + vertical = min(self.plot_area.height // 5, 7) + minute_pixel = (self.scope_hours * 60.0 - 15) // self.width g.set_line_style(width=1) g.translate(0.5, 0.5) @@ -177,7 +177,7 @@ def on_enter_frame(self, scene, context): bar.height = vertical bar_start_time = bar.fact.start_time - self.view_time - minutes = bar_start_time.seconds / 60 + bar_start_time.days * self.scope_hours * 60 + minutes = bar_start_time.seconds // 60 + bar_start_time.days * self.scope_hours * 60 bar.x = round(minutes / minute_pixel) + 0.5 bar.width = round((bar.fact.delta).seconds / 60 / minute_pixel) @@ -185,10 +185,13 @@ def on_enter_frame(self, scene, context): if self.chosen_selection.start_time and self.chosen_selection.width is None: # we have time but no pixels - minutes = round((self.chosen_selection.start_time - self.view_time).seconds / 60 / minute_pixel) + 0.5 + minutes = round((self.chosen_selection.start_time - self.view_time).seconds + / 60 / minute_pixel) + 0.5 self.chosen_selection.x = minutes if self.chosen_selection.end_time: - self.chosen_selection.width = round((self.chosen_selection.end_time - self.chosen_selection.start_time).seconds / 60 / minute_pixel) + self.chosen_selection.width = round(( + self.chosen_selection.end_time - self.chosen_selection.start_time).seconds / + 60 / minute_pixel) else: self.chosen_selection.width = 0 self.chosen_selection.height = self.chosen_selection.parent.height diff --git a/src/hamster/widgets/facttree.py b/src/hamster/widgets/facttree.py index 4c043ae5c..47c7e8ae6 100644 --- a/src/hamster/widgets/facttree.py +++ b/src/hamster/widgets/facttree.py @@ -386,9 +386,8 @@ def set_facts(self, facts): self.days = days self.facts = facts - self.set_row_heights() - if self.height: + self.set_row_heights() if current_fact: fact_ids = [fact.id for fact in facts] if current_fact.id in fact_ids: diff --git a/src/hamster/widgets/reportchooserdialog.py b/src/hamster/widgets/reportchooserdialog.py index 7bcac9f1b..9b2552aa8 100644 --- a/src/hamster/widgets/reportchooserdialog.py +++ b/src/hamster/widgets/reportchooserdialog.py @@ -18,8 +18,8 @@ # along with Project Hamster. If not, see . -import pygtk -pygtk.require('2.0') +import gi +gi.require_version('Gtk', '3.0') import os from gi.repository import GObject as gobject @@ -29,15 +29,15 @@ class ReportChooserDialog(gtk.Dialog): __gsignals__ = { # format, path, start_date, end_date - 'report-chosen': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, + 'report-chosen': (gobject.SignalFlags.RUN_LAST, None, (gobject.TYPE_STRING, gobject.TYPE_STRING)), - 'report-chooser-closed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), + 'report-chooser-closed': (gobject.SignalFlags.RUN_LAST, None, ()), } def __init__(self): - gtk.Dialog.__init__(self) + gobject.GObject.__init__(self) - self.dialog = gtk.FileChooserDialog(title = _(u"Save Report — Time Tracker"), + self.dialog = gtk.FileChooserDialog(title = _("Save Report — Time Tracker"), parent = self, action = gtk.FileChooserAction.SAVE, buttons=(gtk.STOCK_CANCEL, diff --git a/src/hamster/widgets/timeinput.py b/src/hamster/widgets/timeinput.py index e689bceec..deefb7e51 100644 --- a/src/hamster/widgets/timeinput.py +++ b/src/hamster/widgets/timeinput.py @@ -103,7 +103,7 @@ def figure_time(self, str_time): # strip everything non-numeric and consider hours to be first number # and minutes - second number numbers = re.split("\D", str_time) - numbers = filter(lambda x: x!="", numbers) + numbers = [x for x in numbers if x!=""] hours, minutes = None, None diff --git a/wscript b/wscript index efd022567..6346a1aa1 100644 --- a/wscript +++ b/wscript @@ -1,5 +1,5 @@ # -*- python -*- -VERSION = '1.5-alpha' +VERSION = '1.5-alpha 3.2-alpha' APPNAME = 'hamster-time-tracker' top = '.' out = 'build'