Esempio n. 1
0
 def assert_option_resolved(
     *, old_configured: bool = False, new_configured: bool = False, expected: str,
 ) -> None:
     old_container, new_container = OptionValueContainer(), OptionValueContainer()
     old_container.my_opt = old_configured_rv if old_configured else old_default_rv
     new_container.my_opt = new_configured_rv if new_configured else new_default_rv
     assert (
         resolve_options(old_container=old_container, new_container=new_container)
         == expected
     )
Esempio n. 2
0
 def test_iterator(self):
     o = OptionValueContainer()
     o.a = RankedValue(RankedValue.FLAG, 3)
     o.b = RankedValue(RankedValue.FLAG, 2)
     o.c = RankedValue(RankedValue.FLAG, 1)
     names = list(iter(o))
     self.assertListEqual(['a', 'b', 'c'], names)
Esempio n. 3
0
  def for_scope(self, scope, inherit_from_enclosing_scope=True):
    """Return the option values for the given scope.

    Values are attributes of the returned object, e.g., options.foo.
    Computed lazily per scope.

    :API: public
    """

    # First get enclosing scope's option values, if any.
    if scope == GLOBAL_SCOPE or not inherit_from_enclosing_scope:
      values = OptionValueContainer()
    else:
      values = copy.copy(self.for_scope(enclosing_scope(scope)))

    # Now add our values.
    flags_in_scope = self._scope_to_flags.get(scope, [])
    parse_args_request = self._make_parse_args_request(flags_in_scope, values)
    self._parser_hierarchy.get_parser_by_scope(scope).parse_args(parse_args_request)

    # Check for any deprecation conditions, which are evaluated using `self._flag_matchers`.
    if inherit_from_enclosing_scope:
      self._check_and_apply_deprecations(scope, values)

    return values
Esempio n. 4
0
    def for_scope(self, scope):
        """Return the option values for the given scope.

    Values are attributes of the returned object, e.g., options.foo.
    Computed lazily per scope.
    """
        # Short-circuit, if already computed.
        if scope in self._values_by_scope:
            return self._values_by_scope[scope]

        # First get enclosing scope's option values, if any.
        if scope == GLOBAL_SCOPE:
            values = OptionValueContainer()
            if self._legacy_values:
                values.update(vars(
                    self._legacy_values))  # Proxy any legacy option values.
        else:
            values = copy.copy(self.for_scope(scope.rpartition('.')[0]))

        # Now add our values.
        try:
            flags_in_scope = self._scope_to_flags.get(scope, [])
            self._parser_hierarchy.get_parser_by_scope(scope).parse_args(
                flags_in_scope, values)
            self._values_by_scope[scope] = values
            return values
        except ParseError as e:
            self.print_help(str(e))
            sys.exit(1)
Esempio n. 5
0
 def test_iterator(self) -> None:
     o = OptionValueContainer()
     o.a = RankedValue(RankedValue.FLAG, 3)
     o.b = RankedValue(RankedValue.FLAG, 2)
     o.c = RankedValue(RankedValue.FLAG, 1)
     names = list(iter(o))
     self.assertListEqual(["a", "b", "c"], names)
Esempio n. 6
0
    def for_scope(self, scope):
        """Return the option values for the given scope.

    Values are attributes of the returned object, e.g., options.foo.
    Computed lazily per scope.

    :API: public
    """
        # Short-circuit, if already computed.
        if scope in self._values_by_scope:
            return self._values_by_scope[scope]

        # First get enclosing scope's option values, if any.
        if scope == GLOBAL_SCOPE:
            values = OptionValueContainer()
        else:
            values = copy.copy(self.for_scope(enclosing_scope(scope)))

        # Now add our values.
        flags_in_scope = self._scope_to_flags.get(scope, [])
        self._parser_hierarchy.get_parser_by_scope(scope).parse_args(
            flags_in_scope, values)
        self._values_by_scope[scope] = values
        for option in values:
            self._option_tracker.record_option(scope=scope,
                                               option=option,
                                               value=values[option],
                                               rank=values.get_rank(option))
        return values
