Contexts

Contexts are a feature of the hook-based extension system in Tutor, which allows us to keep track of which components of the code created which callbacks. Contexts are very much an internal concept that most plugin developers should not have to worry about.

class tutor.core.hooks.Context(name)

Contexts are used to track in which parts of the code filters and actions have been declared. Let’s look at an example:

from tutor.core.hooks import contexts

with contexts.enter("c1"):
    @filters.add("f1")
    def add_stuff_to_filter(...):
        ...

The fact that our custom filter was added in a certain context allows us to later remove it. To do so, we write:

from tutor import hooks
filters.clear("f1", context="c1")

For instance, contexts make it easy to disable side-effects by plugins, provided they were created with a specific context.

Parameters:

name (str) –

tutor.core.hooks.contexts.enter(name)

Identify created hooks with one or multiple context strings.

Parameters:

name (str) – name of the context that will be attached to hooks.

Rtype t.ContextManager[None]:

Usage:

from tutor.core import hooks

with hooks.contexts.enter("my-context"):
    # declare new actions and filters
    ...

# Later on, actions and filters that were created within this context can be
# disabled with:
hooks.actions.clear_all(context="my-context")
hooks.filters.clear_all(context="my-context")

This is a context manager that will attach a context name to all hook callbacks created within its scope. The purpose of contexts is to solve an issue that is inherent to pluggable hooks: it is difficult to track in which part of the code each hook callback was created. This makes things hard to debug when a single hook callback goes wrong. It also makes it impossible to disable some hook callbacks after they have been created.

We resolve this issue by storing the current contexts in a static list. Whenever a hook is created, the list of current contexts is copied as a contexts attribute. This attribute can be later examined, either for removal or for limiting the set of hook callbacks that should be applied.