From e165b7d684ec73f1010be3c53d73dbf990f9ac4e Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 1 Dec 2020 12:07:29 +0100 Subject: items: Enable custom get value for lists --- rtemsspec/applconfig.py | 34 +++++++++--------------- rtemsspec/interface.py | 41 ++++++++++++++--------------- rtemsspec/items.py | 46 +++++++++++++++------------------ rtemsspec/tests/test_items_itemcache.py | 11 ++++---- 4 files changed, 59 insertions(+), 73 deletions(-) diff --git a/rtemsspec/applconfig.py b/rtemsspec/applconfig.py index 51f5736e..6e3691ce 100644 --- a/rtemsspec/applconfig.py +++ b/rtemsspec/applconfig.py @@ -321,10 +321,6 @@ def _generate(group: Item, options: ItemMap, content: _ContentAdaptor) -> None: content.add_licence_and_copyrights() -def _get_value_none(_ctx: ItemGetValueContext) -> Any: - return None - - def _sphinx_ref(ref: str) -> str: return f":ref:`{ref}`" @@ -354,17 +350,14 @@ _SPHINX_DOC_REFS = { } -def _get_value_sphinx_reference(ctx: ItemGetValueContext) -> Any: - return _SPHINX_DOC_REFS[ctx.key] +def _get_value_sphinx_reference(_ctx: ItemGetValueContext) -> Any: + return _SPHINX_DOC_REFS def _add_sphinx_get_values(mapper: ItemMapper) -> None: - for key in _SPHINX_DOC_REFS: - for opt in ["feature-enable", "feature", "initializer", "integer"]: - doc_ref = f"interface/appl-config-option/{opt}:/document-reference" - mapper.add_get_value(doc_ref, _get_value_none) - mapper.add_get_value(f"{doc_ref}/{key}", - _get_value_sphinx_reference) + for opt in ["feature-enable", "feature", "initializer", "integer"]: + doc_ref = f"interface/appl-config-option/{opt}:/document-reference" + mapper.add_get_value(doc_ref, _get_value_sphinx_reference) def _c_user_ref(ref: str, name: str) -> str: @@ -427,8 +420,8 @@ _DOXYGEN_DOC_REFS = { } -def _get_value_doxygen_reference(ctx: ItemGetValueContext) -> Any: - return _DOXYGEN_DOC_REFS[ctx.key] +def _get_value_doxygen_reference(_ctx: ItemGetValueContext) -> Any: + return _DOXYGEN_DOC_REFS def _get_value_doxygen_url(ctx: ItemGetValueContext) -> Any: @@ -448,14 +441,11 @@ def _get_value_doxygen_unspecfied_type(ctx: ItemGetValueContext) -> Any: def _add_doxygen_get_values(mapper: ItemMapper) -> None: - for key in _DOXYGEN_DOC_REFS: - for opt in ["feature-enable", "feature", "initializer", "integer"]: - doc_ref = f"interface/appl-config-option/{opt}:/document-reference" - mapper.add_get_value(doc_ref, _get_value_none) - mapper.add_get_value(f"{doc_ref}/{key}", - _get_value_doxygen_reference) - name = f"interface/appl-config-option/{opt}:/name" - mapper.add_get_value(name, get_value_hash) + for opt in ["feature-enable", "feature", "initializer", "integer"]: + doc_ref = f"interface/appl-config-option/{opt}:/document-reference" + mapper.add_get_value(doc_ref, _get_value_doxygen_reference) + name = f"interface/appl-config-option/{opt}:/name" + mapper.add_get_value(name, get_value_hash) mapper.add_get_value("interface/define:/name", get_value_hash) mapper.add_get_value("interface/function:/name", get_value_doxygen_function) diff --git a/rtemsspec/interface.py b/rtemsspec/interface.py index 87e6f8b9..04536232 100644 --- a/rtemsspec/interface.py +++ b/rtemsspec/interface.py @@ -31,7 +31,8 @@ from typing import Any, Callable, Dict, Iterator, List, Union, Set from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \ ExpressionMapper, get_value_double_colon, get_value_doxygen_function, \ get_value_hash -from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper +from rtemsspec.items import Item, ItemCache, ItemGetValueContext, \ + ItemGetValueMap, ItemMapper ItemMap = Dict[str, Item] Lines = Union[str, List[str]] @@ -63,25 +64,25 @@ class _InterfaceMapper(ItemMapper): super().__init__(node.item) self._node = node self._code_or_doc = "doc" - self.add_get_value("interface/forward-declaration:code:/name", + self.add_get_value("interface/forward-declaration/code:/name", _get_value_forward_declaration) - self.add_get_value("interface/forward-declaration:doc:/name", + self.add_get_value("interface/forward-declaration/doc:/name", _get_value_forward_declaration) - self.add_get_value("interface/function:doc:/name", + self.add_get_value("interface/function/doc:/name", get_value_doxygen_function) - self.add_get_value("interface/enumerator:doc:/name", + self.add_get_value("interface/enumerator/doc:/name", get_value_double_colon) - self.add_get_value("interface/typedef:doc:/name", + self.add_get_value("interface/typedef/doc:/name", get_value_double_colon) - self.add_get_value("interface/define:doc:/name", get_value_hash) - self.add_get_value("interface/enum:doc:/name", get_value_hash) - self.add_get_value("interface/macro:doc:/name", + self.add_get_value("interface/define/doc:/name", get_value_hash) + self.add_get_value("interface/enum/doc:/name", get_value_hash) + self.add_get_value("interface/macro/doc:/name", get_value_doxygen_function) - self.add_get_value("interface/variable:doc:/name", get_value_hash) + self.add_get_value("interface/variable/doc:/name", get_value_hash) for opt in ["feature-enable", "feature", "initializer", "integer"]: - name = f"interface/appl-config-option/{opt}:doc:/name" + name = f"interface/appl-config-option/{opt}/doc:/name" self.add_get_value(name, get_value_hash) - self.add_get_value("interface/unspecified-function:doc:/name", + self.add_get_value("interface/unspecified-function/doc:/name", get_value_doxygen_function) @contextmanager @@ -92,19 +93,17 @@ class _InterfaceMapper(ItemMapper): yield self._code_or_doc = code_or_doc - def get_value(self, ctx: ItemGetValueContext) -> Any: - if self._code_or_doc == "code" and ctx.item["type"] == "interface": + def get_value_map(self, item: Item) -> ItemGetValueMap: + if self._code_or_doc == "code" and item["type"] == "interface": node = self._node header_file = node.header_file - if ctx.item["interface-type"] == "enumerator": - for child in ctx.item.children("interface-enumerator"): + if item["interface-type"] == "enumerator": + for child in item.children("interface-enumerator"): header_file.add_includes(child) else: - header_file.add_includes(ctx.item) - header_file.add_dependency(node, ctx.item) - return super().get_value( - ItemGetValueContext(ctx.item, f"{self._code_or_doc}:{ctx.path}", - ctx.value, ctx.key, ctx.index)) + header_file.add_includes(item) + header_file.add_dependency(node, item) + return self._get_value_map.get(f"{item.type}/{self._code_or_doc}", {}) def enabled_by_to_defined(self, enabled_by: str) -> str: """ diff --git a/rtemsspec/items.py b/rtemsspec/items.py index 5b7a95af..12ecfb42 100644 --- a/rtemsspec/items.py +++ b/rtemsspec/items.py @@ -42,14 +42,10 @@ class ItemGetValueContext(NamedTuple): key: str index: Any # should be int, but this triggers a mypy error - @property - def type_path_key(self) -> str: - """ Returns the item type followed the path to the key. """ - return f"{self.item.type}:{os.path.join(self.path, self.key)}" - ItemMap = Dict[str, "Item"] ItemGetValue = Callable[[ItemGetValueContext], Any] +ItemGetValueMap = Dict[str, Tuple[ItemGetValue, Any]] def _is_enabled_op_and(enabled: List[str], enabled_by: Any) -> bool: @@ -185,10 +181,8 @@ class Item: """ return self._data.get(key, default) - def get_by_normalized_key_path( - self, - normalized_key_path: str, - get_value: ItemGetValue = _get_value) -> Any: + def get_by_normalized_key_path(self, normalized_key_path: str, + get_value_map: ItemGetValueMap) -> Any: """ Gets the attribute value corresponding to the normalized key path. """ @@ -201,20 +195,16 @@ class Item: except IndexError: index = -1 ctx = ItemGetValueContext(self, path, value, parts[0], index) - try: - value = get_value(ctx) - except KeyError: - value = _get_value(ctx) + get_value, get_value_map = get_value_map.get( + parts[0], (_get_value, {})) + value = get_value(ctx) path = os.path.join(path, key) return value - def get_by_key_path(self, - key_path: str, - prefix: str = "", - get_value: ItemGetValue = _get_value) -> Any: + def get_by_key_path(self, key_path: str, prefix: str = "") -> Any: """ Gets the attribute value corresponding to the key path. """ return self.get_by_normalized_key_path( - normalize_key_path(key_path, prefix), get_value) + normalize_key_path(key_path, prefix), {}) @property def uid(self) -> str: @@ -378,7 +368,7 @@ class ItemMapper(Mapping[str, object]): self._item = item self._recursive = recursive self._prefix = [""] - self._get_value = {} # type: Dict[str, ItemGetValue] + self._get_value_map = {} # type: Dict[str, ItemGetValueMap] @property def item(self) -> Item: @@ -395,7 +385,12 @@ class ItemMapper(Mapping[str, object]): """ Adds a get value for the specified type and key path. """ - self._get_value[type_path_key] = get_value + type_name, path_key = type_path_key.split(":") + keys = path_key.strip("/").split("/") + get_value_map = self._get_value_map.setdefault(type_name, {}) + for key in keys[:-1]: + _, get_value_map = get_value_map.setdefault(key, (_get_value, {})) + get_value_map[keys[-1]] = (get_value, {}) def push_prefix(self, prefix: str) -> None: """ Pushes a key path prefix. """ @@ -412,6 +407,10 @@ class ItemMapper(Mapping[str, object]): yield self.pop_prefix() + def get_value_map(self, item: Item) -> ItemGetValueMap: + """ Returns the get value map for the item. """ + return self._get_value_map.get(item.type, {}) + def map(self, identifier: str) -> Tuple[Item, str, Any]: """ Maps an identifier to the corresponding item and attribute value. @@ -429,7 +428,8 @@ class ItemMapper(Mapping[str, object]): item = self._item.map(uid) prefix = "" key_path = normalize_key_path(key_path, prefix) - value = item.get_by_normalized_key_path(key_path, self.get_value) + value = item.get_by_normalized_key_path(key_path, + self.get_value_map(item)) for func in pipes: value = getattr(self, func)(value) return item, key_path, value @@ -472,10 +472,6 @@ class ItemMapper(Mapping[str, object]): with self.prefix(prefix): return ItemTemplate(text).substitute(self) - def get_value(self, ctx: ItemGetValueContext) -> Any: - """ Gets a value by key and optional index. """ - return self._get_value[ctx.type_path_key](ctx) - class _SpecType(NamedTuple): key: str diff --git a/rtemsspec/tests/test_items_itemcache.py b/rtemsspec/tests/test_items_itemcache.py index 05affc24..4331b335 100644 --- a/rtemsspec/tests/test_items_itemcache.py +++ b/rtemsspec/tests/test_items_itemcache.py @@ -96,6 +96,11 @@ expected , but found ':' ItemCache(config) +def get_x_to_b_value(ctx): + assert ctx.key == "x-to-b" + return ctx.value["b"] + + class Mapper(ItemMapper): def __init__(self, item): super().__init__(item) @@ -109,11 +114,6 @@ class Mapper(ItemMapper): def dup(self, value): return value + value - def get_value(self, ctx): - if ctx.key == "x-to-b": - return ctx.value["b"] - raise KeyError - def test_item_mapper(tmpdir): config = create_item_cache_config_and_copy_spec(tmpdir, "spec-item-cache") @@ -141,6 +141,7 @@ def test_item_mapper(tmpdir): assert mapper["d/c:v"] == "c" assert mapper["d/c:a/b"] == "e" assert mapper["d/c:a/b|u"] == "ue" + mapper.add_get_value(":/a/x-to-b", get_x_to_b_value) assert mapper["d/c:a/x-to-b|u|v"] == "vue" assert mapper["d/c:a/f[1]"] == 2 assert mapper["d/c:a/../a/f[3]/g[0]|dup"] == 8 -- cgit v1.2.3