[pypy-svn] rev 2355 - in pypy/trunk/src/pypy/interpreter: . test

hpk at codespeak.net hpk at codespeak.net
Tue Dec 16 12:36:05 CET 2003


Author: hpk
Date: Tue Dec 16 12:36:04 2003
New Revision: 2355

Modified:
   pypy/trunk/src/pypy/interpreter/function.py
   pypy/trunk/src/pypy/interpreter/gateway.py
   pypy/trunk/src/pypy/interpreter/test/test_function.py
Log:
- added function object introspection (minus __class__
  because we still have no appropriate type object)

- refactored app2interp and interp2app to be subclasses
  of Gateway in order to avoid passing around millions
  of arguments

(holger, samuele)


Modified: pypy/trunk/src/pypy/interpreter/function.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/function.py	(original)
+++ pypy/trunk/src/pypy/interpreter/function.py	Tue Dec 16 12:36:04 2003
@@ -13,17 +13,19 @@
     an object space, a dictionary of globals, default arguments,
     and an arbitrary 'closure' passed to the code object."""
     
-    def __init__(self, space, code, w_globals=None, defs_w=[], closure=None):
-        self.space     = space
-        self.func_code = code       # Code instance
+    def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None):
+        self.space = space
+        self.name = forcename or code.co_name
+        self.doc = getattr(code, 'co_consts', (None,))[0]
+        self.code = code       # Code instance
         self.w_globals = w_globals  # the globals dictionary
         self.closure   = closure    # normally, list of Cell instances or None
         self.defs_w    = defs_w     # list of w_default's
-        self.__name__  = self.func_code.co_name   # XXX
+        self.w_dict = space.newdict([])
 
     def call(self, w_args, w_kwds=None):
         scope_w = self.parse_args(w_args, w_kwds)
-        frame = self.func_code.create_frame(self.space, self.w_globals,
+        frame = self.code.create_frame(self.space, self.w_globals,
                                             self.closure)
         frame.setfastscope(scope_w)
         return frame.run()
@@ -33,7 +35,7 @@
         """ parse args and kwargs to initialize the frame.
         """
         space = self.space
-        signature = self.func_code.signature()
+        signature = self.code.signature()
         argnames, varargname, kwargname = signature
         #
         #   w_args = wrapped sequence of the normal actual parameters
@@ -94,7 +96,7 @@
     # helper functions to build error message for the above
 
     def raise_argerr(self, w_args, w_kwds, too_many):
-        argnames, varargname, kwargname = self.func_code.signature()
+        argnames, varargname, kwargname = self.code.signature()
         nargs = self.space.unwrap(self.space.len(w_args))
         n = len(argnames)
         if n == 0:
@@ -104,7 +106,7 @@
                 msg2 = ""
                 nargs += self.space.unwrap(self.space.len(w_kwds))
             msg = "%s() takes no %sargument (%d given)" % (
-                self.func_code.co_name,
+                self.name, 
                 msg2,
                 nargs)
         else:
@@ -125,7 +127,7 @@
             else:
                 plural = "s"
             msg = "%s() takes %s %d %sargument%s (%d given)" % (
-                self.func_code.co_name,
+                self.name,
                 msg1,
                 n,
                 msg2,
@@ -135,7 +137,7 @@
 
     def raise_argerr_multiple_values(self, argname):
         msg = "%s() got multiple values for keyword argument %s" % (
-            self.func_code.co_name,
+            self.name,
             argname)
         raise OperationError(self.space.w_TypeError, self.space.wrap(msg))
 
@@ -145,11 +147,11 @@
             w_iter = self.space.iter(w_kwds)
             w_key = self.space.next(w_iter)
             msg = "%s() got an unexpected keyword argument '%s'" % (
-                self.func_code.co_name,
+                self.name,
                 self.space.unwrap(w_key))
         else:
             msg = "%s() got %d unexpected keyword arguments" % (
-                self.func_code.co_name,
+                self.name,
                 nkwds)
         raise OperationError(self.space.w_TypeError, self.space.wrap(msg))
 
@@ -180,6 +182,26 @@
         # (for FlowObjSpace)
         return self.space.call(wrap(self), w_args, w_kwds)
 
+    def pypy_getattr(self, name):
+        space = self.space
+        if name == 'func_defaults':
+            if not self.defs_w:
+                return space.w_None
+            else:
+                return space.newtuple(self.defs_w)
+        elif name == 'func_code':
+            return space.wrap(self.code)
+        elif name == 'func_dict':
+            return space.wrap(self.w_dict)
+        elif name == 'func_doc' or name == '__doc__':
+            return space.wrap(self.doc)
+        elif name == 'func_globals':
+            return self.w_globals
+        elif name == 'func_closure':
+            return space.wrap(self.closure)
+        elif name == 'func_name' or name == '__name__': 
+            return space.wrap(self.name)
+        raise OperationError(space.w_AttributeError, space.wrap(name))
 
 class Method(object):
     """A method is a function bound to a specific instance or class."""

Modified: pypy/trunk/src/pypy/interpreter/gateway.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/gateway.py	(original)
+++ pypy/trunk/src/pypy/interpreter/gateway.py	Tue Dec 16 12:36:04 2003
@@ -120,14 +120,14 @@
     # explicitely as the first argument (for plain function), or is read
     # from 'self.space' for methods.
 
-    def __init__(self, name, code, staticglobals=None, staticdefs=[], 
-                 wrapdefaults=0):
-        self.name = name
-        self.code = code
-        self.staticglobals = staticglobals
-        self.staticdefs = staticdefs
+    def __init__(self): 
         self.functioncache = WeakKeyDictionary()  # map {space: Function}
-        self.wrapdefaults = wrapdefaults
+
+        # after initialization the following attributes should be set
+        #   name
+        #   code 
+        #   staticglobals 
+        #   staticdefs 
 
     def __wrap__(self, space):
         # to wrap a Gateway, we first make a real Function object out of it
@@ -186,50 +186,52 @@
         if space in self.functioncache:
             fn = self.functioncache[space]
         else:
-            defs_w = self.staticdefs 
-            if self.wrapdefaults:
-                defs_w = [space.wrap(val) for val in defs_w]
-            fn = Function(space, self.code, w_globals, defs_w)
+            defs = self.getdefaults(space)  # needs to be implemented by subclass
+            fn = Function(space, self.code, w_globals, defs, forcename = self.name)
             self.functioncache[space] = fn
         return fn
 
 
-def app2interp(app, app_name=None):
+class app2interp(Gateway):
     """Build a Gateway that calls 'app' at app-level."""
-    # app must be a function whose name starts with 'app_'.
-    if not isinstance(app, types.FunctionType):
-        if isinstance(app, Gateway):
-            return app
-        raise TypeError, "function expected, got %r instead" % app
-    if app_name is None:
-        if not app.func_name.startswith('app_'):
-            raise ValueError, ("function name must start with 'app_'; "
-                               "%r does not" % app.func_name)
-        app_name = app.func_name[4:]
-    code = pycode.PyCode(None)
-    code._from_code(app.func_code)
-    staticglobals = app.func_globals
-    staticdefs = list(app.func_defaults or ())
-    return Gateway(app_name, code, staticglobals, 
-                   staticdefs, wrapdefaults=1)
+    def __init__(self, app, app_name=None):
+        Gateway.__init__(self)
+        # app must be a function whose name starts with 'app_'.
+        if not isinstance(app, types.FunctionType):
+            raise TypeError, "function expected, got %r instead" % app
+        if app_name is None:
+            if not app.func_name.startswith('app_'):
+                raise ValueError, ("function name must start with 'app_'; "
+                                   "%r does not" % app.func_name)
+            app_name = app.func_name[4:]
+        self.name = app_name
+        self.code = pycode.PyCode(None)
+        self.code._from_code(app.func_code)
+        self.staticglobals = app.func_globals
+        self.staticdefs = list(app.func_defaults or ())
+
+    def getdefaults(self, space):
+        return [space.wrap(val) for val in self.staticdefs]
 
-def interp2app(f, app_name=None):
+class interp2app(Gateway):
     """Build a Gateway that calls 'f' at interp-level."""
-    # f must be a function whose name does NOT starts with 'app_'
-    if not isinstance(f, types.FunctionType):
-        if isinstance(f, Gateway):
-            return f
-        raise TypeError, "function expected, got %r instead" % f
-    if app_name is None:
-        if f.func_name.startswith('app_'):
-            raise ValueError, ("function name %r suspiciously starts "
-                               "with 'app_'" % f.func_name)
-        app_name = f.func_name
-    builtincode = BuiltinCode(f)
-    staticdefs = list(f.func_defaults or ())
-    return Gateway(app_name, builtincode, None, 
-                   staticdefs, wrapdefaults=0)
+    def __init__(self, f, app_name=None):
+        Gateway.__init__(self)
+        # f must be a function whose name does NOT starts with 'app_'
+        if not isinstance(f, types.FunctionType):
+            raise TypeError, "function expected, got %r instead" % f
+        if app_name is None:
+            if f.func_name.startswith('app_'):
+                raise ValueError, ("function name %r suspiciously starts "
+                                   "with 'app_'" % f.func_name)
+            app_name = f.func_name
+        self.code = BuiltinCode(f)
+        self.name = app_name
+        self.staticdefs = list(f.func_defaults or ())
+        self.staticglobals = None
 
+    def getdefaults(self, space):
+        return self.staticdefs
 
 def exportall(d):
     """Publish every function from a dict."""

Modified: pypy/trunk/src/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/test/test_function.py	(original)
+++ pypy/trunk/src/pypy/interpreter/test/test_function.py	Tue Dec 16 12:36:04 2003
@@ -6,6 +6,23 @@
 from pypy.interpreter.pycode import PyCode
 
 
+class AppTestFunctionIntrospection(test.AppTestCase):
+    def test_attributes(self):
+        def f(): pass
+        self.assert_(hasattr(f, 'func_code'))
+        self.assertEquals(f.func_defaults, None)
+        self.assertEquals(f.func_dict, {})
+        self.assertEquals(type(f.func_globals), dict)
+        self.assertEquals(f.func_closure, None)
+        self.assertEquals(f.func_doc, None)
+        self.assertEquals(f.func_name, 'f')
+
+    def test_underunder_attributes(self):
+        def f(): pass
+        self.assertEquals(f.__name__, 'f')
+        self.assertEquals(f.__doc__, None)
+        #XXX self.assert_(hasattr(f, '__class__'))
+
 class AppTestFunction(test.AppTestCase):
     def test_simple_call(self):
         def func(arg1, arg2):


More information about the Pypy-commit mailing list