[Python-checkins] r51912 - in python/branches/bcannon-objcap: Lib/test/test_interpreter.py Modules/interpretermodule.c securing_python.txt

brett.cannon python-checkins at python.org
Mon Sep 18 23:27:52 CEST 2006


Author: brett.cannon
Date: Mon Sep 18 23:27:51 2006
New Revision: 51912

Modified:
   python/branches/bcannon-objcap/Lib/test/test_interpreter.py
   python/branches/bcannon-objcap/Modules/interpretermodule.c
   python/branches/bcannon-objcap/securing_python.txt
Log:
Rework interface for getting the built-ins namespace dict.  Since it is cached
the instant you create an interpreter by the initial execution frame, make it
so that you need a function call to return the dict.  That way people realize
they cannot reassign the dict but it can be mutated.

Need to verify that the sys_dict and modules dicts don't have the same issue.


Modified: python/branches/bcannon-objcap/Lib/test/test_interpreter.py
==============================================================================
--- python/branches/bcannon-objcap/Lib/test/test_interpreter.py	(original)
+++ python/branches/bcannon-objcap/Lib/test/test_interpreter.py	Mon Sep 18 23:27:51 2006
@@ -1,12 +1,3 @@
-"""XXX Use case tests:
-    * cannot open files
-        - test removal of open() as well as change to bz2.
-    * block imports
-        - built-ins
-        - .pyc/.pyo
-        - extension modules
-
-"""
 import interpreter
 
 import unittest
