示例#1
0
    def get_option_help_info(self, args, kwargs):
        """Returns an OptionHelpInfo for the option registered with the given (args, kwargs)."""
        display_args = []
        scoped_cmd_line_args = []
        unscoped_cmd_line_args = []

        for arg in args:
            is_short_arg = len(arg) == 2
            unscoped_cmd_line_args.append(arg)
            if self._scope_prefix:
                scoped_arg = '--{}-{}'.format(self._scope_prefix,
                                              arg.lstrip('-'))
            else:
                scoped_arg = arg
            scoped_cmd_line_args.append(scoped_arg)

            if is_boolean_flag(kwargs):
                if is_short_arg:
                    display_arg = scoped_arg
                else:
                    unscoped_cmd_line_args.append('--no-{}'.format(arg[2:]))
                    scoped_cmd_line_args.append('--no-{}'.format(
                        scoped_arg[2:]))
                    display_arg = '--[no-]{}'.format(scoped_arg[2:])
            else:
                display_arg = '{}={}'.format(scoped_arg,
                                             self.compute_metavar(kwargs))
                if kwargs.get('action') == 'append':
                    display_arg = '{arg_str} ({arg_str}) ...'.format(
                        arg_str=display_arg)
            display_args.append(display_arg)

        if is_boolean_flag(kwargs):
            typ = bool
        else:
            typ = kwargs.get('type', str)
        default = self.compute_default(kwargs)
        help_msg = kwargs.get('help', 'No help available.')
        deprecated_version = kwargs.get('deprecated_version')
        deprecated_message = (
            'DEPRECATED. Will be removed in version {}.'.format(
                deprecated_version) if deprecated_version else None)
        deprecated_hint = kwargs.get('deprecated_hint')
        choices = ', '.join(
            kwargs.get('choices')) if kwargs.get('choices') else None

        ret = OptionHelpInfo(registering_class=kwargs.get(
            'registering_class', type(None)),
                             display_args=display_args,
                             scoped_cmd_line_args=scoped_cmd_line_args,
                             unscoped_cmd_line_args=unscoped_cmd_line_args,
                             typ=typ,
                             fromfile=kwargs.get('fromfile', False),
                             default=default,
                             help=help_msg,
                             deprecated_version=deprecated_version,
                             deprecated_message=deprecated_message,
                             deprecated_hint=deprecated_hint,
                             choices=choices)
        return ret
示例#2
0
文件: parser.py 项目: cheister/pants
  def _validate(self, args, kwargs):
    """Validate option registration arguments."""
    def error(exception_type, arg_name=None, **msg_kwargs):
      if arg_name is None:
        arg_name = args[0] if args else '<unknown>'
      raise exception_type(self.scope, arg_name, **msg_kwargs)

    if not args:
      error(NoOptionNames)
    # validate args.
    for arg in args:
      if not arg.startswith('-'):
        error(OptionNameDash, arg_name=arg)
      if not arg.startswith('--') and len(arg) > 2:
        error(OptionNameDoubleDash, arg_name=arg)

    # Validate kwargs.
    if kwargs.get('action', 'store') not in self._allowed_actions:
      error(InvalidAction, action=kwargs['action'])

    if is_boolean_flag(kwargs) and 'type' in kwargs:
      error(BooleanOptionType)
    if 'implicit_value' in kwargs:
      if is_boolean_flag(kwargs):
        error(BooleanOptionImplicitVal)
      elif kwargs['implicit_value'] is None:
        error(ImplicitValIsNone)
    for kwarg in kwargs:
      if kwarg not in self._allowed_registration_kwargs:
        error(InvalidKwarg, kwarg=kwarg)

    deprecated_ver = kwargs.get('deprecated_version')
    if deprecated_ver is not None:
      check_deprecated_semver(deprecated_ver, check_expired=False)
