cli improved
This commit is contained in:
		
							parent
							
								
									44bfa767a6
								
							
						
					
					
						commit
						2fc2732a65
					
				
					 5 changed files with 67 additions and 11 deletions
				
			
		|  | @ -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 a new issue