diff --git a/CHANGELOG.md b/CHANGELOG.md index 862cfb5e9..e7b03477a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * [Fix] Updates errors so only the error message is displayed (and traceback is hidden) ([#407](https://github.com/ploomber/jupysql/issues/407)) * [Fix] Fixes `%sqlcmd plot` when `--table` or `--column` have spaces ([#409](https://github.com/ploomber/jupysql/issues/409)) * [Doc] Add QuestDB tutorial ([#350](https://github.com/ploomber/jupysql/issues/350)) +* [Feature] Better error messages when function used in plotting API unsupported by DB driver (#441) ## 0.7.1 (2023-04-19) @@ -283,4 +284,4 @@ Converted from an IPython Plugin to an Extension for 1.0 compatibility *Release date: 21-Mar-2013* -* Initial release +* Initial release \ No newline at end of file diff --git a/src/sql/plot.py b/src/sql/plot.py index e8c2be9cf..bbcbdca3b 100644 --- a/src/sql/plot.py +++ b/src/sql/plot.py @@ -6,6 +6,8 @@ from jinja2 import Template from sql.util import flatten +from sqlalchemy.exc import ProgrammingError +from sql import exceptions try: import matplotlib.pyplot as plt @@ -25,7 +27,7 @@ from sql import util -def _summary_stats(conn, table, column, with_=None): +def _summary_stats(conn, table, column, with_=None, driver=None): """Compute percentiles and mean for boxplot""" if not conn: @@ -44,7 +46,14 @@ def _summary_stats(conn, table, column, with_=None): query = template.render(table=table, column=column) - values = conn.execute(query, with_).fetchone() + try: + values = conn.execute(query, with_).fetchone() + except ProgrammingError as e: + print(e) + raise exceptions.UsageError( + f"\nEnsure that percentile_disc " f"function is available on {driver}." + ) + keys = ["q1", "med", "q3", "mean", "N"] return {k: float(v) for k, v in zip(keys, flatten(values))} @@ -124,7 +133,9 @@ def _between(conn, table, column, whislo, whishi, with_=None): # https://github.com/matplotlib/matplotlib/blob/b5ac96a8980fdb9e59c9fb649e0714d776e26701/lib/matplotlib/cbook/__init__.py @modify_exceptions -def _boxplot_stats(conn, table, column, whis=1.5, autorange=False, with_=None): +def _boxplot_stats( + conn, table, column, whis=1.5, autorange=False, with_=None, driver=None +): """Compute statistics required to create a boxplot""" if not conn: conn = sql.connection.Connection.current @@ -141,7 +152,8 @@ def _compute_conf_interval(N, med, iqr): stats = dict() # arithmetic mean - s_stats = _summary_stats(conn, table, column, with_=with_) + + s_stats = _summary_stats(conn, table, column, with_=with_, driver=driver) stats["mean"] = s_stats["mean"] q1, med, q3 = s_stats["q1"], s_stats["med"], s_stats["q3"] @@ -250,6 +262,8 @@ def boxplot(payload, table, column, *, orient="v", with_=None, conn=None, ax=Non payload["connection_info"] = conn._get_curr_sqlalchemy_connection_info() + driver = payload["connection_info"]["driver"] + ax = plt.gca() vert = orient == "v" @@ -257,13 +271,16 @@ def boxplot(payload, table, column, *, orient="v", with_=None, conn=None, ax=Non set_label = ax.set_ylabel if vert else ax.set_xlabel if isinstance(column, str): - stats = [_boxplot_stats(conn, table, column, with_=with_)] + stats = [_boxplot_stats(conn, table, column, with_=with_, driver=driver)] ax.bxp(stats, vert=vert) ax.set_title(f"{column!r} from {table!r}") set_label(column) set_ticklabels([column]) else: - stats = [_boxplot_stats(conn, table, col, with_=with_) for col in column] + stats = [ + _boxplot_stats(conn, table, col, with_=with_, driver=driver) + for col in column + ] ax.bxp(stats, vert=vert) ax.set_title(f"Boxplot from {table!r}") set_ticklabels(column) diff --git a/src/tests/integration/test_mssql.py b/src/tests/integration/test_mssql.py index 63057ea14..d5e1fd864 100644 --- a/src/tests/integration/test_mssql.py +++ b/src/tests/integration/test_mssql.py @@ -112,3 +112,16 @@ def test_sqlplot_boxplot(ip_with_MSSQL, cell): out = ip_with_MSSQL.run_cell(cell) assert type(out.result).__name__ in {"Axes", "AxesSubplot"} + + +def test_unsupported_function(ip_with_MSSQL, test_table_name_dict): + # clean current Axes + plt.cla() + out = ip_with_MSSQL.run_cell( + f"%sqlplot boxplot --table " f"{test_table_name_dict['taxi']} --column x" + ) + assert "Ensure that percentile_disc function is available" in str(out.error_in_exec) + assert ( + "If you need help solving this issue, " + "send us a message: https://ploomber.io/community" in str(out.error_in_exec) + )