Skip to content

Commit

Permalink
redesigned context-not-available error to follow the same principles …
Browse files Browse the repository at this point in the history
…as other IQL errors, inherting from IQLError, thus enabled its handling by self-reflection mechanism
  • Loading branch information
ds-jakub-cierocki committed Jul 15, 2024
1 parent 273e217 commit 7f8b5f4
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 33 deletions.
21 changes: 0 additions & 21 deletions src/dbally/context/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
from abc import ABC


class BaseContextException(Exception, ABC):
"""
A base (abstract) exception for all specification context-related exception.
"""


class ContextNotAvailableError(Exception):
"""
An exception inheriting from BaseContextException pointining that no sufficient context information
was provided by the user while calling view.ask().
"""


class ContextualisationNotAllowed(Exception):
"""
An exception inheriting from BaseContextException pointining that the filter method signature
does not allow to provide an additional context.
"""


# WORKAROUND - traditional inhertiance syntax is not working in context of abstract Exceptions
BaseContextException.register(ContextNotAvailableError)
BaseContextException.register(ContextualisationNotAllowed)
48 changes: 44 additions & 4 deletions src/dbally/iql/_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import ast
from typing import Optional, Union
from typing_extensions import TypeAlias

from dbally.exceptions import DbAllyError


IQLNode: TypeAlias = Union[ast.stmt, ast.expr]


class IQLError(DbAllyError):
"""Base exception for all IQL parsing related exceptions."""
"""
Base exception for all IQL parsing related exceptions.
Attributes:
node: An IQL Node (AST Exprresion) during which processing an error was encountered.
source: Raw LLM response containing IQL filter calls.
"""

node: IQLNode
source: str

def __init__(self, message: str, node: Union[ast.stmt, ast.expr], source: str) -> None:
def __init__(self, message: str, node: IQLNode, source: str) -> None:
message = message + ": " + source[node.col_offset : node.end_col_offset]

super().__init__(message)
Expand All @@ -18,15 +31,15 @@ def __init__(self, message: str, node: Union[ast.stmt, ast.expr], source: str) -
class IQLArgumentParsingError(IQLError):
"""Raised when an argument cannot be parsed into a valid IQL."""

def __init__(self, node: Union[ast.stmt, ast.expr], source: str) -> None:
def __init__(self, node: IQLNode, source: str) -> None:
message = "Not a valid IQL argument"
super().__init__(message, node, source)


class IQLUnsupportedSyntaxError(IQLError):
"""Raised when trying to parse an unsupported syntax."""

def __init__(self, node: Union[ast.stmt, ast.expr], source: str, context: Optional[str] = None) -> None:
def __init__(self, node: IQLNode, source: str, context: Optional[str] = None) -> None:
node_name = node.__class__.__name__

message = f"{node_name} syntax is not supported in IQL"
Expand All @@ -47,3 +60,30 @@ def __init__(self, node: ast.Name, source: str) -> None:

class IQLArgumentValidationError(IQLError):
"""Raised when argument is not valid for a given method."""


class IQLContextNotAllowedError(IQLError):
"""
Raised when a context call/keyword has been passed as an argument to the filter
which does not support contextualization for this specific parameter.
"""

def __init__(
self,
node: IQLNode,
source: str,
arg_name: Optional[str] = None
) -> None:

if arg_name is None:
message = (
"The LLM detected that the context is required to execute the query"
"while the filter signature does not allow it at all."
)
else:
message = (
"The LLM detected that the context is required to execute the query"
f"while the filter signature does allow it for `{arg_name}` argument."
)

super().__init__(message, node, source)
12 changes: 4 additions & 8 deletions src/dbally/iql/_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
IQLError,
IQLFunctionNotExists,
IQLUnsupportedSyntaxError,
IQLContextNotAllowedError
)
from dbally.iql._type_validators import validate_arg_type
from dbally.views.exposed_functions import ExposedFunction, MethodParamWithTyping
Expand Down Expand Up @@ -134,6 +135,7 @@ def _parse_arg(
arg_spec: Optional[MethodParamWithTyping] = None,
parent_func_def: Optional[ExposedFunction] = None,
) -> Any:

if isinstance(arg, ast.List):
return [self._parse_arg(x) for x in arg.elts]

Expand All @@ -143,16 +145,10 @@ def _parse_arg(
raise IQLArgumentParsingError(arg, self.source)

if parent_func_def.context_class is None:
raise ContextualisationNotAllowed(
"The LLM detected that the context is required +\
to execute the query while the filter signature does not allow it at all."
)
raise IQLContextNotAllowedError(arg, self.source)

if not _does_arg_allow_context(arg_spec):
raise ContextualisationNotAllowed(
f"The LLM detected that the context is required +\
to execute the query while the filter signature does allow it for `{arg_spec.name}` argument."
)
raise IQLContextNotAllowedError(arg, self.source, arg_name=arg_spec.name)

return parent_func_def.context_class.select_context(self.contexts)

Expand Down

0 comments on commit 7f8b5f4

Please sign in to comment.