Pyjo.Exception - Exception base class

import Pyjo.Exception

# Create exception classes
class MyApp_X_Foo(Pyjo.Exception.object):
    pass

class MyApp_X_Bar(Pyjo.Exception.object):
    pass

# Throw exceptions and handle them gracefully
from Pyjo.Exception import check
try:
    MyApp_X_Foo.throw('Something went wrong!')
except Exception as e:
    check(e, [
        (MyApp_X_Foo, lambda e: print(f'Foo: {e}')),
        (MyApp_X_Bar, lambda e: print(f'Bar: {e}')),
    ])

# Generate exception classes on demand
from Pyjo.Exception import check, throw
try:
    throw('MyApp.X.Name', 'The name Minion is already taken')
except Exception as e:
    check(e, [
        ('MyApp.X.Name', lambda e: print(f'Name error: {e}')),
        ('default', lambda e: print(f'Error: {e}')),
    ])

Pyjo.Exception is a container for exceptions with context information. It is an Exception, so it is raised and caught as the exceptions of Python are.

See also

Pyjoyment, https://mojolicious.org.

Ported from Mojo::Exception of Mojolicious 9.49.

Functions

exception Pyjo.Exception.Pyjo_Exception(message: Anything = None)[source]

Pyjo.Exception inherits all methods from Exception, Pyjo.Base and Pyjo.String.Mixin and implements the following new ones.

__bool__() → bool[source]
boolean = bool(e)

Always true.

__str__() → str[source]
string = str(e)

Alias for to_str().

frames: list[FrameSummary]
frames = e.frames
e.frames = [frame1, frame2]

Stack trace if available, as a list of traceback.FrameSummary, the most recent first.

# Extract information from the last frame
filename, lineno, name, line = e.frames[-1]
inspect(*sources: str) → Self[source]
e = e.inspect()
e = e.inspect(source1, source2)

Inspect message, frames and optional additional sources to fill lines_before, line and lines_after with context information.

line: list[int | str]
line = e.line
e.line = [3, 'raise Exception()']

The line where the exception occurred if available.

lines_after: list[list[int | str]]
lines = e.lines_after
e.lines_after = [[4, 'print(foo)'], [5, 'print(bar)']]

Lines after the line where the exception occurred if available.

lines_before: list[list[int | str]]
lines = e.lines_before
e.lines_before = [[1, 'foo = 23'], [2, 'bar = 24']]

Lines before the line where the exception occurred if available.

message: str
msg = e.message
e.message = 'Died at test.py line 3.'

Exception message, defaults to Exception!.

classmethod throw(message: Anything = None) → NoReturn[source]
Pyjo.Exception.object.throw('Something went wrong!')

Throw exception from the current execution context.

# Longer version
raise Pyjo.Exception.new('Something went wrong!').trace()
to_str() → str[source]
string = e.to_str()

Render exception. Note that the output format may change as more features are added, only the error message at the beginning is guaranteed not to be modified to allow regex matching.

trace(start: int = 1) → Self[source]
e = e.trace()
e = e.trace(skip)

Generate stack trace and store all frames, defaults to skipping 1 call frame.

# Skip 3 call frames
e.trace(3)

# Skip no call frames
e.trace(0)
property verbose: bool[source]
boolean = e.verbose
e.verbose = boolean

Show more information with to_str(), such as frames, defaults to the value of the PYJO_EXCEPTION_VERBOSE environment variable.

Pyjo.Exception.check(err: Anything, spec: list[tuple[Pattern | list[Pattern] | tuple[Pattern, ...], Callable[[Any], Anything]]]) → bool | None[source]
boolean = check(err, [(MyApp_X_Foo, lambda e: ...)])

Process exceptions by dispatching them to handlers with one or more matching conditions. Exceptions that could not be handled will be raised again automatically.

# Handle various types of exceptions
try:
    dangerous_code()
except Exception as e:
    check(e, [
        (MyApp_X_Foo, lambda e: print(f'Foo: {e}')),
        (re.compile(r'^Could not open'), lambda e: print(f'Open error: {e}')),
        ('default', lambda e: print(f'Something went wrong: {e}')),
    ])

Matching conditions can be classes, or their names, for checks with isinstance() on exception objects, or regular expressions to match string exceptions and stringified exception objects. The matching exception will be the argument passed to the callback.

# Catch MyApp_X_Foo object or a specific string exception
try:
    dangerous_code()
except Exception as e:
    check(e, [
        (MyApp_X_Foo, lambda e: print(f'Foo: {e}')),
        (re.compile(r'^Could not open'), lambda e: print(f'Open error: {e}')),
    ])

A list can be used to share the same handler with multiple conditions, of which only one needs to match. And since exception handlers are just callbacks, they can also throw their own exceptions.

# Handle MyApp_X_Foo and MyApp_X_Bar the same
try:
    dangerous_code()
except Exception as e:
    check(e, [
        ([MyApp_X_Foo, MyApp_X_Bar], lambda e: Pyjo.Exception.object.throw(f'Foo/Bar: {e}')),
    ])

There is currently only one keyword you can use to set special handlers. The default handler is used when no other handler matched.

# Use "default" to catch everything
try:
    dangerous_code()
except Exception as e:
    check(e, [
        ('default', lambda e: print(f'Error: {e}')),
    ])
Pyjo.Exception.throw(first: Anything, *rest: Anything) → NoReturn[source]
throw('Something went wrong!')
throw('MyApp.X.Foo', 'Something went wrong!')
throw(MyApp_X_Foo, 'Something went wrong!')

Raise a Pyjo.Exception, if the class does not exist yet, one is created as a Pyjo.Exception subclass on demand. raise_ is an alias, the name of Mojolicious with an underscore.