Error handling.

This commit is contained in:
Michael Lazar
2015-02-01 03:10:03 -08:00
parent 1449536504
commit 4ff4b98236
6 changed files with 116 additions and 29 deletions

View File

@@ -4,6 +4,8 @@ from contextlib import contextmanager
import praw import praw
from errors import SubmissionURLError, SubredditNameError
def clean(unicode_string): def clean(unicode_string):
""" """
Convert unicode string into ascii-safe characters. Convert unicode string into ascii-safe characters.
@@ -159,9 +161,13 @@ class SubmissionContent(BaseContent):
indent_size=2, indent_size=2,
max_indent_level=4): max_indent_level=4):
try:
with loader(): with loader():
submission = reddit.get_submission(url) submission = reddit.get_submission(url)
except praw.errors.APIException:
raise SubmissionURLError(url)
return cls(submission, loader, indent_size, max_indent_level) return cls(submission, loader, indent_size, max_indent_level)
def reset(self): def reset(self):
@@ -273,9 +279,13 @@ class SubredditContent(BaseContent):
if name == 'all': if name == 'all':
sub = reddit.get_subreddit(name) sub = reddit.get_subreddit(name)
else: else:
try:
with loader(): with loader():
sub = reddit.get_subreddit(name, fetch=True) sub = reddit.get_subreddit(name, fetch=True)
except praw.errors.ClientException:
raise SubredditNameError(name)
return cls('/r/'+sub.display_name, sub.get_hot(limit=None), loader) return cls('/r/'+sub.display_name, sub.get_hot(limit=None), loader)

12
rtv/errors.py Normal file
View File

@@ -0,0 +1,12 @@
class EscapePressed(Exception):
pass
class SubmissionURLError(Exception):
def __init__(self, url):
self.url = url
class SubredditNameError(Exception):
def __init__(self, name):
self.name = name

View File

@@ -1,18 +1,23 @@
import argparse import argparse
import praw import praw
from requests.exceptions import ConnectionError
from errors import SubmissionURLError, SubredditNameError
from utils import curses_session from utils import curses_session
from subreddit import SubredditPage from subreddit import SubredditPage
from submission import SubmissionPage
parser = argparse.ArgumentParser(description='Reddit Terminal Viewer') parser = argparse.ArgumentParser(description='Reddit Terminal Viewer')
parser.add_argument('-s', dest='subreddit', default='front', help='subreddit name') parser.add_argument('-s', dest='subreddit', default='front', help='subreddit name')
parser.add_argument('-l', dest='link', help='full link to a specific submission') parser.add_argument('-l', dest='link', help='full link to a submission')
group = parser.add_argument_group('authentication (optional)') group = parser.add_argument_group('authentication (optional)')
group.add_argument('-u', dest='username', help='reddit username') group.add_argument('-u', dest='username', help='reddit username')
group.add_argument('-p', dest='password', help='reddit password') group.add_argument('-p', dest='password', help='reddit password')
group.add_argument('--debug', action='store_true')
def main(args): def main(args):
try:
reddit = praw.Reddit(user_agent='reddit terminal viewer v0.0') reddit = praw.Reddit(user_agent='reddit terminal viewer v0.0')
reddit.config.decode_html_entities = True reddit.config.decode_html_entities = True
@@ -21,9 +26,32 @@ def main(args):
with curses_session() as stdscr: with curses_session() as stdscr:
if args.link:
# Go directly to submission
page = SubmissionPage(stdscr, reddit, url=args.link)
page.loop()
page = SubredditPage(stdscr, reddit, args.subreddit) page = SubredditPage(stdscr, reddit, args.subreddit)
page.loop() page.loop()
except KeyboardInterrupt:
return
except ConnectionError:
print 'Timeout: Could not connect to website'
except SubmissionURLError as e:
print 'Could not reach submission URL: {}'.format(e.url)
except SubredditNameError as e:
print 'Could not reach subreddit: {}'.format(e.name)
# except Exception:
# if not args.debug:
# print 'Unhandled exception'
# else:
# raise
if __name__ == '__main__': if __name__ == '__main__':
args = parser.parse_args() args = parser.parse_args()

View File

