From 28ed9c502fef8cb1840f4449e5356f845a236700 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 19 Oct 2018 16:34:04 +0200 Subject: [PATCH 1/3] Thorough type check in Todo.__setattr__ --- todoman/model.py | 51 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/todoman/model.py b/todoman/model.py index 024dd582..10a71b40 100644 --- a/todoman/model.py +++ b/todoman/model.py @@ -160,19 +160,44 @@ def clone(self): ) def __setattr__(self, name, value): - # Avoids accidentally setting a field to None when that's not a valid - # attribute. - if not value: - if name in Todo.RRULE_FIELDS: - return object.__setattr__(self, name, '') - if name in Todo.STRING_FIELDS: - return object.__setattr__(self, name, '') - if name in Todo.INT_FIELDS: - return object.__setattr__(self, name, 0) - if name in Todo.LIST_FIELDS: - return object.__setattr__(self, name, []) - - return object.__setattr__(self, name, value) + """Check type and avoid setting fields to None""" + """when that is not a valid attribue.""" + + v = value + + if name in Todo.RRULE_FIELDS: + if value is None: + v = '' + else: + assert isinstance(value, str), ( + "Got {0} for {1} where str was expected" + .format(type(value), name)) + + if name in Todo.STRING_FIELDS: + if value is None: + v = '' + else: + assert isinstance(value, str), ( + "Got {0} for {1} where str was expected" + .format(type(value), name)) + + if name in Todo.INT_FIELDS: + if value is None: + v = 0 + else: + assert isinstance(value, int), ( + "Got {0} for {1} where int was expected" + .format(type(value), name)) + + if name in Todo.LIST_FIELDS: + if value is None: + v = [] + else: + assert isinstance(value, list), ( + "Got {0} for {1} where list was expected" + .format(type(value), name)) + + return object.__setattr__(self, name, v) @property def is_completed(self): From 89a680aebdbc15c628bca739b78a06a1ddcbdf40 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 19 Oct 2018 16:42:39 +0200 Subject: [PATCH 2/3] Formatter: distinguish columnize for text and lists --- todoman/formatters.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/todoman/formatters.py b/todoman/formatters.py index 9ba4c956..2f528386 100644 --- a/todoman/formatters.py +++ b/todoman/formatters.py @@ -85,13 +85,23 @@ def compact_multiple(self, todos): return tabulate(table, tablefmt='plain') - def _columnize(self, label, text): + def _columnize_text(self, label, text): + """Display text, split text by line-endings, on multiple colums,""" + """do nothing if text is empty or None""" + lines = text.splitlines() if text else None + + return self._columnize_list(label, lines) + + def _columnize_list(self, label, lst): + """Display list on multiple columns,""" + """do nothing if list is empty or None""" + rows = [] - lines = text.splitlines() - rows.append([label, lines[0]]) - for line in lines[1:]: - rows.append([None, line]) + if lst: + rows.append([label, lst[0]]) + for line in lst[1:]: + rows.append([None, line]) return rows From ef6ec9968dc1f1f9d041a8c5a61dbd01644d9f70 Mon Sep 17 00:00:00 2001 From: Stefan Haun Date: Fri, 19 Oct 2018 16:47:46 +0200 Subject: [PATCH 3/3] Formatter: Adapt to new function name and remove obsolete checks --- todoman/formatters.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/todoman/formatters.py b/todoman/formatters.py index 2f528386..3e7d185e 100644 --- a/todoman/formatters.py +++ b/todoman/formatters.py @@ -112,10 +112,8 @@ def detailed(self, todo): :param Todo todo: The todo component. """ extra_rows = [] - if todo.description: - extra_rows += self._columnize('Description', todo.description) - if todo.location: - extra_rows += self._columnize('Location', todo.location) + extra_rows += self._columnize_text('Description', todo.description) + extra_rows += self._columnize_text('Location', todo.location) if extra_rows: return '{}\n\n{}'.format(