def usage(shorthelp=False, writeto_stdout=False, detailed_error=None, exitcode=None): """Writes __main__'s docstring to stderr with some help text. Args: shorthelp: bool, if True, prints only flags from the main module, rather than all flags. writeto_stdout: bool, if True, writes help message to stdout, rather than to stderr. detailed_error: str, additional detail about why usage info was presented. exitcode: optional integer, if set, exits with this status code after writing help. """ if writeto_stdout: stdfile = sys.stdout else: stdfile = sys.stderr doc = sys.modules['__main__'].__doc__ if not doc: doc = '\nUSAGE: %s [flags]\n' % sys.argv[0] doc = flags.text_wrap(doc, indent=' ', firstline_indent='') else: # Replace all '%s' with sys.argv[0], and all '%%' with '%'. num_specifiers = doc.count('%') - 2 * doc.count('%%') try: doc %= (sys.argv[0], ) * num_specifiers except (OverflowError, TypeError, ValueError): # Just display the docstring as-is. pass if shorthelp: flag_str = FLAGS.main_module_help() else: flag_str = FLAGS.get_help() try: stdfile.write(doc) if flag_str: stdfile.write('\nflags:\n') stdfile.write(flag_str) stdfile.write('\n') if detailed_error is not None: stdfile.write('\n%s\n' % detailed_error) except IOError as e: # We avoid printing a huge backtrace if we get EPIPE, because # "foo.par --help | less" is a frequent use case. if e.errno != errno.EPIPE: raise if exitcode is not None: sys.exit(exitcode)
def usage(shorthelp=False, writeto_stdout=False, detailed_error=None, exitcode=None): """Writes __main__'s docstring to stderr with some help text. Args: shorthelp: bool, if True, prints only flags from this module, rather than all flags. writeto_stdout: bool, if True, writes help message to stdout, rather than to stderr. detailed_error: str, additional detail about why usage info was presented. exitcode: optional integer, if set, exits with this status code after writing help. """ if writeto_stdout: stdfile = sys.stdout else: stdfile = sys.stderr doc = sys.modules['__main__'].__doc__ if not doc: doc = '\nUSAGE: %s [flags]\n' % sys.argv[0] doc = flags.text_wrap(doc, indent=' ', firstline_indent='') else: # Replace all '%s' with sys.argv[0], and all '%%' with '%'. num_specifiers = doc.count('%') - 2 * doc.count('%%') try: doc %= (sys.argv[0],) * num_specifiers except (OverflowError, TypeError, ValueError): # Just display the docstring as-is. pass if shorthelp: flag_str = FLAGS.main_module_help() else: flag_str = str(FLAGS) try: stdfile.write(doc) if flag_str: stdfile.write('\nflags:\n') stdfile.write(flag_str) stdfile.write('\n') if detailed_error is not None: stdfile.write('\n%s\n' % detailed_error) except IOError as e: # We avoid printing a huge backtrace if we get EPIPE, because # "foo.par --help | less" is a frequent use case. if e.errno != errno.EPIPE: raise if exitcode is not None: sys.exit(exitcode)
def usage(shorthelp=False, writeto_stdout=False, detailed_error=None, exitcode=None): """Writes __main__'s docstring to stderr with some help text. Args: shorthelp: bool, if True, prints only flags from the main module, rather than all flags. writeto_stdout: bool, if True, writes help message to stdout, rather than to stderr. detailed_error: str, additional detail about why usage info was presented. exitcode: optional integer, if set, exits with this status code after writing help. """ if writeto_stdout: stdfile = sys.stdout else: stdfile = sys.stderr doc = sys.modules['__main__'].__doc__ if not doc: doc = f'USAGE: python -m benchmarks.driver <exp> [flags]\n\n' doc = flags.text_wrap(doc, indent=' ', firstline_indent='') if shorthelp: flag_str = FLAGS.main_module_help() else: flag_str = str(FLAGS) try: stdfile.write(doc) if flag_str: stdfile.write('\nflags:\n') stdfile.write(flag_str) stdfile.write('\n') if detailed_error is not None: stdfile.write('\n%s\n' % detailed_error) except IOError as e: # We avoid printing a huge backtrace if we get EPIPE, because # "foo.par --help | less" is a frequent use case. if e.errno != errno.EPIPE: raise if exitcode is not None: sys.exit(exitcode)
def ProcessError( err, name='unknown', message_prefix='You have encountered a bug in the BigQuery CLI.'): """Translate an error message into some printing and a return code.""" if isinstance(err, SystemExit): return err.code # sys.exit called somewhere, hopefully intentionally. response = [] retcode = 1 (etype, value, tb) = sys.exc_info() trace = ''.join(traceback.format_exception(etype, value, tb)) # pragma pylint: disable=line-too-long contact_us_msg = ( 'Please file a bug report in our ' 'public ' 'issue tracker:\n' ' https://issuetracker.google.com/issues/new?component=187149&template=0\n' 'Please include a brief description of ' 'the steps that led to this issue, as well as ' 'any rows that can be made public from ' 'the following information: \n\n') platform_str = ':'.join([ platform.python_implementation(), platform.python_version(), platform.platform() ]) error_details = textwrap.dedent("""\ ======================================== == Platform == %s == bq version == %s == Command line == %s == UTC timestamp == %s == Error trace == %s ======================================== """) % (platform_str, six.ensure_str(VERSION_NUMBER), [ six.ensure_str(item) for item in sys.argv ], time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()), six.ensure_str(trace)) codecs.register_error('strict', codecs.replace_errors) message = bigquery_client.EncodeForPrinting(err) if isinstance(err, (bigquery_client.BigqueryNotFoundError, bigquery_client.BigqueryDuplicateError)): response.append('BigQuery error in %s operation: %s' % (name, message)) retcode = 2 elif isinstance(err, bigquery_client.BigqueryTermsOfServiceError): response.append(str(err) + '\n') response.append(_BIGQUERY_TOS_MESSAGE) elif isinstance(err, bigquery_client.BigqueryInvalidQueryError): response.append('Error in query string: %s' % (message, )) elif (isinstance(err, bigquery_client.BigqueryError) and not isinstance(err, bigquery_client.BigqueryInterfaceError)): response.append('BigQuery error in %s operation: %s' % (name, message)) elif isinstance(err, (app.UsageError, TypeError)): response.append(message) elif (isinstance(err, SyntaxError) or isinstance(err, bigquery_client.BigquerySchemaError)): response.append('Invalid input: %s' % (message, )) elif isinstance(err, flags.Error): response.append('Error parsing command: %s' % (message, )) elif isinstance(err, KeyboardInterrupt): response.append('') else: # pylint: disable=broad-except # Errors with traceback information are printed here. # The traceback module has nicely formatted the error trace # for us, so we don't want to undo that via TextWrap. if isinstance(err, bigquery_client.BigqueryInterfaceError): message_prefix = ( 'Bigquery service returned an invalid reply in %s operation: %s.' '\n\n' 'Please make sure you are using the latest version ' 'of the bq tool and try again. ' 'If this problem persists, you may have encountered a bug in the ' 'bigquery client.' % (name, message)) elif isinstance(err, oauth2client_4_0.client.Error): message_prefix = ( 'Authorization error. This may be a network connection problem, ' 'so please try again. If this problem persists, the credentials ' 'may be corrupt. Try deleting and re-creating your credentials. ' 'You can delete your credentials using ' '"bq init --delete_credentials".' '\n\n' 'If this problem still occurs, you may have encountered a bug ' 'in the bigquery client.') elif (isinstance(err, six.moves.http_client.HTTPException) or isinstance(err, googleapiclient.errors.Error) or isinstance(err, httplib2.HttpLib2Error)): message_prefix = ( 'Network connection problem encountered, please try again.' '\n\n' 'If this problem persists, you may have encountered a bug in the ' 'bigquery client.') message = message_prefix + ' ' + contact_us_msg wrap_error_message = True if wrap_error_message: message = flags.text_wrap(message) print(message) print(error_details) response.append('Unexpected exception in %s operation: %s' % (name, message)) response_message = '\n'.join(response) wrap_error_message = True if wrap_error_message: response_message = flags.text_wrap(response_message) print(response_message) return retcode
def AppcommandsUsage(shorthelp=0, writeto_stdout=0, detailed_error=None, exitcode=None, show_cmd=None, show_global_flags=False): """Output usage or help information. Extracts the __doc__ string from the __main__ module and writes it to stderr. If that string contains a '%s' then that is replaced by the command pathname. Otherwise a default usage string is being generated. The output varies depending on the following: - FLAGS.help - FLAGS.helpshort - show_cmd - show_global_flags Args: shorthelp: print only command and main module flags, rather than all. writeto_stdout: write help message to stdout, rather than to stderr. detailed_error: additional details about why usage info was presented. exitcode: if set, exit with this status code after writing help. show_cmd: show help for this command only (name of command). show_global_flags: show help for global flags. Raises: SystemExit: to indicate exiting the program. """ if writeto_stdout: stdfile = sys.stdout else: stdfile = sys.stderr prefix = ''.rjust(GetMaxCommandLength() + 2) # Deal with header, containing general tool documentation doc = sys.modules['__main__'].__doc__ if doc: help_msg = flags.doc_to_help(doc.replace('%s', GetAppBasename())) stdfile.write(flags.text_wrap(help_msg, flags.get_help_width())) stdfile.write('\n\n\n') if not doc or doc.find('%s') == -1: synopsis = 'USAGE: ' + GetSynopsis() stdfile.write( flags.text_wrap(synopsis, flags.get_help_width(), ' ', '')) stdfile.write('\n\n\n') # Special case just 'help' registered, that means run as 'tool --help'. if len(GetCommandList()) == 1: cmd_names = [] else: cmd_names = [ cmd_name for cmd_name, cmd in GetCommandList().items() if not cmd._hidden ] # pylint: disable=protected-access cmd_names.sort() # Show list of commands if show_cmd is None or show_cmd == 'help': stdfile.write('Any of the following commands:\n') doc = ', '.join(cmd_names) stdfile.write(flags.text_wrap(doc, flags.get_help_width(), ' ')) stdfile.write('\n\n\n') # Prepare list of commands to show help for if show_cmd is not None: cmd_names = [show_cmd] # show only one command elif FLAGS.help or FLAGS.helpshort or shorthelp: cmd_names = [] # Show the command help (none, one specific, or all) for name in cmd_names: command = GetCommandByName(name) try: cmd_help = command.CommandGetHelp(GetCommandArgv(), cmd_names=cmd_names) except Exception as error: # pylint: disable=broad-except cmd_help = "Internal error for command '%s': %s." % (name, str(error)) cmd_help = cmd_help.strip() all_names = ', '.join([command.CommandGetName()] + (command.CommandGetAliases() or [])) if len(all_names) + 1 >= len(prefix) or not cmd_help: # If command/alias list would reach over help block-indent # start the help block on a new line. stdfile.write(flags.text_wrap(all_names, flags.get_help_width())) stdfile.write('\n') prefix1 = prefix else: prefix1 = all_names.ljust(GetMaxCommandLength() + 2) if cmd_help: stdfile.write( flags.text_wrap(cmd_help, flags.get_help_width(), prefix, prefix1)) stdfile.write('\n\n') else: stdfile.write('\n') # When showing help for exactly one command we show its flags if len(cmd_names) == 1: # Need to register flags for command prior to be able to use them. # We do not register them globally so that they do not reappear. # pylint: disable=protected-access cmd_flags = command._command_flags if cmd_flags: stdfile.write('%sFlags for %s:\n' % (prefix, name)) stdfile.write(cmd_flags.get_help(prefix + ' ')) stdfile.write('\n\n') stdfile.write('\n') # Now show global flags as asked for if show_global_flags: stdfile.write('Global flags:\n') if shorthelp: stdfile.write(FLAGS.main_module_help()) else: stdfile.write(FLAGS.get_help()) stdfile.write('\n') else: stdfile.write("Run '%s --help' to get help for global flags." % GetAppBasename()) stdfile.write('\n%s\n' % _UsageFooter(detailed_error, cmd_names)) if exitcode is not None: sys.exit(exitcode)
def test_text_wrap(self): """Test that wrapping works as expected. Also tests that it is using global flags._help_width by default. """ default_help_width = _helpers._DEFAULT_HELP_WIDTH _helpers._DEFAULT_HELP_WIDTH = 10 # Generate a string with length 40, no spaces text = '' expect = [] for n in range(4): line = str(n) line += '123456789' text += line expect.append(line) # Verify we still break wrapped = flags.text_wrap(text).split('\n') self.assertEqual(4, len(wrapped)) self.assertEqual(expect, wrapped) wrapped = flags.text_wrap(text, 80).split('\n') self.assertEqual(1, len(wrapped)) self.assertEqual([text], wrapped) # Normal case, breaking at word boundaries and rewriting new lines input_value = 'a b c d e f g h' expect = { 1: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], 2: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], 3: ['a b', 'c d', 'e f', 'g h'], 4: ['a b', 'c d', 'e f', 'g h'], 5: ['a b c', 'd e f', 'g h'], 6: ['a b c', 'd e f', 'g h'], 7: ['a b c d', 'e f g h'], 8: ['a b c d', 'e f g h'], 9: ['a b c d e', 'f g h'], 10: ['a b c d e', 'f g h'], 11: ['a b c d e f', 'g h'], 12: ['a b c d e f', 'g h'], 13: ['a b c d e f g', 'h'], 14: ['a b c d e f g', 'h'], 15: ['a b c d e f g h'] } for width, exp in expect.items(): self.assertEqual(exp, flags.text_wrap(input_value, width).split('\n')) # We turn lines with only whitespace into empty lines # We strip from the right up to the first new line self.assertEqual('', flags.text_wrap(' ')) self.assertEqual('\n', flags.text_wrap(' \n ')) self.assertEqual('\n', flags.text_wrap('\n\n')) self.assertEqual('\n\n', flags.text_wrap('\n\n\n')) self.assertEqual('\n', flags.text_wrap('\n ')) self.assertEqual('a\n\nb', flags.text_wrap('a\n \nb')) self.assertEqual('a\n\n\nb', flags.text_wrap('a\n \n \nb')) self.assertEqual('a\nb', flags.text_wrap(' a\nb ')) self.assertEqual('\na\nb', flags.text_wrap('\na\nb\n')) self.assertEqual('\na\nb\n', flags.text_wrap(' \na\nb\n ')) self.assertEqual('\na\nb\n', flags.text_wrap(' \na\nb\n\n')) # Double newline. self.assertEqual('a\n\nb', flags.text_wrap(' a\n\n b')) # We respect prefix self.assertEqual(' a\n b\n c', flags.text_wrap('a\nb\nc', 80, ' ')) self.assertEqual('a\n b\n c', flags.text_wrap('a\nb\nc', 80, ' ', '')) # tabs self.assertEqual('a\n b c', flags.text_wrap('a\nb\tc', 80, ' ', '')) self.assertEqual('a\n bb c', flags.text_wrap('a\nbb\tc', 80, ' ', '')) self.assertEqual('a\n bbb c', flags.text_wrap('a\nbbb\tc', 80, ' ', '')) self.assertEqual('a\n bbbb c', flags.text_wrap('a\nbbbb\tc', 80, ' ', '')) self.assertEqual('a\n b\n c\n d', flags.text_wrap('a\nb\tc\td', 3, ' ', '')) self.assertEqual('a\n b\n c\n d', flags.text_wrap('a\nb\tc\td', 4, ' ', '')) self.assertEqual('a\n b\n c\n d', flags.text_wrap('a\nb\tc\td', 5, ' ', '')) self.assertEqual('a\n b c\n d', flags.text_wrap('a\nb\tc\td', 6, ' ', '')) self.assertEqual('a\n b c\n d', flags.text_wrap('a\nb\tc\td', 7, ' ', '')) self.assertEqual('a\n b c\n d', flags.text_wrap('a\nb\tc\td', 8, ' ', '')) self.assertEqual('a\n b c\n d', flags.text_wrap('a\nb\tc\td', 9, ' ', '')) self.assertEqual('a\n b c d', flags.text_wrap('a\nb\tc\td', 10, ' ', '')) # multiple tabs self.assertEqual('a c', flags.text_wrap('a\t\tc', 80, ' ', '')) _helpers._DEFAULT_HELP_WIDTH = default_help_width # restore