Пример #1
0
    def test_failure_type(self) -> None:
        # Prove there is no syntax error in the raw value.
        literal = parse_expression("1.0", acceptable_types=float)
        assert 1.0 == literal

        # Now we can safely assume the ValueError is raise due to type checking.
        with pytest.raises(ValueError):
            parse_expression("1.0", acceptable_types=int)
Пример #2
0
  def test_failure_type(self):
    # Prove there is no syntax error in the raw value.
    literal = parse_expression('1.0', acceptable_types=float)
    self.assertEqual(1.0, literal)

    # Now we can safely assume the ValueError is raise due to type checking.
    with self.assertRaises(ValueError):
      parse_expression('1.0', acceptable_types=int)
Пример #3
0
    def test_failure_type(self):
        # Prove there is no syntax error in the raw value.
        literal = parse_expression('1.0', acceptable_types=float)
        self.assertEqual(1.0, literal)

        # Now we can safely assume the ValueError is raise due to type checking.
        with self.assertRaises(ValueError):
            parse_expression('1.0', acceptable_types=int)
Пример #4
0
    def test_custom_error_type(self):
        class CustomError(Exception):
            pass

        with self.assertRaises(CustomError):
            parse_expression('1.0',
                             acceptable_types=int,
                             raise_type=CustomError)
Пример #5
0
def _convert(val, acceptable_types):
  """Ensure that val is one of the acceptable types, converting it if needed.

  :param string val: The value we're parsing.
  :param acceptable_types: A tuple of expected types for val.
  :returns: The parsed value.
  :raises :class:`pants.options.errors.ParseError`: if there was a problem parsing the val as an
                                                    acceptable type.
  """
  return parse_expression(val, acceptable_types, raise_type=ParseError)
Пример #6
0
  def _getinstance(self, section, option, type_, default=None):
    if not self.has_option(section, option):
      return default

    raw_value = self.get_value(section, option)
    if type_ == str or issubclass(type_, str):
      return raw_value

    key = '{}.{}'.format(section, option)
    return parse_expression(name=key, val=raw_value, acceptable_types=type_,
                            raise_type=self.ConfigError)
Пример #7
0
  def _getinstance(self, section, option, type_, default=None):
    if not self.has_option(section, option):
      return default

    raw_value = self.get_value(section, option)
    # We jump through some hoops here to deal with the fact that `six.string_types` is a tuple of
    # types.
    if (type_ == six.string_types or
        (isinstance(type_, type) and issubclass(type_, six.string_types))):
      return raw_value

    key = '{}.{}'.format(section, option)
    return parse_expression(name=key, val=raw_value, acceptable_types=type_,
                            raise_type=self.ConfigError)
Пример #8
0
  def _getinstance(self, section, option, type_, default=None):
    if not self.has_option(section, option):
      return default

    raw_value = self.get_value(section, option)
    # We jump through some hoops here to deal with the fact that `six.string_types` is a tuple of
    # types.
    if (type_ == six.string_types or
        (isinstance(type_, type) and issubclass(type_, six.string_types))):
      return raw_value

    key = '{}.{}'.format(section, option)
    return parse_expression(name=key, val=raw_value, acceptable_types=type_,
                            raise_type=self.ConfigError)
Пример #9
0
def _convert(val, acceptable_types):
    """Ensure that val is one of the acceptable types, converting it if needed.

    :param val: The value we're parsing (either a string or one of the acceptable types).
    :param acceptable_types: A tuple of expected types for val.
    :returns: The parsed value.
    :raises :class:`pants.options.errors.ParseError`: if there was a problem parsing the val as an
                                                      acceptable type.
    """
    if isinstance(val, acceptable_types):
        return val
    try:
        return parse_expression(val, acceptable_types)
    except ValueError as e:
        raise ParseError(str(e)) from e
Пример #10
0
    def get(self, section, option, type_=str, default=None):
        """Retrieves option from the specified section (or 'DEFAULT') and attempts to parse it as
        type.

        If the specified section does not exist or is missing a definition for the option, the value
        is looked up in the DEFAULT section.  If there is still no definition found, the default
        value supplied is returned.
        """
        if not self.has_option(section, option):
            return default

        raw_value = self.get_value(section, option)
        if issubclass(type_, str):
            return raw_value

        key = f"{section}.{option}"
        return parse_expression(name=key,
                                val=raw_value,
                                acceptable_types=type_,
                                raise_type=self.ConfigError)
Пример #11
0
 def test_success_mixed(self) -> None:
     literal = parse_expression("42", acceptable_types=(float, int))
     assert 42 == literal
Пример #12
0
 def test_success_list_concat(self):
     # This is actually useful in config files.
     self.assertEqual([1, 2, 3],
                      parse_expression('[1, 2] + [3]',
                                       acceptable_types=list))
Пример #13
0
 def test_success_complex_syntax(self):
     self.assertEqual(3, parse_expression('1+2', acceptable_types=int))
Пример #14
0
 def test_success_complex_syntax(self) -> None:
     assert 3 == parse_expression("1+2", acceptable_types=int)
Пример #15
0
 def test_success_complex_syntax(self):
   self.assertEqual(3, parse_expression('1+2', acceptable_types=int))
