aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Harring <ferringb@gmail.com>2023-01-17 00:22:28 -0800
committerArthur Zamarin <arthurzam@gentoo.org>2023-02-05 20:08:21 +0200
commitcc4b8915fd71d09715011b6dadbe9c86e28e0b11 (patch)
treed722b078a92059cbd7293468ff0f9a14d7b8c864
parentrefactor(config): remove the notion of config layer incremental prepend/append. (diff)
downloadpkgcore-cc4b8915fd71d09715011b6dadbe9c86e28e0b11.tar.gz
pkgcore-cc4b8915fd71d09715011b6dadbe9c86e28e0b11.tar.bz2
pkgcore-cc4b8915fd71d09715011b6dadbe9c86e28e0b11.zip
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@gmail.com> Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
-rw-r--r--src/pkgcore/config/basics.py108
-rw-r--r--src/pkgcore/config/central.py58
-rw-r--r--src/pkgcore/scripts/pconfig.py37
-rw-r--r--tests/config/test_cparser.py4
-rw-r--r--tests/scripts/test_pconfig.py9
5 files changed, 32 insertions, 184 deletions
diff --git a/src/pkgcore/config/basics.py b/src/pkgcore/config/basics.py
index 3ab3e73f..ba968ef9 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 350e25f5..0cd2f392 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 00b70a4e..75bb0017 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 a9082adb..bf407e62 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 c9cd40eb..68543361 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'",