Author: Greg Price <[email protected]>
Branch: signatures
Changeset: r59326:aefa224aec97
Date: 2012-12-03 22:48 -0800
http://bitbucket.org/pypy/pypy/changeset/aefa224aec97/
Log: Add types.self notation, for signatures on methods
diff --git a/pypy/annotation/signature.py b/pypy/annotation/signature.py
--- a/pypy/annotation/signature.py
+++ b/pypy/annotation/signature.py
@@ -131,15 +131,18 @@
s_input))
inputcells[:] = args_s
-def apply_bookkeeper(paramtype, bookkeeper):
+def finish_type(paramtype, bookkeeper, func):
+ from pypy.annotation.types import SelfTypeMarker
if isinstance(paramtype, SomeObject):
return paramtype
+ elif isinstance(paramtype, SelfTypeMarker):
+ raise Exception("%r argument declared as annotation.types.self();
class needs decorator rlib.signature.finishsigs()" % (func,))
else:
return paramtype(bookkeeper)
def enforce_signature_args(funcdesc, paramtypes, actualtypes):
assert len(paramtypes) == len(actualtypes)
- params_s = [apply_bookkeeper(paramtype, funcdesc.bookkeeper) for paramtype
in paramtypes]
+ params_s = [finish_type(paramtype, funcdesc.bookkeeper, funcdesc.pyobj)
for paramtype in paramtypes]
for i, (s_param, s_actual) in enumerate(zip(params_s, actualtypes)):
if not s_param.contains(s_actual):
raise Exception("%r argument %d:\n"
@@ -148,4 +151,4 @@
actualtypes[:] = params_s
def enforce_signature_return(funcdesc, sigtype, inferredtype):
- return apply_bookkeeper(sigtype, funcdesc.bookkeeper)
+ return finish_type(sigtype, funcdesc.bookkeeper, funcdesc.pyobj)
diff --git a/pypy/annotation/types.py b/pypy/annotation/types.py
--- a/pypy/annotation/types.py
+++ b/pypy/annotation/types.py
@@ -46,3 +46,9 @@
def instance(class_):
return lambda bookkeeper:
model.SomeInstance(bookkeeper.getuniqueclassdef(class_))
+
+class SelfTypeMarker(object):
+ pass
+
+def self():
+ return SelfTypeMarker()
diff --git a/pypy/rlib/signature.py b/pypy/rlib/signature.py
--- a/pypy/rlib/signature.py
+++ b/pypy/rlib/signature.py
@@ -1,3 +1,4 @@
+from pypy.annotation import types
def signature(*paramtypes, **kwargs):
"""Decorate a function to specify its type signature.
@@ -17,3 +18,22 @@
f._signature_ = (paramtypes, returntype)
return f
return decorator
+
+
+def finishsigs(cls):
+ """Decorate a class to finish any method signatures involving types.self().
+
+ This is required if any method has a signature with types.self() in it.
+ """
+ # A bit annoying to have to use this, but it avoids performing any
+ # terrible hack in the implementation. Eventually we'll offer signatures
+ # on classes, and then that decorator can do this on the side.
+ def fix(sigtype):
+ if isinstance(sigtype, types.SelfTypeMarker):
+ return types.instance(cls)
+ return sigtype
+ for attr in cls.__dict__.values():
+ if hasattr(attr, '_signature_'):
+ paramtypes, returntype = attr._signature_
+ attr._signature_ = (tuple(fix(t) for t in paramtypes),
fix(returntype))
+ return cls
diff --git a/pypy/rlib/test/test_signature.py b/pypy/rlib/test/test_signature.py
--- a/pypy/rlib/test/test_signature.py
+++ b/pypy/rlib/test/test_signature.py
@@ -1,5 +1,5 @@
import py
-from pypy.rlib.signature import signature
+from pypy.rlib.signature import signature, finishsigs
from pypy.annotation import types, model
from pypy.translator.translator import TranslationContext, graphof
@@ -180,3 +180,32 @@
@check_annotator_fails
def bad_for_body():
f(C1())
+
+def test_signature_self():
+ @finishsigs
+ class C(object):
+ @signature(types.self(), types.self(), returns=types.none())
+ def f(self, other):
+ pass
+ class D1(C):
+ pass
+ class D2(C):
+ pass
+
+ def g():
+ D1().f(D2())
+ a = annotate_at(g)
+
+ argtype = sigof(a, C.__dict__['f'])[0]
+ assert isinstance(argtype, model.SomeInstance)
+ assert argtype.classdef.classdesc.pyobj == C
+
+def test_signature_self_error():
+ class C(object):
+ @signature(types.self(), returns=types.none())
+ def incomplete_sig_meth(self):
+ pass
+
+ exc = py.test.raises(Exception, annotate_at, C.incomplete_sig_meth).value
+ assert 'incomplete_sig_meth' in repr(exc.args)
+ assert 'finishsigs' in repr(exc.args)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit