Commit bba019b0 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #512 from tjhance/test_property

Get `cpython/test_property.py` to pass
parents 1b1be210 28a115d2
# expected: fail
# Test case for property
# more tests are in test_descr
......
......@@ -34,6 +34,33 @@ static Box* memberGet(BoxedMemberDescriptor* self, Box* inst, Box* owner) {
Py_FatalError("unimplemented");
}
static void propertyDocCopy(BoxedProperty* prop, Box* fget) {
assert(prop);
assert(fget);
Box* get_doc;
try {
get_doc = getattrInternal(fget, "__doc__", NULL);
} catch (ExcInfo e) {
if (!e.matches(Exception)) {
throw;
}
get_doc = NULL;
}
if (get_doc) {
if (prop->cls == property_cls) {
prop->prop_doc = get_doc;
} else {
/* If this is a property subclass, put __doc__
in dict of the subclass instance instead,
otherwise it gets shadowed by __doc__ in the
class's dict. */
setattr(prop, "__doc__", get_doc);
}
prop->getter_doc = true;
}
}
static Box* propertyInit(Box* _self, Box* fget, Box* fset, Box** args) {
RELEASE_ASSERT(isSubclass(_self->cls, property_cls), "");
Box* fdel = args[0];
......@@ -44,6 +71,12 @@ static Box* propertyInit(Box* _self, Box* fget, Box* fset, Box** args) {
self->prop_set = fset;
self->prop_del = fdel;
self->prop_doc = doc;
self->getter_doc = false;
/* if no docstring given and the getter has one, use that one */
if ((doc == NULL || doc == None) && fget != NULL) {
propertyDocCopy(self, fget);
}
return None;
}
......@@ -93,17 +126,31 @@ static Box* propertyDel(Box* self, Box* obj) {
static Box* property_copy(BoxedProperty* old, Box* get, Box* set, Box* del) {
RELEASE_ASSERT(isSubclass(old->cls, property_cls), "");
if (!get)
if (!get || get == None)
get = old->prop_get;
if (!set)
if (!set || set == None)
set = old->prop_set;
if (!del)
if (!del || del == None)
del = old->prop_del;
// Optimization for the case when the old propery is not subclassed
if (old->cls == property_cls)
return new BoxedProperty(get, set, del, old->prop_doc);
return runtimeCall(old->cls, ArgPassSpec(4), get, set, del, &old->prop_doc, NULL);
if (old->cls == property_cls) {
BoxedProperty* prop = new BoxedProperty(get, set, del, old->prop_doc);
prop->getter_doc = false;
if ((old->getter_doc && get != None) || !old->prop_doc)
propertyDocCopy(prop, get);
return prop;
} else {
Box* doc;
if ((old->getter_doc && get != None) || !old->prop_doc)
doc = None;
else
doc = old->prop_doc;
return runtimeCall(old->cls, ArgPassSpec(4), get, set, del, &doc, NULL);
}
}
static Box* propertyGetter(Box* self, Box* obj) {
......
......@@ -778,6 +778,7 @@ public:
Box* prop_set;
Box* prop_del;
Box* prop_doc;
bool getter_doc;
BoxedProperty(Box* get, Box* set, Box* del, Box* doc)
: prop_get(get), prop_set(set), prop_del(del), prop_doc(doc) {}
......
......@@ -83,3 +83,87 @@ class C(object):
c = C()
c.p = "worked"
print c.p
print 'test the setting of __doc__'
class C(object):
@property
def f(self):
"""doc string of f"""
print C.f.__doc__
print 'test the setting of __doc__ with a __get__'
class Desc(object):
def __get__(self, obj, typ):
print 'desc called'
return "blah"
class ObjWithDocDesc(object):
__doc__ = Desc()
class C(object):
f = property(ObjWithDocDesc)
print C.f.__doc__
print 'test the setting of __doc__ with a __get__ throwing an exception (should get swallowed)'
class Desc(object):
def __get__(self, obj, typ):
raise ValueError("arbitrary exception")
class ObjWithDocDesc(object):
__doc__ = Desc()
class C(object):
f = property(ObjWithDocDesc)
print C.f.__doc__
print 'test the setting of __doc__ with a __get__ throwing an exception (should not get swallowed)'
class Desc(object):
def __get__(self, obj, typ):
raise BaseException("not a subclass of Exception")
class ObjWithDocDesc(object):
__doc__ = Desc()
try:
class C(object):
f = property(ObjWithDocDesc)
except BaseException as e:
print e.message
print 'test the setting of a __doc__ when you copy it'
class Desc(object):
def __get__(self, obj, typ):
print 'desc called'
return "blah"
class ObjWithDocDesc(object):
__doc__ = Desc()
prop = property(ObjWithDocDesc)
print 'made prop'
print prop.__doc__
def g():
"""doc of g"""
return 5
prop2 = prop.getter(g)
print 'made prop2'
print prop2.__doc__
prop3 = prop.setter(lambda self, val : None)
print prop3.__doc__
prop4 = prop.deleter(lambda self, val : None)
print prop4.__doc__
print 'test the setting of a __doc__ when you copy it when using a subclass of property'
class PropertySubclass(property):
pass
class Desc(object):
def __get__(self, obj, typ):
print 'desc called'
return "blah"
class ObjWithDocDesc(object):
__doc__ = Desc()
prop = PropertySubclass(ObjWithDocDesc)
print 'made prop'
print prop.__doc__
def g():
"""doc of g"""
return 5
prop2 = prop.getter(g)
print 'made prop2'
print prop2.__doc__
prop3 = prop.setter(lambda self, val : None)
print prop3.__doc__
prop4 = prop.deleter(lambda self, val : None)
print prop4.__doc__
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment