commit:     07602f09835ad21fed1603cd44923fe6e288c24a
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Tue Jan 17 07:22:56 2023 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Sun Feb  5 18:08:21 2023 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcore.git/commit/?id=07602f09

refactor(config): remove the notion of config layer incremental prepend/append.

Many moons gone past the original config system tried to support the idea
of incrementally stacked values (x y -x z -y == z).  This commit removes
the fundamental core of that functionality; the incremental logic is now 
implemented
in domain specific layers, rather than being a capability of the config layer.

Note: this just removes the logic.  The signature of [before, mid, after] return
is still in place, and will be removed as the API is normalized.  In particular,
pconfig still reports on .prepend/.apend, there just no longer is content there.

That behaviour (and signature) change will be a followon commit.

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcore/config/basics.py       | 95 ++++++++------------------------------
 src/pkgcore/ebuild/portage_conf.py |  6 +--
 tests/config/test_basics.py        | 81 --------------------------------
 tests/config/test_central.py       | 86 ----------------------------------
 tests/config/test_cparser.py       |  5 +-
 5 files changed, 24 insertions(+), 249 deletions(-)

diff --git a/src/pkgcore/config/basics.py b/src/pkgcore/config/basics.py
index 95792ea26..3ab3e73f7 100644
--- a/src/pkgcore/config/basics.py
+++ b/src/pkgcore/config/basics.py
@@ -10,7 +10,6 @@ __all__ = (
     "LazyNamedSectionRef",
     "ConfigSection",
     "DictConfigSection",
-    "FakeIncrementalDictConfigSection",
     "convert_string",
     "convert_asis",
     "convert_hybrid",
@@ -247,50 +246,12 @@ class DictConfigSection(ConfigSection):
     func: typing.Callable
     dict: dict[str, typing.Any]
 
-    def __init__(self, conversion_func, source_dict: dict[str, typing.Any]) -> 
None:
-        """Initialize.
-
-        :type conversion_func: callable.
-        :param conversion_func: called with a ConfigManager, a value from
-            the dict and a type name.
-        :type source_dict: dict with string keys and arbitrary values.
-        """
-        super().__init__()
-        self.func = conversion_func
-        self.dict = source_dict
-
-    def __contains__(self, name: str) -> bool:
-        return name in self.dict
-
-    def keys(self) -> list[str]:
-        return list(self.dict.keys())
-
-    def render_value(self, central, name: str, arg_type: str):
-        try:
-            return self.func(central, self.dict[name], arg_type)
-        except IGNORED_EXCEPTIONS:
-            raise
-        except Exception as e:
-            raise errors.ConfigurationError(
-                f"Failed converting argument {name!r} to {arg_type}"
-            ) from e
-
-
-class FakeIncrementalDictConfigSection(ConfigSection):
-    """Turns a dict and a conversion function into a ConfigSection."""
-
-    func: typing.Callable
-    dict: dict[str, typing.Any]
-
     def __init__(
         self, conversion_func: typing.Callable, source_dict: dict[str, 
typing.Any]
     ) -> None:
         """Initialize.
 
-        A request for a section of a list type will look for
-        name.prepend and name.append keys too, using those for values
-        prepended/appended to the inherited values. The conversion
-        func should return a single sequence for list types and in
+        The conversion func should return a single sequence for list types and 
in
         repr for list types.
 
         :type conversion_func: callable.
@@ -303,47 +264,31 @@ class FakeIncrementalDictConfigSection(ConfigSection):
         self.dict = source_dict
 
     def __contains__(self, name: str) -> bool:
-        return (
-            name in self.dict
-            or name + ".append" in self.dict
-            or name + ".prepend" in self.dict
-        )
+        return name in self.dict
 
     def keys(self) -> list[str]:
-        keys = set()
-        for key in self.dict:
-            if key.endswith(".append"):
-                key = key[:-7]
-            elif key.endswith(".prepend"):
-                key = key[:-8]
-            keys.add(key)
-        return list(keys)
+        return list(self.dict.keys())
 
     def render_value(self, central, name: str, arg_type: str):
         # Check if we need our special incremental magic.
         if arg_type in ("list", "str", "repr") or arg_type.startswith("refs:"):
-            result = []
-            # Careful: None is a valid dict value, so use something else here.
-            missing = object()
-            for subname in (name + ".prepend", name, name + ".append"):
-                val = self.dict.get(subname, missing)
-                if val is missing:
-                    val = None
-                else:
-                    try:
-                        val = self.func(central, val, arg_type)
-                    except IGNORED_EXCEPTIONS:
-                        raise
-                    except Exception as e:
-                        raise errors.ConfigurationError(
-                            f"Failed converting argument {subname!r} to 
{arg_type}"
-                        ) from e
-                result.append(val)
-            if result[0] is result[1] is result[2] is None:
+            try:
+                val = self.func(central, self.dict[name], arg_type)
+            except IGNORED_EXCEPTIONS:
+                raise
+            except Exception as e:
+                raise errors.ConfigurationError(
+                    f"Failed converting argument {name!r} to {arg_type}"
+                ) from e
+            if val is None:
                 raise KeyError(name)
+            result = [None, val, None]
             if arg_type != "repr":
                 # Done.
                 return result
+            # what follows is basically a type annotation shoved into this 
pathway, resulting
+            # in a differing signature from norms.  repr arg_type needs to be 
removed for this reason.
+
             # If "kind" is of some incremental-ish kind or we have
             # .prepend or .append for this key then we need to
             # convert everything we have to the same kind and
@@ -428,7 +373,7 @@ class FakeIncrementalDictConfigSection(ConfigSection):
                     else:
                         converted.append([val])
             return target_kind, converted
-        # Not incremental.
+        # simple types.
         try:
             return self.func(central, self.dict[name], arg_type)
         except IGNORED_EXCEPTIONS:
@@ -597,9 +542,9 @@ def convert_hybrid(central, value, arg_type: str):
 
 # "Invalid name" (pylint thinks these are module-level constants)
 # pylint: disable-msg=C0103
-HardCodedConfigSection = partial(FakeIncrementalDictConfigSection, 
convert_asis)
-ConfigSectionFromStringDict = partial(FakeIncrementalDictConfigSection, 
convert_string)
-AutoConfigSection = partial(FakeIncrementalDictConfigSection, convert_hybrid)
+HardCodedConfigSection = partial(DictConfigSection, convert_asis)
+ConfigSectionFromStringDict = partial(DictConfigSection, convert_string)
+AutoConfigSection = partial(DictConfigSection, convert_hybrid)
 
 
 def section_alias(target, typename: str) -> AutoConfigSection:

diff --git a/src/pkgcore/ebuild/portage_conf.py 
b/src/pkgcore/ebuild/portage_conf.py
index d33d2e37d..84f39ce27 100644
--- a/src/pkgcore/ebuild/portage_conf.py
+++ b/src/pkgcore/ebuild/portage_conf.py
@@ -213,7 +213,7 @@ class PortageConfig(DictMixin):
 
         self._make_repo_syncers(repos_conf, make_conf)
         if repos:
-            self["repo-stack"] = basics.FakeIncrementalDictConfigSection(
+            self["repo-stack"] = basics.DictConfigSection(
                 my_convert_hybrid,
                 {
                     "class": "pkgcore.repository.multiplex.tree",
@@ -248,9 +248,7 @@ class PortageConfig(DictMixin):
             }
         )
 
-        self["livefs"] = basics.FakeIncrementalDictConfigSection(
-            my_convert_hybrid, make_conf
-        )
+        self["livefs"] = basics.DictConfigSection(my_convert_hybrid, make_conf)
 
     def __setitem__(self, key, value):
         self._config[key] = value

diff --git a/tests/config/test_basics.py b/tests/config/test_basics.py
index e04cc7047..10f0841e1 100644
--- a/tests/config/test_basics.py
+++ b/tests/config/test_basics.py
@@ -248,87 +248,6 @@ class TestDictConfigSection:
             section.render_value(None, "list", "spoon")
 
 
-class TestFakeIncrementalDictConfigSection:
-    @staticmethod
-    def _convert(central, value, arg_type):
-        return central, value, arg_type
-
-    @staticmethod
-    def _fail(central, value, arg_type):
-        raise errors.ConfigurationError("fail")
-
-    def test_misc(self):
-        section = basics.FakeIncrementalDictConfigSection(
-            self._convert, {"list": [1, 2]}
-        )
-        assert "foo" not in section
-        assert "list" in section
-        assert ["list"] == list(section.keys())
-        with pytest.raises(errors.ConfigurationError):
-            obj = basics.FakeIncrementalDictConfigSection(self._fail, {"a": 
"b"})
-            obj.render_value(None, "a", "str")
-
-    def test_fake_incrementals(self):
-        section = basics.FakeIncrementalDictConfigSection(
-            self._convert, {"seq.append": [1, 2]}
-        )
-        manager = object()
-        assert [None, None, (manager, [1, 2], "list")] == section.render_value(
-            manager, "seq", "list"
-        )
-
-        def _repr(central, value, arg_type):
-            return "list", ["thing"]
-
-        section = basics.FakeIncrementalDictConfigSection(_repr, {"foo": None})
-        assert ("list", (None, ["thing"], None)) == section.render_value(
-            manager, "foo", "repr"
-        )
-        with pytest.raises(errors.ConfigurationError):
-            obj = basics.FakeIncrementalDictConfigSection(
-                self._fail, {"a.prepend": "b"}
-            )
-            obj.render_value(None, "a", "list")
-
-    def test_repr(self):
-        def asis(central, value, arg_type):
-            assert arg_type == "repr", arg_type
-            return value
-
-        source_dict = {
-            "seq.append": ("list", [1, 2]),
-            "simple": ("bool", True),
-            "multistr": ("str", "body"),
-            "multistr.prepend": ("str", "head"),
-            "refs": ("str", "lost"),
-            "refs.append": ("ref", "main"),
-            "refs.prepend": ("refs", ["a", "b"]),
-            "strlist": ("callable", asis),
-            "strlist.prepend": ("str", "whatever"),
-            "wrong.prepend": ("wrong", "wrong"),
-        }
-        section = basics.FakeIncrementalDictConfigSection(asis, source_dict)
-        manager = object()
-        with pytest.raises(KeyError):
-            section.render_value(manager, "spoon", "repr")
-        assert ("list", [None, None, [1, 2]]) == section.render_value(
-            manager, "seq", "repr"
-        )
-        assert ("bool", True) == section.render_value(manager, "simple", 
"repr")
-        assert ("str", ["head", "body", None]) == section.render_value(
-            manager, "multistr", "repr"
-        )
-        assert ("refs", [["a", "b"], ["lost"], ["main"]]) == 
section.render_value(
-            manager, "refs", "repr"
-        )
-        assert (
-            "list",
-            [["whatever"], ["tests.config.test_basics.asis"], None],
-        ) == section.render_value(manager, "strlist", "repr")
-        with pytest.raises(errors.ConfigurationError):
-            section.render_value(manager, "wrong", "repr")
-
-
 class TestConvertString:
     def test_render_value(self):
         source = {

diff --git a/tests/config/test_central.py b/tests/config/test_central.py
index 5ffb8072b..55b541f8f 100644
--- a/tests/config/test_central.py
+++ b/tests/config/test_central.py
@@ -970,89 +970,3 @@ def test_self_inherit():
     )
     assert manager.collapse_named_section("self")
     assert manager.collapse_section([section])
-
-
-def test_prepend_inherit():
-    manager = central.ConfigManager(
-        [{"sect": basics.HardCodedConfigSection({"inherit.prepend": 
["self"]})}]
-    )
-    check_error(
-        "Collapsing section named 'sect':\n"
-        "Prepending or appending to the inherit list makes no sense",
-        manager.collapse_named_section,
-        "sect",
-    )
-
-
-def test_list_prepend():
-    @configurable(types={"seq": "list"})
-    def seq(seq):
-        return seq
-
-    manager = central.ConfigManager(
-        [
-            {
-                "inh": basics.HardCodedConfigSection(
-                    {
-                        "inherit": ["sect"],
-                        "seq.prepend": ["pre"],
-                    }
-                ),
-                "sect": basics.HardCodedConfigSection(
-                    {
-                        "inherit": ["base"],
-                        "seq": ["1", "2"],
-                    }
-                ),
-            },
-            {
-                "base": basics.HardCodedConfigSection(
-                    {
-                        "class": seq,
-                        "seq.prepend": ["-1"],
-                        "seq.append": ["post"],
-                    }
-                )
-            },
-        ]
-    )
-    assert ["-1", "post"] == manager.objects.seq["base"]
-    assert ["1", "2"] == manager.objects.seq["sect"]
-    assert ["pre", "1", "2"] == manager.objects.seq["inh"]
-
-
-def test_str_prepend():
-    @configurable(types={"string": "str"})
-    def sect(string):
-        return string
-
-    manager = central.ConfigManager(
-        [
-            {
-                "inh": basics.HardCodedConfigSection(
-                    {
-                        "inherit": ["sect"],
-                        "string.prepend": "pre",
-                    }
-                ),
-                "sect": basics.HardCodedConfigSection(
-                    {
-                        "inherit": ["base"],
-                        "string": "b",
-                    }
-                ),
-            },
-            {
-                "base": basics.HardCodedConfigSection(
-                    {
-                        "class": sect,
-                        "string.prepend": "a",
-                        "string.append": "c",
-                    }
-                )
-            },
-        ]
-    )
-    assert "a c" == manager.objects.sect["base"]
-    assert "b" == manager.objects.sect["sect"]
-    assert "pre b" == manager.objects.sect["inh"]

diff --git a/tests/config/test_cparser.py b/tests/config/test_cparser.py
index e7d0b0ea5..a9082adbf 100644
--- a/tests/config/test_cparser.py
+++ b/tests/config/test_cparser.py
@@ -2,6 +2,7 @@ import textwrap
 from io import StringIO
 
 import pytest
+
 from pkgcore.config import central, cparser, errors
 
 
@@ -33,8 +34,6 @@ class TestConfigFromIni:
             [test]
             string = 'hi I am a string'
             list = foo bar baz
-            list.prepend = pre bits
-            list.append = post bits
             true = yes
             false = no
         """
@@ -48,7 +47,7 @@ class TestConfigFromIni:
             (
                 "list",
                 "list",
-                [["pre", "bits"], ["foo", "bar", "baz"], ["post", "bits"]],
+                [None, ["foo", "bar", "baz"], None],
             ),
             ("true", "bool", True),
             ("false", "bool", False),

Reply via email to