Add cmd line app

This commit is contained in:
Tom 2025-02-27 16:45:57 +00:00
parent 68ad80e435
commit 8306fb4c3e
3 changed files with 101 additions and 64 deletions

View File

@ -23,5 +23,7 @@ use `--input` and `--output` to specify input and output files respectively.
There's some handy test data in the `tests/data` directory. For example: There's some handy test data in the `tests/data` directory. For example:
```bash ```bash
gzip -dc tests/data/fdb_list_compact.gz| qubed --from=fdblist gzip -dc tests/data/fdb_list_compact.gz| qubed convert --from=fdb --to=text --output=qube.txt
gzip -dc tests/data/fdb_list_porcelain.gz| qubed convert --from=fdb --to=json --output=qube.json
gzip -dc tests/data/fdb_list_compact.gz | qubed convert --from=fdb --to=html --output=qube.html
``` ```

View File

@ -18,6 +18,9 @@ requires-python = ">= 3.11"
dynamic = ["version"] dynamic = ["version"]
dependencies = [ dependencies = [
"frozendict", "frozendict",
"rich",
"numpy",
"click",
] ]
# Because this is a mixed rust/python project the structure is src/python/qubed rather than the more typical src/qubed # Because this is a mixed rust/python project the structure is src/python/qubed rather than the more typical src/qubed

View File

@ -1,82 +1,114 @@
import argparse import time
import sys
import click
import psutil
from rich.console import Console from rich.console import Console
from rich.layout import Layout
from rich.live import Live
from rich.panel import Panel
from rich.spinner import Spinner
from rich.text import Text
from qubed import Qube from qubed import Qube
from qubed.convert import parse_fdb_list from qubed.convert import parse_fdb_list
console = Console(stderr=True) console = Console(stderr=True)
process = psutil.Process()
PRINT_INTERVAL = 0.25
@click.group()
def main(): def main():
parser = argparse.ArgumentParser( """Command-line tool for working with trees."""
description="Generate a compressed tree from various inputs." pass
)
subparsers = parser.add_subparsers(title="subcommands", required=True)
parser_convert = subparsers.add_parser(
"convert", help="Convert trees from one format to another."
)
# parser_another = subparsers.add_parser(
# "another_subcommand", help="Does something else"
# )
parser_convert.add_argument( @main.command()
@click.option(
"--input", "--input",
type=argparse.FileType("r"), type=click.File("r"),
default=sys.stdin, default="-",
help="Specify the input file (default: standard input).", help="Specify the input file (default: standard input).",
) )
parser_convert.add_argument( @click.option(
"--output", "--output",
type=argparse.FileType("w"), type=click.File("w"),
default=sys.stdout, default="-",
help="Specify the output file (default: standard output).", help="Specify the output file (default: standard output).",
) )
@click.option(
parser_convert.add_argument( "--from",
"--input_format", "from_format",
choices=["fdb", "mars"], type=click.Choice(["fdb", "mars"]),
default="fdb", default="fdb",
help="""Specify the input format: help="Specify the input format: fdb (fdb list --porcelain) or mars (mars list).",
fdb: the output of fdb list --porcelain
mars: the output of mars list
""",
) )
@click.option(
parser_convert.add_argument( "--to",
"--output_format", "to_format",
choices=["text", "html"], type=click.Choice(["text", "html", "json"]),
default="text", default="text",
help="Specify the output format (text or html).", help="Specify the output format: text, html, json.",
) )
parser_convert.set_defaults(func=convert) def convert(input, output, from_format, to_format):
"""Convert trees from one format to another."""
args = parser.parse_args()
args.func(args)
def convert(args):
q = Qube.empty() q = Qube.empty()
for datacube in parse_fdb_list(args.input): t = time.time()
i0 = 0
n0 = 0
depth = 5
log = Text()
summary = Layout()
summary.split_column(
Layout(name="upper"),
Layout(name="qube"),
)
summary["upper"].split_row(
Layout(name="performance"),
Layout(log, name="log"),
)
spinner = Spinner("aesthetic", text="Performance", speed=0.3)
with Live(summary, auto_refresh=False, transient=True, console=console) as live:
for i, datacube in enumerate(parse_fdb_list(input)):
new_branch = Qube.from_datacube(datacube) new_branch = Qube.from_datacube(datacube)
q = q | Qube.from_datacube(datacube) q = q | new_branch
# output = match args.output_format: if time.time() - t > PRINT_INTERVAL:
# case "text": tree = q.__str__(depth=depth)
# str(q) if tree.count("\n") > 20:
# case "html": depth -= 1
# q.html() if tree.count("\n") < 5:
output = "fw" depth += 1
with open(args.output, "w") as f: summary["performance"].update(
f.write(output) Panel(
Text.assemble(
f"The Qube has {q.n_leaves} leaves and {q.n_nodes} internal nodes so far.\n",
f"{(i - i0) / (time.time() - t) / PRINT_INTERVAL:.0f} lines per second. ",
f"{(q.n_leaves - n0) / (time.time() - t):.0f} leaves per second.\n",
f"Memory usage: {process.memory_info().rss / 1024 / 1024:.0f} MB\n",
),
title=spinner.render(time.time()),
border_style="blue",
)
)
summary["qube"].update(
Panel(tree, title=f"Qube (depth {depth})", border_style="blue")
)
summary["log"].update(
Panel(
f"{datacube}", border_style="blue", title="Last Datacube Added"
)
)
live.refresh()
i0 = i
n0 = q.n_leaves
t = time.time()
console.print([1, 2, 3]) output_content = str(q) if to_format == "text" else q.html().html
console.print("[blue underline]Looks like a link") output.write(output_content)
console.print(locals())
console.print("FOO", style="white on blue")
if __name__ == "__main__": if __name__ == "__main__":