[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