Example #1
0
    def test022(self):
        """Parse mix of <date>: <number of hours> | <period>+"""
        stream = StringIO.StringIO(
            "20111202: 4.5\n"
            "20111205: 10:00-12:15, 12:45-17:45  # Comment..."
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 2)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 4.5)
        self.assertEqual(record.project, [""])

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 5))
        self.assertEqual(record.nr_hours, 7.25)
        self.assertEqual(record.project, [""])


        stream = StringIO.StringIO(
            "20111202: 4.5  # Comment...\n"
            "20111202: 10:00-12:15"
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 2)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 4.5)
        self.assertEqual(record.project, [""])

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 2.25)
        self.assertEqual(record.project, [""])


        stream = StringIO.StringIO(
            "20111202: 10:00-12:15, 4.5"
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 1)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 6.75)
        self.assertEqual(record.project, [""])
Example #2
0
 def test003(self):
     """Parse empty line"""
     stream = StringIO.StringIO(
         "\n"
     )
     records = track_time.parse(stream)
     self.assertEqual(len(records), 0)
Example #3
0
def query_hours(
        timesheet_pathname,
        nr_hours_to_work,
        project_pattern,
        nr_weeks_to_report):
    selected_records = track_time.parse(file(timesheet_pathname, "r"))
    to_time_point = track_time.last_day_of_week(datetime.date.today())
    from_time_point = to_time_point - datetime.timedelta(
        days=(nr_weeks_to_report * 7) - 1)
    assert from_time_point.isocalendar()[2] == 1  # Monday.
    assert to_time_point.isocalendar()[2] == 7  # Sunday.
    selected_records = track_time.filter_projects_by_name(selected_records,
        project_pattern)
    selected_records = track_time.filter_projects_by_date(selected_records,
        from_time_point, to_time_point)
    merged_records = track_time.merge_records_by_date(selected_records)
    merged_records = sorted(merged_records, key=lambda record: record.date)

    # Hours per day (work + sick + holiday + vacation).
    table = prettytable.PrettyTable(["Date", "Hours"])
    table.align = "r"

    for record in merged_records:
        table.add_row([
            "{} {}".format(record.date.strftime("%a"), record.date),
            "{:.2f}".format(record.nr_hours)
        ])

    write_table(table)

    merged_records = track_time.merge_records_by_week(selected_records)
    merged_records = sorted(merged_records, key=lambda record: record.date)

    # Weekly balance.
    table = prettytable.PrettyTable(["Week", "Balance"])
    table.align = "r"

    for record in merged_records:
        table.add_row([
            "{} {}".format(record.date.strftime("%a"), record.date),
            "{:+.2f}".format(record.nr_hours - nr_hours_to_work)
        ])

    write_table(table)

    # Balance of the whole period.
    if merged_records:
        table = prettytable.PrettyTable(["Period", "Balance"])
        table.align = "r"

        record = track_time.merge_records(selected_records)
        record.date = merged_records[0].date

        table.add_row([
            "{} {}".format(record.date.strftime("%a"), record.date),
            "{:+.2f}".format(record.nr_hours - (nr_weeks_to_report *
                nr_hours_to_work))
        ])

        write_table(table)
Example #4
0
    def test031(self):
        """Parse <date>: <number of hours>: <project>"""
        stream = StringIO.StringIO(
            "20121030: 3: project_x\n"
            "20121030: 5: project_y # Comment...\n"
            "20121031: 8: project_z"
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 3)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2012, 10, 30))
        self.assertEqual(record.nr_hours, 3.0)
        self.assertEqual(len(record.project), 1)
        self.assertEqual(record.project[0], "project_x")

        record = records[1]
        self.assertEqual(record.date, datetime.date(2012, 10, 30))
        self.assertEqual(record.nr_hours, 5.0)
        self.assertEqual(len(record.project), 1)
        self.assertEqual(record.project[0], "project_y")

        record = records[2]
        self.assertEqual(record.date, datetime.date(2012, 10, 31))
        self.assertEqual(record.nr_hours, 8.0)
        self.assertEqual(len(record.project), 1)
        self.assertEqual(record.project[0], "project_z")