@@ -28,6 +19,12 @@
     to_return.append(False)
 """
 
+test_builtins_contains = """
+import __builtin__
+_return.append(__builtin__.__dict__.__contains__("%s"))
+"""
+
+
 class BaseInterpTests(unittest.TestCase):
 
     def setUp(self):
@@ -49,52 +46,45 @@
 
 class BuiltinsTests(BaseInterpTests):
 
-    """Test interpreter.Interpreter().builtins ."""
+    """Test interpreter.Interpreter().builtins() ."""
 
     def test_get(self):
         # Test the getting of 'builtins'.
-        builtins = self.interp.builtins
+        builtins = self.interp.builtins()
         self.failUnless(isinstance(builtins, dict))
         self.failUnless('object' in builtins)
 
-    def test_set(self):
-        # Make sure setting 'builtins' can be done and has proper type
-        # checking.
-        self.interp.builtins = {}
-        self.failUnlessRaises(TypeError, setattr, self.interp, 'builtins', [])
-
     def test_remove(self):
         # Make sure that something can be removed from built-ins.
-        # XXX
-        pass
+        builtins = self.interp.builtins()
+        del builtins['open']
+        _return = []
+        builtins['_return'] = _return
+        self.interp.execute(test_builtins_contains % 'open')
+        self.failUnless(not _return[-1])
 
     def test_add_remove(self):
         # Make sure you can add to the built-ins and then remove the same
         # object.
-        self.interp.builtins['test'] = 'test'
-        self.interp.execute('test')
-        del self.interp.builtins['test']
-        # XXX self.failUnlessRaises(XXX, interp.execute, 'test')
-
-
-    def test_empty_builtins(self):
-        # Make sure that emptying the built-ins truly make them non-existent.
-        self.interp.builtins = {}
-        # XXX self.failUnlessRaises(XXX, interp.execute, 'object')
-
+        self.interp.builtins()['test'] = 'test'
+        _return = []
+        self.interp.builtins()['_return'] = _return
+        self.interp.execute(test_builtins_contains % 'test')
+        self.failUnless(_return[-1])
+        del self.interp.builtins()['test']
+        self.interp.execute(test_builtins_contains % 'test')
+        self.failUnless(not _return[-1])
+        
     def test_copied(self):
         # Make sure built-ins are unique per interpreter.
-        self.failUnless(self.interp.builtins is not __builtin__.__dict__)
-
-        try:
-            __builtin__.__dict__['test1'] = 'test1'
-            self.failUnless('test1' not in self.interp.builtins)
-        finally:
-            del __builtin__.__dict__['test1']
-        self.interp.builtins['test2'] = 'test2'
-        self.failUnless('test2' not in __builtin__.__dict__)
-
-
+        master_id = id(__builtin__.__dict__)
+        _return = []
+        self.interp.builtins()['_return'] = _return
+        self.interp.execute('import __builtin__;'
+                            '_return.append(id(__builtin__.__dict__))')
+        self.failUnless(_return[-1] != master_id)
+        
+                            
 class ModulesTests(BaseInterpTests):
 
     """Test interpreter.Interpreter().modules ."""
@@ -153,7 +143,7 @@
         sys_dict = self.interp.sys_dict
         sys_dict['version'] = 'test'
         interp_return = []
-        self.interp.builtins['to_return'] = interp_return
+        self.interp.builtins()['to_return'] = interp_return
         self.interp.execute(test_sys_changed)
         self.failUnless(interp_return[0])
 
@@ -183,7 +173,7 @@
 
     def test_file_restrictions(self):
         # You cannot open a file.
-        del self.interp.builtins['open']
+        del self.interp.builtins()['open']
         try:
             self.interp.execute("open(%s, 'w')" % test_support.TESTFN)
         finally:

Modified: python/branches/bcannon-objcap/Modules/interpretermodule.c
==============================================================================
--- python/branches/bcannon-objcap/Modules/interpretermodule.c	(original)
+++ python/branches/bcannon-objcap/Modules/interpretermodule.c	Mon Sep 18 23:27:51 2006
@@ -99,45 +99,29 @@
     Py_RETURN_NONE;
 }
 
-static PyMethodDef interpreter_methods[] = {
-    {"execute", interpreter_exec, METH_O,
-	"Execute the passed-in string in the interpreter"},
-    {NULL}
-};
-
-
 /*
-   Getter for 'builtins'.
-*/
+ Getter for 'builtins'.
+ 
+ There is not setter because the creation of a new interpreter automatically
+ creates the initial execution frame which caches the built-in namespace.
+ */
 static PyObject *
-interpreter_get_builtins(PyObject *self, void *optional)
+interpreter_builtins(PyObject *self)
 {
-	PyObject *builtins = PyInterpreter_GET_INTERP(self)->builtins;
-
-	Py_INCREF(builtins);
-	return builtins;
+    PyObject *builtins = PyInterpreter_GET_INTERP(self)->builtins;
+    
+    Py_INCREF(builtins);
+    return builtins;
 }
 
-/*
-   Setter for 'builtins'.
-*/
-static int
-interpreter_set_builtins(PyObject *self, PyObject *arg, void *optional)
-{
-	PyObject *old_builtins = PyInterpreter_GET_INTERP(self)->builtins;
-
-	if (!PyDict_CheckExact(arg)) {
-		PyErr_SetString(PyExc_TypeError,
-				"'builtins' must be set to a dict");
-		return -1;
-	}
-
-	Py_INCREF(arg);
-	Py_DECREF(old_builtins);
-	PyInterpreter_GET_INTERP(self)->builtins = arg;
+static PyMethodDef interpreter_methods[] = {
+    {"builtins", (PyCFunction)interpreter_builtins, METH_NOARGS,
+        "Return the built-in namespace dict"},
+    {"execute", interpreter_exec, METH_O,
+	"Execute the passed-in string in the interpreter"},
+    {NULL}
+};
 
-	return 0;
-}
 
 /*
    Getter for 'modules'.
@@ -207,8 +191,6 @@
 
 
 static PyGetSetDef interpreter_getset[] = {
-	{"builtins", interpreter_get_builtins, interpreter_set_builtins,
-		"The built-ins dict for the interpreter.", NULL},
 	{"sys_dict", interpreter_get_sys_dict, interpreter_set_sys_dict,
 		"The modules dict for 'sys'.", NULL},
 	{"modules", interpreter_get_modules, interpreter_set_modules,

Modified: python/branches/bcannon-objcap/securing_python.txt
==============================================================================
--- python/branches/bcannon-objcap/securing_python.txt	(original)
+++ python/branches/bcannon-objcap/securing_python.txt	Mon Sep 18 23:27:51 2006
@@ -43,11 +43,7 @@
       interrupt_main() not per-interpreter, and stack_size() can be
       dangerous)
 + Create sandboxed interpreter stdlib module <critical>
-    - Be able to specify built-ins
-        * XXX frames cache built-ins, so setting to a new dict does
-          not get propagated; need to either change ability to assign
-          to built-ins or add functions that allow to set and delete
-          keys individually.
+    - Be able to specify built-ins [done]
     - Set 'sys' module settings
     - Set 'sys.modules'
     - API


More information about the Python-checkins mailing list