Patch 560023 adding docstrings. 2.2 Candidate (after verifying modules were not updated after 2.2).
diff --git a/Lib/rexec.py b/Lib/rexec.py
index 411fcc5..6dc1585a 100644
--- a/Lib/rexec.py
+++ b/Lib/rexec.py
@@ -114,8 +114,18 @@
class RExec(ihooks._Verbose):
+ """Basic restricted execution framework.
- """Restricted Execution environment."""
+ Code executed in this restricted environment will only have access to
+ modules and functions that are deemed safe; you can subclass RExec to
+ add or remove capabilities as desired.
+
+ The RExec class can prevent code from performing unsafe operations like
+ reading or writing disk files, or using TCP/IP sockets. However, it does
+ not protect against code using extremely large amounts of memory or
+ processor time.
+
+ """
ok_path = tuple(sys.path) # That's a policy decision
@@ -135,6 +145,33 @@
nok_builtin_names = ('open', 'file', 'reload', '__import__')
def __init__(self, hooks = None, verbose = 0):
+ """Returns an instance of the RExec class.
+
+ The hooks parameter is an instance of the RHooks class or a subclass
+ of it. If it is omitted or None, the default RHooks class is
+ instantiated.
+
+ Whenever the RExec module searches for a module (even a built-in one)
+ or reads a module's code, it doesn't actually go out to the file
+ system itself. Rather, it calls methods of an RHooks instance that
+ was passed to or created by its constructor. (Actually, the RExec
+ object doesn't make these calls --- they are made by a module loader
+ object that's part of the RExec object. This allows another level of
+ flexibility, which can be useful when changing the mechanics of
+ import within the restricted environment.)
+
+ By providing an alternate RHooks object, we can control the file
+ system accesses made to import a module, without changing the
+ actual algorithm that controls the order in which those accesses are
+ made. For instance, we could substitute an RHooks object that
+ passes all filesystem requests to a file server elsewhere, via some
+ RPC mechanism such as ILU. Grail's applet loader uses this to support
+ importing applets from a URL for a directory.
+
+ If the verbose parameter is true, additional debugging output may be
+ sent to standard output.
+
+ """
ihooks._Verbose.__init__(self, verbose)
# XXX There's a circular reference here:
self.hooks = hooks or RHooks(verbose)
@@ -250,24 +287,67 @@
# The r* methods are public interfaces
def r_exec(self, code):
+ """Execute code within a restricted environment.
+
+ The code parameter must either be a string containing one or more
+ lines of Python code, or a compiled code object, which will be
+ executed in the restricted environment's __main__ module.
+
+ """
m = self.add_module('__main__')
exec code in m.__dict__
def r_eval(self, code):
+ """Evaluate code within a restricted environment.
+
+ The code parameter must either be a string containing a Python
+ expression, or a compiled code object, which will be evaluated in
+ the restricted environment's __main__ module. The value of the
+ expression or code object will be returned.
+
+ """
m = self.add_module('__main__')
return eval(code, m.__dict__)
def r_execfile(self, file):
+ """Execute the Python code in the file in the restricted
+ environment's __main__ module.
+
+ """
m = self.add_module('__main__')
execfile(file, m.__dict__)
def r_import(self, mname, globals={}, locals={}, fromlist=[]):
+ """Import a module, raising an ImportError exception if the module
+ is considered unsafe.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ """
return self.importer.import_module(mname, globals, locals, fromlist)
def r_reload(self, m):
+ """Reload the module object, re-parsing and re-initializing it.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ """
return self.importer.reload(m)
def r_unload(self, m):
+ """Unload the module.
+
+ Removes it from the restricted environment's sys.modules dictionary.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ """
return self.importer.unload(m)
# The s_* methods are similar but also swap std{in,out,err}
@@ -325,26 +405,105 @@
return r
def s_exec(self, *args):
+ """Execute code within a restricted environment.
+
+ Similar to the r_exec() method, but the code will be granted access
+ to restricted versions of the standard I/O streams sys.stdin,
+ sys.stderr, and sys.stdout.
+
+ The code parameter must either be a string containing one or more
+ lines of Python code, or a compiled code object, which will be
+ executed in the restricted environment's __main__ module.
+
+ """
return self.s_apply(self.r_exec, args)
def s_eval(self, *args):
+ """Evaluate code within a restricted environment.
+
+ Similar to the r_eval() method, but the code will be granted access
+ to restricted versions of the standard I/O streams sys.stdin,
+ sys.stderr, and sys.stdout.
+
+ The code parameter must either be a string containing a Python
+ expression, or a compiled code object, which will be evaluated in
+ the restricted environment's __main__ module. The value of the
+ expression or code object will be returned.
return self.s_apply(self.r_eval, args)
+ """
+
def s_execfile(self, *args):
+ """Execute the Python code in the file in the restricted
+ environment's __main__ module.
+
+ Similar to the r_execfile() method, but the code will be granted
+ access to restricted versions of the standard I/O streams sys.stdin,
+ sys.stderr, and sys.stdout.
+
+ """
return self.s_apply(self.r_execfile, args)
def s_import(self, *args):
+ """Import a module, raising an ImportError exception if the module
+ is considered unsafe.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ Similar to the r_import() method, but has access to restricted
+ versions of the standard I/O streams sys.stdin, sys.stderr, and
+ sys.stdout.
+
+ """
return self.s_apply(self.r_import, args)
def s_reload(self, *args):
+ """Reload the module object, re-parsing and re-initializing it.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ Similar to the r_reload() method, but has access to restricted
+ versions of the standard I/O streams sys.stdin, sys.stderr, and
+ sys.stdout.
+
+ """
return self.s_apply(self.r_reload, args)
def s_unload(self, *args):
+ """Unload the module.
+
+ Removes it from the restricted environment's sys.modules dictionary.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ Similar to the r_unload() method, but has access to restricted
+ versions of the standard I/O streams sys.stdin, sys.stderr, and
+ sys.stdout.
+
+ """
return self.s_apply(self.r_unload, args)
# Restricted open(...)
def r_open(self, file, mode='r', buf=-1):
+ """Method called when open() is called in the restricted environment.
+
+ The arguments are identical to those of the open() function, and a
+ file object (or a class instance compatible with file objects)
+ should be returned. RExec's default behaviour is allow opening
+ any file for reading, but forbidding any attempt to write a file.
+
+ This method is implicitly called by code executing in the
+ restricted environment. Overriding this method in a subclass is
+ used to change the policies enforced by a restricted environment.
+
+ """
if mode not in ('r', 'rb'):
raise IOError, "can't open files for writing in restricted mode"
return open(file, mode, buf)