Ejemplo n.º 1
0
 def testLazyFormatNestedExpansion(self):
     fmt = 'exp:{text} lit:{{text}} nest-exp:{nest} nest-lit:{{nest}}'
     expected = 'exp:TEXT lit:{text} nest-exp:TEXT+{text} nest-lit:{nest}'
     actual = console_io.LazyFormat(fmt,
                                    text='TEXT',
                                    nest='{text}+{{text}}')
     self.assertEqual(expected, actual)
Ejemplo n.º 2
0
 def testLazyFormatExplicitDoubleQuote(self):
     fmt = '} {one} {{two}} {'
     expected = '} ONE {two} {'
     actual = console_io.LazyFormat(fmt,
                                    one='ONE',
                                    two='TWO',
                                    three='THREE')
     self.assertEqual(expected, actual)
Ejemplo n.º 3
0
 def testLazyFormatListExample(self):
     fmt = "--dict-flag=^:^a=b,c:d=f,g # => {'a: 'b,c', 'd': 'f,g'}"
     expected = fmt
     actual = console_io.LazyFormat(fmt,
                                    one='ONE',
                                    two='TWO',
                                    three='THREE')
     self.assertEqual(expected, actual)
Ejemplo n.º 4
0
    def _ExpandHelpText(self, text):
        """Expand command {...} references in text.

    Args:
      text: The text chunk to expand.

    Returns:
      The expanded help text.
    """
        return console_io.LazyFormat(text or '',
                                     command=self._command_name,
                                     man_name=self._file_name,
                                     top_command=self._top,
                                     parent_command=' '.join(
                                         self._command_path[:-1]),
                                     index=self._capsule,
                                     **self._sections)
def ExpandHelpText(command, text):
    """Expand command {...} references in text.

  Args:
    command: calliope._CommandCommon, The command object that we're helping.
    text: str, The text chunk to expand.

  Returns:
    str, The expanded help text.
  """
    if text == command.long_help:
        long_help = ''
    else:
        long_help = ExpandHelpText(command, command.long_help)
    path = command.GetPath()
    return console_io.LazyFormat(text or '',
                                 command=' '.join(path),
                                 man_name='_'.join(path),
                                 top_command=path[0],
                                 parent_command=' '.join(path[:-1]),
                                 index=command.short_help,
                                 description=long_help)
Ejemplo n.º 6
0
def ExpandHelpText(command, text, sections=True):
  """Expand command {...} references in text.

  Args:
    command: calliope._CommandCommon, The command object that we're helping.
    text: str, The text chunk to expand.
    sections: bool, Include #... markdown sections if True.

  Returns:
    str, The expanded help text.
  """
  if text == command.long_help:
    long_help = ''
  else:
    long_help = ExpandHelpText(command, command.long_help, sections=False)
  path = command.GetPath()
  if not sections and text:
    section_markdown_index = text.find('\n\n#')
    if section_markdown_index >= 0:
      text = text[:section_markdown_index]

  # The lower case keys in the optional detailed_help dict are user specified
  # parameters to LazyFormat().
  details = {}
  for key, value in getattr(command, 'detailed_help', {}).iteritems():
    if key.islower():
      details[key] = value

  return console_io.LazyFormat(
      text or '',
      command=' '.join(path),
      man_name='_'.join(path),
      top_command=path[0],
      parent_command=' '.join(path[:-1]),
      index=command.short_help,
      description=long_help,
      **details
  )
Ejemplo n.º 7
0
  def _ExpandHelpText(self, text, sections=True):
    """Expand command {...} references in text.

    Args:
      text: The text chunk to expand.
      sections: Include #... markdown sections if True.

    Returns:
      The expanded help text.
    """
    if text == self._docstring:
      description = ''
    else:
      description = self._ExpandHelpText(self._docstring, sections=False)
    if not sections and text:
      section_markdown_index = text.find('\n\n#')
      if section_markdown_index >= 0:
        text = text[:section_markdown_index]

    # The lower case keys in the optional detailed_help dict are user specified
    # parameters to LazyFormat().
    details = {}
    for key, value in self._sections.iteritems():
      if key.islower():
        details[key] = value

    return console_io.LazyFormat(
        text or '',
        command=self._command_name,
        man_name=self._file_name,
        top_command=self._command_path[0],
        parent_command=' '.join(self._command_path[:-1]),
        index=self._capsule,  # TODO(user): This should be capsule=...
        description=description,
        **details
    )
