Skip to content

Commit

Permalink
Do not break if a day only contains a single line.
Browse files Browse the repository at this point in the history
Render a better error message if an entry cannot be parsed.
  • Loading branch information
icemac committed Dec 20, 2023
1 parent 7244be5 commit 9a269e5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
4 changes: 3 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Change log
0.3 (unreleased)
================

- Nothing changed yet.
- Do not break if a day only contains a single line.

- Render a better error message if an entry cannot be parsed.


0.2.1 (2023-12-11)
Expand Down
14 changes: 12 additions & 2 deletions gtimelog2tick.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,17 @@ def read_timelog(
def parse_entry_message(
config: dict,
message: str
) -> tuple[str, str, int]:
) -> tuple[str, str, int | None]:
"""Parse entry message into "project: task", text and task_id."""
project_name, task_name, *text_parts = message.split(':')
try:
project_name, task_name, *text_parts = message.split(':')
except ValueError:
# This can also happen if there is only a single line for a day, which
# is omitted later on, having too little entries is also handled later:
return (
'<no task>',
f'Error: Unable to split {message!r}, it needs one colon or more.',
None)
task_name = task_name.strip()

tick_projects = [
Expand Down Expand Up @@ -265,6 +273,8 @@ def parse_timelog(
task, text, task_id = parse_entry_message(config, entry.message)
worklog = WorkLog(entry, text, task, task_id)
if worklog.hours > 0:
if worklog.task_id is None:
raise DataError(worklog.text)
yield worklog
elif worklog.hours < 0:
raise DataError(f'Negative hours: {worklog}')
Expand Down
39 changes: 39 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,36 @@ def test_gtimelog2tick__parse_timelog__4(env, mocker):
]


def test_gtimelog2tick__parse_timelog__5(env, mocker):
"""It it ignores days with only one entry."""
mocker.patch('gtimelog2tick.get_now',
return_value=datetime.datetime(2023, 12, 7).astimezone())
assert env.run() is None
env.log([
'',
'2023-12-07 10:30: arrived',
])
assert env.run() is None
assert env.get_worklog() == []
assert env.get_ticklog() == []


def test_gtimelog2tick__parse_timelog__6(env, mocker):
"""It raises a DataError if the text cannot be parsed."""
mocker.patch('gtimelog2tick.get_now',
return_value=datetime.datetime(2023, 12, 7).astimezone())
assert env.run() is None
env.log([
'',
'2023-12-07 10:30: arrived',
'2023-12-07 12:25: project2-new',
])
with pytest.raises(gtimelog2tick.DataError) as err:
env.run()
err.match(
"Error: Unable to split 'project2-new', it needs one colon or more.")


def test_full_sync(env):
assert env.run(['--since', '2014-01-01']) is None
env.log([
Expand Down Expand Up @@ -695,6 +725,15 @@ def test_gtimelog2tick__parse_entry_message__6(env):
r" match. \(dev - 2, dev - 23\)")


def test_gtimelog2tick__parse_entry_message__7():
"""It handles entries it cannot parse specially."""
result = gtimelog2tick.parse_entry_message({}, 'arrived')
assert result == (
'<no task>',
"Error: Unable to split 'arrived', it needs one colon or more.",
None)


def test_gtimelog2tick__read_config__1(tmpdir):
"""It renders an exception if the config files does not exist."""
path = pathlib.Path(tmpdir) / 'i-do-not-exist.ini'
Expand Down

0 comments on commit 9a269e5

Please sign in to comment.