Skip to content

API Reference: Errors & Exceptions

Dyno defines a structured exception hierarchy rooted in DynoError to facilitate error handling and debugging.


Bases: Exception

Base exception for all Dyno-specific errors.

Source code in src/dyno/errors.py
class DynoError(Exception):
    """Base exception for all Dyno-specific errors."""

Bases: DynoError

Raised when an operation requires symbols that are not defined.

Source code in src/dyno/errors.py
class UndefinedSymbolError(DynoError):
    """Raised when an operation requires symbols that are not defined."""

Bases: UserWarning

Warning raised when a model references undefined parameters or variables.

Source code in src/dyno/errors.py
class UndefinedSymbolWarning(UserWarning):
    """Warning raised when a model references undefined parameters or variables."""

Bases: DynoError

Raised when the system of equations has structural issues (e.g. non-square system).

Source code in src/dyno/errors.py
class SystemStructureError(DynoError):
    """Raised when the system of equations has structural issues (e.g. non-square system)."""

Bases: DynoError

Source code in src/dyno/errors.py
class SteadyStateError(DynoError):

    def __init__(
        self,
        residuals: Any,
        steady_stats: dict[str, Any] | None = None,
    ) -> None:
        self.residuals = residuals
        self.steady_stats = steady_stats
        message = f"Steady state values don't satisfy model equations. Max residual is {max(abs(r) for r in residuals)}"
        self.details = f"Residuals: {residuals}"
        super().__init__(message)

Bases: DynoError

Raised when Blanchard-Kahn eigenvalue conditions are not satisfied.

evs holds the generalized eigenvalues sorted by modulus, so that callers can still report them.

Source code in src/dyno/errors.py
class BlanchardKahnError(DynoError):
    """Raised when Blanchard-Kahn eigenvalue conditions are not satisfied.

    ``evs`` holds the generalized eigenvalues sorted by modulus, so that
    callers can still report them.
    """

    def __init__(self, message: str, evs: Any = None) -> None:
        self.evs = evs
        super().__init__(message)

Bases: DynoError

Source code in src/dyno/errors.py
class ParserError(DynoError):

    line: int | None
    column: int | None
    message: str
    details: str | None

    def __init__(self, message: str) -> None:
        self.line = None
        self.column = None
        self.details = None
        super().__init__(message)

Bases: ParserError

Source code in src/dyno/errors.py
class LARKParserError(ParserError):

    def __init__(self, lark_error: UnexpectedInput, txt=None) -> None:

        line = lark_error.line
        column = lark_error.column
        if isinstance(lark_error, UnexpectedCharacters):
            message = f"Unexpected characters at {(line,column)}"
        elif isinstance(lark_error, UnexpectedToken):
            value = lark_error.token.value
            if "\n" in value:
                value = "newline"
            message = f"Unexpected token `{value}` at {(line,column)}"
        elif isinstance(lark_error, UnexpectedEOF):
            message = f"Unexpected end of file at {(line,column)}"
        else:
            message = str(type(lark_error))

        if txt is not None:
            details = lark_error.get_context(txt)
            details += str(lark_error)
            hint = _annotation_hint(txt, line)
            if hint is not None:
                message = f"{message}. {hint}"
        else:
            details = str(lark_error)
        super().__init__(message)
        self.column = column
        self.line = line
        self.details = details

Bases: ParserError

Source code in src/dyno/errors.py
class DynareParserError(ParserError):

    def __init__(self, err: "PreprocessorException" | Exception | str) -> None:
        message = str(err)

        line: int | None = getattr(err, "line", None)
        if line is None:
            line = getattr(err, "begin_line", None)

        column: int | None = getattr(err, "column", None)
        if column is None:
            column = getattr(err, "begin_column", None)

        loc = getattr(err, "location", None)
        if loc is not None:
            if line is None:
                line = getattr(loc, "line", getattr(loc, "begin_line", None))
            if column is None:
                column = getattr(loc, "column", getattr(loc, "begin_column", None))

        # Typical dynare-preprocessor message formats:
        # "syntax error, unexpected TIMES: line 46, col 34"
        # "ERROR: in_memory.mod: line 3, cols 1-6: y is not a parameter"
        # "ERROR: in_memory.mod: lines 3-5, cols 1-6: syntax error"
        if line is None:
            m_line = re.search(r"\blines?\s+(\d+)", message, flags=re.IGNORECASE)
            if m_line is not None:
                line = int(m_line.group(1))

        if column is None:
            m_col = re.search(r"\bcols?\s+(\d+)", message, flags=re.IGNORECASE)
            if m_col is not None:
                column = int(m_col.group(1))

        super().__init__(message)
        self.line = line
        self.column = column
        self.details = message