[Python-bugs-list] [ python-Bugs-576990 ] inheriting from property and docstrings
SourceForge.net
noreply@sourceforge.net
Sun, 18 May 2003 15:21:51 -0700
Bugs item #576990, was opened at 2002-07-03 07:42
Message generated for change (Comment added) made by bcannon
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=576990&group_id=5470
Category: Python Interpreter Core
Group: Python 2.2.1
>Status: Closed
>Resolution: Wont Fix
Priority: 5
Submitted By: Roeland Rengelink (rengelink)
Assigned to: Guido van Rossum (gvanrossum)
Summary: inheriting from property and docstrings
Initial Comment:
If I inherit from property, and try to initialize a derived
property object, the doc string doesn't get set. This bug
was introduced in 2.2.1, and is present in 2.3a0:
Compare:
Python 2.2 (#1, Mar 26 2002, 15:46:04)
[GCC 2.95.3 20010315 (SuSE)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> a = myprop(None, None, None, 'hi')
>>> print a.__doc__
hi
and,
Python 2.2.1 (#1, Jun 16 2002, 16:19:48)
[GCC 2.95.3 20010315 (SuSE)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> a = myprop(None, None, None, 'hi')
>>> print a.__doc__
None
There is no problem with the getter/setter functions
passed to the constructor. i.e.: myprop(f,g,h,None) works
identical in 2.2 and 2.2.1
Good luck,
Roeland Rengelink
----------------------------------------------------------------------
>Comment By: Brett Cannon (bcannon)
Date: 2003-05-18 15:21
Message:
Logged In: YES
user_id=357491
Since Guido said I remembered correctly I am closing this as "won't fix".
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2003-05-18 14:05
Message:
Logged In: YES
user_id=6380
Yes, you remember correctly.
----------------------------------------------------------------------
Comment By: Brett Cannon (bcannon)
Date: 2003-05-16 19:39
Message:
Logged In: YES
user_id=357491
I vaguely remember this coming on up on python-dev and it being said that
this would not get fixed. Am I remembering correctly?
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2002-09-24 10:01
Message:
Logged In: YES
user_id=6380
The problem is that class myprop has a __doc__ in its class
__dict__ that is the docstring for myprop, or None if that
class has no docstring. The march through the MRO looking
for an instance attribute descriptor finds this before it
would ever get to the property class, so effectively a
__doc__ property is not inherited.
The simplest workaround I found is this:
class myprop(property):
__doc__ = property.__dict__['__doc__']
(__doc__ = property.__doc__ does not do the right thing, it
gets the property class's docstring rather than the descriptor.)
This is a mess. I'll have to think about whether it's
possible at all to fix it without breaking something else.
I'll also have to think about whether it's worth it.
----------------------------------------------------------------------
Comment By: Thomas Heller (theller)
Date: 2002-09-24 06:12
Message:
Logged In: YES
user_id=11105
Ups, forget my patch. Nothing works, sorry.
----------------------------------------------------------------------
Comment By: Thomas Heller (theller)
Date: 2002-09-24 06:06
Message:
Logged In: YES
user_id=11105
The attached simple fix (descrobj.diff) fixes the problem
for me.
----------------------------------------------------------------------
Comment By: Guido van Rossum (gvanrossum)
Date: 2002-09-24 05:43
Message:
Logged In: YES
user_id=6380
OK, I'll have a look. We've have numerous hacks upon hacks
to get __doc__ to behave right. I don't know if it is within
my powers to fix this without breaking other things. But if
it is, I'll try to fix it in 2.2.1 as well as 2.3.
----------------------------------------------------------------------
Comment By: Roeland Rengelink (rengelink)
Date: 2002-09-09 03:49
Message:
Logged In: YES
user_id=302601
To give a usage example:
(because rhettinger thought this was a very strange use of
properties, and, for all I know, he may be right)
>>> class typed_property(property):
... def __init__(self, tp, doc):
... def getter(inst):
... return inst.__dict__[self]
... def setter(inst, val):
... if not isinstance(val, tp):
... raise TypeError
... inst.__dict__[self] = val
... property.__init__(self, getter, setter,
... None, doc)
...
>>> class A(object):
... a = typed_property(int, 'a prop')
...
>>> inst = A()
>>> inst.a = 1
>>> print inst.a
1
>>> inst.a = 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in setter
TypeError
>>> A.a.__doc__
'a prop'
The last only works in 2.2, and then only if typed_property
itself has no doc string
----------------------------------------------------------------------
Comment By: Raymond Hettinger (rhettinger)
Date: 2002-09-08 15:11
Message:
Logged In: YES
user_id=80475
Okay, now I see what you're trying to do.
Still, it the strangest use of property that I've seen to-date.
Re-opening the bug report.
----------------------------------------------------------------------
Comment By: Raymond Hettinger (rhettinger)
Date: 2002-09-08 14:55
Message:
Logged In: YES
user_id=80475
I think this is based on a misunderstanding of how to use
property. Instead of inheriting from it, you use it as a
function call in a new-style class (derived from object):
This works fine in versions from 2.2 upto 2.3a:
>>> class Myprop(object):
a = property(None,None,None,'a sample docstring')
>>> Myprop.a.__doc__
'a sample docstring'
Marking as invalid and closing.
----------------------------------------------------------------------
Comment By: Roeland Rengelink (rengelink)
Date: 2002-07-09 04:52
Message:
Logged In: YES
user_id=302601
I think I found the problem,
Compare:
>>> property.__doc__
'property(fget=None,.... # the doc string
and
>>> property.__dict__['__doc__']
<member '__doc__' of 'property' objects>
Note that property.__doc__ and property.__dict__['__doc__']
are not the same. Python will go out of its way to prevent this
weird situation in user derived classes.,
1. type_new(name, bases, attrs) will copy attrs to
new_tp.tp_dict, and will also copy attrs['__doc__'] to tp.tp_doc
2. PyType_Ready(tp) will copy tp.tp_doc to
tp.tp_dict['__doc__'] if tp.tp_dict['__doc__'] is undefined
This guarantees that tp.tp_dict['__doc__'] will exist, usually
copying tp.tp_doc, and shadowing property.tp_dict['__doc__']
if tp is derived from property
The solution seems to be:
1. In type_new():
if possible copy attr['__doc__'] to tp.tp_doc, and delete
__doc__ from attr (to prevent ending up in tp_dict)
2. in PyType_Ready():
don't copy tp.tp_doc to tp_dict['__doc__']
These two steps make sure that, tp_dict['__doc__'] no longer
shadows properties.tp_dict['__doc__']. Unfortunately, this
means that tp.__doc__ doesn't generally return the docstrings
for user-defined types. Therefore:
3. in type_get_doc():
return tp.tp_doc also for heap types.
The result of this will be:
1. properties will be subclassable again. (good)
2. __doc__ string become read-only attributes (bad??)
3. test cases in test_descr that assume that
instance.__dict__['__doc__'] exists, will fail
4. a weird test_failure in test_module.py
Patches for this modification are attached, except for
(test_module.py), which I don't understand.
----------------------------------------------------------------------
Comment By: Roeland Rengelink (rengelink)
Date: 2002-07-08 05:23
Message:
Logged In: YES
user_id=302601
Some more details:
In fact 2.2.1 is consistently wrong, whereas 2.2 is
inconsistently right ;), compare:
Python 2.2.1 (#20, Jul 8 2002, 13:25:14)
[GCC 3.1] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> class yourprop(property):
... "A doc string"
...
>>> print myprop(None, None, None, 'Hi there').__doc__
None
>>> print yourprop(None, None, None, 'Hi there').__doc__
A doc string
and
Python 2.2 (#4, Jan 7 2002, 11:59:25)
[GCC 2.95.2 19991024 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> class yourprop(property):
... "A doc string"
...
>>> print myprop(None, None, None, 'Hi there').__doc__
Hi there
>>> print yourprop(None, None, None, 'Hi there').__doc__
A doc string
So, in 2.2.1 myprop(...).__doc__ will allways return
myprop.__doc__. In 2.2 myprop.__doc__ will return the
instance's
__doc__, iff myprop.__doc__ is None.
For the record: I was expecting 'Hi there' (i.e.
obj->prop_doc), as in:
>>> property(None, None, None, 'Hi there').__doc__
'Hi there'
Hope this helps,
Roeland
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=576990&group_id=5470