disable coercion from str->bytes, fix coercion from str->object
[cython.git] / Cython / Compiler / Builtin.py
index a911fbe522ac772074535705010a1da25bbbeb50..64f8969c677514422b65deeb83f2a5a90b485920 100644 (file)
@@ -160,6 +160,11 @@ bad:
 
 pyexec_utility_code = UtilityCode(
 proto = """
+#if PY_VERSION_HEX < 0x02040000
+#ifndef Py_EVAL_H
+#include "eval.h"
+#endif
+#endif
 static PyObject* __Pyx_PyRun(PyObject*, PyObject*, PyObject*);
 """,
 impl = """
@@ -168,40 +173,61 @@ static PyObject* __Pyx_PyRun(PyObject* o, PyObject* globals, PyObject* locals) {
     PyObject* s = 0;
     char *code = 0;
 
-    if (!locals && !globals) {
+    if (!globals || globals == Py_None) {
         globals = PyModule_GetDict(%s);""" % Naming.module_cname + """
         if (!globals)
             goto bad;
+    } else if (!PyDict_Check(globals)) {
+        PyErr_Format(PyExc_TypeError, "exec() arg 2 must be a dict, not %.100s",
+                     globals->ob_type->tp_name);
+        goto bad;
+    }
+    if (!locals || locals == Py_None) {
         locals = globals;
-    } else if (!locals) {
-        locals = globals;
-    } else if (!globals) {
-        globals = locals;
     }
 
-    if (PyUnicode_Check(o)) {
-        s = PyUnicode_AsUTF8String(o);
-        if (!s) goto bad;
-        o = s;
-    #if PY_MAJOR_VERSION >= 3
-    } else if (!PyBytes_Check(o)) {
-    #else
-    } else if (!PyString_Check(o)) {
-    #endif
-        /* FIXME: support file objects and code objects */
-        PyErr_SetString(PyExc_TypeError,
-            "exec currently requires a string as code input.");
-        goto bad;
+
+    if (PyDict_GetItemString(globals, "__builtins__") == NULL) {
+       PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
     }
 
-    #if PY_MAJOR_VERSION >= 3
-    code = PyBytes_AS_STRING(o);
-    #else
-    code = PyString_AS_STRING(o);
-    #endif
-    result = PyRun_String(code, Py_file_input, globals, locals);
+    if (PyCode_Check(o)) {
+        if (PyCode_GetNumFree((PyCodeObject *)o) > 0) {
+            PyErr_SetString(PyExc_TypeError,
+                "code object passed to exec() may not contain free variables");
+            goto bad;
+        }
+       result = PyEval_EvalCode((PyCodeObject *)o, globals, locals);
+    } else {
+        PyCompilerFlags cf;
+        cf.cf_flags = 0;
+       if (PyUnicode_Check(o)) {
+            cf.cf_flags = PyCF_SOURCE_IS_UTF8;
+           s = PyUnicode_AsUTF8String(o);
+           if (!s) goto bad;
+           o = s;
+       #if PY_MAJOR_VERSION >= 3
+       } else if (!PyBytes_Check(o)) {
+       #else
+       } else if (!PyString_Check(o)) {
+       #endif
+           PyErr_SetString(PyExc_TypeError,
+               "exec: arg 1 must be string, bytes or code object");
+           goto bad;
+       }
+       #if PY_MAJOR_VERSION >= 3
+       code = PyBytes_AS_STRING(o);
+       #else
+       code = PyString_AS_STRING(o);
+       #endif
+       if (PyEval_MergeCompilerFlags(&cf)) {
+           result = PyRun_StringFlags(code, Py_file_input, globals, locals, &cf);
+        } else {
+           result = PyRun_String(code, Py_file_input, globals, locals);
+        }
+        Py_XDECREF(s);
+    }
 
-    Py_XDECREF(s);
     return result;
 bad:
     Py_XDECREF(s);
@@ -366,13 +392,15 @@ def init_builtins():
     init_builtin_funcs()
     init_builtin_types()
     init_builtin_structs()
-    global list_type, tuple_type, dict_type, set_type, bytes_type, unicode_type, type_type
+    global list_type, tuple_type, dict_type, set_type, type_type
+    global bytes_type, str_type, unicode_type
     type_type  = builtin_scope.lookup('type').type
     list_type  = builtin_scope.lookup('list').type
     tuple_type = builtin_scope.lookup('tuple').type
     dict_type  = builtin_scope.lookup('dict').type
     set_type   = builtin_scope.lookup('set').type
     bytes_type = builtin_scope.lookup('bytes').type
+    str_type   = builtin_scope.lookup('str').type
     unicode_type = builtin_scope.lookup('unicode').type
 
 init_builtins()