Better error messages in CLI, closes #309

This commit is contained in:
Simon Willison 2021-08-09 15:25:52 -07:00
commit 14f643d9e9
2 changed files with 48 additions and 4 deletions

View file

@ -786,12 +786,25 @@ def insert_upsert_implementation(
db[table].insert_all(
docs, pk=pk, batch_size=batch_size, alter=alter, **extra_kwargs
)
except sqlite3.OperationalError as e:
if e.args and "has no column named" in e.args[0]:
except Exception as e:
if (
isinstance(e, sqlite3.OperationalError)
and e.args
and "has no column named" in e.args[0]
):
raise click.ClickException(
"{}\n\nTry using --alter to add additional columns".format(e.args[0])
)
raise
# If we can find sql= and params= arguments, show those
variables = _find_variables(e.__traceback__, ["sql", "params"])
if "sql" in variables and "params" in variables:
raise click.ClickException(
"{}\n\nsql = {}\nparams={}".format(
str(e), variables["sql"], variables["params"]
)
)
else:
raise
if tracker is not None:
db[table].transform(types=tracker.types)
@ -805,6 +818,18 @@ def _flatten(d):
yield key, value
def _find_variables(tb, vars):
to_find = list(vars)
found = {}
for var in to_find:
if var in tb.tb_frame.f_locals:
vars.remove(var)
found[var] = tb.tb_frame.f_locals[var]
if vars and tb.tb_next:
found.update(_find_variables(tb.tb_next, vars))
return found
@cli.command()
@insert_upsert_options
@click.option(

View file

@ -1256,7 +1256,11 @@ def test_upsert_alter(db_path, tmpdir):
cli.cli, ["upsert", db_path, "dogs", json_path, "--pk", "id"]
)
assert 1 == result.exit_code
assert "no such column: age" == str(result.exception)
assert (
"Error: no such column: age\n\n"
"sql = UPDATE [dogs] SET [age] = ? WHERE [id] = ?\n"
"params=[5, 1]"
) == result.output.strip()
# Should succeed with --alter
result = CliRunner().invoke(
cli.cli, ["upsert", db_path, "dogs", json_path, "--pk", "id", "--alter"]
@ -2304,3 +2308,18 @@ def test_insert_detect_types(tmpdir, option_or_env_var):
)
def test_flatten_helper(input, expected):
assert dict(cli._flatten(input)) == expected
def test_integer_overflow_error(tmpdir):
db_path = str(tmpdir / "test.db")
result = CliRunner().invoke(
cli.cli,
["insert", db_path, "items", "-"],
input=json.dumps({"bignumber": 34223049823094832094802398430298048240}),
)
assert result.exit_code == 1
assert result.output == (
"Error: Python int too large to convert to SQLite INTEGER\n\n"
"sql = INSERT INTO [items] ([bignumber]) VALUES (?);\n"
"params=[34223049823094832094802398430298048240]\n"
)