export/reports POC
- From: "Jorge Vargas" <jorge vargas gmail com>
- To: hamster-applet-devel-list gnome org
- Subject: export/reports POC
- Date: Tue, 28 Oct 2008 17:06:54 -0600
Hello guys, as promise here is my first stab at the export/reports rewrite.
Please consider this is very alpha code and of poor quality control,
right now it works, but nothing more.
Some things I'm going to improve before summiting a real patch
- transform the "output" variable into a class with some handy methods.
- have a proper time measuring object*
- add data range support
- add totals per category
* I found a bug/omission with the time reporting, the code tends to
round up to minutes and pass strings around. shouldn't there be a
proper date/time/datetime class to calculate those values? I
implemented a method to read from timedelta objects. I think we should
have an object that will take care of all the time/date/datetime
conversions.
attached the patch. in order to apply it to the svn checkout you will do
$ patch -p1 < path/to/initial-export.patch
in order to make this run you will need to:
$ cd <your local svn checkout>
$ cp ~/.gnome2/hamster-applet/hamster.db .
$ python -i hamster/export.py
>>> console()
#pprint output of your db
>>> dump_to_file('something.txt',console)
# the above will create ~/something.txt, it is compatible with all functions
# if you want json output, install simplejson (python-simplejson in
debian & familly)
>>> json()
# and to get plain text and html you will need tempita.
$ cd hamster
$ svn co http://svn.pythonpaste.org/Tempita/trunk/tempita tempita
# so you will have tempita as a submodule of hamster
# then you can do
>>> text()
# and
>>> html()
diff -r 6ab2058db7eb hamster/db.py
--- a/hamster/db.py Sun Oct 26 10:13:19 2008 -0600
+++ b/hamster/db.py Tue Oct 28 17:04:30 2008 -0600
@@ -261,6 +261,10 @@ class Storage(hamster.storage.Storage):
end_date = end_date or date
return self.fetchall(query, (_("Unsorted"), date, end_date))
+
+ def __get_facts_by_activity(self,activity_id):
+ query = "select * from facts where activity_id = ?"
+ return self.fetchall(query,(activity_id,))
def __remove_fact(self, fact_id):
query = """
diff -r 6ab2058db7eb hamster/export.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hamster/export.py Tue Oct 28 17:04:30 2008 -0600
@@ -0,0 +1,135 @@
+#dev version code stolen from hamster.hamster-applet
+
+from os.path import *
+import sys
+
+# Allow to use uninstalled
+def _check(path):
+ return exists(path) and isdir(path) and isfile(path+"/AUTHORS")
+
+name = join(dirname(__file__), '..')
+if _check(name):
+ print 'Running uninstalled hamster, modifying PYTHONPATH'
+ sys.path.insert(0, abspath(name))
+else:
+ sys.path.insert(0, abspath("@PYTHONDIR@"))
+ print "Running installed hamster, using [ PYTHONDIR@:$PYTHONPATH]"
+
+import hamster
+from hamster.db import Storage
+print "using hamster from %s" % sys.modules['hamster']
+hamster.HAMSTER_DB = join(abspath(name),'hamster.db')
+print "using hamster.db from %s" % hamster.HAMSTER_DB
+s = Storage(None)
+
+def get_total_time_for_activity(activity_id):
+ import datetime
+ total_time = datetime.timedelta()
+ for fact in s.get_facts_by_activity(activity_id):
+ try:
+ delta = fact['end_time'] - fact['start_time']
+ except TypeError:
+ print fact
+ total_time+=delta
+ from hamster.stuff import format_timedelta
+ return format_timedelta(total_time)
+# from hamster.stuff import format_duration
+# duration = 24.0 * total_time.days + total_time.seconds / 60.0 + total_time.microseconds/(60.0*60.0)
+# duration = 24 * total_time.days + total_time.seconds / 60 + total_time.microseconds/(60*60)
+# return duration
+
+def export_tasks(include='all',exclude=None):
+ output = {}
+ for category in s.get_category_list():
+ current_category = output[category['name']] = {}
+ for activity in s.get_activities(category['id']):
+ current_category[activity['name']] = get_total_time_for_activity(activity['id'])
+ return output
+
+def console():
+ import pprint
+ pprint.pprint(export_tasks())
+
+def json():
+ import simplejson
+ return simplejson.dumps(export_tasks())
+
+def xml():
+ import xml.etree.ElementTree as ET
+
+def text():
+ import tempita
+ template = tempita.Template(
+ """
+ {{py:
+def dict_to_time(timedict):
+ return "%d:%d:%d:%d" % (timedict['days'],timedict['hours'],timedict['minutes'],timedict['seconds'])
+ }}
+ {{for category_name,categories in items.items() }}
+ {{category_name}}
+ {{for activity_name,activities in categories.items()}}
+ {{activity_name}},{{activities | dict_to_time}}
+ {{endfor}}
+ {{endfor}}
+ """)
+ return template.substitute(items = export_tasks())
+
+def html():
+ import tempita
+ template = tempita.HTMLTemplate(
+ """{{py:
+def dict_to_time(timedict):
+ return "%d:%d:%d:%d" % (timedict['days'],timedict['hours'],timedict['minutes'],timedict['seconds'])
+ }}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <meta name="author" content="hamster-applet" />
+ <title>%s</title>
+ <style>
+ body {
+ padding: 12px;
+ }
+ h1 {
+ border-bottom: 1px solid gray;
+ padding-bottom: 4px;
+ }
+ table {margin-left: 24px}
+ th {
+ text-align: left;
+ }
+ tr {padding: 6px;}
+ td {
+ padding: 2px;
+ padding-right: 24px;
+ }
+ </style>
+ </head>
+<body>
+ {{for category_name,categories in items.items() }}
+ <table>
+ <tr>
+ <th>activity</th>
+ <th>duration</th>
+ </tr>
+ {{category_name}}
+ {{for activity_name,activities in categories.items()}}
+ <tr><td>{{activity_name}}</td><td>{{activities | dict_to_time}}</td></tr>
+ {{endfor}}
+ </table>
+ {{endfor}}
+ </html>
+ """)
+ return template.substitute(items = export_tasks())
+
+
+def dump_to_file(filename,function):
+ report_path = join(expanduser("~"), filename)
+ report = open(report_path, "w")
+ report.write(function())
+ report.close()
+
+dump_to_file('test.html',html)
+
diff -r 6ab2058db7eb hamster/storage.py
--- a/hamster/storage.py Sun Oct 26 10:13:19 2008 -0600
+++ b/hamster/storage.py Tue Oct 28 17:04:30 2008 -0600
@@ -48,6 +48,9 @@ class Storage(object):
def get_facts(self, date, end_date = None):
return self.__get_facts(date, end_date)
+
+ def get_facts_by_activity(self, activity_id = None):
+ return self.__get_facts_by_activity(activity_id)
def remove_fact(self, fact_id):
fact = self.get_fact(fact_id)
@@ -104,7 +107,6 @@ class Storage(object):
self.dispatch('activity_updated', ())
return res
-
def get_category_list(self):
return self.__get_category_list()
diff -r 6ab2058db7eb hamster/stuff.py
--- a/hamster/stuff.py Sun Oct 26 10:13:19 2008 -0600
+++ b/hamster/stuff.py Tue Oct 28 17:04:30 2008 -0600
@@ -65,6 +65,28 @@ def format_duration(minutes):
formatted_duration += "%02d:%02d" % (hours, minutes)
return formatted_duration
+
+def format_timedelta(delta):
+ days = delta.days
+ hours = delta.seconds / 3600
+ remaining = delta.seconds % 3600
+ minutes = remaining / 60
+ seconds = remaining % 60
+ #XXX fix microseconds
+ microseconds = delta.microseconds
+ del delta
+ del remaining
+ return locals()
+
+def test_format_timedelta():
+ import datetime
+ bigdelta = datetime.datetime.now() - datetime.datetime(1,1,1)
+ timedict = format_timedelta(bigdelta)
+ newdelta = datetime.timedelta(days=timedict['days'],hours=timedict['hours'],minutes=timedict['minutes'],seconds=timedict['seconds'],microseconds=timedict['microseconds'])
+ print newdelta == bigdelta
+ assert false
+
+
def dateDict(date, prefix):
"""converts date into dictionary, having prefix for all the keys"""
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]