Esempio n. 7
0
    def for_scope(self, scope, inherit_from_enclosing_scope=True):
        """Return the option values for the given scope.

    Values are attributes of the returned object, e.g., options.foo.
    Computed lazily per scope.

    :API: public
    """
        # Short-circuit, if already computed.
        if scope in self._values_by_scope:
            return self._values_by_scope[scope]

        # First get enclosing scope's option values, if any.
        if scope == GLOBAL_SCOPE or not inherit_from_enclosing_scope:
            values = OptionValueContainer()
        else:
            values = copy.copy(self.for_scope(enclosing_scope(scope)))

        # Now add our values.
        flags_in_scope = self._scope_to_flags.get(scope, [])
        self._parser_hierarchy.get_parser_by_scope(scope).parse_args(
            flags_in_scope, values)

        # Check for any deprecation conditions, which are evaluated using `self._flag_matchers`.
        self._check_deprecations(scope, flags_in_scope, values)

        # Cache the values.
        self._values_by_scope[scope] = values

        return values
 def test_iterator(self):
     o = OptionValueContainer()
     o.a = 3
     o.b = 2
     o.c = 1
     names = list(iter(o))
     self.assertListEqual(['a', 'b', 'c'], names)
Esempio n. 9
0
    def test_unknown_values(self) -> None:
        o = OptionValueContainer()
        o.foo = RankedValue(RankedValue.HARDCODED, 1)
        self.assertEqual(1, o.foo)

        with self.assertRaises(AttributeError):
            o.bar
    def test_standard_values(self):
        o = OptionValueContainer()
        o.foo = 1
        self.assertEqual(1, o.foo)

        with self.assertRaises(AttributeError):
            o.bar
 def test_iterator(self):
     o = OptionValueContainer()
     o.add_forwardings({'a': '_a'})
     o.add_forwardings({'b': '_b'})
     o.add_forwardings({'b_prime': '_b'})  # Should be elided in favor of b.
     o.add_forwardings({'c': '_c'})
     names = list(iter(o))
     self.assertListEqual(['a', 'b', 'c'], names)
Esempio n. 12
0
    def for_scope(self, scope, inherit_from_enclosing_scope=True):
        """Return the option values for the given scope.

    Values are attributes of the returned object, e.g., options.foo.
    Computed lazily per scope.

    :API: public
    """
        # Short-circuit, if already computed.
        if scope in self._values_by_scope:
            return self._values_by_scope[scope]

        # First get enclosing scope's option values, if any.
        if scope == GLOBAL_SCOPE or not inherit_from_enclosing_scope:
            values = OptionValueContainer()
        else:
            values = copy.copy(self.for_scope(enclosing_scope(scope)))

        # Now add our values.
        flags_in_scope = self._scope_to_flags.get(scope, [])
        self._parser_hierarchy.get_parser_by_scope(scope).parse_args(
            flags_in_scope, values)

        # If we're the new name of a deprecated scope, also get values from that scope.
        deprecated_scope = self.known_scope_to_info[scope].deprecated_scope
        # Note that deprecated_scope and scope share the same Optionable class, so deprecated_scope's
        # Optionable has a deprecated_options_scope equal to deprecated_scope. Therefore we must
        # check that scope != deprecated_scope to prevent infinite recursion.
        if deprecated_scope is not None and scope != deprecated_scope:
            # Do the deprecation check only on keys that were explicitly set on the deprecated scope
            # (and not on its enclosing scopes).
            explicit_keys = self.for_scope(
                deprecated_scope,
                inherit_from_enclosing_scope=False).get_explicit_keys()
            if explicit_keys:
                warn_or_error(
                    self.known_scope_to_info[scope].
                    deprecated_scope_removal_version,
                    'scope {}'.format(deprecated_scope),
                    'Use scope {} instead (options: {})'.format(
                        scope, ', '.join(explicit_keys)))
                # Update our values with those of the deprecated scope (now including values inherited
                # from its enclosing scope).
                # Note that a deprecated val will take precedence over a val of equal rank.
                # This makes the code a bit neater.
                values.update(self.for_scope(deprecated_scope))

        # Record the value derivation.
        for option in values:
            self._option_tracker.record_option(scope=scope,
                                               option=option,
                                               value=values[option],
                                               rank=values.get_rank(option))

        # Cache the values.
        self._values_by_scope[scope] = values

        return values
