Coverage for archdocs/features/kubernetes/values.py: 100%
38 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 22:03 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-18 22:03 +0000
1import typing
3from archdocs.features.kubernetes import const
6_COMMENT_PREFIX: typing.Final = "#"
7_INLINE_COMMENT_PREFIX: typing.Final = " #"
8_TEMPLATE_MARKER: typing.Final = "{{"
9_LIST_ITEM_PREFIX: typing.Final = "-"
10_LIST_ITEM_INDENT: typing.Final = 2
11_QUOTE_CHARACTERS: typing.Final = "\"'"
12_MEANINGLESS_VALUES: typing.Final = frozenset(("{}", "[]", "null", "~"))
14type _ParentKeys = list[tuple[int, str]]
17def _remove_list_prefix(raw_indent: int, raw_content: str, /) -> tuple[int, str]:
18 if not raw_content.startswith(_LIST_ITEM_PREFIX):
19 return raw_indent, raw_content
20 return raw_indent + _LIST_ITEM_INDENT, raw_content[len(_LIST_ITEM_PREFIX) :].strip()
23def _make_one_value(
24 line_indent: int,
25 value_key: str,
26 raw_value: str,
27 parent_keys: _ParentKeys,
28 /,
29) -> const.ManifestValue | None:
30 if not raw_value:
31 parent_keys.append((line_indent, value_key))
32 return None
33 if _TEMPLATE_MARKER in raw_value or raw_value in _MEANINGLESS_VALUES:
34 return None
35 return const.ManifestValue(
36 value_path=(*(one_parent_key for _, one_parent_key in parent_keys), value_key),
37 raw_value=raw_value,
38 )
41def _read_one_pair(raw_indent: int, raw_content: str, parent_keys: _ParentKeys, /) -> const.ManifestValue | None:
42 line_indent, line_content = _remove_list_prefix(raw_indent, raw_content)
43 value_key, key_separator, raw_value = line_content.partition(":")
44 if not key_separator:
45 return None
46 while parent_keys and parent_keys[-1][0] >= line_indent:
47 parent_keys.pop()
48 return _make_one_value(
49 line_indent,
50 value_key.strip(),
51 raw_value.partition(_INLINE_COMMENT_PREFIX)[0].strip().strip(_QUOTE_CHARACTERS),
52 parent_keys,
53 )
56def _read_one_line(raw_line: str, parent_keys: _ParentKeys, /) -> const.ManifestValue | None:
57 line_content: typing.Final = raw_line.strip()
58 if not line_content or line_content.startswith((_COMMENT_PREFIX, _TEMPLATE_MARKER)):
59 return None
60 return _read_one_pair(len(raw_line) - len(raw_line.lstrip()), line_content, parent_keys)
63def read_manifest_values(raw_source: str) -> const.ManifestValues:
64 # Templated yaml is not yaml, so the nesting is restored from the indentation alone and every
65 # `{{ ... }}` value is dropped: what a rendered chart would put there is nobody's guess here.
66 parent_keys: typing.Final[_ParentKeys] = []
67 all_read_values: typing.Final = [
68 _read_one_line(one_raw_line, parent_keys) for one_raw_line in raw_source.split("\n")
69 ]
70 return tuple(one_value for one_value in all_read_values if one_value is not None)