[pypy-commit] pypy py3k: kill prepare_exec, most of it was already reimpl. in rpython anyway,

pjenvey noreply at buildbot.pypy.org
Fri Dec 14 00:36:22 CET 2012


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r59419:114108122293
Date: 2012-12-13 15:12 -0800
http://bitbucket.org/pypy/pypy/changeset/114108122293/

Log:	kill prepare_exec, most of it was already reimpl. in rpython anyway,
	cleanup/reuse its replacements in compile/eval/exec. support
	memoryview source

diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -498,23 +498,30 @@
         self.w_locals = self.popvalue()
 
     def exec_(self, w_prog, w_globals, w_locals):
-        """The ___builtin__.exec function."""
-        ec = self.space.getexecutioncontext()
+        """The builtins.exec function."""
+        space = self.space
+        ec = space.getexecutioncontext()
         flags = ec.compiler.getcodeflags(self.pycode)
-        w_compile_flags = self.space.wrap(flags)
-        w_resulttuple = prepare_exec(self.space, self.space.wrap(self), w_prog,
-                                     w_globals, w_locals,
-                                     w_compile_flags,
-                                     self.space.wrap(self.get_builtin()),
-                                     self.space.gettypeobject(PyCode.typedef))
-        w_prog, w_globals, w_locals = self.space.fixedview(w_resulttuple, 3)
+
+        if space.isinstance_w(w_prog, space.gettypeobject(PyCode.typedef)):
+            code = space.interp_w(PyCode, w_prog)
+        else:
+            from pypy.interpreter.astcompiler import consts
+            flags |= consts.PyCF_SOURCE_IS_UTF8
+            source, flags = source_as_str(
+                space, w_prog, 'exec', "string, bytes or code", flags)
+            code = ec.compiler.compile(source, "<string>", 'exec', flags)
+
+        w_globals, w_locals = ensure_ns(space, w_globals, w_locals, 'exec',
+                                        self)
+        space.call_method(w_globals, 'setdefault', space.wrap('__builtins__'),
+                          space.wrap(self.get_builtin()))
 
         plain = (self.w_locals is not None and
-                 self.space.is_w(w_locals, self.w_locals))
+                 space.is_w(w_locals, self.w_locals))
         if plain:
             w_locals = self.getdictscope()
-        co = self.space.interp_w(eval.Code, w_prog)
-        co.exec_code(self.space, w_globals, w_locals)
+        code.exec_code(space, w_globals, w_locals)
         if plain:
             self.setdictscope(w_locals)
 
@@ -1369,6 +1376,58 @@
         self.operr = operr
 
 
+def source_as_str(space, w_source, funcname, what, flags):
+    """Return an unwrapped string (without NUL bytes) from some kind of
+    wrapped source string and adjusted compiler flags"""
+    from pypy.interpreter.astcompiler import consts
+
+    if space.isinstance_w(w_source, space.w_unicode):
+        source = space.unicode0_w(w_source).encode('utf-8')
+        flags |= consts.PyCF_IGNORE_COOKIE
+    elif space.isinstance_w(w_source, space.w_bytes):
+        source = space.bytes0_w(w_source)
+    else:
+        try:
+            source = space.bufferstr0_new_w(w_source)
+        except OperationError as e:
+            if not e.match(space, space.w_TypeError):
+                raise
+            raise operationerrfmt(space.w_TypeError,
+                                  "%s() arg 1 must be a %s object",
+                                  funcname, what)
+    return source, flags
+
+
+def ensure_ns(space, w_globals, w_locals, funcname, caller=None):
+    """Ensure globals/locals exist and are of the correct type"""
+    if (not space.is_none(w_globals) and
+        not space.isinstance_w(w_globals, space.w_dict)):
+        raise operationerrfmt(space.w_TypeError,
+                              '%s() arg 2 must be a dict, not %s',
+                              funcname, space.type(w_globals).getname(space))
+    if (not space.is_none(w_locals) and
+        space.lookup(w_locals, '__getitem__') is None):
+        raise operationerrfmt(space.w_TypeError,
+                              '%s() arg 3 must be a mapping or None, not %s',
+                              funcname, space.type(w_locals).getname(space))
+
+    if space.is_none(w_globals):
+        if caller is None:
+            caller = space.getexecutioncontext().gettopframe_nohidden()
+        if caller is None:
+            w_globals = space.newdict()
+            if space.is_none(w_locals):
+                w_locals = w_globals
+        else:
+            w_globals = caller.w_globals
+            if space.is_none(w_locals):
+                w_locals = caller.getdictscope()
+    elif space.is_none(w_locals):
+        w_locals = w_globals
+
+    return w_globals, w_locals
+
+
 ### helpers written at the application-level ###
 # Some of these functions are expected to be generally useful if other
 # parts of the code need to do the same thing as a non-trivial opcode,