Esempio n. 13
0
def _create_scoped_options(
        default_rank: Rank, **options: Union[RankedValue,
                                             Value]) -> OptionValueContainer:
    scoped_options = OptionValueContainer()
    for key, value in options.items():
        if not isinstance(value, RankedValue):
            value = RankedValue(default_rank, value)
        setattr(scoped_options, key, value)
    return scoped_options
Esempio n. 14
0
  def test_indexing(self):
    o = OptionValueContainer()
    o.add_forwardings({'foo': 'bar'})
    o.bar = 1
    self.assertEqual(1, o['foo'])
    self.assertEqual(1, o['bar'])

    with self.assertRaises(AttributeError):
      o['baz']
Esempio n. 15
0
    def test_resolve_conflicting_options(self) -> None:
        resolve_options = partial(
            resolve_conflicting_options,
            old_option="my_opt",
            new_option="my_opt",
            old_scope="old-scope",
            new_scope="new-scope",
        )
        old_val = "ancient"
        new_val = "modern"
        old_default_rv = RankedValue(RankedValue.HARDCODED, old_val)
        new_default_rv = RankedValue(RankedValue.HARDCODED, new_val)
        old_configured_rv = RankedValue(RankedValue.FLAG, old_val)
        new_configured_rv = RankedValue(RankedValue.FLAG, new_val)

        def assert_option_resolved(
            *,
            old_configured: bool = False,
            new_configured: bool = False,
            expected: str,
        ) -> None:
            old_container, new_container = OptionValueContainer(
            ), OptionValueContainer()
            old_container.my_opt = old_configured_rv if old_configured else old_default_rv
            new_container.my_opt = new_configured_rv if new_configured else new_default_rv
            assert resolve_options(old_container=old_container,
                                   new_container=new_container) == expected

        assert_option_resolved(expected=new_val)
        assert_option_resolved(old_configured=True, expected=old_val)
        assert_option_resolved(new_configured=True, expected=new_val)

        # both configured -> raise an error
        old_container, new_container = OptionValueContainer(
        ), OptionValueContainer()
        old_container.my_opt = old_configured_rv
        new_container.my_opt = new_configured_rv
        with pytest.raises(ValueError) as e:
            resolve_options(old_container=old_container,
                            new_container=new_container)
        assert "--old-scope-my-opt" in str(e.value)
        assert "--new-scope-my-opt" in str(e.value)
Esempio n. 16
0
 def test_value_ranking(self):
     o = OptionValueContainer()
     o.add_forwardings({'foo': 'bar'})
     o.bar = RankedValue(RankedValue.CONFIG, 11)
     self.assertEqual(11, o.foo)
     o.bar = RankedValue(RankedValue.HARDCODED, 22)
     self.assertEqual(11, o.foo)
     o.bar = RankedValue(RankedValue.ENVIRONMENT, 33)
     self.assertEqual(33, o.foo)
     o.bar = 44  # No explicit rank is assumed to be a FLAG.
     self.assertEqual(44, o.foo)
 def test_deepcopy(self):
     # deepcopy semantics can get hairy when overriding __setattr__/__getattr__, so we test them.
     o = OptionValueContainer()
     o.add_forwardings({'foo': 'bar'})
     o.add_forwardings({'baz': 'qux'})
     o.bar = 1
     o.qux = {'a': 111}
     p = copy.deepcopy(o)
     o.baz['b'] = 222  # Add to original dict.
     self.assertEqual(1, p.foo)
     self.assertEqual({'a': 111}, p.baz)  # Ensure dict was copied.