Ejemplo n.º 8
0
 def testLazyFormatOneVarExplicitQuote(self):
     fmt = 'This is a {test} with one var and an {{explicit}} {{quote}}.'
     expected = 'This is a TEST with one var and an {explicit} {quote}.'
     actual = console_io.LazyFormat(fmt, test='TEST', explicit='EXPLICIT')
     self.assertEqual(expected, actual)
Ejemplo n.º 9
0
 def testLazyFormatOneVarOneUndefined(self):
     fmt = 'This is a {test} with one var one {undefined}.'
     expected = 'This is a TEST with one var one {undefined}.'
     actual = console_io.LazyFormat(fmt, test='TEST')
     self.assertEqual(expected, actual)
Ejemplo n.º 10
0
 def testLazyFormatOneCallable(self):
     fmt = 'This is a {test} with one var.'
     expected = 'This is a TEST with one var.'
     actual = console_io.LazyFormat(fmt, test=lambda: 'TEST')
     self.assertEqual(expected, actual)
Ejemplo n.º 11
0
 def testLazyFormatNoVars(self):
     fmt = 'This is a test with no vars.'
     expected = fmt
     actual = console_io.LazyFormat(fmt, test='TEST')
     self.assertEqual(expected, actual)
Ejemplo n.º 12
0
 def testLazyFormatLotsOfBraces(self):
     fmt = '{{}'
     expected = fmt
     actual = console_io.LazyFormat(fmt, test='TEST', one='ONE')
     self.assertEqual(expected, actual)
Ejemplo n.º 13
0
 def testLazyFormatUnbalancedBrace(self):
     fmt = '{foo'
     expected = fmt
     actual = console_io.LazyFormat(fmt, test='TEST', one='ONE')
     self.assertEqual(expected, actual)
