This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: inheriting from property and docstrings
Type: Stage:
Components: Interpreter Core Versions: Python 2.2
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: gvanrossum Nosy List: brett.cannon, gvanrossum, rengelink, rhettinger, theller
Priority: normal Keywords:

Created on 2002-07-03 14:42 by rengelink, last changed 2022-04-10 16:05 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
patch.diff rengelink, 2002-07-09 11:52 patch making property derivable (again)...
descrobj.diff theller, 2002-09-24 13:06 patch for property type
Messages (13)
msg11453 - (view) Author: Roeland Rengelink (rengelink) Date: 2002-07-03 14:42
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   
   
   
msg11454 - (view) Author: Roeland Rengelink (rengelink) Date: 2002-07-08 12:23
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
msg11455 - (view) Author: Roeland Rengelink (rengelink) Date: 2002-07-09 11:52
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. 
msg11456 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2002-09-08 21:55
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.
msg11457 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2002-09-08 22:11
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.
msg11458 - (view) Author: Roeland Rengelink (rengelink) Date: 2002-09-09 10:49
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
msg11459 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2002-09-24 12:43
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.
msg11460 - (view) Author: Thomas Heller (theller) * (Python committer) Date: 2002-09-24 13:06
Logged In: YES 
user_id=11105

The attached simple fix (descrobj.diff) fixes the problem
for me.
msg11461 - (view) Author: Thomas Heller (theller) * (Python committer) Date: 2002-09-24 13:12
Logged In: YES 
user_id=11105

Ups, forget my patch. Nothing works, sorry.
msg11462 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2002-09-24 17:01
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.
msg11463 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2003-05-17 02:39
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?
msg11464 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2003-05-18 21:05
Logged In: YES 
user_id=6380

Yes, you remember correctly.
msg11465 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2003-05-18 22:21
Logged In: YES 
user_id=357491

Since Guido said I remembered correctly I am closing this as "won't fix".
History
Date User Action Args
2022-04-10 16:05:29adminsetgithub: 36844
2002-07-03 14:42:03rengelinkcreate