commit:     cc4b8915fd71d09715011b6dadbe9c86e28e0b11
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Tue Jan 17 08:22:28 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=cc4b8915

refactor(config): remove prepend/append incremental return signature fully.

The previous commit disabled the logic to generate prepend/val/append- nothing 
used it-
this commit realigns the client consumers to expect a single value unless 
they're invoked
arg_type="repr".

Essentially, now if you ask the config layer for a value, you don't have to 
know if it's
a value that is considered 'incremental'- you just get back a python object for 
what you asked,
ready for usage.

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

 src/pkgcore/config/basics.py   | 108 ++---------------------------------------
 src/pkgcore/config/central.py  |  58 +++-------------------
 src/pkgcore/scripts/pconfig.py |  37 ++++++--------
 tests/config/test_cparser.py   |   4 +-
 tests/scripts/test_pconfig.py  |   9 ++--
 5 files changed, 32 insertions(+), 184 deletions(-)

diff --git a/src/pkgcore/config/basics.py b/src/pkgcore/config/basics.py
index 3ab3e73f7..ba968ef96 100644
--- a/src/pkgcore/config/basics.py
+++ b/src/pkgcore/config/basics.py
@@ -269,111 +269,9 @@ class DictConfigSection(ConfigSection):
     def keys(self) -> list[str]:
         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:"):
