1
0
Fork 0
mirror of https://github.com/topydo/topydo.git synced 2024-05-20 05:48:35 +00:00

Handle errors in file I/O more gracefully

Show an error on I/O errors, permissions or Unicode decoding issues.

Open issue is that errors are not printed properly in the column UI.
Instead of calling CLIApplicationBase.error(), the column UI should
pass on the error to the user in a way that does not involve stderr.
This commit is contained in:
Bram Schoenmakers 2017-02-22 21:27:43 +01:00
parent dea65c346c
commit 56d98b6058
5 changed files with 69 additions and 26 deletions

View file

@ -21,6 +21,9 @@ This module deals with todo.txt files.
import codecs
import os.path
class TodoFileException(Exception):
pass
class TodoFile(object):
"""
@ -38,8 +41,9 @@ class TodoFile(object):
todofile = codecs.open(self.path, 'r', encoding="utf-8")
todos = todofile.readlines()
todofile.close()
except IOError:
pass
except (PermissionError, IOError, UnicodeDecodeError) as err:
raise TodoFileException('Error while reading: {}'.format(str(err))) from err
todofile.close()
return todos
@ -51,14 +55,17 @@ class TodoFile(object):
to the file.
"""
todofile = codecs.open(self.path, 'w', encoding="utf-8")
try:
todofile = codecs.open(self.path, 'w', encoding="utf-8")
if p_todos is list:
for todo in p_todos:
todofile.write(str(todo))
else:
todofile.write(p_todos)
if p_todos is list:
for todo in p_todos:
todofile.write(str(todo))
else:
todofile.write(p_todos)
todofile.write("\n")
todofile.close()
todofile.write("\n")
todofile.close()
except (PermissionError, IOError) as err:
raise TodoFileException('Error while writing: {}'.format(str(err))) from err
todofile.close()

View file

@ -23,6 +23,7 @@ import getopt
import sys
from topydo.lib.Color import AbstractColor, Color
from topydo.lib.TodoFile import TodoFileException
from topydo.lib.TopydoString import TopydoString
MAIN_OPTS = "ac:C:d:ht:v"
@ -157,7 +158,12 @@ def _retrieve_archive():
and the second element is a TodoFile.
"""
archive_file = TodoFile.TodoFile(config().archive())
archive = TodoListBase.TodoListBase(archive_file.read())
try:
archive = TodoListBase.TodoListBase(archive_file.read())
except TodoFileException as err:
error('Could not read archive file: {}.'.format(err))
archive = None
return (archive, archive_file)
@ -234,7 +240,10 @@ class CLIApplicationBase(object):
command.execute()
if archive.dirty:
archive_file.write(archive.print_todos())
try:
archive_file.write(archive.print_todos())
except TodoFileException as err:
error('Item(s) could not be archived: {}'.format(str(err)))
def _help(self, args):
if args is None:
@ -298,8 +307,12 @@ class CLIApplicationBase(object):
if self.backup:
self.backup.save(self.todolist)
self.todofile.write(self.todolist.print_todos())
self.todolist.dirty = False
try:
self.todofile.write(self.todolist.print_todos())
self.todolist.dirty = False
except TodoFileException as err:
error(str(err))
error('The last operation could not be saved.')
self.backup = None

View file

@ -19,7 +19,7 @@
import sys
from topydo.ui.CLIApplicationBase import CLIApplicationBase, error
from topydo.lib import TodoFile
from topydo.lib.TodoFile import TodoFile, TodoFileException
from topydo.lib.Config import config, ConfigError
# First thing is to poke the configuration and check whether it's sane
@ -32,7 +32,7 @@ except ConfigError as config_error:
sys.exit(1)
from topydo.Commands import get_subcommand
from topydo.lib import TodoList
from topydo.lib.TodoList import TodoList
class CLIApplication(CLIApplicationBase):
@ -47,8 +47,12 @@ class CLIApplication(CLIApplicationBase):
""" Main entry function. """
args = self._process_flags()
self.todofile = TodoFile.TodoFile(config().todotxt())
self.todolist = TodoList.TodoList(self.todofile.read())
self.todofile = TodoFile(config().todotxt())
try:
self.todolist = TodoList(self.todofile.read())
except TodoFileException as err:
error('Could not read todo file: {}'.format(str(err)))
try:
(subcommand, args) = get_subcommand(args)

View file

@ -30,8 +30,9 @@ from topydo.lib.Sorter import Sorter
from topydo.lib.Filter import get_filter_list, RelevanceFilter, DependencyFilter
from topydo.lib.Utils import get_terminal_size
from topydo.lib.View import View
from topydo.lib.TodoFile import TodoFileException
from topydo.lib.TodoFileWatched import TodoFileWatched
from topydo.lib import TodoList
from topydo.lib.TodoList import TodoList
from topydo.ui.CLIApplicationBase import CLIApplicationBase, error, GENERIC_HELP
from topydo.ui.columns.CommandLineWidget import CommandLineWidget
from topydo.ui.columns.ConsoleWidget import ConsoleWidget
@ -110,14 +111,26 @@ class UIApplication(CLIApplicationBase):
self.alt_layout_path = value
def callback():
self.todolist.erase()
self.todolist.add_list(self.todofile.read())
self._update_all_columns()
self._redraw()
try:
todos = self.todofile.read()
self.todolist.erase()
self.todolist.add_list(todos)
self._update_all_columns()
self._redraw()
except TodoFileException as err:
self._print_to_console(
'Error: Could not read todo file: {}'.format(err))
self.column_width = config().column_width()
self.todofile = TodoFileWatched(config().todotxt(), callback)
self.todolist = TodoList.TodoList(self.todofile.read())
try:
todos = self.todofile.read()
except TodoFileException as err:
error('Error: Could not read todo file: {}'.format(err))
sys.exit(1)
self.todolist = TodoList(todos)
self.marked_todos = set()

View file

@ -20,6 +20,7 @@ import os.path
import shlex
import sys
from topydo.lib.TodoFile import TodoFileException
from topydo.ui.CLIApplicationBase import CLIApplicationBase, error, GENERIC_HELP
from topydo.ui.prompt.TopydoCompleter import TopydoCompleter
from prompt_toolkit.shortcuts import prompt
@ -60,7 +61,12 @@ class PromptApplication(CLIApplicationBase):
instance.
"""
self.todolist.erase()
self.todolist.add_list(self.todofile.read())
try:
self.todolist.add_list(self.todofile.read())
except TodoFileException as err:
error('Could not read todo file: {}'.format(str(err)))
self.completer = TopydoCompleter(self.todolist)
def run(self):