示例#3
0
  def get_option_help_info(self, args, kwargs):
    """Returns an OptionHelpInfo for the option registered with the given (args, kwargs).

    :API: public
    """
    display_args = []
    scoped_cmd_line_args = []
    unscoped_cmd_line_args = []

    for arg in args:
      is_short_arg = len(arg) == 2
      unscoped_cmd_line_args.append(arg)
      if self._scope_prefix:
        scoped_arg = '--{}-{}'.format(self._scope_prefix, arg.lstrip('-'))
      else:
        scoped_arg = arg
      scoped_cmd_line_args.append(scoped_arg)

      if is_boolean_flag(kwargs):
        if is_short_arg:
          display_arg = scoped_arg
        else:
          unscoped_cmd_line_args.append('--no-{}'.format(arg[2:]))
          scoped_cmd_line_args.append('--no-{}'.format(scoped_arg[2:]))
          display_arg = '--[no-]{}'.format(scoped_arg[2:])
      else:
        display_arg = '{}={}'.format(scoped_arg, self.compute_metavar(kwargs))
        if kwargs.get('action') == 'append':
          display_arg = '{arg_str} ({arg_str}) ...'.format(arg_str=display_arg)
      display_args.append(display_arg)

    if is_boolean_flag(kwargs):
      typ = bool
    else:
      typ = kwargs.get('type', str)
    default = self.compute_default(kwargs)
    help_msg = kwargs.get('help', 'No help available.')
    deprecated_version = kwargs.get('deprecated_version')
    deprecated_message = None
    if deprecated_version:
      deprecated_tense = self._get_deprecated_tense(deprecated_version)
      deprecated_message = 'DEPRECATED. {} removed in version: {}'.format(deprecated_tense,
                                                                          deprecated_version)
    deprecated_hint = kwargs.get('deprecated_hint')
    choices = ', '.join(kwargs.get('choices')) if kwargs.get('choices') else None

    ret = OptionHelpInfo(registering_class=kwargs.get('registering_class', type(None)),
                         display_args=display_args,
                         scoped_cmd_line_args=scoped_cmd_line_args,
                         unscoped_cmd_line_args=unscoped_cmd_line_args,
                         typ=typ,
                         fromfile=kwargs.get('fromfile', False),
                         default=default,
                         help=help_msg,
                         deprecated_version=deprecated_version,
                         deprecated_message=deprecated_message,
                         deprecated_hint=deprecated_hint,
                         choices=choices)
    return ret
示例#4
0
 def capture_the_flags(*args, **kwargs):
   for arg in args:
     flags.add(arg)
     if len(arg) == 2:
       short_flags.add(arg)
     elif is_boolean_flag(kwargs):
       flags.add('--no-{}'.format(arg[2:]))
示例#5
0
 def capture_the_flags(*args, **kwargs):
     for arg in args:
         flags.add(arg)
         if len(arg) == 2:
             short_flags.add(arg)
         elif is_boolean_flag(kwargs):
             flags.add('--no-{}'.format(arg[2:]))
示例#6
0
    def _compute_default(self, dest, kwargs):
        """Compute the default value to use for an option's registration.

    The source of the default value is chosen according to the ranking in RankedValue.
    """
        config_section = 'DEFAULT' if self._scope == GLOBAL_SCOPE else self._scope
        udest = dest.upper()
        if self._scope == GLOBAL_SCOPE:
            # For convenience, we allow three forms of env var for global scope options.
            # The fully-specified env var is PANTS_DEFAULT_FOO, which is uniform with PANTS_<SCOPE>_FOO
            # for all the other scopes.  However we also allow simply PANTS_FOO. And if the option name
            # itself starts with 'pants-' then we also allow simply FOO. E.g., PANTS_WORKDIR instead of
            # PANTS_PANTS_WORKDIR or PANTS_DEFAULT_PANTS_WORKDIR. We take the first specified value we
            # find, in this order: PANTS_DEFAULT_FOO, PANTS_FOO, FOO.
            env_vars = [
                'PANTS_DEFAULT_{0}'.format(udest), 'PANTS_{0}'.format(udest)
            ]
            if udest.startswith('PANTS_'):
                env_vars.append(udest)
        else:
            sanitized_env_var_scope = self._ENV_SANITIZER_RE.sub(
                '_', config_section.upper())
            env_vars = ['PANTS_{0}_{1}'.format(sanitized_env_var_scope, udest)]
        value_type = self.str_to_bool if is_boolean_flag(
            kwargs) else kwargs.get('type', str)
        env_val_str = None
        if self._env:
            for env_var in env_vars:
                if env_var in self._env:
                    env_val_str = self._env.get(env_var)
                    break
        env_val = None if env_val_str is None else value_type(env_val_str)
        if kwargs.get('action') == 'append':
            config_val_strs = self._config.getlist(
                config_section, dest) if self._config else None
            config_val = (None if config_val_strs is None else [
                value_type(config_val_str)
                for config_val_str in config_val_strs
            ])
            default = []
        else:
            config_val_str = (self._config.get(
                config_section, dest, default=None) if self._config else None)
            config_val = None if config_val_str is None else value_type(
                config_val_str)
            default = None
        hardcoded_val = kwargs.get('default')
        return RankedValue.choose(None, env_val, config_val, hardcoded_val,
                                  default)