Esempio n. 18
0
    def test_indexing(self) -> None:
        o = OptionValueContainer()
        o.foo = RankedValue(RankedValue.CONFIG, 1)
        self.assertEqual(1, o["foo"])

        self.assertEqual(1, o.get("foo"))
        self.assertEqual(1, o.get("foo", 2))
        self.assertIsNone(o.get("unknown"))
        self.assertEqual(2, o.get("unknown", 2))

        with self.assertRaises(AttributeError):
            o["bar"]
    def test_indexing(self):
        o = OptionValueContainer()
        o.foo = 1
        self.assertEqual(1, o['foo'])

        self.assertEqual(1, o.get('foo'))
        self.assertEqual(1, o.get('foo', 2))
        self.assertIsNone(o.get('unknown'))
        self.assertEqual(2, o.get('unknown', 2))

        with self.assertRaises(AttributeError):
            o['bar']
Esempio n. 20
0
    def test_is_flagged(self) -> None:
        o = OptionValueContainer()

        o.foo = RankedValue(RankedValue.NONE, 11)
        self.assertFalse(o.is_flagged("foo"))

        o.foo = RankedValue(RankedValue.CONFIG, 11)
        self.assertFalse(o.is_flagged("foo"))

        o.foo = RankedValue(RankedValue.ENVIRONMENT, 11)
        self.assertFalse(o.is_flagged("foo"))

        o.foo = RankedValue(RankedValue.FLAG, 11)
        self.assertTrue(o.is_flagged("foo"))
Esempio n. 21
0
 def test_value_ranking(self) -> None:
     o = OptionValueContainer()
     o.foo = RankedValue(RankedValue.CONFIG, 11)
     self.assertEqual(11, o.foo)
     self.assertEqual(RankedValue.CONFIG, o.get_rank("foo"))
     o.foo = RankedValue(RankedValue.HARDCODED, 22)
     self.assertEqual(11, o.foo)
     self.assertEqual(RankedValue.CONFIG, o.get_rank("foo"))
     o.foo = RankedValue(RankedValue.ENVIRONMENT, 33)
     self.assertEqual(33, o.foo)
     self.assertEqual(RankedValue.ENVIRONMENT, o.get_rank("foo"))
     o.foo = RankedValue(RankedValue.FLAG, 44)
     self.assertEqual(44, o.foo)
     self.assertEqual(RankedValue.FLAG, o.get_rank("foo"))
 def test_value_ranking(self):
     o = OptionValueContainer()
     o.foo = RankedValue(RankedValue.CONFIG, 11)
     self.assertEqual(11, o.foo)
     self.assertEqual(RankedValue.CONFIG, o.get_rank('foo'))
     o.foo = RankedValue(RankedValue.HARDCODED, 22)
     self.assertEqual(11, o.foo)
     self.assertEqual(RankedValue.CONFIG, o.get_rank('foo'))
     o.foo = RankedValue(RankedValue.ENVIRONMENT, 33)
     self.assertEqual(33, o.foo)
     self.assertEqual(RankedValue.ENVIRONMENT, o.get_rank('foo'))
     o.foo = 44  # No explicit rank is assumed to be a FLAG.
     self.assertEqual(44, o.foo)
     self.assertEqual(RankedValue.FLAG, o.get_rank('foo'))
    def test_is_flagged(self):
        o = OptionValueContainer()
        o.add_forwardings({'foo': 'bar'})

        o.bar = RankedValue(RankedValue.NONE, 11)
        self.assertFalse(o.is_flagged('foo'))

        o.bar = RankedValue(RankedValue.CONFIG, 11)
        self.assertFalse(o.is_flagged('foo'))

        o.bar = RankedValue(RankedValue.ENVIRONMENT, 11)
        self.assertFalse(o.is_flagged('foo'))

        o.bar = RankedValue(RankedValue.FLAG, 11)
        self.assertTrue(o.is_flagged('foo'))
    def test_forwarding(self):
        o = OptionValueContainer()
        o.add_forwardings({'foo': 'bar'})
        o.bar = 1
        self.assertEqual(1, o.foo)
        o.bar = 2
        self.assertEqual(2, o.foo)

        o.add_forwardings({'baz': 'qux'})
        o.qux = 3
        self.assertEqual(2, o.foo)
        self.assertEqual(3, o.baz)

        # Direct setting overrides forwarding.
        o.foo = 4
        self.assertEqual(4, o.foo)