Ejemplo n.º 14
0
    def __init__(self, command, parent, include_hidden_flags=True):

        self.release = command.ReleaseTrack().id
        self.path = command.GetPath()
        self.name = command.name.replace('_', '-')
        self.hidden = command.IsHidden()
        self.flags = {}
        self.positionals = []
        self.sections = {}
        parent_command = parent.name.replace('_', '-') if parent else ''
        self.release, capsule = self.__Release(
            command, self.release, getattr(command, 'short_help', ''))
        self.capsule = console_io.LazyFormat(_NormalizeDescription(capsule),
                                             command=self.name,
                                             parent_command=parent_command)
        self.release, description = self.__Release(
            command, self.release, getattr(command, 'long_help', ''))
        self.description = console_io.LazyFormat(
            _NormalizeDescription(description),
            command=self.name,
            index=self.capsule,
            parent_command=parent_command)
        sections = getattr(command, 'detailed_help', None)
        if sections:
            for s in sections:
                if s == 'brief':
                    self.release, self.capsule = self.__Release(
                        command, self.release, sections[s])
                else:
                    self.sections[s] = console_io.LazyFormat(
                        _NormalizeDescription(sections[s]),
                        command=self.name,
                        index=self.capsule,
                        description=self.description,
                        parent_command=parent_command)
        self.commands = {}
        # _parent is explicitly private so it won't appear in serialized output.
        self._parent = parent
        if parent:
            parent.commands[self.name] = self
        args = command.ai

        # Initialize the mutually exclusive flag groups.
        group_count = {}
        group_name = {}
        for arg in args.flag_args:
            for name in arg.option_strings:
                if name.startswith('--'):
                    name = name.replace('_', '-')
                    if not self.__Ancestor(name):
                        g = args.mutex_groups.get(arg.dest, None)
                        if g:
                            group_name[name] = g
                            if g in group_count:
                                group_count[g] += 1
                            else:
                                group_count[g] = 1
        group_id_count = 0
        group_id = {}
        # Sorted iteration preserves group_id[] indices across separate invocations
        # where the mutex groups do not change.
        for _, g in sorted(group_name.iteritems()):
            if group_count[g] > 1:
                group_count[g] = 0  # Don't check this group again!
                group_id_count += 1
                group_id[g] = '{}.{}'.format(self.name, group_id_count)

        # Collect the flags.
        for arg in sorted(args.flag_args):
            for name in arg.option_strings:
                if name.startswith('--'):
                    name = name.replace('_', '-')
                    # Don't include ancestor flags.
                    if not self.__Ancestor(name):
                        flag = Flag(name,
                                    description=arg.help,
                                    default=arg.default)
                        # ArgParse does not have an explicit Boolean flag type. By
                        # convention a flag with arg.nargs=0 and action='store_true' or
                        # action='store_false' is a Boolean flag. arg.type gives no hint
                        # (arg.type=bool would have been so easy) and we don't have access
                        # to args.action here. Even then the flag can take on non-Boolean
                        # values. If arg.default is not specified then it will be None, but
                        # it can be set to anything. So we do a conservative 'truthiness'
                        # test here.
                        if arg.nargs == 0:
                            flag.type = 'bool'
                            flag.default = True if arg.default else False
                        else:
                            if arg.type == int:
                                flag.type = 'int'
                            elif arg.type == float:
                                flag.type = 'float'
                            if arg.nargs == '*':
                                pass
                            elif arg.nargs == '?':
                                flag.countmax = 1
                            elif arg.nargs == '+':
                                flag.countmin = 1
                            elif isinstance(arg.nargs, (int, long)):
                                flag.countmin = arg.nargs
                                flag.countmax = arg.nargs
                            elif arg.required:
                                flag.countmin = 1
                                flag.countmax = 1
                            if arg.metavar:
                                flag.value = arg.metavar
                            else:
                                flag.value = name[2:].upper()
                        if arg.choices:
                            choices = sorted(arg.choices)
                            if choices == ['false', 'true']:
                                flag.type = 'bool'
                            else:
                                flag.choices = choices
                        flag.category = arg.category or ''
                        if arg.required:
                            flag.required = 1
                        flag.resource = getattr(arg, 'completion_resource', '')
                        if name in group_name and group_name[name] in group_id:
                            flag.group = group_id[group_name[name]]
                        if include_hidden_flags or not flag.hidden:
                            self.flags[flag.name] = flag

        # Collect the positionals.
        for arg in args.positional_args:
            name = arg.dest.replace('_', '-')
            positional = Positional(name,
                                    description=_NormalizeDescription(
                                        arg.help))
            if arg.metavar:
                positional.value = arg.metavar
            if arg.nargs != 0:
                if arg.nargs == '*':
                    pass
                elif arg.nargs == '?':
                    positional.countmax = 1
                elif arg.nargs == '+':
                    positional.countmin = 1
                elif isinstance(arg.nargs, (int, long)):
                    positional.countmin = arg.nargs
                    positional.countmax = arg.nargs
                elif arg.required:
                    positional.countmin = 1
                    positional.countmax = 1
            positional.resource = getattr(arg, 'completion_resource', '')
            self.positionals.append(positional)
Ejemplo n.º 15
0
    def __init__(self, command, parent):

        self.commands = {}
        self.flags = {}
        self.is_global = not bool(parent)
        self.is_group = command.is_group
        self.is_hidden = command.IsHidden()
        self.name = command.name.replace('_', '-')
        self.path = command.GetPath()
        self.positionals = []
        self.release = command.ReleaseTrack().id
        self.sections = {}
        command_path_string = ' '.join(self.path)
        parent_path_string = ' '.join(parent.path) if parent else ''
        self.release, capsule = self.__Release(
            command, self.release, getattr(command, 'short_help', ''))

        # This code block must be meticulous on when and where LazyFormat expansion
        # is applied to the markdown snippets. First, no expanded text should be
        # passed as a LazyFormat kwarg. Second, no unexpanded text should appear
        # in the CLI tree. The LazyFormat calls are ordered to make sure that
        # doesn't happen.
        capsule = _NormalizeDescription(capsule)
        sections = {}
        self.release, description = self.__Release(
            command, self.release, getattr(command, 'long_help', ''))
        detailed_help = getattr(command, 'detailed_help', {})
        sections.update(detailed_help)
        description = _NormalizeDescription(description)
        if 'DESCRIPTION' not in sections:
            sections['DESCRIPTION'] = description
        notes = command.GetNotesHelpSection()
        if notes:
            sections['NOTES'] = notes
        if sections:
            for name, contents in sections.iteritems():
                # islower() section names were used to convert markdown in command
                # docstrings into the static self.section[] entries seen here.
                if name.isupper():
                    self.sections[name] = console_io.LazyFormat(
                        _NormalizeDescription(contents),
                        command=command_path_string,
                        index=capsule,
                        description=description,
                        parent_command=parent_path_string)
        self.capsule = console_io.LazyFormat(
            capsule,
            command=command_path_string,
            man_name='.'.join(self.path),
            top_command=self.path[0] if self.path else '',
            parent_command=parent_path_string,
            **sections)

        # _parent is explicitly private so it won't appear in serialized output.
        self._parent = parent
        if parent:
            parent.commands[self.name] = self
        args = command.ai

        # Collect the command specific flags.
        for arg in args.flag_args:
            for name in arg.option_strings:
                if name.startswith('--'):
                    # Don't include ancestor flags, with the exception of --help.
                    if name != '--help' and self.__Ancestor(name):
                        continue
                    name = name.replace('_', '-')
                    flag = Flag(arg, name)
                    self.flags[flag.name] = flag

        # Collect the ancestor flags.
        for arg in args.ancestor_flag_args:
            for name in arg.option_strings:
                if name.startswith('--'):
                    name = name.replace('_', '-')
                    flag = Flag(arg, name)
                    self.flags[flag.name] = flag

        # Collect the positionals.
        for arg in args.positional_args:
            name = arg.dest.replace('_', '-')
            positional = Positional(arg, name)
            self.positionals.append(positional)

        # Collect the arg group constraints.
        self.constraints = Constraint(args)
