Пример #1
0
    def test_session_and_task(self, mock_now):
        mock_now.return_value = datetime(2020, 1, 1, tzinfo=timezone.utc)
        with tempfile.NamedTemporaryFile() as fh:
            instance = Log(fh.name)

            instance.commit(wc.TOKEN_SESSION,
                            wc.TOKEN_START,
                            time="2020-01-01T00:00:00+00:00")
            instance.commit(
                wc.TOKEN_TASK,
                wc.TOKEN_START,
                time="2020-01-01T00:00:00+00:00",
                identifier="task1",
            )
            instance.commit(
                wc.TOKEN_TASK,
                wc.TOKEN_STOP,
                time="2020-01-01T01:00:00+00:00",
                identifier="task1",
            )
            instance.commit(
                wc.TOKEN_SESSION,
                wc.TOKEN_STOP,
                time="2020-01-01T01:00:00+00:00",
            )

            fh.seek(0)

            content = fh.read().decode()
            self.assertMatchSnapshot(content)
Пример #2
0
def run() -> None:
    """ Main method """
    logger = configure_logger()
    parser = get_arg_parser()

    cli_args = parser.parse_args()
    log_level = wc.LOG_LEVELS[min(cli_args.verbosity, len(wc.LOG_LEVELS) - 1)]
    logger.setLevel(log_level)

    logger.debug(f"Parsed CLI arguments: {cli_args}")
    logger.debug(f"Path to config files: {wc.CONFIG_FILES}")

    if cli_args.subcmd is None:
        parser.print_help()
        return

    cfg = ConfigParser()
    cfg.read(wc.CONFIG_FILES)

    with StringIO() as ss:
        cfg.write(ss)
        ss.seek(0)
        logger.debug(f"Config content:\n{ss.read()}\nEOF")

    worklog_fp = os.path.expanduser(cfg.get("worklog", "path"))
    log = Log(worklog_fp)

    limits = json.loads(cfg.get("workday", "auto_break_limit_minutes"))
    durations = json.loads(cfg.get("workday", "auto_break_duration_minutes"))
    log.auto_break = AutoBreak(limits, durations)

    dispatch(log, parser, cli_args, cfg)
Пример #3
0
    def test_ok(self):
        logger = logging.getLogger("test_logger")
        with patch.object(logger, "error") as mock_logger:
            fp = self._get_testdata_fp("doctor_session_ok")
            instance = Log(fp, logger=logger)
            instance.doctor()

            mock_logger.assert_not_called()
Пример #4
0
    def test_report_with_tasks(self):
        fp = self._get_testdata_fp("report_with_tasks")
        instance = Log(fp)
        date_from = datetime(2020, 1, 1, tzinfo=timezone.utc)
        date_to = datetime(2020, 3, 1, tzinfo=timezone.utc)
        instance.report(date_from, date_to)

        out, _ = self._capsys.readouterr()
        self.assertMatchSnapshot(out)
Пример #5
0
    def test_tracking_off(self):
        with patch("worklog.constants.LOCAL_TIMEZONE", new=timezone.utc):
            fp = self._get_testdata_fp("status_tracking_off")
            instance = Log(fp)
            query_date = date(2020, 1, 1)

            instance.status(8, 10, query_date=query_date)

        out, _ = self._capsys.readouterr()
        self.assertMatchSnapshot(out)
Пример #6
0
    def test_report_with_tasks_and_autobreak(self):
        fp = self._get_testdata_fp("report_with_tasks")
        instance = Log(fp)
        instance.auto_break = AutoBreak(limits=[0], durations=[60])
        date_from = datetime(2020, 1, 1, tzinfo=timezone.utc)
        date_to = datetime(2020, 3, 1, tzinfo=timezone.utc)
        instance.report(date_from, date_to)

        out, _ = self._capsys.readouterr()
        self.assertMatchSnapshot(out)
Пример #7
0
    def test_wrong_order(self):
        logger = logging.getLogger("test_logger")
        with patch.object(logger, "error") as mock_logger:
            fp = self._get_testdata_fp("doctor_session_wrong_order")
            instance = Log(fp, logger=logger)
            instance.doctor()

            calls = (call(
                ErrMsg.WRONG_SESSION_ORDER.value.format(date="2020-01-01")), )

            mock_logger.assert_has_calls(calls)