示例#7
0
文件: parser.py 项目: megaserg/pants
 def _argparse_register(self, args, kwargs):
   """Do the deferred argparse registration."""
   # This check prevents repeat registration of the same option, e.g., during bootstrapping,
   # when we parse some global options multiple times.
   if args[0] not in self._argparse_registered_args:
     self._validate(args, kwargs)
     argparse_kwargs = self._clean_argparse_kwargs(kwargs)
     if is_boolean_flag(argparse_kwargs):
       inverse_args = self._create_inverse_args(args)
       if inverse_args:
         inverse_argparse_kwargs = self._create_inverse_kwargs(argparse_kwargs)
         group = self._argparser.add_mutually_exclusive_group()
         group.add_argument(*args, **argparse_kwargs)
         group.add_argument(*inverse_args, **inverse_argparse_kwargs)
       else:
         self._argparser.add_argument(*args, **argparse_kwargs)
     else:
       self._argparser.add_argument(*args, **argparse_kwargs)
   self._argparse_registered_args.update(args)
示例#8
0
    def _register(self, dest, args, kwargs):
        """Register the option for parsing (recursively if needed)."""
        argparse_kwargs, recursive = self._clean_argparse_kwargs(dest, args, kwargs)
        if is_boolean_flag(argparse_kwargs):
            inverse_args = self._create_inverse_args(args)
            if inverse_args:
                inverse_argparse_kwargs = self._create_inverse_kwargs(argparse_kwargs)
                group = self._argparser.add_mutually_exclusive_group()
                group.add_argument(*args, **argparse_kwargs)
                group.add_argument(*inverse_args, **inverse_argparse_kwargs)
            else:
                self._argparser.add_argument(*args, **argparse_kwargs)
        else:
            self._argparser.add_argument(*args, **argparse_kwargs)

        if recursive:
            # Propagate registration down to inner scopes.
            for child_parser in self._child_parsers:
                kwargs.pop("recursive_root", False)
                child_parser._register(dest, args, kwargs)
示例#9
0
  def _register(self, dest, args, kwargs):
    """Register the option for parsing (recursively if needed)."""
    argparse_kwargs, recursive = self._clean_argparse_kwargs(dest, args, kwargs)
    if is_boolean_flag(argparse_kwargs):
      inverse_args = self._create_inverse_args(args)
      if inverse_args:
        inverse_argparse_kwargs = self._create_inverse_kwargs(argparse_kwargs)
        group = self._argparser.add_mutually_exclusive_group()
        group.add_argument(*args, **argparse_kwargs)
        group.add_argument(*inverse_args, **inverse_argparse_kwargs)
      else:
        self._argparser.add_argument(*args, **argparse_kwargs)
    else:
      self._argparser.add_argument(*args, **argparse_kwargs)

    if recursive:
      # Propagate registration down to inner scopes.
      for child_parser in self._child_parsers:
        kwargs.pop('recursive_root', False)
        child_parser._register(dest, args, kwargs)