-            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
-            # return all three.
-            #
-            # (we do not get called for separate reprs for the
-            # .prepend or .append because those are filtered from
-            # .keys(). If we do not filter those from .keys()
-            # central gets upset because it does not know their
-            # type. Perhaps this means we should have a separate
-            # .keys() used together with repr, not sure yet
-            # --marienz)
-            #
-            # The problem here is that we may get unsuitable for
-            # incremental or differing types for the three reprs
-            # we run, so we need to convert to a suitable common
-            # kind.
-            if result[0] is None and result[2] is None:
-                # Simple case: no extra data, so no need for any
-                # conversions.
-                kind, val = result[1]
-                if kind in ("list", "str") or kind == "refs":
-                    # Caller expects a three-tuple.
-                    return kind, (None, val, None)
-                else:
-                    # non-incremental, just return as-is.
-                    return kind, val
-            # We have more than one return value. Figure out what
-            # target to convert to. Choices are list, str and refs.
-            kinds = set(v[0] for v in result if v is not None)
-            if "refs" in kinds or "ref" in kinds:
-                # If we have any refs we have to convert to refs.
-                target_kind = "refs"
-            elif kinds == set(["str"]):
-                # If we have only str we can just use that.
-                target_kind = "str"
-            else:
-                # Convert to list. May not make any sense, but is
-                # the best we can do.
-                target_kind = "list"
-            converted = []
-            for val in result:
-                if val is None:
-                    converted.append(None)
-                    continue
-                kind, val = val
-                if kind == "ref":
-                    if target_kind != "refs":
-                        raise ValueError(
-                            "Internal issue detected: kind(ref), "
-                            f"target_kind({target_kind!r}), name({name!r}), "
-                            f"val({val!r}), arg_type({arg_type!r})"
-                        )
-                    converted.append([val])
-                elif kind == "refs":
-                    if target_kind != "refs":
-                        raise ValueError(
-                            "Internal issue detected: kind(refs), "
-                            f"target_kind({target_kind!r}), name({name!r}), "
-                            f"val({val!r}), arg_type({arg_type!r})"
-                        )
-                    converted.append(val)
-                elif kind == "list":
-                    if target_kind == "str":
-                        raise ValueError(
-                            "Internal issue detected: kind(str), "
-                            f"target_kind({target_kind!r}), name({name!r}), "
-                            f"val({val!r}), arg_type({arg_type!r})"
-                        )
-                    converted.append(val)
-                else:
-                    # Everything else gets converted to a string first.
-                    if kind == "callable":
-                        val = "%s.%s" % (val.__module__, val.__name__)
-                    elif kind in ("bool", "int", "str"):
-                        val = str(val)
-                    else:
-                        raise errors.ConfigurationError(f"unsupported type 
{kind!r}")
-                    # Then convert the str to list if needed.
-                    if target_kind == "str":
-                        converted.append(val)
-                    else:
-                        converted.append([val])
-            return target_kind, converted
-        # simple types.
+    def render_value(
+        self, central, name: str, arg_type: str
+    ) -> typing.Union[typing.Any, tuple[str, typing.Any]]:
         try:
             return self.func(central, self.dict[name], arg_type)
         except IGNORED_EXCEPTIONS:

diff --git a/src/pkgcore/config/central.py b/src/pkgcore/config/central.py
index 350e25f5e..0cd2f392e 100644
--- a/src/pkgcore/config/central.py
+++ b/src/pkgcore/config/central.py
@@ -8,11 +8,9 @@ __all__ = (
     "ConfigManager",
 )
 
-import functools
 import typing
 import weakref
 from collections import defaultdict, deque, namedtuple
-from itertools import chain
 
 from snakeoil import klass, mappings
 from snakeoil.compatibility import IGNORED_EXCEPTIONS
@@ -69,43 +67,14 @@ class _ConfigStack(defaultdict[str, list[typing.Any]]):
     def __init__(self) -> None:
         super().__init__(list)
 
-    def render_vals(
+    def render_value(
         self, manager, key: str, type_name: str
-    ) -> typing.Iterator[typing.Any]:
+    ) -> typing.Optional[typing.Any]:
         for data in self.get(key, ()):
             if key in data.section:
-                yield data.section.render_value(manager, key, type_name)
-
-    def render_val(
-        self, manager, key: str, type_name: str
-    ) -> typing.Optional[typing.Any]:
-        for val in self.render_vals(manager, key, type_name):
-            return val
+                return data.section.render_value(manager, key, type_name)
         return None
 
-    def render_prepends(self, manager, key: str, type_name: str) -> 
list[typing.Any]:
-        results = []
-        # keep in mind that the sequence we get is a top -> bottom walk of the 
config
-        # as such for this operation we have to reverse it when building the 
content-
-        # specifically, reverse the ordering, but not the content of each item.
-        data = []
-        for content in self.render_vals(manager, key, type_name):
-            data.append(content)
-            if content[1]:
-                break
-
-        for prepend, this_content, append in reversed(data):
-            if this_content:
-                results = [this_content]
-            if prepend:
-                results = [prepend] + results
-            if append:
-                results += [append]
-
-        if type_name != "str":
-            results = list(chain.from_iterable(results))
-        return results
-
 
 class CollapsedConfig:
 
@@ -463,13 +432,7 @@ class ConfigManager:
             current_conf = section_stack[0]
             if "inherit" not in current_conf:
                 continue
-            prepend, inherits, append = current_conf.render_value(
-                self, "inherit", "list"
-            )
-            if prepend is not None or append is not None:
-                raise errors.ConfigurationError(
-                    "Prepending or appending to the inherit list makes no 
sense"
-                )
+            inherits = current_conf.render_value(self, "inherit", "list")
             for inherit in inherits:
                 if inherit == current_section:
                     # self-inherit.  Mkae use of section_stack to handle this.
@@ -516,11 +479,11 @@ class ConfigManager:
             for key in data.section.keys():
                 config_stack[key].append(data)
 
-        kls = config_stack.render_val(self, "class", "callable")
+        kls = config_stack.render_value(self, "class", "callable")
         if kls is None:
             raise errors.ConfigurationError("no class specified")
         type_obj = basics.ConfigType(kls)
-        is_default = bool(config_stack.render_val(self, "default", "bool"))
+        is_default = bool(config_stack.render_value(self, "default", "bool"))
 
         for key in ("inherit", "inherit-only", "class", "default"):
             config_stack.pop(key, None)
@@ -561,14 +524,7 @@ class ConfigManager:
             if typename.startswith("lazy_"):
                 typename = typename[5:]
 
-            if typename.startswith("refs:") or typename in ("list", "str"):
-                result = config_stack.render_prepends(self, key, typename)
-                if typename == "str":
-                    # TODO: figure out why this is needed and likely remove it.
-                    # it's likely just doing ' '.join([item])
-                    result = " ".join(result)
-            else:
-                result = config_stack.render_val(self, key, typename)
+            result = config_stack.render_value(self, key, typename)
 
             if is_ref:
                 result = [result]

diff --git a/src/pkgcore/scripts/pconfig.py b/src/pkgcore/scripts/pconfig.py
index 00b70a4ef..75bb00171 100644
--- a/src/pkgcore/scripts/pconfig.py
+++ b/src/pkgcore/scripts/pconfig.py
@@ -319,29 +319,24 @@ def _dump_uncollapsed_section(config, out, err, section):
         kind, value = section.render_value(config, key, "repr")
         out.write(f"# type: {kind}")
         if kind == "list":
-            for name, val in zip((key + ".prepend", key, key + ".append"), 
value):
-                if val:
-                    out.write(repr(name), " = ", " ".join(repr(v) for v in 
val))
+            out.write(repr(key), " = ", " ".join(repr(v) for v in value))
             continue
         if kind in ("refs", "str"):
-            for name, val in zip((key + ".prepend", key, key + ".append"), 
value):
-                if not val:
-                    continue
-                out.write(repr(name), " = ", autoline=False)
-                if kind == "str":
-                    out.write(repr(val))
-                else:
-                    out.write()
-                    out.first_prefix.append("    ")
-                    try:
-                        for subnr, subsection in enumerate(val):
-                            subname = f"nested section {subnr + 1}"
-                            out.write(subname)
-                            out.write("=" * len(subname))
-                            _dump_uncollapsed_section(config, out, err, 
subsection)
-                            out.write()
-                    finally:
-                        out.first_prefix.pop()
+            out.write(repr(key), " = ", autoline=False)
+            if kind == "str":
+                out.write(repr(value))
+            else:
+                out.write()
+                out.first_prefix.append("    ")
+                try:
+                    for subnr, subsection in enumerate(value):
+                        subname = f"nested section {subnr + 1}"
+                        out.write(subname)
+                        out.write("=" * len(subname))
+                        _dump_uncollapsed_section(config, out, err, subsection)
+                        out.write()
+                finally:
+                    out.first_prefix.pop()
             continue
         out.write(f"{key!r} = ", autoline=False)
         if kind == "callable":

diff --git a/tests/config/test_cparser.py b/tests/config/test_cparser.py
index a9082adbf..bf407e62c 100644
--- a/tests/config/test_cparser.py
+++ b/tests/config/test_cparser.py
@@ -43,11 +43,11 @@ class TestConfigFromIni:
         assert list(config.keys()) == ["test"]
         section = config["test"]
         for key, arg_type, value in (
-            ("string", "str", [None, "hi I am a string", None]),
+            ("string", "str", "hi I am a string"),
             (
                 "list",
                 "list",
-                [None, ["foo", "bar", "baz"], None],
+                ["foo", "bar", "baz"],
             ),
             ("true", "bool", True),
             ("false", "bool", False),

diff --git a/tests/scripts/test_pconfig.py b/tests/scripts/test_pconfig.py
index c9cd40eb2..685433617 100644
--- a/tests/scripts/test_pconfig.py
+++ b/tests/scripts/test_pconfig.py
@@ -296,11 +296,10 @@ class WeirdSection(basics.ConfigSection):
             raise KeyError(name)
         if arg_type != "repr":
             raise errors.ConfigurationError(f"{arg_type!r} unsupported")
-        return "refs", [
+        return (
+            "refs",
             ["spork", basics.HardCodedConfigSection({"foo": "bar"})],
-            None,
-            None,
-        ]
+        )
 
 
 class TestDumpUncollapsed(ArgParseMixin):
@@ -337,7 +336,7 @@ class TestDumpUncollapsed(ArgParseMixin):
                 "    nested section 2",
                 "    ================",
                 "    # type: refs",
-                "    'sects.prepend' = ",
+                "    'sects' = ",
                 "        nested section 1",
                 "        ================",
                 "        named section 'spork'",

Reply via email to