@@ -1485,43 +1544,3 @@
 ''', filename=__file__)
 
 import_all_from = app.interphook('import_all_from')
-
-app = gateway.applevel(r'''
-    def prepare_exec(f, prog, globals, locals, compile_flags, builtin, codetype):
-        """Manipulate parameters to exec statement to (codeobject, dict, dict).
-        """
-        if (globals is None and locals is None and
-            isinstance(prog, tuple) and
-            (len(prog) == 2 or len(prog) == 3)):
-            globals = prog[1]
-            if len(prog) == 3:
-                locals = prog[2]
-            prog = prog[0]
-        if globals is None:
-            globals = f.f_globals
-            if locals is None:
-                locals = f.f_locals
-        if locals is None:
-            locals = globals
-
-        if not isinstance(globals, dict):
-            raise TypeError(
-                "exec() arg 2 must be a dict or None, not %s" %
-                type(globals).__name__)
-        globals.setdefault('__builtins__', builtin)
-        if not isinstance(locals, dict):
-            if not hasattr(locals, '__getitem__'):
-                raise TypeError(
-                    "exec() arg 3 must be a mapping or None, not %s" %
-                    type(locals).__name__)
-
-        if not isinstance(prog, codetype):
-            filename = '<string>'
-            if not isinstance(prog, (str, bytes)):
-                raise TypeError("exec() arg 1 must be a string, bytes, "
-                                "or code object")
-            prog = compile(prog, filename, 'exec', compile_flags, 1)
-        return (prog, globals, locals)
-''', filename=__file__)
-
-prepare_exec    = app.interphook('prepare_exec')
diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py
--- a/pypy/module/__builtin__/compiling.py
+++ b/pypy/module/__builtin__/compiling.py
@@ -3,7 +3,7 @@
 """
 
 from pypy.interpreter.pycode import PyCode
-from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import OperationError
 from pypy.interpreter.astcompiler import consts, ast
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.argument import Arguments
@@ -25,7 +25,7 @@
 compile; if absent or zero these statements do influence the compilation,
 in addition to any features explicitly specified.
 """
-
+    from pypy.interpreter.pyopcode import source_as_str
     ec = space.getexecutioncontext()
     if flags & ~(ec.compiler.compiler_flags | consts.PyCF_ONLY_AST |
                  consts.PyCF_DONT_IMPLY_DEDENT | consts.PyCF_SOURCE_IS_UTF8):
@@ -33,23 +33,13 @@
                              space.wrap("compile() unrecognized flags"))
 
     flags |= consts.PyCF_SOURCE_IS_UTF8
-    ast_node = None
-    w_ast_type = space.gettypeobject(ast.AST.typedef)
-    source_str = None
-    if space.is_true(space.isinstance(w_source, w_ast_type)):
+    ast_node = source = None
+    if space.isinstance_w(w_source, space.gettypeobject(ast.AST.typedef)):
         ast_node = space.interp_w(ast.mod, w_source)
         ast_node.sync_app_attrs(space)
-    elif space.isinstance_w(w_source, space.w_unicode):
-        w_utf_8_source = space.call_method(w_source, "encode",
-                                           space.wrap("utf-8"))
-        source_str = space.bytes0_w(w_utf_8_source)
-        flags |= consts.PyCF_IGNORE_COOKIE
-    elif space.isinstance_w(w_source, space.w_bytes):
-        source_str = space.bytes0_w(w_source)
     else:
-        msg = space.wrap(
-            "compile() arg 1 must be a string, bytes, AST or code object")
-        raise OperationError(space.w_TypeError, msg)
+        source, flags = source_as_str(space, w_source, 'compile',
+                                      "string, bytes, AST or code", flags)
 
     if not dont_inherit:
         caller = ec.gettopframe_nohidden()
@@ -58,16 +48,16 @@
 
     if mode not in ('exec', 'eval', 'single'):
         raise OperationError(space.w_ValueError,
-                             space.wrap("compile() arg 3 must be 'exec' "
-                                        "or 'eval' or 'single'"))
+                             space.wrap("compile() arg 3 must be 'exec', "
+                                        "'eval' or 'single'"))
     # XXX optimize is not used
 
     if ast_node is None:
         if flags & consts.PyCF_ONLY_AST:
-            mod = ec.compiler.compile_to_ast(source_str, filename, mode, flags)
+            mod = ec.compiler.compile_to_ast(source, filename, mode, flags)
             return space.wrap(mod)
         else:
-            code = ec.compiler.compile(source_str, filename, mode, flags)
+            code = ec.compiler.compile(source, filename, mode, flags)
     else:
         code = ec.compiler.compile_ast(ast_node, filename, mode, flags)
     return space.wrap(code)
@@ -80,58 +70,36 @@
 are dictionaries, defaulting to the current current globals and locals.
 If only globals is given, locals defaults to it.
 """
-    w = space.wrap
+    from pypy.interpreter.pyopcode import ensure_ns, source_as_str
+    w_globals, w_locals = ensure_ns(space, w_globals, w_locals, 'eval')
 
-    is_unicode = space.is_true(space.isinstance(w_code, space.w_unicode))
-    if (is_unicode or space.is_true(space.isinstance(w_code, space.w_bytes))):
-        w_strip = w(u' \t') if is_unicode else space.wrapbytes(' \t')
-        # XXX: w_code.lstrip could be overriden
-        w_code = compile(space, space.call_method(w_code, 'lstrip', w_strip),
-                         "<string>", "eval")
+    if space.isinstance_w(w_code, space.gettypeobject(PyCode.typedef)):
+        code = space.interp_w(PyCode, w_code)
+    else:
+        source, flags = source_as_str(space, w_code, 'eval',
+                                      "string, bytes or code",
+                                      consts.PyCF_SOURCE_IS_UTF8)
+        # source.lstrip(' \t')
+        i = 0
+        for c in source:
+            if c not in ' \t':
+                if i:
+                    source = source[i:]
+                break
+            i += 1
 
-    codeobj = space.interpclass_w(w_code)
-    if not isinstance(codeobj, PyCode):
-        raise OperationError(space.w_TypeError,
-              w('eval() arg 1 must be a string or code object'))
-
-    if (not space.is_none(w_globals) and
-        not space.isinstance_w(w_globals, space.w_dict)):
-        raise operationerrfmt(space.w_TypeError,
-                              'eval() arg 2 must be a dict, not %s',
-                              space.type(w_globals).getname(space))
-    if (not space.is_none(w_locals) and
-        space.lookup(w_locals, '__getitem__') is None):
-        raise operationerrfmt(space.w_TypeError,
-                              'eval() arg 3 must be a mapping or None, not %s',
-                              space.type(w_locals).getname(space))
-
-    if space.is_none(w_globals):
-        caller = space.getexecutioncontext().gettopframe_nohidden()
-        if caller is None:
-            w_globals = space.newdict()
-            if space.is_none(w_locals):
-                w_locals = w_globals
-        else:
-            w_globals = caller.w_globals
-            if space.is_none(w_locals):
-                w_locals = caller.getdictscope()
-    elif space.is_none(w_locals):
-        w_locals = w_globals
+        ec = space.getexecutioncontext()
+        code = ec.compiler.compile(source, "<string>", 'eval', flags)
 
     # xxx removed: adding '__builtins__' to the w_globals dict, if there
     # is none.  This logic was removed as costly (it requires to get at
     # the gettopframe_nohidden()).  I bet no test fails, and it's a really
     # obscure case.
 
-    return codeobj.exec_code(space, w_globals, w_locals)
+    return code.exec_code(space, w_globals, w_locals)
 
 def exec_(space, w_prog, w_globals=None, w_locals=None):
-    if w_globals is None:
-        w_globals = space.w_None
-    if w_locals is None:
-        w_locals = space.w_None
-    ec = space.getexecutioncontext()
-    frame = ec.gettopframe_nohidden()
+    frame = space.getexecutioncontext().gettopframe_nohidden()
     frame.exec_(w_prog, w_globals, w_locals)
 
 def build_class(space, w_func, w_name, __args__):
diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -495,6 +495,15 @@
         assert ns['foo'] == 'café'
         assert eval(b"# coding: latin1\n'caf\xe9'\n") == 'café'
 
+    def test_memoryview_compile(self):
+        m = memoryview(b'2 + 1')
+        co = compile(m, 'baz', 'eval')
+        assert eval(co) == 3
+        assert eval(m) == 3
+        ns = {}
+        exec(memoryview(b'r = 2 + 1'), ns)
+        assert ns['r'] == 3
+
     def test_recompile_ast(self):
         import _ast
         # raise exception when node type doesn't match with compile mode


More information about the pypy-commit mailing list