Example #5
0
 def test002(self):
     """Parse comment"""
     stream = StringIO.StringIO(
       "# This is a comment\n"
     )
     records = track_time.parse(stream)
     self.assertEqual(len(records), 0)
Example #6
0
 def test004(self):
     """Parse line with only whitespace"""
     stream = StringIO.StringIO(
         " \n"
         "\t\n"
     )
     records = track_time.parse(stream)
     self.assertEqual(len(records), 0)
Example #7
0
    def test_merge_records_by_category(self):
        records = track_time.parse(file("categories-001.txt"))

        merged_records = track_time.merge_records_by_category(records)
        self.assertEqual(len(merged_records), 4)

        self.assertEqual(merged_records[0].project, ["project"])
        self.assertEqual(merged_records[1].project, ["holiday"])
        self.assertEqual(merged_records[2].project, ["vacation"])
        self.assertEqual(merged_records[3].project, ["sick"])
Example #8
0
    def test011(self):
        """Parse <date>: <number of hours>"""
        stream = StringIO.StringIO(
            "20111202: 8\n"
            "20111205: 4.5  # Comment..."
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 2)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 8.0)
        self.assertEqual(record.project, [""])

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 5))
        self.assertEqual(record.nr_hours, 4.5)
        self.assertEqual(record.project, [""])

        stream = StringIO.StringIO(
            "20111202: 8  # Comment...\n"
            "20111202: 4.5\n"
            "20111202: 3, 4"
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 3)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 8.0)
        self.assertEqual(record.project, [""])

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 4.5)
        self.assertEqual(record.project, [""])

        record = records[2]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 7.0)
        self.assertEqual(record.project, [""])
Example #9
0
    def test_merge_child_projects_with_parents(self):
        records = track_time.parse(file("sub_projects-001.txt"))

        merged_records = track_time.merge_child_projects_with_parents(records)
        self.assertEqual(len(merged_records), 2)

        self.assertEqual(merged_records[0].date, None)
        self.assertEqual(merged_records[0].nr_hours, 48)
        self.assertEqual(merged_records[0].project, ["my_project_a"])

        self.assertEqual(merged_records[1].date, None)
        self.assertEqual(merged_records[1].nr_hours, 48)
        self.assertEqual(merged_records[1].project, ["my_project_b"])
Example #10
0
    def test051(self):
        """Parse Unicode characters"""
        stream = StringIO.StringIO(
            "20111202: 8:30-12:00, 12:30-17:00: prøject_ø # Cømment...\n"
        )

        records = track_time.parse(stream)
        self.assertEqual(len(records), 1)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 8)
        self.assertEqual(len(record.project), 1)
        self.assertEqual(record.project[0], "prøject_ø")
Example #11
0
    def test_filter_projects_by_name(self):
        records = track_time.parse(file("sub_projects-001.txt"))
        self.assertEqual(len(records), 20)

        selected_records = track_time.filter_projects_by_name(records)
        self.assertEqual(len(selected_records), 20)

        selected_records = track_time.filter_projects_by_name(records,
            project_name_pattern="my_project_b/*")
        self.assertEqual(len(selected_records), 10)

        selected_records = track_time.filter_projects_by_name(records,
            project_name_pattern="*/blog")
        self.assertEqual(len(selected_records), 4)
Example #12
0
    def test_merge_records_by_week(self):
        records = track_time.parse(file("sub_projects-001.txt"))

        merged_records = track_time.merge_records_by_week(records)
        self.assertEqual(len(merged_records), 5)
        self.assertEqual(merged_records[0].date, datetime.date(2013, 12, 30))
        self.assertEqual(merged_records[1].date, datetime.date(2014, 1, 6))
        self.assertEqual(merged_records[2].date, datetime.date(2014, 1, 27))
        self.assertEqual(merged_records[3].date, datetime.date(2014, 2, 3))
        self.assertEqual(merged_records[4].date, datetime.date(2014, 2, 10))

        self.assertEqual(merged_records[0].nr_hours, 30)
        self.assertEqual(merged_records[1].nr_hours, 18)
        self.assertEqual(merged_records[2].nr_hours, 13)
        self.assertEqual(merged_records[3].nr_hours, 23)
        self.assertEqual(merged_records[4].nr_hours, 12)