Esempio n. 25
0
 def _format_for_global_scope(show_advanced, show_deprecated, args, kwargs):
     parser = Parser(
         env={},
         config=Config.load([]),
         scope_info=GlobalOptions.get_scope_info(),
         parent_parser=None,
     )
     parser.register(*args, **kwargs)
     # Force a parse to generate the derivation history.
     parser.parse_args(
         Parser.ParseArgsRequest((), OptionValueContainer(), lambda: [], 0,
                                 []))
     oshi = HelpInfoExtracter("").get_option_scope_help_info(
         "", parser, False)
     return HelpFormatter(show_advanced=show_advanced,
                          show_deprecated=show_deprecated,
                          color=False).format_options(oshi)
    def test_deepcopy(self):
        # copy semantics can get hairy when overriding __setattr__/__getattr__, so we test them.
        o = OptionValueContainer()
        o.foo = 1
        o.bar = {'a': 111}

        p = copy.deepcopy(o)

        # Verify that the result is in fact a copy.
        self.assertEqual(1, p.foo)  # Has original attribute.
        o.baz = 42
        self.assertFalse(hasattr(
            p, 'baz'))  # Does not have attribute added after the copy.

        # Verify that it's a deep copy by modifying a referent in o and reading it in p.
        o.bar['b'] = 222
        self.assertEqual({'a': 111}, p.bar)
Esempio n. 27
0
    def test_deepcopy(self) -> None:
        # copy semantics can get hairy when overriding __setattr__/__getattr__, so we test them.
        o = OptionValueContainer()
        o.foo = RankedValue(RankedValue.FLAG, 1)
        o.bar = RankedValue(RankedValue.FLAG, {"a": 111})

        p = copy.deepcopy(o)

        # Verify that the result is in fact a copy.
        self.assertEqual(1, p.foo)  # Has original attribute.
        o.baz = RankedValue(RankedValue.FLAG, 42)
        self.assertFalse(hasattr(p, "baz"))  # Does not have attribute added after the copy.

        # Verify that it's a deep copy by modifying a referent in o and reading it in p.
        # TODO: add type hints to ranked_value.py and option_value_container.py so that this works.
        o.bar["b"] = 222  # type: ignore[index]
        self.assertEqual({"a": 111}, p.bar)
Esempio n. 28
0
  def for_scope(self, scope):
    """Return the option values for the given scope.

    Values are attributes of the returned object, e.g., options.foo.
    Computed lazily per scope.
    """
    # Short-circuit, if already computed.
    if scope in self._values_by_scope:
      return self._values_by_scope[scope]

    # First get enclosing scope's option values, if any.
    if scope == GLOBAL_SCOPE:
      values = OptionValueContainer()
    else:
      values = copy.deepcopy(self.for_scope(scope.rpartition('.')[0]))

    # Now add our values.
    flags_in_scope = self._scope_to_flags.get(scope, [])
    self._parser_hierarchy.get_parser_by_scope(scope).parse_args(flags_in_scope, values)
    self._values_by_scope[scope] = values
    return values
Esempio n. 29
0
def test_scope_existence() -> None:
    class NoScope(Subsystem):
        pass

    with pytest.raises(OptionsError) as excinfo:
        NoScope.get_scope_info()
    assert "NoScope must set options_scope" in str(excinfo.value)

    with pytest.raises(OptionsError) as excinfo:
        NoScope(OptionValueContainer({}))
    assert "NoScope must set options_scope" in str(excinfo.value)

    class StringScope(Subsystem):
        options_scope = "good"

    assert "good" == StringScope.options_scope

    class Intermediate(Subsystem):
        pass

    class Indirect(Intermediate):
        options_scope = "good"

    assert "good" == Indirect.options_scope