Handlers

Uriel allows you to optionally implement four handler functions, that are called at specific times every time you build your web site.

These handler functions are defined in the lib/handlers.py file in your project.

When Uriel first creates a new project, the contents of the lib/handlers.py look like this:

##############################################################################
# handlers.py                                                                #
##############################################################################

# The following symbols are imported using magic:
#
# import uriel
# from uriel import Page
# from uriel import Node
# from uriel import FileNode
# from uriel import VirtualNode
# from uriel import HandlerError
# from uriel import log
# from uriel import escape

#def init(project_root):
#    pass

#def before_render_node_tree(project_root, root_node):
#    pass

#def after_render_node_tree(project_root, root_node):
#    pass

#def cleanup(project_root, root_node):
#    pass

Notice how all of the functions are commented out? If a handler function doesn't exist, then Uriel will not call it.

To enable a handler function, uncomment it in lib/handlers.py and add your own code.

See the Uriel API Reference for more information about what is available to reference inside handler functions.

Uriel Execution Life Cycle

When Uriel builds your web site, it performs the following steps, in order. Handler function steps are highlighted in bold.

Step Comments
create_project_root When uriel is run against a directory name that does not exist, it will create the initial project root directory.
init_project_root Creates initial files and directories in the project root. Restores the public directory to match the contents of the static directory, deleting any previously generated files in the process.
init_modules Import the lib/soju.py and lib/handlers.py modules.
init() Calls the init(project_root) function in lib/handlers.py
create_file_node_tree Read the node files and turn them into an in-memory tree of Node object instances.
before_render_node_tree() Calls the before_render_node_tree(project_root, root_node) function in lib/handlers.py
augment_node_tree Augments Node object instances with additional values before rendering.
render_node_tree Renders nodes and templates together in memory, in preparation for writing the HTML files into the public directory.
after_render_node_tree() Calls the after_render_node_tree(project_root, root_node) function in lib/handlers.py. This is especially useful if you need to make any changes to the Node objects in memory after the HTML page rendering, but before the RSS feed rendering.
write_dynamic_nodes Writes the rendered nodes out to HTML files in the public directory.
write_additional_files Write additional generated files (RSS, Sitemap, robots.txt). If an RSS feed is generated, this step involves rendering some nodes a second time for the RSS feed.
copy_static_files The contents of the static directory are copied into the public directory.
cleanup() Calls the cleanup(project_root, root_node) function in lib/handlers.py

VirtualNode Example

On this documentation site, we have two handler functions defined. Here are the relevant functions from lib/handlers.py on this project:

def before_render_node_tree(project_root, root_node):
    # find the node for the Handlers page
    # (the nodes/handlers file)
    example_root = root_node.find_node_by_path("handlers")

    # create a new virtual node under the Handers page, with the node path
    # "handlers/virtual", as a child of the "handlers" node
    vnode = VirtualNode(project_root,
                        example_root.get_path() + "/virtual",
                        example_root)

    # add the VirtualNode to the list of child nodes for the parent
    # "handlers" node
    example_root.add_child(vnode)

    # N.B. we need to add the parent node in the VirtualNode constructor, and
    #      also call the add_child() method on the parent node, so that the
    #      parent/child relationship is established in both directions

    # set the Title and RSS-Include headers for this vnode
    #
    # uriel canonicalizes all header names to lowercase internally, so we
    # set headers in all lowercase when creating vnodes
    vnode.set_header("title", "VirtualNode Example")
    vnode.set_header("rss-include", "true")

    # set the node body contents
    vnode.set_body(
        "<p>Hello from a VirtualNode.</p>\n" +
        "\n" +
        "<p>See the {{node-link:handlers}} page for more details.</p>"
    )

def after_render_node_tree(project_root, root_node):
    # find the node for the virtual node we created earlier in the
    # before_render_node_tree() handler function
    vnode = root_node.find_node_by_path("handlers/virtual")

    # get the node body
    body = vnode.get_body()

    # modify our local copy of the node body contents
    body += "\n\n<p>This is a special message for RSS readers only.</p>"

    # set the node body to our modified string
    vnode.set_body(body)

The code above generates a new virtual node in its before_render_node_tree() implementation.

The after_render_node_tree() implementation also modifies the same virtual node, to change the node body contents before the RSS feed is generated.

You can see the results below:

Generated Page RSS Feed
VirtualNode Example https://documentation.uriel.foo/rss.xml

Tags: user-defined-python-code

This page was generated by Uriel with the following settings:

Page Details

Resource Path Project File
Node handlers nodes/handlers
Template default.html templates/default.html
URL /handlers/ public/handlers/index.html

Node Headers

Header (Lowercase) Value
tags user-defined-python-code
title Handlers
breadcrumb-separator &raquo;
canonical-url https://documentation.uriel.foo
rss-description Uriel Documentation
rss-image-height 32
rss-image-url /favicon-32x32.png
rss-image-width 32
rss-max-entries 50
rss-title Uriel Documentation
rss-url /rss.xml
sitemap-max-entries 10000
sitemap-url /sitemap.xml
tag-node tag
template default.html

Node Timestamps

Type Value
Created
Modified 2026-06-10T23:25:17-04:00

Node Methods

Method Value
get_parent_node() index
get_path() handlers
get_node_type() file
get_url() /handlers/
get_canonical_url() https://documentation.uriel.foo/handlers/
get_name() handlers
get_display_name() Handlers
get_title() Handlers
get_escaped_title() Handlers
get_link() <a href="/handlers/">Handlers</a>
get_canonical_link() <a href="https://documentation.uriel.foo/handlers/">Handlers</a>
get_link_prefix() <p>
get_link_suffix() </p>
get_tags() ['user-defined-python-code']
get_dest_dir() ./public/handlers
get_dest_file() ./public/handlers/index.html
get_breadcrumb_separator() &raquo;