Skip to content

NLTRenderer

The main class for rendering NLT templates. Imported from pyrx_nlt.

python
from pyrx_nlt import NLTRenderer, RenderResult

Constructor

python
class NLTRenderer:
def __init__(
self,
contact: dict[str, Any],
trigger_event: dict[str, Any] | None = None,
additional_events: dict[str, dict[str, Any]] | None = None,
event_store: EventStore | None = None,
template_loader: TemplateLoader | None = None,
) -> None: ...

Parameters

ParameterTypeDefaultDescription
contactdict[str, Any](required)Contact data with flat fields and properties JSONB. Keys at root level are accessed in snake_case; keys in properties are accessed in original case then snake_case.
trigger_eventdict[str, Any] | NoneNoneThe event that triggered this template render. Must have event_name (str) and attributes (dict) keys.
additional_eventsdict[str, dict[str, Any]] | NoneNoneAdditional named events, keyed by event name. Each value must have an attributes dict.
event_storeEventStore | NoneNoneOptional async event lookup protocol for fetching events not in additional_events.
template_loaderTemplateLoader | NoneNoneOptional template loader for {extends} template inheritance.

Data Structure

python
contact = {
"first_name": "Jane", # flat fields (snake_case)
"email": "[email protected]",
"properties": { # nested JSONB
"Plan": "premium",
"Address": {"City": "NYC", "State": "NY"},
"Tags": ["vip", "active"],
"Orders": [
{"Name": "Widget", "Price": 29.99},
],
},
}
 
trigger_event = {
"event_name": "purchase",
"attributes": {
"Order ID": "ORD-001",
"Amount": 99.99,
},
}
 
additional_events = {
"signup": {"attributes": {"Source": "referral"}},
"payment": {"attributes": {"Amount": 150.00}},
}

render()

python
def render(
self,
subject_template: str,
body_template: str,
) -> RenderResult

Render both subject and body templates. Resets suppression state before each call.

If any required expression in either the subject or body resolves to null, the entire result is suppressed -- both html and subject are set to None.

Parameters

ParameterTypeDescription
subject_templatestrNLT template string for the email subject line.
body_templatestrNLT template string for the email body HTML.

Returns

RenderResult -- see RenderResult below.

Example

python
result = renderer.render(
subject_template='Order `{the Order ID from the trigger event}`',
body_template='<p>Total: `{the Amount from the trigger event, as "currency"}`</p>',
)
 
if not result.suppressed:
send_email(subject=result.subject, html=result.html)

render_text()

python
def render_text(self, template: str) -> str | None

Render a single template string, resolving all AST nodes. Returns None if any required expression suppresses the send.

Parameters

ParameterTypeDescription
templatestrNLT template string to render.

Returns

str | None -- the rendered text, or None if suppressed.

Example

python
text = renderer.render_text("Hello, `{the user's First Name}`!")
# "Hello, Jane!"
 
suppressed = renderer.render_text("`{the user's Policy Number, required}`")
# None (if Policy Number is missing)

resolve()

python
def resolve(self, expr: NLTExpression) -> str | None

Resolve a single NLTExpression to its string value. Applies math, transforms, formatting, filters, and pluralization in order. Returns None if the expression has required=True and the value is missing. Sets self.suppressed as a side effect.

Resolution Order

  1. Resolve raw value from data source
  2. Handle null: check required, apply fallback, return empty string
  3. Apply math operation (if present)
  4. Convert to string
  5. Apply text transform (uppercase / lowercase / titlecase / capitalize)
  6. Apply format spec (currency / date / percentage)
  7. Apply filter chain (operates on raw value, re-resolved)
  8. Apply pluralization

Parameters

ParameterTypeDescription
exprNLTExpressionA parsed NLT expression dataclass.

Returns

str | None -- the resolved string value, or None if suppressed.


resolve_raw()

python
def resolve_raw(
self,
source: str,
attribute_path: str,
event_name: str | None = None,
) -> Any

Resolve a source/attribute to a raw Python value (not stringified). Used internally by list, table, aggregate, for-loop, and condition nodes that need the original data type (list, dict, number) rather than a string.

Parameters

ParameterTypeDescription
sourcestrData source: "user", "trigger_event", or "named_event".
attribute_pathstrThe attribute name, e.g. "First Name", "Orders". Supports dot notation for nested access.
event_namestr | NoneEvent name for named_event source. None for other sources.

Returns

Any -- the raw Python value (dict, list, number, string, or None).


RenderResult

python
from pyrx_nlt import RenderResult
 
@dataclass
class RenderResult:
html: str | None # Rendered HTML body, None if suppressed
subject: str | None # Rendered subject line, None if suppressed
suppressed: bool = False # True if any required field was missing
suppressed_reason: str | None = None # Descriptive reason for suppression
unresolved_expressions: list[str] = [] # Expressions that could not be parsed
has_rendering_errors: bool = False # True if any expressions were unresolved
FieldTypeDescription
htmlstr | NoneThe rendered HTML body. None if the send was suppressed.
subjectstr | NoneThe rendered subject line. None if the send was suppressed.
suppressedboolTrue if any required expression resolved to null. Defaults to False.
suppressed_reasonstr | NoneA human-readable description of why the send was suppressed, e.g. "Required attribute 'Order ID' is missing".
unresolved_expressionslist[str]List of {...} expression blocks that could not be parsed. These are left as literal text in the output.
has_rendering_errorsboolTrue if any expressions in the template could not be resolved. Convenience flag equivalent to len(unresolved_expressions) > 0.

EventStore Protocol

python
from pyrx_nlt.renderer import EventStore
 
class EventStore(Protocol):
async def get_latest(
self,
contact_id: str,
event_name: str,
) -> dict[str, Any] | None: ...

Protocol for looking up the latest event of a given type for a contact. Used as a fallback when an event referenced in a template is not available in additional_events.

Note

Currently reserved for future async integration. The synchronous rendering pipeline does not invoke async methods. Defined for forward compatibility.

Return Value

A dict with an attributes key containing the event data, or None if no matching event exists:

python
{"attributes": {"Amount": 150.00, "Status": "completed"}}

TemplateLoader Protocol

python
from pyrx_nlt.renderer import TemplateLoader
 
class TemplateLoader(Protocol):
def load(self, template_name: str) -> str | None: ...

Protocol for loading base templates by name, used by the {extends} template inheritance feature.

Parameters

ParameterTypeDescription
template_namestrThe name of the template to load, as specified in {extends "name"}.

Returns

str | None -- the raw template string, or None if the template is not found. If None is returned, the child template is rendered as-is.