示例#10
0
文件: parser.py 项目: lclementi/pants
 def _argparse_register(self, args, kwargs):
     """Do the deferred argparse registration."""
     # This check prevents repeat registration of the same option, e.g., during bootstrapping,
     # when we parse some global options multiple times.
     if args[0] not in self._argparse_registered_args:
         self._validate(args, kwargs)
         argparse_kwargs = self._clean_argparse_kwargs(kwargs)
         if is_boolean_flag(argparse_kwargs):
             inverse_args = self._create_inverse_args(args)
             if inverse_args:
                 inverse_argparse_kwargs = self._create_inverse_kwargs(
                     argparse_kwargs)
                 group = self._argparser.add_mutually_exclusive_group()
                 group.add_argument(*args, **argparse_kwargs)
                 group.add_argument(*inverse_args,
                                    **inverse_argparse_kwargs)
             else:
                 self._argparser.add_argument(*args, **argparse_kwargs)
         else:
             self._argparser.add_argument(*args, **argparse_kwargs)
     self._argparse_registered_args.update(args)
示例#11
0
文件: parser.py 项目: irfnhm/pants
  def _compute_default(self, dest, kwargs):
    """Compute the default value to use for an option's registration.

    The source of the default value is chosen according to the ranking in RankedValue.
    """
    config_section = 'DEFAULT' if self._scope == GLOBAL_SCOPE else self._scope
    udest = dest.upper()
    if self._scope == GLOBAL_SCOPE:
      # For convenience, we allow three forms of env var for global scope options.
      # The fully-specified env var is PANTS_DEFAULT_FOO, which is uniform with PANTS_<SCOPE>_FOO
      # for all the other scopes.  However we also allow simply PANTS_FOO. And if the option name
      # itself starts with 'pants-' then we also allow simply FOO. E.g., PANTS_WORKDIR instead of
      # PANTS_PANTS_WORKDIR or PANTS_DEFAULT_PANTS_WORKDIR. We take the first specified value we
      # find, in this order: PANTS_DEFAULT_FOO, PANTS_FOO, FOO.
      env_vars = ['PANTS_DEFAULT_{0}'.format(udest), 'PANTS_{0}'.format(udest)]
      if udest.startswith('PANTS_'):
        env_vars.append(udest)
    else:
      sanitized_env_var_scope = self._ENV_SANITIZER_RE.sub('_', config_section.upper())
      env_vars = ['PANTS_{0}_{1}'.format(sanitized_env_var_scope, udest)]
    value_type = self.str_to_bool if is_boolean_flag(kwargs) else kwargs.get('type', str)
    env_val_str = None
    if self._env:
      for env_var in env_vars:
        if env_var in self._env:
          env_val_str = self._env.get(env_var)
          break
    env_val = None if env_val_str is None else value_type(env_val_str)
    if kwargs.get('action') == 'append':
      config_val_strs = self._config.getlist(config_section, dest) if self._config else None
      config_val = (None if config_val_strs is None else
                    [value_type(config_val_str) for config_val_str in config_val_strs])
      default = []
    else:
      config_val_str = (self._config.get(config_section, dest, default=None)
                        if self._config else None)
      config_val = None if config_val_str is None else value_type(config_val_str)
      default = None
    hardcoded_val = kwargs.get('default')
    return RankedValue.choose(None, env_val, config_val, hardcoded_val, default)
