Usage in frameworks and Zope¶
One major issue with using compile_restricted directly in a framework is, that you have to use try-except statements to handle problems and it might be a bit harder to provide useful information to the user.
RestrictedPython provides four specialized compile_restricted methods:
compile_restricted_execcompile_restricted_evalcompile_restricted_singlecompile_restricted_function
Those four methods return a named tuple (CompileResult) with four elements:
code<code>object orNoneiferrorsis not emptyerrorsa tuple with error messages
warningsa list with warnings
used_namesa dictionary mapping collected used names to
True.
These details can be used to inform the user about the compiled source code.
Modifying the builtins is straight forward, it is just a dictionary containing the available library elements. Modification normally means removing elements from existing builtins or adding allowed elements by copying from globals.
For frameworks it could possibly also be useful to change the handling of specific Python language elements. For that use case RestrictedPython provides the possibility to pass an own policy.
A policy is basically a special NodeTransformer that could be instantiated with three params for errors, warnings and used_names, it should be a subclass of RestrictedPython.RestrictingNodeTransformer.
from RestrictedPython import compile_restricted
from RestrictedPython import RestrictingNodeTransformer
class OwnRestrictingNodeTransformer(RestrictingNodeTransformer):
pass
policy_instance = OwnRestrictingNodeTransformer(
errors=[],
warnings=[],
used_names=[]
)
All compile_restricted* methods do have an optional parameter policy, where a specific policy could be provided.
source_code = """
def do_something():
pass
"""
policy = OwnRestrictingNodeTransformer
byte_code = compile_restricted(
source_code,
filename='<inline code>',
mode='exec',
policy=policy # policy class
)
exec(byte_code, globals(), None)
One special case “unrestricted RestrictedPython” (defined to unblock ports of Zope Packages to Python 3) is to actually use RestrictedPython in an unrestricted mode, by providing a Null-Policy (aka None).
That special case would be written as:
from RestrictedPython import compile_restricted
source_code = """
def do_something():
pass
"""
byte_code = compile_restricted(
source_code,
filename='<inline code>',
mode='exec',
policy=None # Null-Policy -> unrestricted
)
exec(byte_code, globals(), None)