mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Completed the patch for Bug #215126.
* Fixes an incorrect variable in a PyDict_CheckExact. * Allow general mapping locals arguments for the execfile() function and exec statement. * Add tests.
This commit is contained in:
		
							parent
							
								
									32083f64a7
								
							
						
					
					
						commit
						66bd233225
					
				
					 5 changed files with 93 additions and 6 deletions
				
			
		|  | @ -282,6 +282,11 @@ def keys(self): | ||||||
|         self.assertEqual(eval('globals()', g, m), g) |         self.assertEqual(eval('globals()', g, m), g) | ||||||
|         self.assertEqual(eval('locals()', g, m), m) |         self.assertEqual(eval('locals()', g, m), m) | ||||||
|         self.assertRaises(TypeError, eval, 'a', m) |         self.assertRaises(TypeError, eval, 'a', m) | ||||||
|  |         class A: | ||||||
|  |             "Non-mapping" | ||||||
|  |             pass | ||||||
|  |         m = A() | ||||||
|  |         self.assertRaises(TypeError, eval, 'a', g, m) | ||||||
| 
 | 
 | ||||||
|         # Verify that dict subclasses work as well |         # Verify that dict subclasses work as well | ||||||
|         class D(dict): |         class D(dict): | ||||||
|  | @ -336,6 +341,26 @@ def test_execfile(self): | ||||||
|         locals['z'] = 0 |         locals['z'] = 0 | ||||||
|         execfile(TESTFN, globals, locals) |         execfile(TESTFN, globals, locals) | ||||||
|         self.assertEqual(locals['z'], 2) |         self.assertEqual(locals['z'], 2) | ||||||
|  | 
 | ||||||
|  |         class M: | ||||||
|  |             "Test mapping interface versus possible calls from execfile()." | ||||||
|  |             def __init__(self): | ||||||
|  |                 self.z = 10 | ||||||
|  |             def __getitem__(self, key): | ||||||
|  |                 if key == 'z': | ||||||
|  |                     return self.z | ||||||
|  |                 raise KeyError | ||||||
|  |             def __setitem__(self, key, value): | ||||||
|  |                 if key == 'z': | ||||||
|  |                     self.z = value | ||||||
|  |                     return | ||||||
|  |                 raise KeyError | ||||||
|  | 
 | ||||||
|  |         locals = M() | ||||||
|  |         locals['z'] = 0 | ||||||
|  |         execfile(TESTFN, globals, locals) | ||||||
|  |         self.assertEqual(locals['z'], 2) | ||||||
|  | 
 | ||||||
|         unlink(TESTFN) |         unlink(TESTFN) | ||||||
|         self.assertRaises(TypeError, execfile) |         self.assertRaises(TypeError, execfile) | ||||||
|         import os |         import os | ||||||
|  |  | ||||||
|  | @ -44,6 +44,63 @@ def test_duplicate_global_local(self): | ||||||
|         except SyntaxError: |         except SyntaxError: | ||||||
|             pass |             pass | ||||||
| 
 | 
 | ||||||
|  |     def test_exec_with_general_mapping_for_locals(self): | ||||||
|  | 
 | ||||||
|  |         class M: | ||||||
|  |             "Test mapping interface versus possible calls from eval()." | ||||||
|  |             def __getitem__(self, key): | ||||||
|  |                 if key == 'a': | ||||||
|  |                     return 12 | ||||||
|  |                 raise KeyError | ||||||
|  |             def __setitem__(self, key, value): | ||||||
|  |                 self.results = (key, value) | ||||||
|  |             def keys(self): | ||||||
|  |                 return list('xyz') | ||||||
|  | 
 | ||||||
|  |         m = M() | ||||||
|  |         g = globals() | ||||||
|  |         exec 'z = a' in g, m | ||||||
|  |         self.assertEqual(m.results, ('z', 12)) | ||||||
|  |         try: | ||||||
|  |             exec 'z = b' in g, m | ||||||
|  |         except NameError: | ||||||
|  |             pass | ||||||
|  |         else: | ||||||
|  |             self.fail('Did not detect a KeyError') | ||||||
|  |         exec 'z = dir()' in g, m | ||||||
|  |         self.assertEqual(m.results, ('z', list('xyz'))) | ||||||
|  |         exec 'z = globals()' in g, m | ||||||
|  |         self.assertEqual(m.results, ('z', g)) | ||||||
|  |         exec 'z = locals()' in g, m | ||||||
|  |         self.assertEqual(m.results, ('z', m)) | ||||||
|  |         try: | ||||||
|  |             exec 'z = b' in m | ||||||
|  |         except TypeError: | ||||||
|  |             pass | ||||||
|  |         else: | ||||||
|  |             self.fail('Did not validate globals as a real dict') | ||||||
|  | 
 | ||||||