示例#12
0
文件: parser.py 项目: cheister/pants
  def _compute_value(self, dest, kwargs, flag_vals):
    """Compute the value to use for an option.

    The source of the default value is chosen according to the ranking in RankedValue.
    """
    is_fromfile = kwargs.get('fromfile', False)
    action = kwargs.get('action')
    if is_fromfile and action and action != 'append':
      raise ParseError('Cannot fromfile {} with an action ({}) in scope {}'
                       .format(dest, action, self._scope))

    config_section = GLOBAL_SCOPE_CONFIG_SECTION if self._scope == GLOBAL_SCOPE else self._scope
    udest = dest.upper()
    if self._scope == GLOBAL_SCOPE:
      # For convenience, we allow three forms of env var for global scope options.
      # The fully-specified env var is PANTS_DEFAULT_FOO, which is uniform with PANTS_<SCOPE>_FOO
      # for all the other scopes.  However we also allow simply PANTS_FOO. And if the option name
      # itself starts with 'pants-' then we also allow simply FOO. E.g., PANTS_WORKDIR instead of
      # PANTS_PANTS_WORKDIR or PANTS_DEFAULT_PANTS_WORKDIR. We take the first specified value we
      # find, in this order: PANTS_DEFAULT_FOO, PANTS_FOO, FOO.
      env_vars = ['PANTS_DEFAULT_{0}'.format(udest), 'PANTS_{0}'.format(udest)]
      if udest.startswith('PANTS_'):
        env_vars.append(udest)
    else:
      sanitized_env_var_scope = self._ENV_SANITIZER_RE.sub('_', config_section.upper())
      env_vars = ['PANTS_{0}_{1}'.format(sanitized_env_var_scope, udest)]

    value_type = self.str_to_bool if is_boolean_flag(kwargs) else kwargs.get('type', str)

    env_val_str = None
    if self._env:
      for env_var in env_vars:
        if env_var in self._env:
          env_val_str = self._env.get(env_var)
          break

    config_val_str = self._config.get(config_section, dest, default=None)
    config_source_file = self._config.get_source_for_option(config_section, dest)
    if config_source_file is not None:
      config_source_file = os.path.relpath(config_source_file)

    def expand(val_str):
      if is_fromfile and val_str and val_str.startswith('@') and not val_str.startswith('@@'):
        fromfile = val_str[1:]
        try:
          with open(fromfile) as fp:
            return fp.read().strip()
        except IOError as e:
          raise self.FromfileError('Failed to read {} in {} from file {}: {}'.format(
            dest, self._scope_str(), fromfile, e))
      else:
        # Support a literal @ for fromfile values via @@.
        return val_str[1:] if is_fromfile and val_str.startswith('@@') else val_str

    def parse_typed_list(val_str):
      return None if val_str is None else [value_type(x) for x in list_option(expand(val_str))]

    def parse_typed_item(val_str):
      return None if val_str is None else value_type(expand(val_str))

    flag_val = None
    if flag_vals:
      if action == 'append':
        flag_val = [parse_typed_item(v) for v in flag_vals]
      elif len(flag_vals) > 1:
        raise ParseError('Multiple cmd line flags specified for option {} in {}'.format(
          dest, self._scope_str()))
      else:
        flag_val = parse_typed_item(flag_vals[0])

    default, parse = ([], parse_typed_list) if action == 'append' else (None, parse_typed_item)

    config_val = parse(config_val_str)
    env_val = parse(env_val_str)
    hardcoded_val = kwargs.get('default')

    config_details = 'in {}'.format(config_source_file) if config_source_file else None

    # Note: ranked_vals is guaranteed to have at least one element, and none of the values
    # of any of its elements will be None.
    ranked_vals = list(reversed(list(RankedValue.prioritized_iter(
      flag_val, env_val, config_val, hardcoded_val, default))))
    choices = kwargs.get('choices')
    for ranked_val in ranked_vals:
      details = config_details if ranked_val.rank == RankedValue.CONFIG else None
      self._option_tracker.record_option(scope=self._scope,
                                         option=dest,
                                         value=ranked_val.value,
                                         rank=ranked_val.rank,
                                         deprecation_version=kwargs.get('deprecated_version'),
                                         details=details)

    def check(val):
      if choices is not None and val is not None and val not in choices:
        raise ParseError('{} is not an allowed value for option {} in {}. '
                         'Must be one of: {}'.format(
          val, dest, self._scope_str(), choices
        ))
      return val

    if action == 'append':
      merged_rank = ranked_vals[-1].rank
      merged_val = [check(val) for vals in ranked_vals for val in vals.value]
      return RankedValue(merged_rank, merged_val)
    else:
      map(lambda rv: check(rv.value), ranked_vals)
      return ranked_vals[-1]
