Skip to content

Commit

Permalink
[resotocore][feat] Add list table output (#1812)
Browse files Browse the repository at this point in the history
  • Loading branch information
aquamatthias committed Nov 2, 2023
1 parent 0366429 commit 69b12a0
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
42 changes: 42 additions & 0 deletions resotocore/resotocore/cli/command.py
Expand Up @@ -119,6 +119,8 @@
Property,
ArrayKind,
PropertyPath,
TransformKind,
AnyKind,
)
from resotocore.model.resolve_in_graph import NodePath
from resotocore.model.typed_model import to_json, to_js, from_js
Expand Down Expand Up @@ -2553,6 +2555,7 @@ def args_info(self) -> ArgsInfo:
return [
ArgInfo("--csv", help_text="format", option_group="format"),
ArgInfo("--markdown", help_text="format", option_group="format"),
ArgInfo("--json-table", help_text="format", option_group="format"),
ArgInfo(
expects_value=True,
help_text="comma separated list of properties to show",
Expand All @@ -2565,6 +2568,7 @@ def parse(self, arg: Optional[str] = None, ctx: CLIContext = EmptyContext, **kwa
output_type = parser.add_mutually_exclusive_group()
output_type.add_argument("--csv", dest="csv", action="store_true")
output_type.add_argument("--markdown", dest="markdown", action="store_true")
output_type.add_argument("--json-table", dest="json_table", action="store_true")
parsed, properties_list = parser.parse_known_args(arg.split() if arg else [])
properties = " ".join(properties_list) if properties_list else None

Expand Down Expand Up @@ -2661,6 +2665,38 @@ def to_csv_string(lst: List[Any]) -> str:
result.append(value)
yield to_csv_string(result)

async def json_table_stream(in_stream: JsStream, model: Model) -> JsGen:
def kind_of(path: List[str]) -> str:
if path[0] in Section.lookup_sections:
return kind_of(path[2:])
if path[0] in Section.content:
path = path[1:]
kind = model.kind_by_path(".".join(path))
if isinstance(kind, TransformKind):
return kind.source_kind.fqn if kind.source_kind else AnyKind().fqn
else:
return kind.fqn

# header columns
yield {
"columns": [
{
"name": name,
"kind": kind_of(path),
"display": " ".join(word.capitalize() for word in name.split("_")),
}
for path, name in props_to_show
],
}
# data columns
async with in_stream.stream() as s:
async for elem in s:
if is_node(elem):
yield {
"id": elem["id"],
"row": {name: js_value_at(elem, prop_path) for prop_path, name in props_to_show},
}

def markdown_stream(in_stream: JsStream) -> JsGen:
chunk_size = 500

Expand Down Expand Up @@ -2732,6 +2768,12 @@ def fmt(in_stream: JsGen) -> JsGen:
return csv_stream(in_stream)
elif parsed.markdown:
return markdown_stream(in_stream)
elif parsed.json_table:

async def load_model() -> Model:
return await self.dependencies.model_handler.load_model(ctx.graph_name)

return stream.flatmap(stream.call(load_model), partial(json_table_stream, in_stream))
else:
return stream.map(in_stream, lambda elem: fmt_json(elem) if isinstance(elem, dict) else str(elem))

Expand Down
1 change: 1 addition & 0 deletions resotocore/resotocore/model/graph_access.py
Expand Up @@ -80,6 +80,7 @@ class Section:

# The list of all lookup sections
lookup_sections_ordered = [ancestors, descendants, usage]
lookup_sections = set(lookup_sections_ordered)

# The list of all sections
all_ordered = [*content_ordered, *lookup_sections_ordered]
Expand Down
20 changes: 17 additions & 3 deletions resotocore/tests/resotocore/cli/command_test.py
Expand Up @@ -573,7 +573,7 @@ async def test_list_command(cli: CLI) -> None:

# List is using the correct type
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
result = await cli.execute_cli_command(f"json {json.dumps(props)}" " | list a,b,c,d,e,f", stream.list)
result = await cli.execute_cli_command(f"json {json.dumps(props)} | list a,b,c,d,e,f", stream.list)
assert result[0] == ["a=a, b=true, c=false, e=12, f=1.234"]

# Queries that use the reported section, also interpret the list format in the reported section
Expand All @@ -585,21 +585,35 @@ async def test_list_command(cli: CLI) -> None:
# List supports csv output
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
result = await cli.execute_cli_command(
f"json {json.dumps(props)}" " | list --csv a,b,c,d,e,f,non_existent", stream.list
f"json {json.dumps(props)} | list --csv a,b,c,d,e,f,non_existent", stream.list
)
assert result[0] == ['"a","b","c","d","e","f","non_existent"', '"a",True,False,"",12,1.234,""']

# List supports markdown output
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
result = await cli.execute_cli_command(
f"json {json.dumps(props)}" " | list --markdown a,b,c,d,e,f,non_existent", stream.list
f"json {json.dumps(props)} | list --markdown a,b,c,d,e,f,non_existent", stream.list
)
assert result[0] == [
"|a|b |c |d |e |f |non_existent|",
"|-|----|-----|----|--|-----|------------|",
"|a|true|false|null|12|1.234|null |",
]

# List supports markdown output
result = await cli.execute_cli_command(
'json {"id": "foo", "reported":{}, "name": "a", "some_int": 1} | list --json-table name, some_int', stream.list
)
assert result[0] == [
{
"columns": [
{"display": "Name", "kind": "string", "name": "name"},
{"display": "Some Int", "kind": "int32", "name": "some_int"},
],
},
{"id": "foo", "row": {"name": "a", "some_int": 1}},
]

# List supports only markdown or csv, but not both at the same time
props = dict(id="test", a="a", b=True, c=False, d=None, e=12, f=1.234, reported={})
with pytest.raises(CLIParseError):
Expand Down

0 comments on commit 69b12a0

Please sign in to comment.