def main():
    """Main entry point"""

    # Squelch SSL warnings
    logging.captureWarnings(True)
    if six.PY3:
        # These ones get triggered even when capturing warnings is turned on
        warnings.simplefilter('ignore', ResourceWarning)  # pylint:disable=E0602

    # Set the terminal title
    if os.getenv('DISPLAY'):
        title = 'rtv {0}'.format(__version__)
        sys.stdout.write('\x1b]2;{0}\x07'.format(title))
        sys.stdout.flush()

    args = Config.get_args()
    fargs, bindings = Config.get_file(args.get('config'))

    # Apply the file config first, then overwrite with any command line args
    config = Config()
    config.update(**fargs)
    config.update(**args)

    # If key bindings are supplied in the config file, overwrite the defaults
    if bindings:
        config.keymap.set_bindings(bindings)

    if config['copy_config']:
        return copy_default_config()
    if config['copy_mailcap']:
        return copy_default_mailcap()
    if config['list_themes']:
        return Theme.print_themes()

    # Load the browsing history from previous sessions
    config.load_history()

    # Load any previously saved auth session token
    config.load_refresh_token()
    if config['clear_auth']:
        config.delete_refresh_token()

    if config['log']:
        # Log request headers to the file (print hack only works on python 3.x)
        # from http import client
        # _http_logger = logging.getLogger('http.client')
        # client.HTTPConnection.debuglevel = 2
        # def print_to_file(*args, **_):
        #     if args[0] != "header:":
        #         _http_logger.info(' '.join(args))
        # client.print = print_to_file
        logging.basicConfig(
            level=logging.DEBUG,
            filename=config['log'],
            format='%(asctime)s:%(levelname)s:%(filename)s:%(lineno)d:%(message)s')
    else:
        # Add an empty handler so the logger doesn't complain
        logging.root.addHandler(logging.NullHandler())

    # Make sure the locale is UTF-8 for unicode support
    default_locale = locale.setlocale(locale.LC_ALL, '')
    try:
        encoding = locale.getlocale()[1] or locale.getdefaultlocale()[1]
    except ValueError:
        # http://stackoverflow.com/a/19961403
        # OS X on some terminals will set the LC_CTYPE to "UTF-8"
        # (as opposed to something like "en_US.UTF-8") and python
        # doesn't know how to handle it.
        _logger.warning('Error parsing system locale: `%s`,'
                        ' falling back to utf-8', default_locale)
        encoding = 'UTF-8'

    if not encoding or encoding.lower() != 'utf-8':
        text = ('System encoding was detected as (%s) instead of UTF-8'
                ', falling back to ascii only mode' % encoding)
        warnings.warn(text)
        config['ascii'] = True

    if packages.__praw_bundled__:
        praw_info = 'packaged, commit {}'.format(packages.__praw_hash__[:12])
    else:
        praw_info = 'system installed v{}'.format(praw.__version__)

    # Update the webbrowser module's default behavior
    patch_webbrowser()
    if webbrowser_import_warning:
        _logger.warning('webbrowser module was unexpectedly imported before'
                        '$BROWSER could be overwritten')

    # Construct the reddit user agent
    user_agent = docs.AGENT.format(version=__version__)

    debug_info = [
        'rtv version: rtv {}'.format(__version__),
        'rtv module path: {}'.format(os.path.abspath(__file__)),
        'python version: {}'.format(sys.version.replace('\n', ' ')),
        'python executable: {}'.format(sys.executable),
        'praw version: {}'.format(praw_info),
        'locale, encoding: {}, {}'.format(default_locale, encoding),
        'Environment Variables']
    for name, value in [
        ('BROWSER', BROWSER),
        ('DISPLAY', os.getenv('DISPLAY')),
        ('EDITOR', os.getenv('EDITOR')),
        ('LANG', os.getenv('LANG')),
        ('PAGER', os.getenv('PAGER')),
        ('RTV_BROWSER', RTV_BROWSER),
        ('RTV_EDITOR', os.getenv('RTV_EDITOR')),
        ('RTV_PAGER', os.getenv('RTV_PAGER')),
        ('RTV_URLVIEWER', os.getenv('RTV_URLVIEWER')),
        ('TERM', os.getenv('TERM')),
        ('VISUAL', os.getenv('VISUAL')),
        ('XDG_CONFIG_HOME', os.getenv('XDG_CONFIG_HOME')),
        ('XDG_DATA_HOME', os.getenv('XDG_DATA_HOME')),
    ]:
        debug_info.append('  {:<16}: {}'.format(name, value or ''))
    debug_info.append('')
    debug_text = '\n'.join(debug_info)

    _logger.info(debug_text)
    if config['debug_info']:
        print(debug_text)
        return

    try:
        with curses_session() as stdscr:

            term = Terminal(stdscr, config)

            if config['monochrome'] or config['theme'] == 'monochrome':
                _logger.info('Using monochrome theme')
                theme = Theme(use_color=False)
            elif config['theme'] and config['theme'] != 'default':
                _logger.info('Loading theme: %s', config['theme'])
                theme = Theme.from_name(config['theme'])
            else:
                # Set to None to let the terminal figure out which theme
                # to use depending on if colors are supported or not
                theme = None
            term.set_theme(theme)

            with term.loader('Initializing', catch_exception=False):
                reddit = praw.Reddit(user_agent=user_agent,
                                     decode_html_entities=False,
                                     disable_update_check=True,
                                     timeout=10,  # 10 second request timeout
                                     handler=RequestHeaderRateLimiter())

            # Dial the request cache up from 30 seconds to 5 minutes
            # I'm trying this out to make navigation back and forth
            # between pages quicker, it may still need to be fine tuned.
            reddit.config.api_request_delay = 300

            # Authorize on launch if the refresh token is present
            oauth = OAuthHelper(reddit, term, config)
            if config['autologin'] and config.refresh_token:
                oauth.authorize(autologin=True)

            # Open the supplied submission link before opening the subreddit
            if config['link']:
                # Expand shortened urls like https://redd.it/
                # Praw won't accept the shortened versions, add the reddit
                # headers to avoid a 429 response from reddit.com
                url = requests.head(
                    config['link'],
                    headers=reddit.http.headers,
                    allow_redirects=True
                ).url

                page = None
                with term.loader('Loading submission'):
                    try:
                        page = SubmissionPage(reddit, term, config, oauth, url)
                    except Exception as e:
                        _logger.exception(e)
                        raise SubmissionError('Unable to load {0}'.format(url))
                while page:
                    page = page.loop()

            page = None
            name = config['subreddit']
            with term.loader('Loading subreddit'):
                try:
                    page = SubredditPage(reddit, term, config, oauth, name)
                except Exception as e:
                    # If we can't load the subreddit that was requested, try
                    # to load the "popular" page instead so at least the
                    # application still launches. This used to use the user's
                    # front page, but some users have an empty front page.
                    _logger.exception(e)
                    page = SubredditPage(reddit, term, config, oauth, 'popular')
                    raise SubredditError('Unable to load {0}'.format(name))

            # Launch the subreddit page
            while page:
                page = page.loop()

    except ConfigError as e:
        _logger.exception(e)
        print(e)
    except Exception as e:
        _logger.exception(e)
        import traceback
        exit_message = '\n'.join([
            debug_text,
            traceback.format_exc(),
            'rtv has crashed. Please report this traceback at:',
            'https://github.com/michael-lazar/rtv/issues\n'])
        sys.stderr.write(exit_message)
        return 1  # General error exception code
    except KeyboardInterrupt:
        pass
    finally:
        # Try to save the browsing history
        config.save_history()
        # Ensure sockets are closed to prevent a ResourceWarning
        if 'reddit' in locals():
            reddit.handler.http.close()