示例#13
0
文件: parser.py 项目: cheister/pants
  def parse_args(self, flags, namespace):
    """Set values for this parser's options on the namespace object."""
    flag_value_map = self._create_flag_value_map(flags)

    for args, kwargs in self._unnormalized_option_registrations_iter():
      self._validate(args, kwargs)
      dest = kwargs.get('dest') or self._select_dest(args)
      is_bool = is_boolean_flag(kwargs)

      def consume_flag(flag):
        self._check_deprecated(dest, kwargs)
        del flag_value_map[flag]

      # Compute the values provided on the command line for this option.  Note tha there may be
      # multiple values, for any combination of the following reasons:
      #   - The user used the same flag multiple times.
      #   - The user specified a boolean flag (--foo) and its inverse (--no-foo).
      #   - The option has multiple names, and the user used more than one of them.
      #
      # We also check if the option is deprecated, but we only do so if the option is explicitly
      # specified as a command-line flag, so we don't spam users with deprecated option values
      # specified in config, which isn't something they control.
      implicit_value = kwargs.get('implicit_value')
      flag_vals = []

      def add_flag_val(v):
        if v is None:
          if implicit_value is None:
            raise ParseError('Missing value for command line flag {} in {}'.format(
              arg, self._scope_str()))
          else:
            flag_vals.append(implicit_value)
        else:
          flag_vals.append(v)

      for arg in args:
        if is_bool:
          if arg in flag_value_map:
            flag_vals.append('true' if kwargs['action'] == 'store_true' else 'false')
            consume_flag(arg)
          elif self._inverse_arg(arg) in flag_value_map:
            flag_vals.append('false' if kwargs['action'] == 'store_true' else 'true')
            consume_flag(self._inverse_arg(arg))
        else:
          if arg in flag_value_map:
            for v in flag_value_map[arg]:
              add_flag_val(v)
            consume_flag(arg)

      # Get the value for this option, falling back to defaults as needed.
      try:
        val = self._compute_value(dest, kwargs, flag_vals)
      except ParseError as e:
        # Reraise a new exception with context on the option being processed at the time of error.
        # Note that other exception types can be raised here that are caught by ParseError (e.g.
        # BooleanConversionError), hence we reference the original exception type by e.__class__.
        raise type(e)(
          'Error computing value for {} in {} (may also be from PANTS_* environment variables):\n'
          '{}'.format(', '.join(args), self._scope_str(), e)
        )

      setattr(namespace, dest, val)

    # See if there are any unconsumed flags remaining.
    if flag_value_map:
      raise ParseError('Unrecognized command line flags on {}: {}'.format(
        self._scope_str(), ', '.join(flag_value_map.keys())))

    return namespace
示例#14
0
文件: parser.py 项目: megaserg/pants
  def _compute_default(self, kwargs):
    """Compute the default value to use for an option's registration.

    The source of the default value is chosen according to the ranking in RankedValue.

    Note: Only call if kwargs has a 'dest' key set.
    """
    dest = kwargs['dest']
    is_fromfile = kwargs.get('fromfile', False)
    action = kwargs.get('action')
    if is_fromfile and action and action != 'append':
      raise ParseError('Cannot fromfile {} with an action ({}) in scope {}'
                       .format(dest, action, self._scope))

    config_section = 'DEFAULT' if self._scope == GLOBAL_SCOPE else self._scope
    udest = dest.upper()
    if self._scope == GLOBAL_SCOPE:
      # For convenience, we allow three forms of env var for global scope options.
      # The fully-specified env var is PANTS_DEFAULT_FOO, which is uniform with PANTS_<SCOPE>_FOO
      # for all the other scopes.  However we also allow simply PANTS_FOO. And if the option name
      # itself starts with 'pants-' then we also allow simply FOO. E.g., PANTS_WORKDIR instead of
      # PANTS_PANTS_WORKDIR or PANTS_DEFAULT_PANTS_WORKDIR. We take the first specified value we
      # find, in this order: PANTS_DEFAULT_FOO, PANTS_FOO, FOO.
      env_vars = ['PANTS_DEFAULT_{0}'.format(udest), 'PANTS_{0}'.format(udest)]
      if udest.startswith('PANTS_'):
        env_vars.append(udest)
    else:
      sanitized_env_var_scope = self._ENV_SANITIZER_RE.sub('_', config_section.upper())
      env_vars = ['PANTS_{0}_{1}'.format(sanitized_env_var_scope, udest)]

    value_type = self.str_to_bool if is_boolean_flag(kwargs) else kwargs.get('type', str)

    env_val_str = None
    if self._env:
      for env_var in env_vars:
        if env_var in self._env:
          env_val_str = self._env.get(env_var)
          break

    config_val_str = self._config.get(config_section, dest, default=None)
    config_source_file = self._config.get_source_for_option(config_section, dest)
    if config_source_file is not None:
      config_source_file = os.path.relpath(config_source_file)

    def expand(val_str):
      if is_fromfile and val_str and val_str.startswith('@') and not val_str.startswith('@@'):
        fromfile = val_str[1:]
        try:
          with open(fromfile) as fp:
            return fp.read().strip()
        except IOError as e:
          raise self.FromfileError('Failed to read {} from file {}: {}'.format(dest, fromfile, e))
      else:
        # Support a literal @ for fromfile values via @@.
        return val_str[1:] if is_fromfile and val_str.startswith('@@') else val_str

    def parse_typed_list(val_str):
      return None if val_str is None else [value_type(x) for x in list_option(expand(val_str))]

    def parse_typed_item(val_str):
      return None if val_str is None else value_type(expand(val_str))

    # Handle the forthcoming conversions argparse will need to do by placing our parse hook - we
    # handle the conversions for env and config ourselves below.  Unlike the env and config
    # handling, `action='append'` does not need to be handled specially since appended flag values
    # come as single items' thus only `parse_typed_item` is ever needed for the flag value type
    # conversions.
    if is_fromfile:
      kwargs['type'] = parse_typed_item

    default, parse = ([], parse_typed_list) if action == 'append' else (None, parse_typed_item)
    config_val = parse(config_val_str)
    env_val = parse(env_val_str)
    hardcoded_val = kwargs.get('default')

    config_details = 'in {}'.format(config_source_file) if config_source_file else None

    choices = list(RankedValue.prioritized_iter(None, env_val, config_val, hardcoded_val, default))
    for choice in reversed(choices):
      details = config_details if choice.rank == RankedValue.CONFIG else None
      self._option_tracker.record_option(scope=self._scope, option=dest, value=choice.value,
                                         rank=choice.rank, details=details)

    return choices[0]