Пример #16
0
 def test_success_simple(self):
   literal = parse_expression("'42'", acceptable_types=string_types)
   self.assertEqual('42', literal)
Пример #17
0
 def test_success_list_concat(self) -> None:
     # This is actually useful in config files.
     assert [1, 2, 3] == parse_expression("[1, 2] + [3]",
                                          acceptable_types=list)
Пример #18
0
 def test_success_simple(self) -> None:
     literal = parse_expression("'42'", acceptable_types=str)
     assert "42" == literal
Пример #19
0
 def test_success_complex_syntax(self) -> None:
     self.assertEqual(3, parse_expression("1+2", acceptable_types=int))
Пример #20
0
 def test_success_simple(self) -> None:
     literal = parse_expression("'42'", acceptable_types=str)
     self.assertEqual("42", literal)
Пример #21
0
 def test_success_mixed(self):
   literal = parse_expression('42', acceptable_types=(float, int))
   self.assertEqual(42, literal)
Пример #22
0
 def test_success_simple(self):
     literal = parse_expression("'42'",
                                acceptable_types=future.utils.string_types)
     self.assertEqual('42', literal)
Пример #23
0
 def test_success_list_concat(self):
   # This is actually useful in config files.
   self.assertEqual([1, 2, 3], parse_expression('[1, 2] + [3]', acceptable_types=list))
Пример #24
0
 def test_success_mixed(self):
     literal = parse_expression('42', acceptable_types=(float, int))
     self.assertEqual(42, literal)
Пример #25
0
  def test_custom_error_type(self):
    class CustomError(Exception):
      pass

    with self.assertRaises(CustomError):
      parse_expression('1.0', acceptable_types=int, raise_type=CustomError)
Пример #26
0
    def create(
        cls, env: Mapping[str, str], args: Sequence[str], *, allow_pantsrc: bool
    ) -> OptionsBootstrapper:
        """Parses the minimum amount of configuration necessary to create an OptionsBootstrapper.

        :param env: An environment dictionary.
        :param args: An args array.
        :param allow_pantsrc: True to allow pantsrc files to be used. Unless tests are expecting to
          consume pantsrc files, they should pass False in order to avoid reading files from
          absolute paths. Production usecases should pass True to allow options values to make the
          decision of whether to respect pantsrc files.
        """
        with warnings.catch_warnings(record=True):
            # We can't use pants.engine.fs.FileContent here because it would cause a circular dep.
            @dataclass(frozen=True)
            class FileContent:
                path: str
                content: bytes

            def filecontent_for(path: str) -> FileContent:
                return FileContent(
                    ensure_text(path),
                    read_file(path, binary_mode=True),
                )

            bargs = cls._get_bootstrap_args(args)

            config_file_paths = cls.get_config_file_paths(env=env, args=args)
            config_files_products = [filecontent_for(p) for p in config_file_paths]
            pre_bootstrap_config = Config.load(config_files_products, env=env)

            initial_bootstrap_options = cls.parse_bootstrap_options(
                env, bargs, pre_bootstrap_config
            )
            bootstrap_option_values = initial_bootstrap_options.for_global_scope()

            # Now re-read the config, post-bootstrapping. Note the order: First whatever we bootstrapped
            # from (typically pants.toml), then config override, then rcfiles.
            full_config_paths = pre_bootstrap_config.sources()
            if allow_pantsrc and bootstrap_option_values.pantsrc:
                rcfiles = [
                    os.path.expanduser(str(rcfile))
                    for rcfile in bootstrap_option_values.pantsrc_files
                ]
                existing_rcfiles = list(filter(os.path.exists, rcfiles))
                full_config_paths.extend(existing_rcfiles)

            full_config_files_products = [filecontent_for(p) for p in full_config_paths]
            post_bootstrap_config = Config.load(
                full_config_files_products,
                seed_values=bootstrap_option_values.as_dict(),
                env=env,
            )

            # Finally, we expand any aliases and re-populate the bootstrap args, in case there
            # were any from aliases.
            # stuhood: This could potentially break the rust client when aliases are used:
            # https://github.com/pantsbuild/pants/pull/13228#discussion_r728223889
            alias_vals = post_bootstrap_config.get("cli", "alias")
            alias_dict = parse_expression(
                name="cli.alias",
                val=alias_vals[-1] if alias_vals else "{}",
                acceptable_types=dict,
            )
            alias = CliAlias.from_dict(alias_dict)

            args = alias.expand_args(tuple(args))
            bargs = cls._get_bootstrap_args(args)

            # We need to set this env var to allow various static help strings to reference the
            # right name (via `pants.util.docutil`), and we need to do it as early as possible to
            # avoid needing to lazily import code to avoid chicken-and-egg-problems. This is the
            # earliest place it makes sense to do so and is generically used by both the local and
            # remote pants runners.
            os.environ["PANTS_BIN_NAME"] = bootstrap_option_values.pants_bin_name

            env_tuples = tuple(
                sorted(
                    (item for item in env.items() if item[0].startswith("PANTS_")),
                )
            )
            return cls(
                env_tuples=env_tuples,
                bootstrap_args=bargs,
                args=args,
                config=post_bootstrap_config,
                alias=alias,
            )