Example #13
0
def query_project(
        timesheet_pathname,
        project_pattern,
        aggregate):
    records = track_time.parse(file(timesheet_pathname, "r"))
    selected_records = track_time.filter_projects_by_name(records,
        project_pattern)
    merged_records = track_time.merge_records_by_project(selected_records)

    if aggregate:
        merged_records = track_time.merge_child_projects_with_parents(
            merged_records)

    # Number of hours per projects ---------------------------------------------
    table = prettytable.PrettyTable(["Project", "Hours", "Days"])
    table.align["Project"] = "l"
    table.align["Hours"] = "r"
    table.align["Days"] = "r"
    table.sortby="Project"

    for record in merged_records:
        table.add_row([
            record.project_string(),
            "{:.2f}".format(record.nr_hours),
            "{:.2f}".format(record.nr_days)
        ])

    write_table(table)


    # Number of hours overall --------------------------------------------------
    table = prettytable.PrettyTable(["Hours", "Days"])
    table.align["Hours"] = "r"
    table.align["Days"] = "r"

    nr_hours = 0.0
    nr_days = 0.0
    for record in merged_records:
        nr_hours += record.nr_hours
        nr_days += record.nr_days

    table.add_row([
        "{:.2f}".format(nr_hours),
        "{:.2f}".format(nr_days)
    ])

    write_table(table)
Example #14
0
    def test061(self):
        """Parse sub-projects"""
        stream = StringIO.StringIO(
            "20111202: 8: a/b/c/d/e/f"
        )

        records = track_time.parse(stream)
        self.assertEqual(len(records), 1)

        record = records[0]
        self.assertEqual(len(record.project), 6)
        self.assertEqual(record.project[0], "a")
        self.assertEqual(record.project[1], "b")
        self.assertEqual(record.project[2], "c")
        self.assertEqual(record.project[3], "d")
        self.assertEqual(record.project[4], "e")
        self.assertEqual(record.project[5], "f")
Example #15
0
    def test101(self):
        """Parse error when input is wrongly formatted"""
        lines = [
            "20111202:",
            "20111202: project_a",
            "201x1202: 8",
            "20111202: 8:05-9x",
        ]

        for line in lines:
            with self.assertRaises(ValueError) as context_manager:
                stream = StringIO.StringIO(
                  line
                )
                records = track_time.parse(stream)
            exception = context_manager.exception
            self.assert_(str(exception).find("Parse error") != -1)
Example #16
0
    def test010(self):
        """Parse <date>"""
        stream = StringIO.StringIO(
            "20111202\n"
            "20111205  # Comment..."
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 2)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 8.0)
        self.assertEqual(record.project, [""])

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 5))
        self.assertEqual(record.nr_hours, 8.0)
        self.assertEqual(record.project, [""])
Example #17
0
    def test021(self):
        """Parse <date>: <period>+"""
        stream = StringIO.StringIO(
            "20111202: 8:30-12:00, 12:30-17:00  # Comment...\n"
            "20111205: 10:00-12:15, 12:45-17:45"
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 2)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 8)
        self.assertEqual(record.project, [""])

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 5))
        self.assertEqual(record.nr_hours, 7.25)
        self.assertEqual(record.project, [""])