示例#15
0
    def _compute_default(self, dest, kwargs):
        """Compute the default value to use for an option's registration.

    The source of the default value is chosen according to the ranking in RankedValue.
    """
        is_fromfile = kwargs.get('fromfile', False)
        action = kwargs.get('action')
        if is_fromfile and action and action != 'append':
            raise ParseError(
                'Cannot fromfile {} with an action ({}) in scope {}'.format(
                    dest, action, self._scope))

        config_section = 'DEFAULT' if self._scope == GLOBAL_SCOPE else self._scope
        udest = dest.upper()
        if self._scope == GLOBAL_SCOPE:
            # For convenience, we allow three forms of env var for global scope options.
            # The fully-specified env var is PANTS_DEFAULT_FOO, which is uniform with PANTS_<SCOPE>_FOO
            # for all the other scopes.  However we also allow simply PANTS_FOO. And if the option name
            # itself starts with 'pants-' then we also allow simply FOO. E.g., PANTS_WORKDIR instead of
            # PANTS_PANTS_WORKDIR or PANTS_DEFAULT_PANTS_WORKDIR. We take the first specified value we
            # find, in this order: PANTS_DEFAULT_FOO, PANTS_FOO, FOO.
            env_vars = [
                'PANTS_DEFAULT_{0}'.format(udest), 'PANTS_{0}'.format(udest)
            ]
            if udest.startswith('PANTS_'):
                env_vars.append(udest)
        else:
            sanitized_env_var_scope = self._ENV_SANITIZER_RE.sub(
                '_', config_section.upper())
            env_vars = ['PANTS_{0}_{1}'.format(sanitized_env_var_scope, udest)]

        value_type = self.str_to_bool if is_boolean_flag(
            kwargs) else kwargs.get('type', str)

        env_val_str = None
        if self._env:
            for env_var in env_vars:
                if env_var in self._env:
                    env_val_str = self._env.get(env_var)
                    break

        config_val_str = self._config.get(config_section, dest, default=None)

        def expand(val_str):
            if is_fromfile and val_str and val_str.startswith(
                    '@') and not val_str.startswith('@@'):
                fromfile = val_str[1:]
                try:
                    with open(fromfile) as fp:
                        return fp.read().strip()
                except IOError as e:
                    raise self.FromfileError(
                        'Failed to read {} from file {}: {}'.format(
                            dest, fromfile, e))
            else:
                # Support a literal @ for fromfile values via @@.
                return val_str[1:] if is_fromfile and val_str.startswith(
                    '@@') else val_str

        def parse_typed_list(val_str):
            return None if val_str is None else [
                value_type(x) for x in list_option(expand(val_str))
            ]

        def parse_typed_item(val_str):
            return None if val_str is None else value_type(expand(val_str))

        # Handle the forthcoming conversions argparse will need to do by placing our parse hook - we
        # handle the conversions for env and config ourselves below.  Unlike the env and config
        # handling, `action='append'` does not need to be handled specially since appended flag values
        # come as single items' thus only `parse_typed_item` is ever needed for the flag value type
        # conversions.
        if is_fromfile:
            kwargs['type'] = parse_typed_item

        default, parse = ([], parse_typed_list) if action == 'append' else (
            None, parse_typed_item)
        config_val = parse(config_val_str)
        env_val = parse(env_val_str)
        hardcoded_val = kwargs.get('default')
        return RankedValue.choose(None, env_val, config_val, hardcoded_val,
                                  default)
