I don't have a solution, only a workaround:
undoCellContext[expr_] := Module[{ccSymbols, rules},
ccSymbols =
Cases[expr, _Symbol, \[Infinity]] // DeleteDuplicates //
Select[StringStartsQ["$CellContext`"]@*ToString];
rules = (# -> Symbol[SymbolName[#]]Symbol["Global`"<>SymbolName[#]]) & /@ ccSymbols;
expr /. rules
]
Once[...,"Notebook"] // undoCellContext
As an optimization, when LeafCount[expr]
is suitably large, undoCellContext
could switch from building a list and deleting duplicates to populating a HashSet within the delayed rule given to Cases.
It would also perhaps help if undoCellContext
held the expression, and the replacement symbols, unevaluated until it was done with it.
We could "Fix" Once on versions where it's misbehavinbg:
If[$VersionNumber<=14.,
Unprotect[Once];
Once`Private`$overridden = True;
Once[expr__,"Notebook"] := Block[{Once`Private`$overridden = False},
Once[expr, "Notebook"] // undoCellContext
] /; Once`Private`$overridden
Protect[Once];
]
For reference, Once
is not guilty. The underlying problem is that PersistentObject[...,"Notebook"]["Value"]
converts Global
on readout.</code> symbols to <code>$CellContext