def main ( ) : logging . captureWarnings ( True ) if six . PY3 : warnings . simplefilter ( 'ignore' , ResourceWarning ) if os . getenv ( 'DISPLAY' ) : title = 'rtv {0}' . format ( __version__ ) sys . stdout . write ( '\x1b]2;{0}\x07' . format ( title ) ) sys . stdout . flush ( ) args = Config . get_args ( ) fargs , bindings = Config . get_file ( args . get ( 'config' ) ) config = Config ( ) config . update ( ** fargs ) config . update ( ** args ) if bindings : config . keymap . set_bindings ( bindings ) if config [ 'copy_config' ] : return copy_default_config ( ) if config [ 'copy_mailcap' ] : return copy_default_mailcap ( ) if config [ 'list_themes' ] : return Theme . print_themes ( ) config . load_history ( ) config . load_refresh_token ( ) if config [ 'clear_auth' ] : config . delete_refresh_token ( ) if config [ 'log' ] : logging . basicConfig ( level = logging . DEBUG , filename = config [ 'log' ] , format = '%(asctime)s:%(levelname)s:%(filename)s:%(lineno)d:%(message)s' ) else : logging . root . addHandler ( logging . NullHandler ( ) ) default_locale = locale . setlocale ( locale . LC_ALL , '' ) try : encoding = locale . getlocale ( ) [ 1 ] or locale . getdefaultlocale ( ) [ 1 ] except ValueError : _logger . warning ( 'Error parsing system locale: `%s`,' ' falling back to utf-8' , default_locale ) encoding = 'UTF-8' if not encoding or encoding . lower ( ) != 'utf-8' : text = ( 'System encoding was detected as (%s) instead of UTF-8' ', falling back to ascii only mode' % encoding ) warnings . warn ( text ) config [ 'ascii' ] = True if packages . __praw_bundled__ : praw_info = 'packaged, commit {}' . format ( packages . __praw_hash__ [ : 12 ] ) else : praw_info = 'system installed v{}' . format ( praw . __version__ ) patch_webbrowser ( ) if webbrowser_import_warning : _logger . warning ( 'webbrowser module was unexpectedly imported before' '$BROWSER could be overwritten' ) user_agent = docs . AGENT . format ( version = __version__ ) debug_info = [ 'rtv version: rtv {}' . format ( __version__ ) , 'rtv module path: {}' . format ( os . path . abspath ( __file__ ) ) , 'python version: {}' . format ( sys . version . replace ( '\n' , ' ' ) ) , 'python executable: {}' . format ( sys . executable ) , 'praw version: {}' . format ( praw_info ) , 'locale, encoding: {}, {}' . format ( default_locale , encoding ) , 'Environment Variables' ] for name , value in [ ( 'BROWSER' , BROWSER ) , ( 'DISPLAY' , os . getenv ( 'DISPLAY' ) ) , ( 'EDITOR' , os . getenv ( 'EDITOR' ) ) , ( 'LANG' , os . getenv ( 'LANG' ) ) , ( 'PAGER' , os . getenv ( 'PAGER' ) ) , ( 'RTV_BROWSER' , RTV_BROWSER ) , ( 'RTV_EDITOR' , os . getenv ( 'RTV_EDITOR' ) ) , ( 'RTV_PAGER' , os . getenv ( 'RTV_PAGER' ) ) , ( 'RTV_URLVIEWER' , os . getenv ( 'RTV_URLVIEWER' ) ) , ( 'TERM' , os . getenv ( 'TERM' ) ) , ( 'VISUAL' , os . getenv ( 'VISUAL' ) ) , ( 'XDG_CONFIG_HOME' , os . getenv ( 'XDG_CONFIG_HOME' ) ) , ( 'XDG_DATA_HOME' , os . getenv ( 'XDG_DATA_HOME' ) ) , ] : debug_info . append ( '  {:<16}: {}' . format ( name , value or '' ) ) debug_info . append ( '' ) debug_text = '\n' . join ( debug_info ) _logger . info ( debug_text ) if config [ 'debug_info' ] : print ( debug_text ) return try : with curses_session ( ) as stdscr : term = Terminal ( stdscr , config ) if config [ 'monochrome' ] or config [ 'theme' ] == 'monochrome' : _logger . info ( 'Using monochrome theme' ) theme = Theme ( use_color = False ) elif config [ 'theme' ] and config [ 'theme' ] != 'default' : _logger . info ( 'Loading theme: %s' , config [ 'theme' ] ) theme = Theme . from_name ( config [ 'theme' ] ) else : theme = None term . set_theme ( theme ) with term . loader ( 'Initializing' , catch_exception = False ) : reddit = praw . Reddit ( user_agent = user_agent , decode_html_entities = False , disable_update_check = True , timeout = 10 , handler = RequestHeaderRateLimiter ( ) ) reddit . config . api_request_delay = 300 oauth = OAuthHelper ( reddit , term , config ) if config [ 'autologin' ] and config . refresh_token : oauth . authorize ( autologin = True ) if config [ 'link' ] : url = requests . head ( config [ 'link' ] , headers = reddit . http . headers , allow_redirects = True ) . url page = None with term . loader ( 'Loading submission' ) : try : page = SubmissionPage ( reddit , term , config , oauth , url ) except Exception as e : _logger . exception ( e ) raise SubmissionError ( 'Unable to load {0}' . format ( url ) ) while page : page = page . loop ( ) page = None name = config [ 'subreddit' ] with term . loader ( 'Loading subreddit' ) : try : page = SubredditPage ( reddit , term , config , oauth , name ) except Exception as e : _logger . exception ( e ) page = SubredditPage ( reddit , term , config , oauth , 'popular' ) raise SubredditError ( 'Unable to load {0}' . format ( name ) ) while page : page = page . loop ( ) except ConfigError as e : _logger . exception ( e ) print ( e ) except Exception as e : _logger . exception ( e ) import traceback exit_message = '\n' . join ( [ debug_text , traceback . format_exc ( ) , 'rtv has crashed. Please report this traceback at:' , 'https://github.com/michael-lazar/rtv/issues\n' ] ) sys . stderr . write ( exit_message ) return 1 except KeyboardInterrupt : pass finally : config . save_history ( ) if 'reddit' in locals ( ) : reddit . handler . http . close ( )
Main entry point