Coverage for art_studio_tz/cli.py: 61%
130 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-28 09:38 +0200
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-28 09:38 +0200
1"""Command Line Interface (CLI) for quotes project."""
2import os
3from io import StringIO
4from sqlalchemy.engine import Engine
5import pathlib
6import rich
7from rich.table import Table
8from contextlib import contextmanager
9from typing import List
11import art_studio_tz
13import typer
17app = typer.Typer(add_completion=True)
20@app.command()
21def version():
22 """Return version of app_quote application"""
23 print(art_studio_tz.__version__)
25@app.command()
26def start(url: str = typer.Option("https://zenquotes.io/api/random", "-u", "--url", help="URL for get quotes, default https://zenquotes.io/api/random"),
27 pause: float = typer.Option(5, "-p", "--pause", help="pause between requests quotes in seconds, default 5 seconds")):
28 """Get quote from url and add to db. with pause between requests.
29 url - URL for get quotes, default https://zenquotes.io/api/random
30 pause - pause between requests quotes in seconds, default 5 seconds"""
31 with quote_db() as db:
32 try:
33 db.start(url, pause)
34 except art_studio_tz.BadReqest:
35 print(f"Could not get quote from {url}")
37@app.command("list")
38def list_quote(
39 author: str = typer.Option(None, "-a", "--author", help="sort for author")
40):
41 """
42 List quotes in db.
43 """
44 with quote_db() as db:
45 the_quote = db.list_quote(author=author)
46 table = Table(box=rich.box.SIMPLE)
47 table.add_column("ID")
48 table.add_column("TimeStep")
49 table.add_column("Quote")
50 table.add_column("Author")
51 for t in the_quote:
52 author = "" if t.author is None else t.author
53 table.add_row(str(t.id),t.timestep, t.text, author)
54 out = StringIO()
55 rich.print(table, file=out)
56 print(out.getvalue())
58@app.command()
59def add(
60 text: List[str],
61 author: str = typer.Option(None, "-a", "--author", help="Author quote")
62):
63 """Add a quote to db."""
64 text = " ".join(text) if text else None
65 with quote_db() as db:
66 db.add_quote(art_studio_tz.Quote(text=text, author=author))
68@app.command()
69def delete(quote_id: int):
70 """Remove quote in db with given id."""
71 with quote_db() as db:
72 try:
73 db.delete_quote(quote_id)
74 except art_studio_tz.InvalidQuoteId:
75 print(f"Error: Invalid qupte id {quote_id}")
77@app.command()
78def update(
79 quote_id: int,
80 author: str = typer.Option(None, "-o", "--owner"),
81 text: List[str] = typer.Option(None, "-t", "--text"),
82):
83 """Modify a quote in db with given id with new info."""
84 text = " ".join(text) if text else None
85 with quote_db() as db:
86 try:
87 db.update_quote(
88 quote_id, art_studio_tz.Quote(text=text, author=author)
89 )
90 except art_studio_tz.InvalidQuoteId:
91 print(f"Error: Invalid quote id {quote_id}")
93@app.command()
94def config():
95 """List the path to the quotes db."""
96 with quote_db() as db:
97 print(db.path())
100@app.command()
101def count():
102 """Return number of quotes in db."""
103 with quote_db() as db:
104 print(db.count())
106@app.command()
107def get(user: str = typer.Option(..., "-u", "--user", help="Database user"),
108 password: str = typer.Option(..., "-p", "--password", help="Database password"),
109 host: str = typer.Option("localhost", "-H", "--host", help="Database host, default localhost"),
110 port: int = typer.Option(3306, "-P", "--port", help="Database port, default 3306"),
111 database: str = typer.Option("quotes_db", "-d", "--database", help="Database name, default quotes_db"),
112 url: str = typer.Option("https://zenquotes.io/api/quotes", "--url", help="URL for get quotes, default https://zenquotes.io/api/random"),
113 ):
114 """Get 50 quotes from url and add to mySQL"""
115 with quote_db_sql(user=user, password=password, host=host, port=port, database=database) as db_sql:
116 try:
117 db_sql.get_some_quotes(url)
118 except art_studio_tz.BadReqest:
119 print(f"Could not get quote from {url}")
121@app.command()
122def list_sql(
123 user: str = typer.Option(..., "-u", "--user", help="Database user"),
124 password: str = typer.Option(..., "-p", "--password", help="Database password"),
125 host: str = typer.Option("localhost", "-H", "--host", help="Database host, default localhost"),
126 port: int = typer.Option(3306, "-P", "--port", help="Database port, default 3306"),
127 database: str = typer.Option("quotes_db", "-d", "--database", help="Database name, default quotes_db"),
128 author: str = typer.Option(None, "-a", "--author", help="sort for author")
129):
130 """
131 List quotes in mySQL
132 """
133 with quote_db_sql(user=user, password=password, host=host, port=port, database=database) as db_sql:
134 the_quote = db_sql.list_quote(author=author)
135 table = Table(box=rich.box.SIMPLE)
136 table.add_column("ID")
137 table.add_column("TimeStep")
138 table.add_column("Quote")
139 table.add_column("Author")
140 for t in the_quote:
141 author = "" if t.author is None else t.author
142 table.add_row(str(t.id), str(t.timestep), t.text, author)
143 out = StringIO()
144 rich.print(table, file=out)
145 print(out.getvalue())
147@app.command()
148def delete_all_sql(user: str = typer.Option(..., "-u", "--user", help="Database user"),
149 password: str = typer.Option(..., "-p", "--password", help="Database password"),
150 host: str = typer.Option("localhost", "-H", "--host", help="Database host, default localhost"),
151 port: int = typer.Option(3306, "-P", "--port", help="Database port, default 3306"),
152 database: str = typer.Option("quotes_db", "-d", "--database", help="Database name, default quotes_db"),
153 ):
154 """Delete all quotes in mySQL"""
155 with quote_db_sql(user=user, password=password, host=host, port=port, database=database) as db_sql:
156 try:
157 db_sql.delete_all()
158 except Exception as err:
159 print(f"Could not delete quotes in {database} because {err}")
161@app.command()
162def list_latest_5(
163 user: str = typer.Option(..., "-u", "--user", help="Database user"),
164 password: str = typer.Option(..., "-p", "--password", help="Database password"),
165 host: str = typer.Option("localhost", "-H", "--host", help="Database host, default localhost"),
166 port: int = typer.Option(3306, "-P", "--port", help="Database port, default 3306"),
167 database: str = typer.Option("quotes_db", "-d", "--database", help="Database name, default quotes_db"),
168 number: int = typer.Option(5, "-n", "--number", help="Number of latest quotes to list, default 5")
169):
170 """
171 list latest 'number' quotes in mySQL, default 5
172 """
173 with quote_db_sql(user=user, password=password, host=host, port=port, database=database) as db_sql:
174 the_quote = db_sql.get_latest(number)
175 table = Table(box=rich.box.SIMPLE)
176 table.add_column("ID")
177 table.add_column("TimeStep")
178 table.add_column("Quote")
179 table.add_column("Author")
180 for t in the_quote:
181 author = "" if t.author is None else t.author
182 table.add_row(str(t.id), str(t.timestep), t.text, author)
183 out = StringIO()
184 rich.print(table, file=out)
185 print(out.getvalue())
187@app.callback(invoke_without_command=True)
188def main(ctx: typer.Context):
189 """
190 quotes is a small command line task tracking application.
191 """
192 if ctx.invoked_subcommand is None:
193 list_quote(author=None)
195def get_path():
197 db_path_env = os.getenv("QUOTES_DB_DIR", "")
198 if db_path_env:
199 db_path = pathlib.Path(db_path_env)
200 else:
201 db_path = pathlib.Path(os.getcwd())
202 return db_path
205@contextmanager
206def quote_db():
207 """Context manager for QuoteDB.
209 Yields:
210 QuoteDB: QuoteDB instance
211 """
212 db_path = get_path()
213 db = art_studio_tz.QuoteDB(db_path)
214 yield db
216@contextmanager
217def quote_db_sql(user: str, password: str, host: str, port: int, database: str):
218 """
219 Context manager for QuoteDBsql.
221 Args:
222 user (str): username for database
223 password (str): password for database
224 host (str): hostname for database
225 port (int): port for database
226 database (str): database name
228 Yields:
229 QuoteDBsql: QuoteDBsql instance
230 """
231 db = art_studio_tz.QuoteDBsql(user=user, password=password, host=host, port=port, database=database)
232 try:
233 yield db
234 finally:
235 if hasattr(db, "engine") and isinstance(db.engine, Engine):
236 db.engine.dispose()