Пример #8
0
    def test_list_tasks(self):
        fp = self._get_testdata_fp("tasks_multiple_nested")
        instance = Log(fp)
        instance.list_tasks()

        out, err = self._capsys.readouterr()
        expected = """These tasks are listed in the log:
task1 (2)
task2 (2)
task3 (2)
"""
        assert out == expected
Пример #9
0
    def test_stop_entry_missing_single(self):
        logger = logging.getLogger("test_logger")
        with patch.object(logger, "error") as mock_logger:
            fp = self._get_testdata_fp("doctor_session_stop_missing_single")
            instance = Log(fp, logger=logger)
            instance.doctor()

            calls = (call(
                ErrMsg.MISSING_SESSION_ENTRY.value.format(
                    type=wc.TOKEN_STOP, date="2020-01-01")), )

            mock_logger.assert_has_calls(calls)
Пример #10
0
    def test_tracking_off_with_fmt(self):
        with patch("worklog.constants.LOCAL_TIMEZONE", new=timezone.utc):
            fp = self._get_testdata_fp("status_tracking_off")
            instance = Log(fp)
            query_date = date(2020, 1, 1)

            instance.status(8,
                            10,
                            query_date=query_date,
                            fmt="{tracking_status}")

        out, _ = self._capsys.readouterr()
        self.assertEqual(out, "off")
Пример #11
0
    def test_task_start_entry_missing(self):
        logger = logging.getLogger("test_logger")
        with patch.object(logger, "error") as mock_logger:
            fp = self._get_testdata_fp("doctor_task_start_missing")
            instance = Log(fp, logger=logger)
            instance.doctor()

            calls = (call(
                ErrMsg.MISSING_TASK_ENTRY.value.format(type=wc.TOKEN_START,
                                                       date="2020-01-01",
                                                       task_id="task1")), )

            mock_logger.assert_has_calls(calls)
Пример #12
0
    def test_stop_session_with_running_task(self, mock_now):
        mock_now.return_value = datetime(2020, 1, 1, tzinfo=timezone.utc)
        with tempfile.NamedTemporaryFile() as fh:
            instance = Log(fh.name)

            instance.commit(wc.TOKEN_SESSION,
                            wc.TOKEN_START,
                            time="2020-01-01T00:00:00+00:00")
            instance.commit(
                wc.TOKEN_TASK,
                wc.TOKEN_START,
                time="2020-01-01T00:00:00+00:00",
                identifier="task1",
            )

            with self.assertRaises(SystemExit) as err:
                instance.commit(
                    wc.TOKEN_SESSION,
                    wc.TOKEN_STOP,
                    time="2020-01-01T01:00:00+00:00",
                )

            _, stderr = self._capsys.readouterr()

            self.assertEqual(
                stderr,
                ErrMsg.STOP_SESSION_TASKS_RUNNING.value.format(
                    active_tasks=["task1"]) + "\n",
            )
            self.assertTrue(err.exception.code, 1)
Пример #13
0
    def test_day_with_no_content_fmt(self):
        with patch("worklog.constants.LOCAL_TIMEZONE", new=timezone.utc):
            fp = self._get_testdata_fp("status_tracking_off")
            instance = Log(fp)
            query_date = date(2020, 1, 2)

            with self.assertRaises(SystemExit) as err:
                instance.status(8,
                                10,
                                query_date=query_date,
                                fmt="{tracking_status}")

        stdout, _ = self._capsys.readouterr()
        self.assertEqual(stdout, ErrMsg.NA.value)
        self.assertEqual(err.exception.code, 0)
Пример #14
0
    def test_empty(self):
        fp = self._get_testdata_fp("status_empty")
        instance = Log(fp)
        query_date = date(2020, 1, 1)

        with self.assertRaises(SystemExit) as err:
            instance.status(8, 10, query_date=query_date)

        _, stderr = self._capsys.readouterr()
        self.assertEqual(
            stderr,
            ErrMsg.EMPTY_LOG_DATA.value + "\n",
        )

        self.assertEqual(err.exception.code, 1)
Пример #15
0
    def test_empty_with_fmt(self):
        fp = self._get_testdata_fp("status_empty")
        instance = Log(fp)
        query_date = date(2020, 1, 1)

        with self.assertRaises(SystemExit) as err:
            instance.status(8,
                            10,
                            query_date=query_date,
                            fmt="{tracking_status}")

        out, _ = self._capsys.readouterr()
        self.assertEqual(out, ErrMsg.NA.value)

        self.assertEqual(err.exception.code, 0)
