class HNGui(object): """ The Pyhn Gui object """ def __init__(self, cache_manager): self.cache_manager = cache_manager self.already_build = False self.which = "top" self.config = Config() self.palette = self.config.get_palette() def main(self): """ Main Gui function which create Ui object, build interface and run the loop """ self.ui = urwid.raw_display.Screen() self.ui.register_palette(self.palette) self.build_interface() self.ui.run_wrapper(self.run) def build_help(self): """ Fetch all key bindings and build help message """ self.bindings = {} self.help_msg = [] self.help_msg.append(urwid.AttrWrap(urwid.Text('\n Key bindings \n'), 'title')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) for binding in self.config.parser.items('keybindings'): self.bindings[binding[0]] = binding[1] line = urwid.AttrWrap( urwid.Text(' %s: %s ' % (binding[1], binding[0].replace('_', ' '))), 'help') self.help_msg.append(line) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append(urwid.AttrWrap( urwid.Text(' Thanks for using Pyhn %s! ' % VERSION, align='center'), 'title')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(' Website: http://github.com/socketubs/pyhn '), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(' Author : socketubs '), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help = Popup(self.help_msg, ('help', 'help'), (0, 1), self.view) def build_interface(self): """ Build interface, refresh cache if needed, update stories listbox, create header, footer, view and the loop. """ if self.cache_manager.is_outdated(): self.cache_manager.refresh() self.stories = self.cache_manager.get_stories() self.update_stories(self.stories) self.header_content = [ ('fixed', 4, urwid.Padding(urwid.AttrWrap(urwid.Text(' N°'), 'header'))), urwid.AttrWrap(urwid.Text('TOP STORIES', align="center"), 'title'), ('fixed', 5, urwid.Padding(urwid.AttrWrap(urwid.Text('SCORE'), 'header'))), ('fixed', 8, urwid.Padding(urwid.AttrWrap(urwid.Text('COMMENTS'), 'header')))] self.header = urwid.Columns(self.header_content, dividechars=1) self.footer = urwid.AttrMap( urwid.Text('Welcome in pyhn by socketubs (https://github.com/socketubs/pyhn)', align='center'), 'footer') self.view = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), header=self.header, footer=self.footer) self.loop = urwid.MainLoop( self.view, self.palette, screen=self.ui, handle_mouse=False, unhandled_input=self.keystroke) self.build_help() self.already_build = True def set_help(self): """ Set help msg in footer """ self.view.set_footer(urwid.AttrWrap(urwid.Text(self.help, align="center"), 'help')) def set_footer(self, msg, style="normal"): """ Set centered footer message """ if style == "normal": self.footer = urwid.AttrWrap(urwid.Text(msg), 'footer') self.view.set_footer(self.footer) elif style == "error": self.footer = urwid.AttrWrap(urwid.Text(msg), 'footer-error') self.view.set_footer(self.footer) def set_header(self, msg): """ Set header story message """ self.header_content[1] = urwid.AttrWrap(urwid.Text(msg, align="center"), 'title') self.view.set_header(urwid.Columns(self.header_content, dividechars=1)) def keystroke(self, input): """ All key bindings are computed here """ # QUIT if input in ('q', 'Q'): raise urwid.ExitMainLoop() # LINKS elif input in self.bindings['open_story_link'].split(','): self.open_webbrowser(self.listbox.get_focus()[0].url) elif input in self.bindings['show_story_link'].split(','): self.set_footer(self.listbox.get_focus()[0].url) elif input in self.bindings['open_comments_link'].split(','): if self.listbox.get_focus()[0].comments_url == -1: self.set_footer('No comments') else: self.open_webbrowser(self.listbox.get_focus()[0].comments_url) elif input in self.bindings['show_comments_link'].split(','): if self.listbox.get_focus()[0].comments_url == -1: self.set_footer('No comments') else: self.set_footer(self.listbox.get_focus()[0].comments_url) elif input in self.bindings['open_submitter_link'].split(','): if self.listbox.get_focus()[0].submitter_url == -1: self.set_footer('Anonymous submitter') else: self.open_webbrowser(self.listbox.get_focus()[0].submitter_url) elif input in self.bindings['show_submitter_link'].split(','): if self.listbox.get_focus()[0].submitter_url == -1: self.set_footer('Anonymous submitter') else: self.set_footer(self.listbox.get_focus()[0].submitter_url) # MOVEMENTS elif input in self.bindings['down'].split(','): if self.listbox.focus_position - 1 in self.walker.positions(): self.listbox.set_focus(self.walker.prev_position(self.listbox.focus_position)) elif input in self.bindings['up'].split(','): if self.listbox.focus_position + 1 in self.walker.positions(): self.listbox.set_focus(self.walker.next_position(self.listbox.focus_position)) elif input in self.bindings['page_up'].split(','): self.listbox._keypress_page_up(self.ui.get_cols_rows()) elif input in self.bindings['page_down'].split(','): self.listbox._keypress_page_down(self.ui.get_cols_rows()) elif input in self.bindings['first_story'].split(','): self.listbox.set_focus(self.walker.positions()[0]) elif input in self.bindings['last_story'].split(','): self.listbox.set_focus(self.walker.positions()[-1]) # STORIES elif input in ('n',): threading.Thread(None, self.async_refresher, None, ('newest', 'NEWEST STORIES'), {}).start() elif input in ('t',): threading.Thread(None, self.async_refresher, None, ('top', 'TOP STORIES'), {}).start() elif input in ('b',): self.set_footer('Syncing best stories...') threading.Thread(None, self.async_refresher, None, ('best', 'BEST STORIES'), {}).start() # OTHERS elif input in self.bindings['refresh'].split(','): threading.Thread(None, self.async_refresher, None, (), {}).start() elif input in self.bindings['reload_config'].split(','): self.reload_config() elif input in ('h', 'H', '?'): keys = True while True: if keys: self.ui.draw_screen(self.ui.get_cols_rows(), self.help.render(self.ui.get_cols_rows(), True)) keys = self.ui.get_input() if 'h' or 'H' or '?' or 'escape' in keys: break def async_refresher(self, which=None, header=None): if which is None: which = self.which if self.cache_manager.is_outdated(which): self.cache_manager.refresh(which) stories = self.cache_manager.get_stories(which) self.update_stories(stories) if header is not None: self.set_header(header) self.which = which self.loop.draw_screen() def update_stories(self, stories): """ Reload listbox and walker with new stories """ items = [] for story in stories: items.append(ItemWidget(story)) if self.already_build: self.walker[:] = items self.update() else: self.walker = urwid.SimpleListWalker(items) self.listbox = urwid.ListBox(self.walker) def open_webbrowser(self, url): """ Handle url and open sub process with web browser """ if self.config.parser.get('settings', 'browser_cmd') == "__default__": python_bin = sys.executable browser_output = subprocess.Popen( [python_bin, '-m', 'webbrowser', '-t', url], stdout=subprocess.PIPE, stderr=subprocess.PIPE) else: cmd = self.config.parser.get('settings', 'browser_cmd') try: p = subprocess.Popen( cmd.replace('__url__', url), shell=True, close_fds=True, stderr=subprocess.PIPE) returncode = p.wait() except KeyboardInterrupt: stderr = "User keyboard interrupt detected!" self.set_footer(stderr, style="error") return if returncode > 0: stderr = p.communicate()[1] self.set_footer("%s" % stderr, style="error") def update(self): """ Update footer about focus story """ focus = self.listbox.get_focus()[0] if focus.submitter == "": msg = "submitted %s" % focus.published_time else: msg = "submitted %s by %s" % (focus.published_time, focus.submitter) self.set_footer(msg) def reload_config(self): """ Create new Config object, reload colors, refresh cache if needed and redraw screen. """ self.set_footer('Reloading configuration') self.config = Config() self.build_help() self.palette = self.config.get_palette() self.build_interface() self.loop.draw_screen() self.set_footer('Configuration file reloaded!') if self.config.parser.get('settings', 'cache') != self.cache_manager.cache_path: self.cache_manager.cache_path = self.config.parser.get('settings', 'cache') def run(self): """ Run the loop """ urwid.connect_signal(self.walker, 'modified', self.update) try: self.loop.run() except KeyboardInterrupt: urwid.ExitMainLoop()
class HNGui(object): """ The Pyhn Gui object """ def __init__(self, cache_manager): self.cache_manager = cache_manager self.already_build = False self.on_comments = False self.which = "top" self.config = Config() self.poller = Poller( self, delay=int(self.config.parser.get('settings', 'refresh_interval'))) self.palette = self.config.get_palette() self.show_comments = self.config.parser.get( 'interface', 'show_comments') in TRUE_WORDS self.show_score = self.config.parser.get('interface', 'show_score') in TRUE_WORDS self.show_published_time = self.config.parser.get( 'interface', 'show_published_time') in TRUE_WORDS def main(self): """ Main Gui function which create Ui object, build interface and run the loop """ self.ui = urwid.raw_display.Screen() self.ui.register_palette(self.palette) self.build_interface() self.ui.run_wrapper(self.run) def build_help(self): """ Fetch all key bindings and build help message """ self.bindings = {} self.help_msg = [] self.help_msg.append( urwid.AttrWrap(urwid.Text('\n Key bindings \n'), 'title')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) for binding in self.config.parser.items('keybindings'): self.bindings[binding[0]] = binding[1] line = urwid.AttrWrap( urwid.Text(' %s: %s ' % (binding[1], binding[0].replace('_', ' '))), 'help') self.help_msg.append(line) self.help_msg.append( urwid.AttrWrap(urwid.Text(' ctrl mouse-left: open story link'), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append( urwid.AttrWrap( urwid.Text(' Thanks for using Pyhn %s! ' % __version__, align='center'), 'title')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append( urwid.AttrWrap(urwid.Text(' Author : toxinu'), 'help')) self.help_msg.append( urwid.AttrWrap( urwid.Text(' Code : https://github.com/toxinu/pyhn '), 'help')) self.help_msg.append( urwid.AttrWrap(urwid.Text(' Website: http://toxinu.github.io '), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help_msg.append(urwid.AttrWrap(urwid.Text(''), 'help')) self.help = Popup(self.help_msg, ('help', 'help'), (0, 1), self.view) def build_interface(self): """ Build interface, refresh cache if needed, update stories listbox, create header, footer, view and the loop. """ if self.cache_manager.is_outdated(): self.cache_manager.refresh() self.stories = self.cache_manager.get_stories() self.update_stories(self.stories) self.header_content = [ ('fixed', 4, urwid.Padding(urwid.AttrWrap(urwid.Text(' N°'), 'header'))), urwid.AttrWrap(urwid.Text('TOP STORIES', align="center"), 'title'), ] if self.show_published_time: self.header_content.append( ('fixed', 15, urwid.Padding( urwid.AttrWrap(urwid.Text('PUBLISHED TIME'), 'header'))), ) if self.show_score: self.header_content.append( ('fixed', 5, urwid.Padding(urwid.AttrWrap(urwid.Text('SCORE'), 'header'))), ) if self.show_comments: self.header_content.append( ('fixed', 8, urwid.Padding(urwid.AttrWrap(urwid.Text('COMMENTS'), 'header')))) self.header = urwid.Columns(self.header_content, dividechars=1) self.footer = urwid.AttrMap( urwid.Text( 'Welcome in pyhn by toxinu ' '(https://github.com/toxinu/pyhn)', align='center'), 'footer') self.view = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), header=self.header, footer=self.footer) self.loop = urwid.MainLoop(self.view, self.palette, screen=self.ui, handle_mouse=True, unhandled_input=self.keystroke) self.build_help() self.already_build = True def set_help(self): """ Set help msg in footer """ self.view.set_footer( urwid.AttrWrap(urwid.Text(self.help, align="center"), 'help')) def set_footer(self, msg, style="normal"): """ Set centered footer message """ if style == "normal": self.footer = urwid.AttrWrap(urwid.Text(msg), 'footer') self.view.set_footer(self.footer) elif style == "error": self.footer = urwid.AttrWrap(urwid.Text(msg), 'footer-error') self.view.set_footer(self.footer) def set_header(self, msg): """ Set header story message """ self.header_content[1] = urwid.AttrWrap( urwid.Text(msg, align="center"), 'title') self.view.set_header(urwid.Columns(self.header_content, dividechars=1)) def keystroke(self, input): """ All key bindings are computed here """ # QUIT if input in ('q', 'Q'): self.exit(must_raise=True) # LINKS if input in self.bindings['open_comments_link'].split(','): if not self.listbox.get_focus()[0].comments_url: self.set_footer('No comments') else: if not self.on_comments: self.show_comments(self.listbox.get_focus()[0]) self.on_comments = True else: self.update_stories( self.cache_manager.get_stories(self.which)) self.on_comments = False self.open_webbrowser(self.listbox.get_focus()[0].comments_url) if input in self.bindings['show_comments_link'].split(','): if not self.listbox.get_focus()[0].comments_url: self.set_footer('No comments') else: self.set_footer(self.listbox.get_focus()[0].comments_url) if input in self.bindings['open_story_link'].split(','): self.open_webbrowser(self.listbox.get_focus()[0].url) if input in self.bindings['show_story_link'].split(','): self.set_footer(self.listbox.get_focus()[0].url) if input in self.bindings['open_submitter_link'].split(','): if not self.listbox.get_focus()[0].submitter_url: self.set_footer('No submitter') else: self.open_webbrowser(self.listbox.get_focus()[0].submitter_url) if input in self.bindings['show_submitter_link'].split(','): if not self.listbox.get_focus()[0].submitter_url: self.set_footer('No submitter') else: self.set_footer(self.listbox.get_focus()[0].submitter_url) # MOVEMENTS if input in self.bindings['down'].split(','): if self.listbox.focus_position - 1 in self.walker.positions(): self.listbox.set_focus( self.walker.prev_position(self.listbox.focus_position)) if input in self.bindings['up'].split(','): if self.listbox.focus_position + 1 in self.walker.positions(): self.listbox.set_focus( self.walker.next_position(self.listbox.focus_position)) if input in self.bindings['page_up'].split(','): self.listbox._keypress_page_up(self.ui.get_cols_rows()) if input in self.bindings['page_down'].split(','): self.listbox._keypress_page_down(self.ui.get_cols_rows()) if input in self.bindings['first_story'].split(','): self.listbox.set_focus(self.walker.positions()[0]) if input in self.bindings['last_story'].split(','): self.listbox.set_focus(self.walker.positions()[-1]) # STORIES if input in self.bindings['newest_stories'].split(','): self.set_footer('Syncing newest stories...') threading.Thread(None, self.async_refresher, None, ('newest', 'NEWEST STORIES'), {}).start() if input in self.bindings['top_stories'].split(','): self.set_footer('Syncing top stories...') threading.Thread(None, self.async_refresher, None, ('top', 'TOP STORIES'), {}).start() if input in self.bindings['best_stories'].split(','): self.set_footer('Syncing best stories...') threading.Thread(None, self.async_refresher, None, ('best', 'BEST STORIES'), {}).start() if input in self.bindings['show_stories'].split(','): self.set_footer('Syncing show stories...') threading.Thread(None, self.async_refresher, None, ('show', 'SHOW STORIES'), {}).start() if input in self.bindings['show_newest_stories'].split(','): self.set_footer('Syncing show newest stories...') threading.Thread(None, self.async_refresher, None, ('show_newest', 'SHOW NEWEST STORIES'), {}).start() if input in self.bindings['ask_stories'].split(','): self.set_footer('Syncing ask stories...') threading.Thread(None, self.async_refresher, None, ('ask', 'ASK STORIES'), {}).start() if input in self.bindings['jobs_stories'].split(','): self.set_footer('Syncing jobs stories...') threading.Thread(None, self.async_refresher, None, ('jobs', 'JOBS STORIES'), {}).start() # OTHERS if input in self.bindings['refresh'].split(','): self.set_footer('Refreshing new stories...') threading.Thread(None, self.async_refresher, None, (), { 'force': True }).start() if input in self.bindings['reload_config'].split(','): self.reload_config() if input in ('h', 'H', '?'): keys = True while True: if keys: self.ui.draw_screen( self.ui.get_cols_rows(), self.help.render(self.ui.get_cols_rows(), True)) keys = self.ui.get_input() if 'h' or 'H' or '?' or 'escape' in keys: break # MOUSE if len(input) > 1 and input[0] == 'ctrl mouse release': self.open_webbrowser(self.listbox.get_focus()[0].url) def async_refresher(self, which=None, header=None, force=False): if which is None: which = self.which if self.cache_manager.is_outdated(which) or force: self.cache_manager.refresh(which) stories = self.cache_manager.get_stories(which) self.update_stories(stories) if header is not None: self.set_header(header) self.which = which self.loop.draw_screen() def update_stories(self, stories): """ Reload listbox and walker with new stories """ items = [] item_ids = [] for story in stories: if story.id is not None and story.id in item_ids: story.title = "- %s" % story.title items.append( ItemWidget(story, self.show_published_time, self.show_score, self.show_comments)) else: items.append( ItemWidget(story, self.show_published_time, self.show_score, self.show_comments)) item_ids.append(story.id) if self.already_build: self.walker[:] = items self.update() else: self.walker = urwid.SimpleListWalker(items) self.listbox = urwid.ListBox(self.walker) def show_comments(self, story): pass def open_webbrowser(self, url): """ Handle url and open sub process with web browser """ if self.config.parser.get('settings', 'browser_cmd') == "__default__": python_bin = sys.executable subprocess.Popen([python_bin, '-m', 'webbrowser', '-t', url], stdout=subprocess.PIPE, stderr=subprocess.PIPE) else: cmd = self.config.parser.get('settings', 'browser_cmd') try: p = subprocess.Popen(cmd.replace('__url__', url), shell=True, close_fds=True, stderr=subprocess.PIPE) returncode = p.wait() except KeyboardInterrupt: stderr = "User keyboard interrupt detected!" self.set_footer(stderr, style="error") return if returncode > 0: stderr = p.communicate()[1] self.set_footer("%s" % stderr, style="error") def update(self): """ Update footer about focus story """ focus = self.listbox.get_focus()[0] if not focus.submitter: msg = "submitted %s" % focus.published_time else: msg = "submitted %s by %s" % (focus.published_time, focus.submitter) self.set_footer(msg) def reload_config(self): """ Create new Config object, reload colors, refresh cache if needed and redraw screen. """ self.set_footer('Reloading configuration') self.config = Config() self.build_help() self.palette = self.config.get_palette() self.build_interface() self.loop.draw_screen() self.set_footer('Configuration file reloaded!') if self.config.parser.get('settings', 'cache') != self.cache_manager.cache_path: self.cache_manager.cache_path = self.config.parser.get( 'settings', 'cache') def exit(self, must_raise=False): self.poller.is_running = False self.poller.join() if must_raise: raise urwid.ExitMainLoop() urwid.ExitMainLoop() def run(self): urwid.connect_signal(self.walker, 'modified', self.update) try: self.poller.start() self.loop.run() except KeyboardInterrupt: self.exit() print('Exiting... Bye!')
class HNGui(object): def __init__(self, cache_manager): self.cache_manager = cache_manager self.already_build = False self.which = "top" self.config = Config() self.palette = self.config.get_palette() def main(self): self.ui = urwid.raw_display.Screen() self.ui.register_palette(self.palette) self.build_interface() self.ui.run_wrapper(self.run) def build_interface(self): if self.cache_manager.is_outdated(): self.cache_manager.refresh() self.stories = self.cache_manager.get_stories() self.update_stories(self.stories) self.header_content = [ ('fixed', 4, urwid.Padding(urwid.AttrWrap( urwid.Text(' N°'), 'header'))), urwid.AttrWrap(urwid.Text('TOP STORIES', align="center"), 'title'), ('fixed', 5, urwid.Padding(urwid.AttrWrap( urwid.Text('SCORE'), 'header'))), ('fixed', 8, urwid.Padding(urwid.AttrWrap( urwid.Text('COMMENTS'), 'header'))), ] self.header = urwid.Columns(self.header_content, dividechars=1) self.footer = urwid.AttrMap(urwid.Text('Welcome in pyhn by socketubs (https://github.com/socketubs/pyhn)', align='center'), 'footer') self.view = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), header=self.header, footer=self.footer) self.loop = urwid.MainLoop(self.view, self.palette, screen=self.ui, unhandled_input=self.keystroke) self.already_build = True def set_help(self): msg = "J: Go next -- K: Go prev -- T: Top -- B: Best -- N: Newest -- R: Refresh -- Enter: Open link -- C: Open comments link -- ?, H: Help -- Q: Quit" self.view.set_footer(urwid.AttrWrap(urwid.Text(msg, align="center"), 'help')) def set_footer(self, msg): self.view.set_footer(urwid.AttrWrap(urwid.Text(msg), 'footer')) def set_header(self, msg): self.header_content[1] = urwid.AttrWrap(urwid.Text(msg, align="center"), 'title') self.view.set_header(urwid.Columns(self.header_content, dividechars=1)) def keystroke(self, input): if input in ('q', 'Q'): raise urwid.ExitMainLoop() elif input is 'enter': self.open_webbrowser(self.listbox.get_focus()[0].url) elif input in ('n', 'N'): self.set_footer('Retrieving newest stories...') if self.cache_manager.is_outdated('newest'): self.cache_manager.refresh('newest') stories = self.cache_manager.get_stories('newest') self.update_stories(stories) self.set_header('NEWEST STORIES') self.which = "newest" elif input in ('t', 'T'): self.set_footer('Retrieving top stories...') if self.cache_manager.is_outdated('top'): self.cache_manager.refresh('top') stories = self.cache_manager.get_stories('top') self.update_stories(stories) self.set_header('TOP STORIES') self.which = "top" elif input in ('b', 'B'): self.set_footer('Retrieving best stories...') if self.cache_manager.is_outdated('best'): self.cache_manager.refresh('best') stories = self.cache_manager.get_stories('best') self.update_stories(stories) self.set_header('BEST STORIES') self.which = "best" elif input in self.config.parser.get('keybindings', 'refresh').split(','): self.cache_manager.refresh(self.which) stories = self.cache_manager.get_stories(self.which) self.update_stories(stories) elif input in self.config.parser.get('keybindings', 'open_comments').split(','): self.open_webbrowser(self.listbox.get_focus()[0].comments_url) elif input in ('h', 'H', '?'): self.set_help() elif input in self.config.parser.get('keybindings', 'down').split(','): if self.listbox.focus_position - 1 in self.walker.positions(): self.listbox.set_focus(self.walker.prev_position(self.listbox.focus_position)) elif input in self.config.parser.get('keybindings', 'up').split(','): if self.listbox.focus_position + 1 in self.walker.positions(): self.listbox.set_focus(self.walker.next_position(self.listbox.focus_position)) elif input in self.config.parser.get('keybindings', 'reload_config').split(','): self.reload_config() def update_stories(self, stories): items = [] for story in stories: items.append(ItemWidget(story)) if self.already_build: self.walker[:] = items self.update() else: self.walker = urwid.SimpleListWalker(items) self.listbox = urwid.ListBox(self.walker) def open_webbrowser(self, url): python_bin = sys.executable browser_output = subprocess.Popen([python_bin, '-m', 'webbrowser', '-t', url],stdout=subprocess.PIPE,stderr=subprocess.PIPE) def update(self): focus = self.listbox.get_focus()[0] self.set_footer('submitted %s by %s' % (focus.publishedTime, focus.submitter)) def reload_config(self): self.set_footer('Reloading configuration') self.config = Config() self.palette = self.config.get_palette() self.build_interface() self.loop.draw_screen() self.set_footer('Configuration file reloaded!') if self.config.parser.get('settings', 'cache') != self.cache_manager.cache_path: self.cache_manager.cache_path = self.config.parser.get('settings', 'cache') def run(self): urwid.connect_signal(self.walker, 'modified', self.update) try: self.loop.run() except KeyboardInterrupt: urwid.ExitMainLoop()