Error handling.
This commit is contained in:
@@ -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
12
rtv/errors.py
Normal 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
|
||||||
30
rtv/main.py
30
rtv/main.py
@@ -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()
|
||||||
|
|||||||
22
rtv/page.py
22
rtv/page.py
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
24
rtv/utils.py
24
rtv/utils.py
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user