Commit bfded4d9 authored by Darko Poljak's avatar Darko Poljak

pep8

parent 9adc35f7
......@@ -36,11 +36,13 @@ MAIL = 'nico-ctt at schottelius.org'
WWW = 'http://www.nico.schottelius.org/software/ctt/'
# Name of the folder to create - should not contain special characters
# to ensure cross-os compatibility
DISKFORMAT = DATETIMEFORMAT
DISKFORMAT = DATETIMEFORMAT
class Error(Exception):
pass
# Our output format
def user_timedelta(seconds):
"""Format timedelta for the user"""
......@@ -59,15 +61,17 @@ def user_timedelta(seconds):
return (hours, minutes, seconds)
def ctt_dir():
home = os.environ['HOME']
ctt_dir = os.path.join(home, ".ctt")
return ctt_dir
def project_dir(project):
project_dir = os.path.join(ctt_dir(), project)
return project_dir
return os.listdir(ctt_dir)
# return os.listdir(ctt_dir)
......@@ -26,6 +26,7 @@ import os
log = logging.getLogger(__name__)
class ListProjects(object):
"""Return existing projects"""
......@@ -33,7 +34,6 @@ class ListProjects(object):
def commandline(cls, args):
cls.print_projects()
@classmethod
def print_projects(cls):
for project in cls.list_projects():
......
......@@ -21,16 +21,13 @@
#
#
import calendar
import datetime
import logging
import time
import os
import os.path
import re
import sys
import glob
import collections
......@@ -39,11 +36,12 @@ import ctt.listprojects
log = logging.getLogger(__name__)
class Report(object):
"""Create a report on tracked time"""
def __init__(self, project, start_date, end_date,
output_format, regexp, ignore_case):
output_format, regexp, ignore_case):
self.project = project
self.project_dir = ctt.project_dir(self.project)
......@@ -63,7 +61,7 @@ class Report(object):
def commandline(cls, args):
# Report time for all projects
if args.all:
projects=ctt.listprojects.ListProjects.list_projects()
projects = ctt.listprojects.ListProjects.list_projects()
else:
projects = []
......@@ -75,8 +73,8 @@ class Report(object):
reports = collections.OrderedDict()
for project in projects:
report = cls(project=project, start_date=args.start,
end_date=args.end, output_format=args.output_format,
regexp=args.regexp, ignore_case=args.ignore_case)
end_date=args.end, output_format=args.output_format,
regexp=args.regexp, ignore_case=args.ignore_case)
report_data = report.report()
reports[report.project] = (report, report_data)
total_time = total_time + report.total_time
......@@ -84,7 +82,6 @@ class Report(object):
cls.summary(total_time)
@staticmethod
def print_report_time_entries(report_data, output_format, summary):
''' Print time entries from report_data report using output_format.
......@@ -109,54 +106,58 @@ class Report(object):
report, report_data = reports[project]
if summary:
for time in report_data:
if not time in summary_report:
if time not in summary_report:
summary_report[time] = report_data[time]
else:
summary_report[time].extend(report_data[time])
else:
report.header()
Report.print_report_time_entries(report_data,
output_format, summary)
output_format, summary)
# For summary do not print time entries.
# if summary:
# Report.print_report_time_entries(summary_report,
# output_format, summary)
def _init_date(self, start_date, end_date):
"""Setup date - either default or user given values"""
now = datetime.datetime.now()
first_day_this_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
next_month = first_day_this_month.replace(day=28) + datetime.timedelta(days=4)
first_day_this_month = now.replace(
day=1, hour=0, minute=0, second=0, microsecond=0)
next_month = first_day_this_month.replace(
day=28) + datetime.timedelta(days=4)
first_day_next_month = next_month.replace(day=1)
last_day_this_month = first_day_next_month - datetime.timedelta(seconds=1)
last_day_this_month = first_day_next_month - datetime.timedelta(
seconds=1)
default_start_date = first_day_this_month
default_end_date = last_day_this_month
#default_end_date = first_day - datetime.timedelta(days=1)
#default_start_date = default_end_date.replace(day=1)
# default_end_date = first_day - datetime.timedelta(days=1)
# default_start_date = default_end_date.replace(day=1)
try:
if start_date:
self.start_date = datetime.datetime.strptime(start_date[0], ctt.DATEFORMAT)
self.start_date = datetime.datetime.strptime(
start_date[0], ctt.DATEFORMAT)
else:
self.start_date = default_start_date
if end_date:
self.end_date = datetime.datetime.strptime(end_date[0], ctt.DATEFORMAT)
self.end_date = datetime.datetime.strptime(
end_date[0], ctt.DATEFORMAT)
else:
self.end_date = default_end_date
except ValueError as e:
raise ctt.Error(e)
self.end_date = self.end_date.replace(hour=23,minute=59,second=59)
self.end_date = self.end_date.replace(
hour=23, minute=59, second=59)
if self.start_date >= self.end_date:
raise ctt.Error("End date must be after start date (%s >= %s)" %
(self.start_date, self.end_date))
(self.start_date, self.end_date))
def _init_report_db(self):
"""Read all contents from db"""
......@@ -168,13 +169,19 @@ class Report(object):
for dirname in os.listdir(self.project_dir):
log.debug("Dirname: %s" % dirname)
try:
dir_datetime = datetime.datetime.strptime(dirname, ctt.DISKFORMAT)
dir_datetime = datetime.datetime.strptime(
dirname, ctt.DISKFORMAT)
except ValueError:
raise ctt.Error("Invalid time entry {entry} for project {project}, aborting!".format(entry=dirname, project=self.project))
raise ctt.Error(("Invalid time entry {entry} for project "
"{project}, aborting!").format(
entry=dirname, project=self.project))
if dir_datetime >= self.start_date and dir_datetime <= self.end_date:
filename = os.path.join(self.project_dir, dirname, ctt.FILE_DELTA)
comment_filename = os.path.join(self.project_dir, dirname, ctt.FILE_COMMENT)
if (dir_datetime >= self.start_date and
dir_datetime <= self.end_date):
filename = os.path.join(
self.project_dir, dirname, ctt.FILE_DELTA)
comment_filename = os.path.join(
self.project_dir, dirname, ctt.FILE_COMMENT)
# Check for matching comment
comment = None
......@@ -183,10 +190,11 @@ class Report(object):
comment = fd.read().rstrip('\n')
# If regular expression given, but not matching, skip entry
if self.regexp and not re.search(self.regexp, comment, self.search_flags):
if (self.regexp and
not re.search(self.regexp, comment,
self.search_flags)):
continue
self._report_db[dirname] = {}
if comment:
self._report_db[dirname]['comment'] = comment
......@@ -194,7 +202,8 @@ class Report(object):
with open(filename, "r") as fd:
self._report_db[dirname]['delta'] = fd.read().rstrip('\n')
log.debug("Recording: %s: %s" % (dirname, self._report_db[dirname]['delta']))
log.debug("Recording: %s: %s"
% (dirname, self._report_db[dirname]['delta']))
else:
log.debug("Skipping: %s" % dirname)
......@@ -202,14 +211,14 @@ class Report(object):
def header(self):
project_name = os.path.basename(self.project)
print("Report for %s between %s and %s" %
(project_name, self.start_date, self.end_date))
(project_name, self.start_date, self.end_date))
@staticmethod
def summary(total_time):
hours, minutes, seconds = ctt.user_timedelta(total_time)
print("Total time tracked: %sh %sm %ss." %
(hours, minutes, seconds))
(hours, minutes, seconds))
@property
def total_time(self):
......@@ -223,17 +232,16 @@ class Report(object):
return count
def _get_report_entry(self, time, entry):
''' Get one time entry data.
'''
report = {}
start_datetime = datetime.datetime.strptime(time, ctt.DATETIMEFORMAT)
start_datetime = datetime.datetime.strptime(time, ctt.DATETIMEFORMAT)
delta = datetime.timedelta(seconds=int(float(entry['delta'])))
end_datetime = (start_datetime + delta).replace(microsecond = 0)
end_datetime = (start_datetime + delta).replace(microsecond=0)
report['start_datetime'] = start_datetime.strftime(ctt.DATETIMEFORMAT)
report['end_datetime'] = end_datetime.strftime(ctt.DATETIMEFORMAT)
report['end_datetime'] = end_datetime.strftime(ctt.DATETIMEFORMAT)
report['delta'] = delta
report['delta_seconds'] = int(float(entry['delta']))
......@@ -245,7 +253,6 @@ class Report(object):
report['comment'] = False
return report
def report(self):
"""Return total time tracked"""
......@@ -254,7 +261,7 @@ class Report(object):
for time in time_keys:
entry = self._report_db[time]
report = self._get_report_entry(time, entry)
if not time in entries:
if time not in entries:
entries[time] = [report]
else:
entries[time].append(report)
......
......@@ -22,7 +22,9 @@
import os
import unittest
fixtures_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures"))
fixtures_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
"fixtures"))
class CttTestCase(unittest.TestCase):
def setUp(self):
......
......@@ -25,12 +25,13 @@ import ctt
import ctt.listprojects as cttls
import ctt.test
class ListProjectsTestCase(ctt.test.CttTestCase):
def test_list_projects(self):
projects = cttls.ListProjects.list_projects()
expected_projects = [ 'foo1', 'foo2', 'foo3', 'spam-eggs',
'test-1', 'test-2', 'test-3', ]
expected_projects = ['foo1', 'foo2', 'foo3', 'spam-eggs',
'test-1', 'test-2', 'test-3', ]
gotten_projects = sorted(projects)
self.assertEqual(gotten_projects, expected_projects)
......
......@@ -51,17 +51,17 @@ class ReportTestCase(ctt.test.CttTestCase):
report_data = {
'2016-04-07-0826': [
{
'start_datetime': '2016-04-07-0826',
'end_datetime': '2016-04-07-2359',
'comment': 'foo1',
'delta': '6',
'delta_seconds': '6',
'delta_minutes': '0',
'start_datetime': '2016-04-07-0826',
'end_datetime': '2016-04-07-2359',
'comment': 'foo1',
'delta': '6',
'delta_seconds': '6',
'delta_minutes': '0',
},
],
}
report.Report.print_report_time_entries(report_data, ctt.REPORTFORMAT,
False)
False)
output = self._get_output()
expected_output = "2016-04-07-0826 (6): foo1"
self.assertEqual(output, expected_output)
......@@ -70,44 +70,46 @@ class ReportTestCase(ctt.test.CttTestCase):
report_data = {
'2016-04-07-0826': [
{
'start_datetime': '2016-04-07-0826',
'end_datetime': '2016-04-07-2359',
'comment': 'foo1',
'delta': '6',
'delta_seconds': '6',
'delta_minutes': '0',
'start_datetime': '2016-04-07-0826',
'end_datetime': '2016-04-07-2359',
'comment': 'foo1',
'delta': '6',
'delta_seconds': '6',
'delta_minutes': '0',
},
],
'2016-04-07-0926': [
{
'start_datetime': '2016-04-07-0926',
'end_datetime': '2016-04-07-2359',
'comment': 'foo12',
'delta': '10',
'delta_seconds': '10',
'delta_minutes': '0',
'start_datetime': '2016-04-07-0926',
'end_datetime': '2016-04-07-2359',
'comment': 'foo12',
'delta': '10',
'delta_seconds': '10',
'delta_minutes': '0',
},
],
}
report.Report.print_report_time_entries(report_data, ctt.REPORTFORMAT,
True)
True)
output = self._get_output()
expected_output = ("2016-04-07-0826 (6): foo1\n"
"2016-04-07-0926 (10): foo12")
"2016-04-07-0926 (10): foo12")
self.assertEqual(output, expected_output)
def test_print_reports(self):
reports = collections.OrderedDict()
for project in ('foo1', 'foo2'):
rep = report.Report(project, ('2016-04-07',), ('2016-04-08',),
ctt.REPORTFORMAT, None, None)
rep = report.Report(project, ('2016-04-07', ), ('2016-04-08', ),
ctt.REPORTFORMAT, None, None)
report_data = rep.report()
reports[project] = (rep, report_data)
expected_output = (
"Report for foo1 between 2016-04-07 00:00:00 and 2016-04-08 23:59:59\n"
"Report for foo1 between 2016-04-07 00:00:00 and "
"2016-04-08 23:59:59\n"
"2016-04-07-0826 (0:00:06): foo1\n"
"2016-04-08-1200 (1:23:20): foo1 12\n"
"Report for foo2 between 2016-04-07 00:00:00 and 2016-04-08 23:59:59\n"
"Report for foo2 between 2016-04-07 00:00:00 and "
"2016-04-08 23:59:59\n"
"2016-04-07-0810 (0:00:10): foo2"
)
rep.print_reports(reports, ctt.REPORTFORMAT, summary=False)
......@@ -132,8 +134,8 @@ class ReportTestCase(ctt.test.CttTestCase):
# self.assertEqual(output, expected_output)
def test__init_date(self):
rep = report.Report('foo1', ('2016-04-07',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
rep = report.Report('foo1', ('2016-04-07', ), ('2016-04-07', ),
ctt.REPORTFORMAT, None, None)
expected_start_date = datetime.datetime(2016, 4, 7)
expected_end_date = datetime.datetime(2016, 4, 7, 23, 59, 59)
self.assertEqual(rep.start_date, expected_start_date)
......@@ -141,44 +143,46 @@ class ReportTestCase(ctt.test.CttTestCase):
@unittest.expectedFailure
def test__init_date_fail(self):
rep = report.Report('foo1', ('2016-04-08',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
report.Report('foo1', ('2016-04-08', ), ('2016-04-07', ),
ctt.REPORTFORMAT, None, None)
def test__init_date_defaults(self):
rep = report.Report('foo1', None, None,
ctt.REPORTFORMAT, None, None)
ctt.REPORTFORMAT, None, None)
now = datetime.datetime.now()
expected_start_date = now.replace(day=1, hour=0, minute=0, second=0,
microsecond=0)
next_month = expected_start_date.replace(day=28) + datetime.timedelta(days=4)
microsecond=0)
next_month = expected_start_date.replace(day=28) + datetime.timedelta(
days=4)
first_day_next_month = next_month.replace(day=1)
expected_end_date = first_day_next_month - datetime.timedelta(seconds=1)
expected_end_date = first_day_next_month - datetime.timedelta(
seconds=1)
self.assertEqual(rep.start_date, expected_start_date)
self.assertEqual(rep.end_date, expected_end_date)
@unittest.expectedFailure
def test__init_report_db_fail(self):
rep = report.Report('unexisting', ('2016-04-07',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
report.Report('unexisting', ('2016-04-07',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
def test__init_report_db(self):
rep = report.Report('foo1', ('2016-04-07',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
expected_db = {
'2016-04-07-0826': {
'comment': 'foo1',
'delta': '6.248274'
},
ctt.REPORTFORMAT, None, None)
expected_db = {
'2016-04-07-0826': {
'comment': 'foo1',
'delta': '6.248274'
},
}
self.assertEqual(rep._report_db, expected_db)
def test_header(self):
rep = report.Report('foo1', ('2016-04-07',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
ctt.REPORTFORMAT, None, None)
rep.header()
output = self._get_output()
self.assertEqual(output, ("Report for foo1 between 2016-04-07 00:00:00"
" and 2016-04-07 23:59:59"))
" and 2016-04-07 23:59:59"))
def test_summary(self):
report.Report.summary(10)
......@@ -187,35 +191,35 @@ class ReportTestCase(ctt.test.CttTestCase):
def test_total_time(self):
rep = report.Report('foo1', ('2016-04-07',), ('2016-04-07',),
ctt.REPORTFORMAT, None, None)
ctt.REPORTFORMAT, None, None)
total_time = rep.total_time
expected_total_time = 6.248274
expected_total_time = 6.248274
self.assertEqual(total_time, expected_total_time)
def test_report(self):
rep = report.Report('foo1', ('2016-04-07',), ('2016-04-08',),
ctt.REPORTFORMAT, None, None)
ctt.REPORTFORMAT, None, None)
expected_entries = {
'2016-04-07-0826': [
{
'2016-04-07-0826': [
{
'start_datetime': '2016-04-07-0826',
'end_datetime': '2016-04-07-0826',
'comment': 'foo1',
'delta': datetime.timedelta(seconds=6),
'delta_seconds': 6,
'delta_minutes': 0,
},
],
'2016-04-08-1200': [
{
},
],
'2016-04-08-1200': [
{
'start_datetime': '2016-04-08-1200',
'end_datetime': '2016-04-08-1323',
'comment': 'foo1 12',
'delta': datetime.timedelta(seconds=5000),
'delta_seconds': 5000,
'delta_minutes': 83,
},
],
},
],
}
entries = rep.report()
self.assertEqual(entries, expected_entries)
......
......@@ -28,6 +28,7 @@ import os
import datetime
import shutil
class TrackerTestCase(ctt.test.CttTestCase):
def setUp(self):
......@@ -43,7 +44,7 @@ class TrackerTestCase(ctt.test.CttTestCase):
def test___init__(self):
project = 'foo1'
expected_project_dir = os.path.join(ctt.test.fixtures_dir,
os.path.join('.ctt', project))
os.path.join('.ctt', project))
tracker = tr.Tracker(project)
self.assertEqual(tracker.project, project)
self.assertEqual(tracker.project_dir, expected_project_dir)
......@@ -52,31 +53,31 @@ class TrackerTestCase(ctt.test.CttTestCase):
self.assertIsNone(tracker.comment)
self.assertFalse(tracker._tracked_time)
tracker = tr.Tracker(project, start_datetime=('2016-04-09-0900',))
tracker = tr.Tracker(project, start_datetime=('2016-04-09-0900', ))
self.assertEqual(tracker.start_datetime,
datetime.datetime(2016, 4, 9, 9, 0))
datetime.datetime(2016, 4, 9, 9, 0))
self.assertIsNone(tracker.end_datetime)
self.assertFalse(tracker._tracked_time)
tracker = tr.Tracker(project, start_datetime=('2016-04-04-0900',),
end_datetime=('2016-04-09-2000',))
tracker = tr.Tracker(project, start_datetime=('2016-04-04-0900', ),
end_datetime=('2016-04-09-2000',))
self.assertEqual(tracker.start_datetime,
datetime.datetime(2016, 4, 4, 9, 0))
datetime.datetime(2016, 4, 4, 9, 0))
self.assertEqual(tracker.end_datetime,
datetime.datetime(2016, 4, 9, 20, 0))
datetime.datetime(2016, 4, 9, 20, 0))
self.assertTrue(tracker._tracked_time)
@unittest.expectedFailure
def test__init__fail(self):
project = 'foo1'
tracker = tr.Tracker(project, start_datetime=('2016-04-090900',))
tr.Tracker(project, start_datetime=('2016-04-090900', ))
def test_delta(self):
project = 'foo1'
start_dt = datetime.datetime(2016, 4, 4, 9, 0)
end_dt = datetime.datetime(2016, 4, 9, 20, 0)
tracker = tr.Tracker(project, start_datetime=('2016-04-04-0900',),
end_datetime=('2016-04-09-2000',))
tracker = tr.Tracker(project, start_datetime=('2016-04-04-0900', ),
end_datetime=('2016-04-09-2000', ))
expected_delta = end_dt - start_dt
tracker._tracked_time = True
delta = tracker.delta(True)
......@@ -93,7 +94,7 @@ class TrackerTestCase(ctt.test.CttTestCase):
project = 'foo1'
start_dt = '2016-04-09-1730'
tracker = tr.Tracker(project, start_datetime=(start_dt,),
comment=True)
comment=True)
end_dt = datetime.datetime(2016, 4, 9, hour=17, minute=45)
expected_delta = str(15 * 60) + '.0\n' # seconds
tracker.end_datetime = end_dt
......@@ -102,7 +103,7 @@ class TrackerTestCase(ctt.test.CttTestCase):
tracker.comment = expected_comment
expected_comment += "\n"
timedir = os.path.join(ctt.test.fixtures_dir, '.ctt', project,
'2016-04-09-1730')
'2016-04-09-1730')
self.rm_dirs.append(timedir)
if os.path.exists(timedir):
shutil.rmtree(timedir)
......@@ -124,15 +125,15 @@ class TrackerTestCase(ctt.test.CttTestCase):
project = 'foo1'
start_dt = '2016-04-09-1730'
tracker = tr.Tracker(project, start_datetime=(start_dt,),
comment=True)
comment=True)
end_dt = datetime.datetime(2016, 4, 9, hour=17, minute=45)
expected_delta = 15 * 60 # seconds
# expected_delta = 15 * 60 # seconds
tracker.end_datetime = end_dt
tracker._tracked_time = True
expected_comment = "test"
tracker.comment = expected_comment
timedir = os.path.join(ctt.test.fixtures_dir, '.ctt', project,
'2016-04-09-1730')
'2016-04-09-1730')
self.rm_dirs.append(timedir)
if os.path.exists(timedir):
shutil.rmtree(timedir)
......
......@@ -22,17 +22,17 @@
import datetime
import logging
import time
import os
import os.path
import sys
import ctt
log = logging.getLogger(__name__)
class Tracker:
def __init__(self, project, start_datetime = None, end_datetime = None, comment = True):
def __init__(self, project, start_datetime=None, end_datetime=None,
comment=True):
self.project = project
self.project_dir = ctt.project_dir(project)
......@@ -42,12 +42,14 @@ class Tracker:
# Setup default values
try:
if start_datetime:
self.start_datetime = datetime