Ejemplo n.º 16
0
 def testLazyFormatOneVarAndImplicitBraces(self):
     fmt = 'This { : is a {test} ? } with { one } var.'
     expected = 'This { : is a TEST ? } with { one } var.'
     actual = console_io.LazyFormat(fmt, test='TEST', one='ONE')
     self.assertEqual(expected, actual)
Ejemplo n.º 17
0
  def __init__(self, command, parent, include_hidden_flags=True):

    self.group = isinstance(command, backend.CommandGroup)
    self.commands = {}
    self.flags = {}
    self.groups = {}
    self.hidden = command.IsHidden()
    self.name = command.name.replace('_', '-')
    self.path = command.GetPath()
    self.positionals = []
    self.release = command.ReleaseTrack().id
    self.sections = {}
    command_path_string = ' '.join(self.path)
    parent_path_string = ' '.join(parent.path) if parent else ''
    self.release, capsule = self.__Release(
        command, self.release, getattr(command, 'short_help', ''))

    # This code block must be meticulous on when and where LazyFormat expansion
    # is applied to the markdown snippets. First, no expanded text should be
    # passed as a LazyFormat kwarg. Second, no unexpanded text should appear
    # in the CLI tree. The LazyFormat calls are ordered to make sure that
    # doesn't happen.
    capsule = _NormalizeDescription(capsule)
    sections = {}
    self.release, description = self.__Release(
        command, self.release, getattr(command, 'long_help', ''))
    detailed_help = getattr(command, 'detailed_help', {})
    sections.update(detailed_help)
    description = _NormalizeDescription(description)
    if 'DESCRIPTION' not in sections:
      sections['DESCRIPTION'] = description
    notes = command.GetNotesHelpSection()
    if notes:
      sections['NOTES'] = notes
    if sections:
      for name, contents in sections.iteritems():
        # islower() section names were used to convert markdown in command
        # docstrings into the static self.section[] entries seen here.
        if name.isupper():
          self.sections[name] = console_io.LazyFormat(
              _NormalizeDescription(contents),
              command=command_path_string,
              man_name='.'.join(self.path),
              top_command=self.path[0] if self.path else '',
              parent_command=parent_path_string,
              index=capsule,
              description=description,
              **sections)
    self.capsule = console_io.LazyFormat(
        capsule,
        command=command_path_string,
        man_name='.'.join(self.path),
        top_command=self.path[0] if self.path else '',
        parent_command=parent_path_string,
        **sections)

    # _parent is explicitly private so it won't appear in serialized output.
    self._parent = parent
    if parent:
      parent.commands[self.name] = self
    args = command.ai

    # Initialize the mutually exclusive flag groups.
    group_count = {}
    group_name = {}
    for arg in args.flag_args:
      for name in arg.option_strings:
        if name.startswith('--'):
          name = name.replace('_', '-')
          if not self.__Ancestor(name):
            g = args.mutex_groups.get(arg.dest, None)
            if g:
              group_name[name] = g
              if g in group_count:
                group_count[g] += 1
              else:
                group_count[g] = 1
    group_id_count = 0
    group_id = {}
    # Sorted iteration preserves group_id[] indices across separate invocations
    # where the mutex groups do not change.
    for _, g in sorted(group_name.iteritems()):
      if group_count[g] > 1:
        group_count[g] = 0  # Don't check this group again!
        group_id_count += 1
        group_id[g] = '{}.{}'.format(self.name, group_id_count)
        self.groups[group_id[g]] = command.ai.group_attr[g]

    # Collect the flags.
    for arg in sorted(args.flag_args):
      for name in arg.option_strings:
        if name.startswith('--'):
          name = name.replace('_', '-')
          # Don't include ancestor flags.
          if not self.__Ancestor(name):
            flag = Flag(arg, name)
            if flag.name in group_name and group_name[flag.name] in group_id:
              flag.group = group_id[group_name[flag.name]]
            if include_hidden_flags or not flag.hidden:
              self.flags[flag.name] = flag

    # Collect the positionals.
    for arg in args.positional_args:
      name = arg.dest.replace('_', '-')
      positional = Positional(arg, name)
      self.positionals.append(positional)
