Exceptions
Exception objects can not be created directly by UL4 templates, but UL4
templates can work with exceptions and access their attributes. The function
isexception returns True if the argument is an exception object and
exception objects have an attribute context that exposed the __cause__
or __context__ attribute of the Python exception object.
Exceptions that happen in UL4 templates use exception chaining to add
information about the location of the error while the exception bubbles up the
Python call stack. So the exception will be e.g. a TypeError object
and its __cause__ attribute (which is accessible as the UL4 attribute
context) specifies the immediate location inside the UL4 source code where
the exception happened (and its __cause__ is the location that called that
one etc.). So if we have the following UL4 template:
<?def x(i)?>
Print: <?print 1/i?>
Render: <?render x(i-1)?>
<?end def?>
Initial render: <?render x(3)?>
Calling the template will result in a ZeroDivisionError exception. We
can format a nice UL4 stacktrace (in HTML) for this exception with the
following UL4 code:
<?def frame(exc)?>
<?if exc.context?>
<?render frame(exc.context)?>
<?end if?>
<?if exc.location?>
<li>
<p>
<b><?printx type(exc)?></b>
in template <b><?printx exc.location.template.name?></b>
: line <?printx exc.location.line?>
; col <?printx exc.location.col?>
</p>
<p>
<?print exc.location.sourceprefix?>
<b><?print exc.location.source?></b>
<?print exc.location.sourcesuffix?>
</p>
</li>
<?else?>
<li>
<p>
<b><?printx type(exc).__name__?></b><?if str(exc)?>: <?print str(exc)?><?end if?>
</p>
</li>
<?end if?>
<?end def?>
<ul>
<?render frame(exc)?>
</ul>