Skip to content

frappe._() does not work inside a Builder Page Data Script, even though the function is included in the sandbox globals. #626

@frappenizer

Description

@frappenizer

Description

frappe._() does not work inside a Builder Page Data Script, even though the function is included in the sandbox globals.

Steps to reproduce

  1. Create a Builder Page
  2. Add a Page Data Script containing: data.update({"text": frappe._("Supplier")})
  3. Bind a text block's Data Key to text
  4. Preview the page

Expected behavior

The translated string appears (e.g. "Lieferant" for German).

Actual behavior

'str object' has no attribute 'get' — or an empty string is rendered.

Root cause

File: builder/builder/utils.py — function get_safer_globals()

The _ function is only available inside the frappe namespace (line 241):

frappe=NamespaceDict(
    ...
    _=frappe._,   # line 241 — only here
    ...
)

When the sandbox script calls frappe._("text"), RestrictedPython compiles the attribute access frappe._ into _getattr_(frappe, "_"). The _getattr_ guard (from frappe.utils.safe_exec._validate_attribute_read) blocks all attribute names starting with _:

# frappe/utils/safe_exec.py line 571:
if name.startswith("_"):
    raise AttributeError(f'"{name}" is an invalid attribute name because it starts with "_"')

This means frappe._() can never succeed — the guard kills it before the function is ever reached.

Fix

Add _=frappe._ to the top-level of the out NamespaceDict, matching how Frappe's own get_safe_globals() works:

Environment

  • Frappe/ERPNext version: v16
  • Builder version: 1.24.7

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions