Customizing one instance#

@Renderer.register(...) changes a renderer class and every instance created from it. To change one renderer object only, call register_handler on the instance. It takes the same classifiers as register.

"""Per-instance customization: one MarkdownRenderer that hides import lines."""
from handcalcs.renderers import MarkdownRenderer


def hide_import(renderer, node, base_context):
    return ""


def make_renderer():
    renderer = MarkdownRenderer()
    renderer.register_handler("import", hide_import)
    return renderer
import math
a = 2
b = math.sqrt(a)
Output (MarkdownRenderer)
\[\begin{aligned} a &= 2 \\ b &= \sqrt{a} = \sqrt{2} = 1.4142 \end{aligned}\]
$$\begin{aligned} a &= 2 \\ b &= \sqrt{a} = \sqrt{2} = 1.4142 \end{aligned}$$

Other MarkdownRenderer objects still show imports.

When to use it#

  • Quick experiments in a notebook, without defining a class.

  • Per-request settings in an application, where each request builds its own renderer.

  • Tests, where a handler must not leak into other tests.

For anything you reuse, a subclass is clearer: it has a name, can be selected in Jupyter, and can be imported from your own package.

How it works#

Each renderer instance copies its class’s handler and rule tables when it is created, and register_handler adds to the copies. Registering a bare node type ("import") replaces that node’s handler; registering a rule ("import:post") appends to that node’s rule list. Instances created before a class-level register call keep the old tables.

Next: the cookbook, for complete recipes.