Skip to content

Commit

Permalink
re-organizing modules to prevent importing errors (#787)
Browse files Browse the repository at this point in the history
  • Loading branch information
neelasha23 authored Aug 28, 2023
1 parent b538512 commit 0e9d363
Show file tree
Hide file tree
Showing 22 changed files with 852 additions and 793 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* [Fix] Fix Twice message printing when switching to the current connection ([#772](https://github.com/ploomber/jupysql/issues/772))
* [Fix] Error when using %sqlplot in snowflake ([#697](https://github.com/ploomber/jupysql/issues/697))
* [Doc] Fixes documentation inaccuracy that said `:variable` was deprecated (we brought it back in `0.9.0`)
* [Fix] Descriptive error messages when specific syntax error occurs when running query in DuckDB or Oracle.

## 0.9.1 (2023-08-10)

Expand Down
15 changes: 8 additions & 7 deletions src/sql/cmd/snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from sql.exceptions import UsageError
from sql.cmd.cmd_utils import CmdParser
from sql.store import store
from sql import store_utils
from sql.display import Table, Message


Expand Down Expand Up @@ -64,7 +65,7 @@ def snippets(others):
help="Force delete all stored snippets",
required=False,
)
all_snippets = util.get_all_keys()
all_snippets = store_utils.get_all_keys()
if len(others) == 1:
if others[0] in all_snippets:
return str(store[others[0]])
Expand All @@ -87,7 +88,7 @@ def snippets(others):
return Table(["Stored snippets"], [[snippet] for snippet in all_snippets])

if args.delete:
deps = util.get_key_dependents(args.delete)
deps = store_utils.get_key_dependents(args.delete)
if deps:
deps = ", ".join(deps)
raise UsageError(
Expand All @@ -97,18 +98,18 @@ def snippets(others):
)
else:
key = args.delete
remaining_keys = util.del_saved_key(key)
remaining_keys = store_utils.del_saved_key(key)
return _modify_display_msg(key, remaining_keys)

elif args.delete_force:
key = args.delete_force
deps = util.get_key_dependents(key)
remaining_keys = util.del_saved_key(key)
deps = store_utils.get_key_dependents(key)
remaining_keys = store_utils.del_saved_key(key)
return _modify_display_msg(key, remaining_keys, deps)

elif args.delete_force_all:
deps = util.get_key_dependents(args.delete_force_all)
deps = store_utils.get_key_dependents(args.delete_force_all)
deps.append(args.delete_force_all)
for key in deps:
remaining_keys = util.del_saved_key(key)
remaining_keys = store_utils.del_saved_key(key)
return _modify_display_msg(", ".join(deps), remaining_keys)
8 changes: 2 additions & 6 deletions src/sql/connection/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from sql.store import store
from sql.telemetry import telemetry
from sql import exceptions, display
from sql.error_message import detail
from sql.error_handler import handle_exception
from sql.parse import (
escape_string_literals_with_colon_prefix,
find_named_parameters,
Expand Down Expand Up @@ -935,11 +935,7 @@ def _start_sqlalchemy_connection(cls, engine, connect_str):
connection = engine.connect()
return connection
except OperationalError as e:
detailed_msg = detail(e)
if detailed_msg is not None:
raise exceptions.RuntimeError(detailed_msg) from e
else:
raise exceptions.RuntimeError(str(e)) from e
handle_exception(e)
except Exception as e:
raise _error_invalid_connection_info(e, connect_str) from e

Expand Down
102 changes: 102 additions & 0 deletions src/sql/error_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from sql import display
from sql import util
from sql.store_utils import get_all_keys
from sql.exceptions import RuntimeError, TableNotFoundError


ORIGINAL_ERROR = "\nOriginal error message from DB driver:\n"
CTE_MSG = (
"If using snippets, you may pass the --with argument explicitly.\n"
"For more details please refer: "
"https://jupysql.ploomber.io/en/latest/compose.html#with-argument"
)
POSTGRES_MSG = """\nLooks like you have run into some issues.
Review our DB connection via URL strings guide:
https://jupysql.ploomber.io/en/latest/connecting.html .
Using Ubuntu? Check out this guide: "
https://help.ubuntu.com/community/PostgreSQL#fe_sendauth:_
no_password_supplied\n"""


def _snippet_typo_error_message(query):
"""Function to generate message for possible
snippets if snippet name in user query is a
typo
"""
if query:
tables = util.extract_tables_from_query(query)
for table in tables:
suggestions = util.find_close_match(table, get_all_keys())
err_message = f"There is no table with name {table!r}."
if len(suggestions) > 0:
suggestions_message = util.get_suggestions_message(suggestions)
return f"{err_message}{suggestions_message}"
return ""


def _detailed_message_with_error_type(error, query):
"""Function to generate descriptive error message.
Currently it handles syntax error messages, table not found messages
and password issue when connecting to postgres
"""
original_error = str(error)
syntax_error_substrings = [
"syntax error",
"error in your sql syntax",
"incorrect syntax",
"invalid sql",
]
not_found_substrings = [
"does not exist",
"not found",
"could not find",
"no such table",
]
if util.if_substring_exists(original_error.lower(), syntax_error_substrings):
return f"{CTE_MSG}\n\n{ORIGINAL_ERROR}{original_error}\n", RuntimeError
elif util.if_substring_exists(original_error.lower(), not_found_substrings):
typo_err_msg = _snippet_typo_error_message(query)
if typo_err_msg:
return (
f"{CTE_MSG}\n\n{typo_err_msg}\n\n"
f"{ORIGINAL_ERROR}{original_error}\n",
TableNotFoundError,
)
else:
return f"{CTE_MSG}\n\n{ORIGINAL_ERROR}{original_error}\n", RuntimeError
elif "fe_sendauth: no password supplied" in original_error:
return f"{POSTGRES_MSG}\n{ORIGINAL_ERROR}{original_error}\n", RuntimeError
return None, None


def _display_error_msg_with_trace(error, message):
"""Displays the detailed error message and prints
original stack trace as well."""
if message is not None:
display.message(message)
error.modify_exception = True
raise error


def _raise_error(error, message, error_type):
"""Raise specific error from the detailed message. If detailed
message is None reraise original error"""
if message is not None:
raise error_type(message) from error
else:
raise RuntimeError(str(error)) from error


def handle_exception(error, query=None, short_error=True):
"""
This function is the entry point for detecting error type
and handling it accordingly.
"""
if util.is_sqlalchemy_error(error) or util.is_non_sqlalchemy_error(error):
detailed_message, error_type = _detailed_message_with_error_type(error, query)
if short_error:
_raise_error(error, detailed_message, error_type)
else:
_display_error_msg_with_trace(error, detailed_message)
else:
raise error
39 changes: 0 additions & 39 deletions src/sql/error_message.py

This file was deleted.

Loading

0 comments on commit 0e9d363

Please sign in to comment.