[pypy-commit] pypy default: # python 'property' for rpython
aachurin
noreply at buildbot.pypy.org
Wed Mar 11 12:23:26 CET 2015
Author: Andrey Churin <aachurin at gmail.com>
Branch:
Changeset: r76325:8c6cd439d1d1
Date: 2015-03-11 14:13 +0300
http://bitbucket.org/pypy/pypy/changeset/8c6cd439d1d1/
Log: # python 'property' for rpython
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -12,7 +12,7 @@
SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint,
s_None, s_ImpossibleValue, SomeBool, SomeTuple,
SomeImpossibleValue, SomeUnicodeString, SomeList, HarmlesslyBlocked,
- SomeWeakRef, SomeByteArray, SomeConstantType)
+ SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty)
from rpython.annotator.classdef import InstanceSource, ClassDef
from rpython.annotator.listdef import ListDef, ListItem
from rpython.annotator.dictdef import DictDef
@@ -301,6 +301,8 @@
s1 = self.immutablevalue(x1)
assert isinstance(s1, SomeInstance)
result = SomeWeakRef(s1.classdef)
+ elif tp is property:
+ return SomeProperty(x)
elif ishashable(x) and x in BUILTIN_ANALYZERS:
_module = getattr(x,"__module__","unknown")
result = SomeBuiltin(BUILTIN_ANALYZERS[x], methodname="%s.%s" % (_module, x.__name__))
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -482,6 +482,19 @@
self.all_enforced_attrs = [] # no attribute allowed
def add_source_attribute(self, name, value, mixin=False):
+ if isinstance(value, property):
+ # special case for property object
+ if value.fget is not None:
+ newname = name + '__getter__'
+ func = func_with_new_name(value.fget, newname)
+ self.add_source_attribute(newname, func, mixin)
+ if value.fset is not None:
+ newname = name + '__setter__'
+ func = func_with_new_name(value.fset, newname)
+ self.add_source_attribute(newname, func, mixin)
+ self.classdict[name] = Constant(value)
+ return
+
if isinstance(value, types.FunctionType):
# for debugging
if not hasattr(value, 'class_'):
diff --git a/rpython/annotator/model.py b/rpython/annotator/model.py
--- a/rpython/annotator/model.py
+++ b/rpython/annotator/model.py
@@ -587,6 +587,19 @@
return False
+class SomeProperty(SomeObject):
+ # used for union error only
+ immutable = True
+ knowntype = type(property)
+
+ def __init__(self, prop):
+ self.fget = prop.fget
+ self.fset = prop.fset
+
+ def can_be_none(self):
+ return False
+
+
s_None = SomeNone()
s_Bool = SomeBool()
s_Int = SomeInteger()
diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4326,6 +4326,82 @@
assert isinstance(s, annmodel.SomeString)
assert not s.can_be_none()
+ def test_property_getter(self):
+ class O1(object):
+ def __init__(self, x):
+ self._x = x
+ @property
+ def x(self):
+ return self._x
+ def f(n):
+ o = O1(n)
+ return o.x + getattr(o, 'x')
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert isinstance(s, annmodel.SomeInteger)
+ op = list(graphof(a, f).iterblocks())[0].operations
+ i = 0
+ c = 0
+ while i < len(op):
+ if op[i].opname == 'getattr':
+ c += 1
+ assert op[i].args[1].value == 'x__getter__'
+ i += 1
+ assert i < len(op) and op[i].opname == 'simple_call' and \
+ op[i].args[0] == op[i - 1].result
+ i += 1
+ assert c == 2
+
+ def test_property_setter(self):
+ class O2(object):
+ def __init__(self):
+ self._x = 0
+ def set_x(self, v):
+ self._x = v
+ x = property(fset=set_x)
+ def f(n):
+ o = O2()
+ o.x = n
+ setattr(o, 'x', n)
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int])
+ op = list(graphof(a, f).iterblocks())[0].operations
+ i = 0
+ c = 0
+ while i < len(op):
+ if op[i].opname == 'getattr':
+ c += 1
+ assert op[i].args[1].value == 'x__setter__'
+ i += 1
+ assert i < len(op) and op[i].opname == 'simple_call' and \
+ op[i].args[0] == op[i - 1].result and len(op[i].args) == 2
+ i += 1
+ assert c == 2
+
+ def test_property_unionerr(self):
+ class O1(object):
+ def __init__(self, x):
+ self._x = x
+ @property
+ def x(self):
+ return self._x
+ class O2(O1):
+ def set_x(self, v):
+ self._x = v
+ x = property(fset=set_x)
+ def f1(n):
+ o = O2(n)
+ return o.x
+ def f2(n):
+ o = O2(n)
+ o.x = 20
+ a = self.RPythonAnnotator()
+ with py.test.raises(annmodel.UnionError) as exc:
+ a.build_types(f1, [int])
+ a = self.RPythonAnnotator()
+ with py.test.raises(annmodel.UnionError) as exc:
+ a.build_types(f2, [int])
+
def g(n):
return [0, 1, 2, n]
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -5,7 +5,7 @@
from __future__ import absolute_import
from rpython.flowspace.operation import op
-from rpython.flowspace.model import const
+from rpython.flowspace.model import const, Constant
from rpython.annotator.model import (SomeObject, SomeInteger, SomeBool,
SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue,
SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod,
@@ -715,6 +715,50 @@
op.simple_call(get_setslice.result, v_start, v_stop, v_iterable)]
+def _find_property_meth(s_obj, attr, meth):
+ result = []
+ for clsdef in s_obj.classdef.getmro():
+ dct = clsdef.classdesc.classdict
+ if attr not in dct:
+ continue
+ obj = dct[attr]
+ if (not isinstance(obj, Constant) or
+ not isinstance(obj.value, property)):
+ return
+ result.append(getattr(obj.value, meth))
+ return result
+
+
+ at op.getattr.register_transform(SomeInstance)
+def getattr_SomeInstance(annotator, v_obj, v_attr):
+ s_attr = annotator.annotation(v_attr)
+ if not s_attr.is_constant() or not isinstance(s_attr.const, str):
+ return
+ attr = s_attr.const
+ getters = _find_property_meth(annotator.annotation(v_obj), attr, 'fget')
+ if getters:
+ if all(getters):
+ get_getter = op.getattr(v_obj, const(attr + '__getter__'))
+ return [get_getter, op.simple_call(get_getter.result)]
+ elif not any(getters):
+ raise AnnotatorError("Attribute %r is unreadable" % attr)
+
+
+ at op.setattr.register_transform(SomeInstance)
+def setattr_SomeInstance(annotator, v_obj, v_attr, v_value):
+ s_attr = annotator.annotation(v_attr)
+ if not s_attr.is_constant() or not isinstance(s_attr.const, str):
+ return
+ attr = s_attr.const
+ setters = _find_property_meth(annotator.annotation(v_obj), attr, 'fset')
+ if setters:
+ if all(setters):
+ get_setter = op.getattr(v_obj, const(attr + '__setter__'))
+ return [get_setter, op.simple_call(get_setter.result, v_value)]
+ elif not any(setters):
+ raise AnnotatorError("Attribute %r is unwritable" % attr)
+
+
class __extend__(SomeBuiltin):
def call(self, args, implicit_init=False):
args_s, kwds = args.unpack()
More information about the pypy-commit
mailing list