|  |         class A: | ||||||
|  |             "Non-mapping" | ||||||
|  |             pass | ||||||
|  |         m = A() | ||||||
|  |         try: | ||||||
|  |             exec 'z = a' in g, m | ||||||
|  |         except TypeError: | ||||||
|  |             pass | ||||||
|  |         else: | ||||||
|  |             self.fail('Did not validate locals as a mapping') | ||||||
|  | 
 | ||||||
|  |         # Verify that dict subclasses work as well | ||||||
|  |         class D(dict): | ||||||
|  |             def __getitem__(self, key): | ||||||
|  |                 if key == 'a': | ||||||
|  |                     return 12 | ||||||
|  |                 return dict.__getitem__(self, key) | ||||||
|  |         d = D() | ||||||
|  |         exec 'z = a' in g, d | ||||||
|  |         self.assertEqual(d['z'], 12) | ||||||
|  | 
 | ||||||
|     def test_complex_args(self): |     def test_complex_args(self): | ||||||
| 
 | 
 | ||||||
|         def comp_args((a, b)): |         def comp_args((a, b)): | ||||||
|  |  | ||||||
|  | @ -269,7 +269,8 @@ Core and builtins | ||||||
| - Bug #951851: Python crashed when reading import table of certain | - Bug #951851: Python crashed when reading import table of certain | ||||||
|   Windows DLLs. |   Windows DLLs. | ||||||
| 
 | 
 | ||||||
| - Bug #215126.  The locals argument to eval() now accepts any mapping type. | - Bug #215126.  The locals argument to eval(), execfile(), and exec now | ||||||
|  |   accept any mapping type. | ||||||
| 
 | 
 | ||||||
| - marshal now shares interned strings. This change introduces | - marshal now shares interned strings. This change introduces | ||||||
|   a new .pyc magic. |   a new .pyc magic. | ||||||
|  |  | ||||||
|  | @ -539,11 +539,15 @@ builtin_execfile(PyObject *self, PyObject *args) | ||||||
| 	PyCompilerFlags cf; | 	PyCompilerFlags cf; | ||||||
| 	int exists; | 	int exists; | ||||||
| 
 | 
 | ||||||
| 	if (!PyArg_ParseTuple(args, "s|O!O!:execfile", | 	if (!PyArg_ParseTuple(args, "s|O!O:execfile", | ||||||
| 			&filename, | 			&filename, | ||||||
| 			&PyDict_Type, &globals, | 			&PyDict_Type, &globals, | ||||||
| 			&PyDict_Type, &locals)) | 			&locals)) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | 	if (locals != Py_None && !PyMapping_Check(locals)) { | ||||||
|  | 		PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
| 	if (globals == Py_None) { | 	if (globals == Py_None) { | ||||||
| 		globals = PyEval_GetGlobals(); | 		globals = PyEval_GetGlobals(); | ||||||
| 		if (locals == Py_None) | 		if (locals == Py_None) | ||||||
|  |  | ||||||
|  | @ -1643,7 +1643,7 @@ PyEval_EvalFrame(PyFrameObject *f) | ||||||
| 			w = GETITEM(names, oparg); | 			w = GETITEM(names, oparg); | ||||||
| 			v = POP(); | 			v = POP(); | ||||||
| 			if ((x = f->f_locals) != NULL) { | 			if ((x = f->f_locals) != NULL) { | ||||||
| 				if (PyDict_CheckExact(v)) | 				if (PyDict_CheckExact(x)) | ||||||
| 					err = PyDict_SetItem(x, w, v); | 					err = PyDict_SetItem(x, w, v); | ||||||
| 				else | 				else | ||||||
| 					err = PyObject_SetItem(x, w, v); | 					err = PyObject_SetItem(x, w, v); | ||||||
|  | @ -4116,9 +4116,9 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals, | ||||||
| 		    "exec: arg 2 must be a dictionary or None"); | 		    "exec: arg 2 must be a dictionary or None"); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	if (!PyDict_Check(locals)) { | 	if (!PyMapping_Check(locals)) { | ||||||
| 		PyErr_SetString(PyExc_TypeError, | 		PyErr_SetString(PyExc_TypeError, | ||||||
| 		    "exec: arg 3 must be a dictionary or None"); | 		    "exec: arg 3 must be a mapping or None"); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	if (PyDict_GetItemString(globals, "__builtins__") == NULL) | 	if (PyDict_GetItemString(globals, "__builtins__") == NULL) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Raymond Hettinger
						Raymond Hettinger