fix(page-data-script): make translation actually callable as _(...) - #745
fix(page-data-script): make translation actually callable as _(...)#745suparikoli wants to merge 2 commits into
_(...)#745Conversation
frappe._() in a Page Data Script never reaches frappe's translate
function at all: `frappe._` is an attribute read, and safe_exec's
_getattr_ guard rejects any attribute name starting with "_" before it
gets anywhere near resolving what "_" is bound to (see
_validate_attribute_read in frappe/utils/safe_exec.py). That's true no
matter where "_" is defined in the frappe namespace, so nesting it
differently wouldn't have helped.
A bare name reference isn't an attribute read, so `_(...)` at the top
level of the sandbox globals works fine - which is also where
frappe.utils.safe_exec's own render_safe_globals() puts it. Added the
same top-level `_=frappe._` to builder's get_safer_globals().
Added a test that runs a script through execute_script() using
`_("Supplier")` and checks it resolves instead of raising, plus an
assertion that `frappe._(...)` still fails the way it always will, so
nobody "fixes" this again by moving `_` back under the frappe
namespace.
Fixes frappe#626
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Reviews (2): Last reviewed commit: "chore: trim oversized comments" | Re-trigger Greptile |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #745 +/- ##
===========================================
+ Coverage 66.05% 71.20% +5.14%
===========================================
Files 37 63 +26
Lines 4982 7320 +2338
===========================================
+ Hits 3291 5212 +1921
- Misses 1691 2108 +417 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude <noreply@anthropic.com>
|
Automated review (Claude Code) Change looks correct. Two minor test nits (non-blocking):
This is an automated review and may be wrong — generated by a Claude Code devbox, not a human. |
Fixes #626.
The issue's diagnosis is right and I ran it down the same way to be sure before touching anything:
frappe._("Supplier")in a Page Data Script never gets anywhere nearfrappe._.frappe._is an attribute read, and RestrictedPython compiles that to_getattr_(frappe, "_"). That guard function is_getattr_for_safe_execinfrappe/utils/safe_exec.py, and it calls_validate_attribute_read, which rejects any attribute name starting with"_"unconditionally, before it even looks at what the attribute would resolve to:So nesting
_=frappe._differently inside thefrappenamespace wouldn't have changed anything -frappe._(...)can't work regardless of where_is defined, because it's the attribute access itself that's rejected, not a lookup failure.A bare name reference (
_("Supplier"), no dot) compiles to a plain global lookup, which doesn't go through_getattr_at all - RestrictedPython only wraps attribute access, not name resolution. That's exactly what frappe's ownrender_safe_globals()(the base sandbox builder'sget_safer_globals()extends) already relies on: it puts_=frappe._at the top level ofout, not underout.frappe. Builder's version has it nested one level down, which is the actual gap. Moved it to match.Added a test in
test_utils.pyalongside the existingexecute_scriptones: runsdata.text = _("Supplier")throughexecute_script()and checks it resolves to"Supplier"(no translation is loaded for that string in a test run, so it comes back unchanged, which is expected), and separately asserts thatfrappe._("Supplier")still raises - want that locked in so nobody "fixes" this again later by moving_back underfrappe, which would look reasonable but doesn't actually work.Ran
ruff checkandruff format --checkagainst both changed files - clean. Didn't have a live site to run the actual test against; the reasoning above is what I'm relying on instead, traced against currentfrappe/utils/safe_exec.pyandrender_safe_globals()rather than assumed.