示例#16
0
文件: parser.py 项目: scode/pants
  def _compute_default(self, dest, kwargs):
    """Compute the default value to use for an option's registration.

    The source of the default value is chosen according to the ranking in RankedValue.
    """
    is_fromfile = kwargs.get('fromfile', False)
    action = kwargs.get('action')
    if is_fromfile and action:
      raise ParseError('Cannot fromfile {} with an action ({}) in scope {}'
                       .format(dest, action, self._scope))

    config_section = 'DEFAULT' if self._scope == GLOBAL_SCOPE else self._scope
    udest = dest.upper()
    if self._scope == GLOBAL_SCOPE:
      # For convenience, we allow three forms of env var for global scope options.
      # The fully-specified env var is PANTS_DEFAULT_FOO, which is uniform with PANTS_<SCOPE>_FOO
      # for all the other scopes.  However we also allow simply PANTS_FOO. And if the option name
      # itself starts with 'pants-' then we also allow simply FOO. E.g., PANTS_WORKDIR instead of
      # PANTS_PANTS_WORKDIR or PANTS_DEFAULT_PANTS_WORKDIR. We take the first specified value we
      # find, in this order: PANTS_DEFAULT_FOO, PANTS_FOO, FOO.
      env_vars = ['PANTS_DEFAULT_{0}'.format(udest), 'PANTS_{0}'.format(udest)]
      if udest.startswith('PANTS_'):
        env_vars.append(udest)
    else:
      sanitized_env_var_scope = self._ENV_SANITIZER_RE.sub('_', config_section.upper())
      env_vars = ['PANTS_{0}_{1}'.format(sanitized_env_var_scope, udest)]

    value_type = self.str_to_bool if is_boolean_flag(kwargs) else kwargs.get('type', str)

    env_val_str = None
    if self._env:
      for env_var in env_vars:
        if env_var in self._env:
          env_val_str = self._env.get(env_var)
          break

    def expand(val_str):
      if is_fromfile and val_str and val_str.startswith('@') and not val_str.startswith('@@'):
        fromfile = val_str[1:]
        try:
          with open(fromfile) as fp:
            return fp.read().strip()
        except IOError as e:
          raise self.FromfileError('Failed to read {} from file {}: {}'.format(dest, fromfile, e))
      else:
        # Support a literal @ for fromfile values via @@.
        return val_str[1:] if is_fromfile and val_str.startswith('@@') else val_str

    if is_fromfile:
      kwargs['type'] = lambda flag_val_str: value_type(expand(flag_val_str))  # Expand flag values.

    env_val = None if env_val_str is None else value_type(expand(env_val_str))  # Expand env values.

    config_val = None
    if action == 'append':
      config_val_strs = self._config.getlist(config_section, dest) if self._config else None
      if config_val_strs is not None:
        config_val = [value_type(config_val_str) for config_val_str in config_val_strs]
      default = []
    else:
      config_val_str = (self._config.get(config_section, dest, default=None)
                        if self._config else None)
      if config_val_str is not None:
        config_val = value_type(expand(config_val_str))  # Expand config values.
      default = None

    hardcoded_val = kwargs.get('default')  # We don't expand hard coded defaults.
    return RankedValue.choose(None, env_val, config_val, hardcoded_val, default)