Ejemplo n.º 18
0
    def __init__(self, command, parent, include_hidden_flags=True):

        self.group = isinstance(command, backend.CommandGroup)
        self.commands = {}
        self.flags = {}
        self.groups = {}
        self.hidden = command.IsHidden()
        self.name = command.name.replace('_', '-')
        self.path = command.GetPath()
        self.positionals = []
        self.release = command.ReleaseTrack().id
        self.sections = {}
        parent_command = parent.name.replace('_', '-') if parent else ''
        self.release, capsule = self.__Release(
            command, self.release, getattr(command, 'short_help', ''))
        self.capsule = console_io.LazyFormat(_NormalizeDescription(capsule),
                                             command=self.name,
                                             parent_command=parent_command)
        self.release, description = self.__Release(
            command, self.release, getattr(command, 'long_help', ''))
        description = console_io.LazyFormat(_NormalizeDescription(description),
                                            command=self.name,
                                            index=self.capsule,
                                            parent_command=parent_command)
        sections = getattr(command, 'detailed_help', None)
        if sections:
            for s in sections:
                # islower() section names were used to convert markdown in command
                # docstrings into the static self.section[] entries seen here.
                if s.isupper():
                    self.sections[s] = console_io.LazyFormat(
                        _NormalizeDescription(sections[s]),
                        command=self.name,
                        index=self.capsule,
                        description=description,
                        parent_command=parent_command)
        if 'DESCRIPTION' not in self.sections:
            self.sections['DESCRIPTION'] = description
        # _parent is explicitly private so it won't appear in serialized output.
        self._parent = parent
        if parent:
            parent.commands[self.name] = self
        args = command.ai

        # Initialize the mutually exclusive flag groups.
        group_count = {}
        group_name = {}
        for arg in args.flag_args:
            for name in arg.option_strings:
                if name.startswith('--'):
                    name = name.replace('_', '-')
                    if not self.__Ancestor(name):
                        g = args.mutex_groups.get(arg.dest, None)
                        if g:
                            group_name[name] = g
                            if g in group_count:
                                group_count[g] += 1
                            else:
                                group_count[g] = 1
        group_id_count = 0
        group_id = {}
        # Sorted iteration preserves group_id[] indices across separate invocations
        # where the mutex groups do not change.
        for _, g in sorted(group_name.iteritems()):
            if group_count[g] > 1:
                group_count[g] = 0  # Don't check this group again!
                group_id_count += 1
                group_id[g] = '{}.{}'.format(self.name, group_id_count)
                self.groups[group_id[g]] = command.ai.group_attr[g]

        # Collect the flags.
        for arg in sorted(args.flag_args):
            for name in arg.option_strings:
                if name.startswith('--'):
                    name = name.replace('_', '-')
                    # Don't include ancestor flags.
                    if not self.__Ancestor(name):
                        flag = Flag(arg, name)
                        if flag.name in group_name and group_name[
                                flag.name] in group_id:
                            flag.group = group_id[group_name[flag.name]]
                        if include_hidden_flags or not flag.hidden:
                            self.flags[flag.name] = flag

        # Collect the positionals.
        for arg in args.positional_args:
            name = arg.dest.replace('_', '-')
            positional = Positional(arg, name)
            self.positionals.append(positional)