cli improved

This commit is contained in:
James Turk 2023-05-07 23:31:20 -05:00
parent 44bfa767a6
commit 2fc2732a65
5 changed files with 67 additions and 11 deletions

View File

@ -1,3 +1,12 @@
## Usage
```
por bkr --recipe examples.fruits.recipe show
por bkr --recipe examples.fruits.recipe reset
por bkr --recipe examples.fruits.recipe run --input words=examples/fruits.csv
por bkr --recipe examples.fruits.recipe show
```
## Michael's Email
### Data Dictionay

View File

@ -5,6 +5,10 @@ description = ""
authors = ["James Turk <dev@jamesturk.net>"]
readme = "README.md"
[tool.poetry.scripts]
bkr = 'beakers.cli:app'
[tool.poetry.dependencies]
python = "^3.11"
scrapeghost = {path = "../scrapeghost", develop = true}

View File

@ -23,6 +23,10 @@ class Beaker(abc.ABC):
def add_item(self, item: dict, from_table=None, from_id=None) -> None:
pass
@abc.abstractmethod
def reset(self):
pass
class TempBeaker(Beaker):
def __init__(self, name: str, recipe):
@ -38,6 +42,9 @@ class TempBeaker(Beaker):
def items(self):
yield from self._items
def reset(self):
self._items = []
class SqliteBeaker(Beaker):
def __init__(self, name: str, recipe):
@ -64,3 +71,7 @@ class SqliteBeaker(Beaker):
f"INSERT INTO {self.name} (data) VALUES (?)", (json.dumps(item),)
)
self.recipe.db.commit()
def reset(self):
self.cursor.execute(f"DELETE FROM {self.name}")
self.recipe.db.commit()

View File

@ -1,9 +1,12 @@
import importlib
from types import SimpleNamespace
import typer
import sys
from typing import List, Optional
from typing_extensions import Annotated
from beakers.beakers import SqliteBeaker
app = typer.Typer()
@ -14,28 +17,49 @@ def _load_recipe(dotted_path: str):
return getattr(mod, name)
@app.command()
def reset(recipe: Annotated[str, typer.Option(...)]):
mod = _load_recipe(recipe)
mod.reset()
@app.callback()
def main(
ctx: typer.Context,
recipe: str = typer.Option(None, envvar="BEAKER_RECIPE"),
):
if not recipe:
typer.secho(
"Missing recipe; pass --recipe or set env[BEAKER_RECIPE]",
fg=typer.colors.RED,
)
raise typer.Exit(1)
ctx.obj = _load_recipe(recipe)
@app.command()
def show(recipe: Annotated[str, typer.Option(...)]):
mod = _load_recipe(recipe)
mod.show()
def reset(ctx: typer.Context):
for beaker in ctx.obj.beakers.values():
if isinstance(beaker, SqliteBeaker):
if bl := len(beaker):
beaker.reset()
typer.secho(f"{beaker.name} reset ({bl})", fg=typer.colors.RED)
else:
typer.secho(f"{beaker.name} empty", fg=typer.colors.GREEN)
@app.command()
def show(ctx: typer.Context):
ctx.obj.show()
@app.command()
def run(
recipe: Annotated[str, typer.Option(...)],
ctx: typer.Context,
input: Annotated[Optional[List[str]], typer.Option(...)] = None,
):
mod = _load_recipe(recipe)
has_data = any(ctx.obj.beakers.values())
if not has_data and not input:
typer.secho("No data; pass --input to seed beaker(s)", fg=typer.colors.RED)
raise typer.Exit(1)
for input_str in input:
beaker, filename = input_str.split("=")
mod.csv_to_beaker(filename, beaker)
mod.run_once()
ctx.obj.csv_to_beaker(filename, beaker)
ctx.obj.run_once()
if __name__ == "__main__":

View File

@ -152,6 +152,14 @@ class Recipe:
for from_b, to_b, edge in self.graph.out_edges(node, data=True):
print(f" {from_b} -> {to_b} ({edge})")
def reset(self):
count = 0
for beaker in self.beakers.values():
if isinstance(beaker, SqliteBeaker):
beaker.reset()
count += 1
typer.secho(f"reset {count} beakers")
def run_once(self):
log.info("run_once", recipe=self)
loop = asyncio.get_event_loop()