cli improved
This commit is contained in:
parent
44bfa767a6
commit
2fc2732a65
@ -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
|
## Michael's Email
|
||||||
|
|
||||||
### Data Dictionay
|
### Data Dictionay
|
||||||
|
@ -5,6 +5,10 @@ description = ""
|
|||||||
authors = ["James Turk <dev@jamesturk.net>"]
|
authors = ["James Turk <dev@jamesturk.net>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.scripts]
|
||||||
|
bkr = 'beakers.cli:app'
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.11"
|
python = "^3.11"
|
||||||
scrapeghost = {path = "../scrapeghost", develop = true}
|
scrapeghost = {path = "../scrapeghost", develop = true}
|
||||||
|
@ -23,6 +23,10 @@ class Beaker(abc.ABC):
|
|||||||
def add_item(self, item: dict, from_table=None, from_id=None) -> None:
|
def add_item(self, item: dict, from_table=None, from_id=None) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def reset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TempBeaker(Beaker):
|
class TempBeaker(Beaker):
|
||||||
def __init__(self, name: str, recipe):
|
def __init__(self, name: str, recipe):
|
||||||
@ -38,6 +42,9 @@ class TempBeaker(Beaker):
|
|||||||
def items(self):
|
def items(self):
|
||||||
yield from self._items
|
yield from self._items
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._items = []
|
||||||
|
|
||||||
|
|
||||||
class SqliteBeaker(Beaker):
|
class SqliteBeaker(Beaker):
|
||||||
def __init__(self, name: str, recipe):
|
def __init__(self, name: str, recipe):
|
||||||
@ -64,3 +71,7 @@ class SqliteBeaker(Beaker):
|
|||||||
f"INSERT INTO {self.name} (data) VALUES (?)", (json.dumps(item),)
|
f"INSERT INTO {self.name} (data) VALUES (?)", (json.dumps(item),)
|
||||||
)
|
)
|
||||||
self.recipe.db.commit()
|
self.recipe.db.commit()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.cursor.execute(f"DELETE FROM {self.name}")
|
||||||
|
self.recipe.db.commit()
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import importlib
|
import importlib
|
||||||
|
from types import SimpleNamespace
|
||||||
import typer
|
import typer
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from typing_extensions import Annotated
|
from typing_extensions import Annotated
|
||||||
|
|
||||||
|
from beakers.beakers import SqliteBeaker
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
|
||||||
|
|
||||||
@ -14,28 +17,49 @@ def _load_recipe(dotted_path: str):
|
|||||||
return getattr(mod, name)
|
return getattr(mod, name)
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.callback()
|
||||||
def reset(recipe: Annotated[str, typer.Option(...)]):
|
def main(
|
||||||
mod = _load_recipe(recipe)
|
ctx: typer.Context,
|
||||||
mod.reset()
|
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()
|
@app.command()
|
||||||
def show(recipe: Annotated[str, typer.Option(...)]):
|
def reset(ctx: typer.Context):
|
||||||
mod = _load_recipe(recipe)
|
for beaker in ctx.obj.beakers.values():
|
||||||
mod.show()
|
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()
|
@app.command()
|
||||||
def run(
|
def run(
|
||||||
recipe: Annotated[str, typer.Option(...)],
|
ctx: typer.Context,
|
||||||
input: Annotated[Optional[List[str]], typer.Option(...)] = None,
|
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:
|
for input_str in input:
|
||||||
beaker, filename = input_str.split("=")
|
beaker, filename = input_str.split("=")
|
||||||
mod.csv_to_beaker(filename, beaker)
|
ctx.obj.csv_to_beaker(filename, beaker)
|
||||||
mod.run_once()
|
ctx.obj.run_once()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -152,6 +152,14 @@ class Recipe:
|
|||||||
for from_b, to_b, edge in self.graph.out_edges(node, data=True):
|
for from_b, to_b, edge in self.graph.out_edges(node, data=True):
|
||||||
print(f" {from_b} -> {to_b} ({edge})")
|
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):
|
def run_once(self):
|
||||||
log.info("run_once", recipe=self)
|
log.info("run_once", recipe=self)
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
Loading…
Reference in New Issue
Block a user