Пример #16
0
    def test_file_mode(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            fp = Path(tmpdir, "foobar")
            instance = Log(fp)

            self.assertTrue(os.access(fp, os.R_OK))
            self.assertTrue(os.access(fp, os.W_OK))
Пример #17
0
    def test_day_with_no_content(self):
        with patch("worklog.constants.LOCAL_TIMEZONE", new=timezone.utc):
            fp = self._get_testdata_fp("status_tracking_off")
            instance = Log(fp)
            query_date = date(2020, 1, 2)

            with self.assertRaises(SystemExit) as err:
                instance.status(8, 10, query_date=query_date)

        _, stderr = self._capsys.readouterr()
        self.assertEqual(
            stderr,
            ErrMsg.EMPTY_LOG_DATA_FOR_DATE.value.format(query_date=query_date)
            + "\n",
        )
        self.assertEqual(err.exception.code, 1)
Пример #18
0
 def test_file_is_read(self):
     fp = self._get_testdata_fp("session_simple")
     instance = Log(fp)
     self.assertFalse(instance._log_df.empty)
Пример #19
0
    def test_file_created(self):
        with tempfile.TemporaryDirectory() as tmpdir:
            fp = Path(tmpdir, "foobar")
            instance = Log(fp)

            self.assertTrue(fp.exists())
Пример #20
0
    def test_invalid_category(self):
        with tempfile.NamedTemporaryFile() as fh:
            instance = Log(fh.name)

            with self.assertRaises(ValueError):
                instance.commit("foobar", wc.TOKEN_START)
Пример #21
0
def dispatch(
    log: Log, parser: ArgumentParser, cli_args: Namespace, cfg: ConfigParser
) -> None:
    """
    Dispatch request to Log instance based on CLI arguments and
    configuration values.
    """
    if cli_args.subcmd == wc.SUBCMD_SESSION:
        if cli_args.type in [wc.TOKEN_START, wc.TOKEN_STOP]:
            log.commit(
                wc.TOKEN_SESSION,
                cli_args.type,
                cli_args.offset_minutes,
                cli_args.time,
                force=cli_args.force,
            )
    elif cli_args.subcmd == wc.SUBCMD_TASK:
        if cli_args.type in [wc.TOKEN_START, wc.TOKEN_STOP]:
            if cli_args.type == wc.TOKEN_START and cli_args.auto_stop:
                commit_dt = calc_log_time(cli_args.offset_minutes, cli_args.time)
                log.stop_active_tasks(commit_dt)
            log.commit(
                wc.TOKEN_TASK,
                cli_args.type,
                cli_args.offset_minutes,
                cli_args.time,
                identifier=cli_args.id,
            )
        elif cli_args.type == "list":
            log.list_tasks()
        elif cli_args.type == "report":
            log.task_report(cli_args.id)
    elif cli_args.subcmd == wc.SUBCMD_STATUS:
        hours_target = float(cfg.get("workday", "hours_target"))
        hours_max = float(cfg.get("workday", "hours_max"))
        fmt = cli_args.fmt
        query_date = date.today()
        if cli_args.yesterday:
            query_date -= timedelta(days=1)
        elif cli_args.date:
            query_date = cli_args.date.date()
        log.status(hours_target, hours_max, query_date=query_date, fmt=fmt)
    elif cli_args.subcmd == wc.SUBCMD_DOCTOR:
        log.doctor()
    elif cli_args.subcmd == wc.SUBCMD_LOG:
        n = cli_args.number
        no_pager_max_entries = int(cfg.get("worklog", "no_pager_max_entries"))
        use_pager = not cli_args.no_pager and (cli_args.all or n > no_pager_max_entries)
        categories = cli_args.category
        if not cli_args.all:
            log.log(cli_args.number, use_pager, categories)
        else:
            log.log(-1, use_pager, categories)
    elif cli_args.subcmd == wc.SUBCMD_REPORT:
        log.report(cli_args.date_from, cli_args.date_to)
Пример #22
0
    def test_invalid_type(self):
        with tempfile.NamedTemporaryFile() as fh:
            instance = Log(fh.name)

            with self.assertRaises(ValueError):
                instance.commit(wc.TOKEN_SESSION, "foobar")