mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +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('locals()', g, m), 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 | ||||
|         class D(dict): | ||||
|  | @ -336,6 +341,26 @@ def test_execfile(self): | |||
|         locals['z'] = 0 | ||||
|         execfile(TESTFN, globals, locals) | ||||
|         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) | ||||
|         self.assertRaises(TypeError, execfile) | ||||
|         import os | ||||
|  |  | |||
|  | @ -44,6 +44,63 @@ def test_duplicate_global_local(self): | |||
|         except SyntaxError: | ||||
|             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 comp_args((a, b)): | ||||
|  |  | |||
|  | @ -269,7 +269,8 @@ Core and builtins | |||
| - Bug #951851: Python crashed when reading import table of certain | ||||
|   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 | ||||
|   a new .pyc magic. | ||||
|  |  | |||
|  | @ -539,11 +539,15 @@ builtin_execfile(PyObject *self, PyObject *args) | |||
| 	PyCompilerFlags cf; | ||||
| 	int exists; | ||||
| 
 | ||||
| 	if (!PyArg_ParseTuple(args, "s|O!O!:execfile", | ||||
| 	if (!PyArg_ParseTuple(args, "s|O!O:execfile", | ||||
| 			&filename, | ||||
| 			&PyDict_Type, &globals, | ||||
| 			&PyDict_Type, &locals)) | ||||
| 			&locals)) | ||||
| 		return NULL; | ||||
| 	if (locals != Py_None && !PyMapping_Check(locals)) { | ||||
| 		PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if (globals == Py_None) { | ||||
| 		globals = PyEval_GetGlobals(); | ||||
| 		if (locals == Py_None) | ||||
|  |  | |||
|  | @ -1643,7 +1643,7 @@ PyEval_EvalFrame(PyFrameObject *f) | |||
| 			w = GETITEM(names, oparg); | ||||
| 			v = POP(); | ||||
| 			if ((x = f->f_locals) != NULL) { | ||||
| 				if (PyDict_CheckExact(v)) | ||||
| 				if (PyDict_CheckExact(x)) | ||||
| 					err = PyDict_SetItem(x, w, v); | ||||
| 				else | ||||
| 					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"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (!PyDict_Check(locals)) { | ||||
| 	if (!PyMapping_Check(locals)) { | ||||
| 		PyErr_SetString(PyExc_TypeError, | ||||
| 		    "exec: arg 3 must be a dictionary or None"); | ||||
| 		    "exec: arg 3 must be a mapping or None"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (PyDict_GetItemString(globals, "__builtins__") == NULL) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Raymond Hettinger
						Raymond Hettinger