Skip to content

Commit 28cde0e

Browse files
author
symphony-dbcli
committed
Fix #245: Resolve PR typecheck failures
1 parent 10c8341 commit 28cde0e

5 files changed

Lines changed: 40 additions & 29 deletions

File tree

litecli/main.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from datetime import datetime
1313
from io import open
1414
from time import time
15-
from typing import Any, Generator, Iterable, cast
15+
from typing import Any, Generator, Iterable, Literal, TextIO, cast
1616

1717
import click
1818
import sqlparse
@@ -75,13 +75,13 @@ def __init__(
7575
self,
7676
sqlexecute: SQLExecute | None = None,
7777
prompt: str | None = None,
78-
logfile: Any | None = None,
78+
logfile: TextIO | None = None,
7979
auto_vertical_output: bool = False,
8080
warn: bool | None = None,
8181
liteclirc: str | None = None,
8282
) -> None:
8383
self.sqlexecute = sqlexecute
84-
self.logfile = logfile
84+
self.logfile: TextIO | Literal[False] | None = logfile
8585

8686
# Load config.
8787
c = self.config = get_config(liteclirc)
@@ -473,7 +473,9 @@ def one_iteration(text: str | None = None) -> None:
473473
try:
474474
start = time()
475475
assert self.sqlexecute is not None
476-
cur = self.sqlexecute.conn and self.sqlexecute.conn.cursor()
476+
conn = self.sqlexecute.conn
477+
assert conn is not None
478+
cur = conn.cursor()
477479
context, sql, duration = special.handle_llm(text, cur)
478480
if context:
479481
click.echo("LLM Reponse:")
@@ -535,7 +537,9 @@ def one_iteration(text: str | None = None) -> None:
535537
except KeyboardInterrupt:
536538
try:
537539
# since connection can be sqlite3 or sqlean, it's hard to annotate the type for interrupt. so ignore the type hint warning.
538-
sqlexecute.conn.interrupt() # type: ignore[attr-defined]
540+
conn = sqlexecute.conn
541+
if conn is not None:
542+
conn.interrupt() # type: ignore[attr-defined]
539543
except Exception as e:
540544
self.echo(
541545
"Encountered error while cancelling query: {}".format(e),
@@ -792,7 +796,7 @@ def _on_completions_refreshed(self, new_completer: SQLCompleter) -> None:
792796

793797
def get_completions(self, text: str, cursor_positition: int) -> Iterable[Completion]:
794798
with self._completer_lock:
795-
return cast(Iterable[Completion], self.completer.get_completions(Document(text=text, cursor_position=cursor_positition), None))
799+
return self.completer.get_completions(Document(text=text, cursor_position=cursor_positition), None)
796800

797801
def get_prompt(self, string: str) -> str:
798802
self.logger.debug("Getting prompt %r", string)
@@ -934,7 +938,7 @@ def cli(
934938
database: str,
935939
dbname: str,
936940
prompt: str | None,
937-
logfile: Any | None,
941+
logfile: TextIO | None,
938942
auto_vertical_output: bool,
939943
table: bool,
940944
csv: bool,

litecli/packages/completion_engine.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import Any
3+
from typing import Any, cast
44

55
import sqlparse
66
from sqlparse.sql import Comparison, Identifier, Where, Token
@@ -243,7 +243,7 @@ def is_operand(x: str | None) -> bool:
243243
return [{"type": "user"}]
244244
elif token_v in ("select", "where", "having"):
245245
# Check for a table alias or schema qualification
246-
parent = (identifier and identifier.get_parent_name()) or []
246+
parent = _get_parent_name(identifier)
247247

248248
tables = extract_tables(full_text)
249249
if parent:
@@ -265,7 +265,7 @@ def is_operand(x: str | None) -> bool:
265265
elif (token_v.endswith("join") and isinstance(token, Token) and token.is_keyword) or (
266266
token_v in ("copy", "from", "update", "into", "describe", "truncate", "desc", "explain")
267267
):
268-
schema = (identifier and identifier.get_parent_name()) or []
268+
schema = _get_parent_name(identifier)
269269

270270
# Suggest tables from either the currently-selected schema or the
271271
# public schema if no schema has been specified
@@ -284,14 +284,14 @@ def is_operand(x: str | None) -> bool:
284284
elif token_v in ("table", "view", "function"):
285285
# E.g. 'DROP FUNCTION <funcname>', 'ALTER TABLE <tablname>'
286286
rel_type = token_v
287-
schema = (identifier and identifier.get_parent_name()) or []
287+
schema = _get_parent_name(identifier)
288288
if schema:
289289
return [{"type": rel_type, "schema": schema}]
290290
else:
291291
return [{"type": "schema"}, {"type": rel_type, "schema": []}]
292292
elif token_v == "on":
293293
tables = extract_tables(full_text) # [(schema, table, alias), ...]
294-
parent = (identifier and identifier.get_parent_name()) or []
294+
parent = _get_parent_name(identifier)
295295
if parent:
296296
# "ON parent.<suggestion>"
297297
# parent can be either a schema name or table alias
@@ -333,3 +333,11 @@ def is_operand(x: str | None) -> bool:
333333

334334
def identifies(id: Any, schema: str | None, table: str, alias: str | None) -> bool:
335335
return (id == alias) or (id == table) or (schema is not None and (id == schema + "." + table))
336+
337+
338+
def _get_parent_name(identifier: Identifier | None) -> str | list[str]:
339+
if identifier is None:
340+
return []
341+
342+
parent = identifier.get_parent_name()
343+
return cast(str, parent) if parent else []

litecli/packages/special/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
from __future__ import annotations
44
from types import FunctionType
55

6-
from typing import Callable, Any
6+
from typing import TypeVar
77

88
__all__: list[str] = []
99

10+
_Exported = TypeVar("_Exported")
1011

11-
def export(defn: Callable[..., Any]) -> Callable[..., Any]:
12+
13+
def export(defn: _Exported) -> _Exported:
1214
"""Decorator to explicitly mark functions that are exposed in a lib."""
13-
# ty, requires explict check for callable of tyep | function type to access __name__
15+
# ty requires an explicit callable/type check to access __name__.
1416
if isinstance(defn, (type, FunctionType)):
1517
globals()[defn.__name__] = defn
1618
__all__.append(defn.__name__)

litecli/packages/special/llm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def ensure_litecli_template(replace: bool = False) -> None:
264264

265265

266266
@export
267-
def handle_llm(text: str, cur: DBCursor) -> tuple[str, str | None, float]:
267+
def handle_llm(text: str, cur: DBCursor) -> tuple[str, str, float]:
268268
"""This function handles the special command `\\llm`.
269269
270270
If it deals with a question that results in a SQL query then it will return
@@ -375,7 +375,7 @@ def sql_using_llm(
375375
cur: DBCursor,
376376
question: str | None = None,
377377
verbose: bool = False,
378-
) -> tuple[str, str | None, str | None]:
378+
) -> tuple[str, str, str | None]:
379379
if cur is None:
380380
raise RuntimeError("Connect to a datbase and try again.")
381381
schema_query = """

tests/test_main.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from collections import namedtuple
55
from datetime import datetime
66
from textwrap import dedent
7+
from typing import Any, cast
78
from unittest.mock import patch
89

910
import click
@@ -149,9 +150,8 @@ def output(monkeypatch, terminal_size, testdata, explicit_pager, expect_pager):
149150

150151
class TestOutput:
151152
def get_size(self):
152-
size = namedtuple("Size", "rows columns")
153-
size.columns, size.rows = terminal_size
154-
return size
153+
Size = namedtuple("Size", "rows columns")
154+
return Size(rows=terminal_size[1], columns=terminal_size[0])
155155

156156
class TestExecute:
157157
host = "test"
@@ -166,7 +166,7 @@ class PromptBuffer(PromptSession):
166166
output = TestOutput()
167167

168168
m.prompt_app = PromptBuffer()
169-
m.sqlexecute = TestExecute()
169+
m.sqlexecute = cast(Any, TestExecute())
170170
m.explicit_pager = explicit_pager
171171

172172
def echo_via_pager(s):
@@ -233,18 +233,15 @@ def test_conditional_pager(monkeypatch):
233233
SPECIAL_COMMANDS["pager"].handler("")
234234

235235

236-
def test_reserved_space_is_integer():
236+
def test_reserved_space_is_integer(monkeypatch):
237237
"""Make sure that reserved space is returned as an integer."""
238238

239-
def stub_terminal_size():
240-
return (5, 5)
239+
def stub_terminal_size(_fallback=(80, 24)):
240+
return os.terminal_size((5, 5))
241241

242-
old_func = shutil.get_terminal_size
243-
244-
shutil.get_terminal_size = stub_terminal_size # type: ignore[assignment]
242+
monkeypatch.setattr(shutil, "get_terminal_size", stub_terminal_size)
245243
lc = LiteCli()
246244
assert isinstance(lc.get_reserved_space(), int)
247-
shutil.get_terminal_size = old_func
248245

249246

250247
@dbtest
@@ -285,7 +282,7 @@ def test_initialize_logging_expands_user_log_file(monkeypatch, tmp_path):
285282
monkeypatch.setenv("HOME", str(home))
286283
monkeypatch.setenv("USERPROFILE", str(home))
287284

288-
m = object.__new__(LiteCli)
285+
m = cast(Any, object.__new__(LiteCli))
289286
m.config = {"main": {"log_file": "~/.cache/litecli/log", "log_level": "INFO"}}
290287
echo_messages = []
291288
m.echo = lambda *args, **kwargs: echo_messages.append((args, kwargs))

0 commit comments

Comments
 (0)