Example #18
0
    def test041(self):
        """Parse <date>: <period>+: <project>"""
        stream = StringIO.StringIO(
            "20111202: 8:30-12:00, 12:30-17:00: project_a\n"
            "20111205: 10:00-12:15, 12:45-17:45: project_b # Comment..."
        )
        records = track_time.parse(stream)
        self.assertEqual(len(records), 2)

        record = records[0]
        self.assertEqual(record.date, datetime.date(2011, 12, 2))
        self.assertEqual(record.nr_hours, 8)
        self.assertEqual(len(record.project), 1)
        self.assertEqual(record.project[0], "project_a")

        record = records[1]
        self.assertEqual(record.date, datetime.date(2011, 12, 5))
        self.assertEqual(record.nr_hours, 7.25)
        self.assertEqual(len(record.project), 1)
        self.assertEqual(record.project[0], "project_b")
Example #19
0
def query_vacation(
        timesheet_pathname,
        nr_hours_to_work,  # Per week.
        nr_hours_vacation):  # Per year.
    records = track_time.parse(file(timesheet_pathname, "r"))
    merged_records = track_time.merge_records_by_category(records)

    # Vacation -----------------------------------------------------------------
    record_by_category = {record.project_string(): record for record in
        merged_records}
    vacation_record = record_by_category["vacation"]
    nr_hours_spent = vacation_record.nr_hours
    nr_hours_left = nr_hours_vacation - nr_hours_spent
    nr_days_left = nr_hours_left / 8.0

    table = prettytable.PrettyTable(["Available", "Spent", "Balance (h)",
        "Balance (d)"])
    table.align = "r"

    table.add_row([
        "{:.2f}".format(nr_hours_vacation),
        "{:.2f}".format(nr_hours_spent),
        "{:.2f}".format(nr_hours_left),
        "{:.2f}".format(nr_days_left)
    ])

    write_table(table, header="vacation")


    # Overtime -----------------------------------------------------------------
    # Number of hours that should have been spent on work, by the end of the
    # week.
    to_time_point = track_time.last_day_of_week(datetime.date.today())
    week_number = to_time_point.isocalendar()[1]
    nr_hours_to_work *= week_number

    # Number of hours that have been spent on work, in whatever way.
    nr_hours_spent_on_work = sum([record.nr_hours for record in merged_records])

    nr_hours_overtime = nr_hours_spent_on_work - nr_hours_to_work
    nr_days_overtime = nr_hours_overtime / 8.0

    table = prettytable.PrettyTable(["To work", "Worked", "Balance (h)",
        "Balance (d)"])
    table.align = "r"

    table.add_row([
        "{:.2f}".format(nr_hours_to_work),
        "{:.2f}".format(nr_hours_spent_on_work),
        "{:.2f}".format(nr_hours_overtime),
        "{:.2f}".format(nr_days_overtime)
    ])

    write_table(table, header="overtime")

    # Overall ------------------------------------------------------------------
    balance_vacation = nr_hours_left
    balance_overtime = nr_hours_overtime
    balance_in_hours = nr_hours_left + nr_hours_overtime
    balance_in_days = balance_in_hours / 8.0

    table = prettytable.PrettyTable(["Balance vacation", "Balance overtime",
        "Balance (h)", "Balance (d)"])
    table.align = "r"

    table.add_row([
        "{:.2f}".format(balance_vacation),
        "{:.2f}".format(balance_overtime),
        "{:.2f}".format(balance_in_hours),
        "{:.2f}".format(balance_in_days)
    ])

    write_table(table, header="balance")
Example #20
0
    def test_merge_records_by_date(self):
        records = track_time.parse(file("sub_projects-001.txt"))

        merged_records = track_time.merge_records_by_date(records)
        self.assertEqual(len(merged_records), 16)
Example #21
0
 def test_filter_projects_by_date(self):
     records = track_time.parse(file("sub_projects-001.txt"))
     selected_records = track_time.filter_projects_by_date(records,
         from_time_point=datetime.date(2014, 2, 2),
         to_time_point=datetime.date(2014, 2, 5))
     self.assertEqual(len(selected_records), 5)
Example #22
0
 def test001(self):
     """Parse empty file"""
     stream = StringIO.StringIO()
     records = track_time.parse(stream)
     self.assertEqual(len(records), 0)