@@ -75,6 +75,9 @@ class BasePage(object):
Base terminal viewer incorperates a cursor to navigate content Base terminal viewer incorperates a cursor to navigate content
""" """
MIN_HEIGHT = 10
MIN_WIDTH = 20
def __init__(self, stdscr, content, **kwargs): def __init__(self, stdscr, content, **kwargs):
self.stdscr = stdscr self.stdscr = stdscr
@@ -107,21 +110,27 @@ class BasePage(object):
def draw(self): def draw(self):
n_rows, n_cols = self.stdscr.getmaxyx() n_rows, n_cols = self.stdscr.getmaxyx()
if n_rows < self.MIN_HEIGHT or n_cols < self.MIN_WIDTH:
return
self._header_window = self.stdscr.derwin(1, n_cols, 0, 0) self._header_window = self.stdscr.derwin(1, n_cols, 0, 0)
self._content_window = self.stdscr.derwin(1, 0) self._content_window = self.stdscr.derwin(1, 0)
self.draw_header() self._draw_header()
self.draw_content() self._draw_content()
self.add_cursor() self.add_cursor()
def draw_header(self): def draw_item(self, window, data, inverted):
raise NotImplementedError
def _draw_header(self):
n_rows, n_cols = self._header_window.getmaxyx() n_rows, n_cols = self._header_window.getmaxyx()
self._header_window.erase() self._header_window.erase()
self._header_window.addnstr(0, 0, self.content.name, n_cols-1) self._header_window.addnstr(0, 0, self.content.name, n_cols-1)
def draw_content(self): def _draw_content(self):
""" """
Loop through submissions and fill up the content page. Loop through submissions and fill up the content page.
""" """
@@ -153,9 +162,6 @@ class BasePage(object):
self._content_window.refresh() self._content_window.refresh()
def draw_item(self, window, data, inverted):
raise NotImplementedError
def _move_cursor(self, direction): def _move_cursor(self, direction):
self.remove_cursor() self.remove_cursor()
@@ -167,7 +173,7 @@ class BasePage(object):
# If we don't redraw, ACS_VLINE gets screwed up when changing the # If we don't redraw, ACS_VLINE gets screwed up when changing the
# attr back to normal. There may be a way around this. # attr back to normal. There may be a way around this.
if True: #if redraw if True: #if redraw
self.draw_content() self._draw_content()
self.add_cursor() self.add_cursor()

View File

@@ -1,10 +1,11 @@
import curses import curses
import sys import sys
from errors import SubredditNameError
from page import BasePage from page import BasePage
from submission import SubmissionPage from submission import SubmissionPage
from content import SubredditContent from content import SubredditContent
from utils import LoadScreen, text_input from utils import LoadScreen, text_input, display_message
class SubredditPage(BasePage): class SubredditPage(BasePage):
@@ -56,11 +57,21 @@ class SubredditPage(BasePage):
def refresh_content(self, name=None): def refresh_content(self, name=None):
name = name or self.name
try:
self.content = SubredditContent.from_name(
self.reddit, name, self.loader)
except SubredditNameError:
display_message(self.stdscr, 'Invalid Subreddit')
else:
self.nav.page_index, self.nav.cursor_index = 0, 0 self.nav.page_index, self.nav.cursor_index = 0, 0
self.nav.inverted = False self.nav.inverted = False
self.name = name if name else self.name self.name = name
self.content = SubredditContent.from_name(self.reddit, self.name, self.loader)
self.stdscr.clear() #self.stdscr.clear()
self.draw() self.draw()
def prompt_subreddit(self): def prompt_subreddit(self):

View File

@@ -5,8 +5,7 @@ import threading
from curses import textpad from curses import textpad
from contextlib import contextmanager from contextlib import contextmanager
class EscapePressed(Exception): from errors import EscapePressed
pass
def text_input(window): def text_input(window):
""" """
@@ -40,6 +39,27 @@ def text_input(window):
return out return out
def display_message(stdscr, message):
"Display a message box at the center of the screen and wait for a keypress"
message_len = len(message)
n_rows, n_cols = stdscr.getmaxyx()
s_row = (n_rows - 2) / 2
s_col = (n_cols - message_len - 1) / 2
window = stdscr.derwin(3, message_len+2, s_row, s_col)
window.erase()
window.border()
window.addstr(1, 1, message)
window.refresh()
stdscr.getch()
window.clear()
window = None
stdscr.refresh()
class LoadScreen(object): class LoadScreen(object):
def __init__(self, stdscr): def __init__(self, stdscr):