Dynamic documentation for instances of classes¶
The functionality in this module allows to define specific docstrings
of instances of a class, which are different from the class docstring.
A typical use case is given by cached methods: the documentation of a
cached method should not be the documentation of the class
CachedMethod
; it should be the documentation of the underlying
method.
In order to use this, define a class docstring as usual. Also define a
method def _instancedoc_(self)
which should return the docstring of
the instance self
. Finally, add the decorator @instancedoc
to
the class.
Warning
Since the __doc__
attribute is never inherited, the decorator
@instancedoc
must be added to all subclasses of the class
defining _instancedoc_
. Doing it on the base class is not
sufficient.
EXAMPLES:
sage: from sage.docs.instancedoc import instancedoc
sage: @instancedoc
....: class X(object):
....: "Class docstring"
....: def _instancedoc_(self):
....: return "Instance docstring"
sage: X.__doc__
'Class docstring'
sage: X().__doc__
'Instance docstring'
For a Cython cdef class
, a decorator cannot be used. Instead, call
instancedoc()
as a function after defining the class:
sage: cython('''
....: from sage.docs.instancedoc import instancedoc
....: cdef class Y:
....: "Class docstring"
....: def _instancedoc_(self):
....: return "Instance docstring"
....: instancedoc(Y)
....: ''')
sage: Y.__doc__
'File:...\nClass docstring'
sage: Y().__doc__
'Instance docstring'
One can still add a custom __doc__
attribute on a particular
instance:
sage: obj = X()
sage: obj.__doc__ = "Very special doc"
sage: print(obj.__doc__)
Very special doc
This normally does not work on extension types:
sage: Y().__doc__ = "Very special doc"
Traceback (most recent call last):
...
AttributeError: attribute '__doc__' of 'Y' objects is not writable
This is an example involving a metaclass, where the instances are
classes. In this case, the _instancedoc_
from the metaclass is only
used if the instance of the metaclass (the class) does not have a
docstring:
sage: @instancedoc
....: class Meta(type):
....: "Metaclass doc"
....: def _instancedoc_(self):
....: return "Docstring for {}".format(self)
sage: from six import with_metaclass
sage: class T(with_metaclass(Meta, object)):
....: pass
sage: print(T.__doc__)
Docstring for <class '__main__.T'>
sage: class U(with_metaclass(Meta, object)):
....: "Special doc for U"
sage: print(U.__doc__)
Special doc for U
-
class
sage.docs.instancedoc.
InstanceDocDescriptor
¶ Bases:
object
Descriptor for dynamic documentation, to be installed as the
__doc__
attribute.INPUT:
classdoc
– (string) class documentationinstancedoc
– (method) documentation for an instanceattr
– (string, default__doc__
) attribute name to use for custom docstring on the instance.
EXAMPLES:
sage: from sage.docs.instancedoc import InstanceDocDescriptor sage: def instancedoc(self): ....: return "Instance doc" sage: docattr = InstanceDocDescriptor("Class doc", instancedoc) sage: class Z(object): ....: __doc__ = InstanceDocDescriptor("Class doc", instancedoc) sage: Z.__doc__ 'Class doc' sage: Z().__doc__ 'Instance doc'
We can still override the
__doc__
attribute of the instance:sage: obj = Z() sage: obj.__doc__ = "Custom doc" sage: obj.__doc__ 'Custom doc' sage: del obj.__doc__ sage: obj.__doc__ 'Instance doc'
-
sage.docs.instancedoc.
instancedoc
(cls)¶ Add support for
_instancedoc_
to the classcls
.Typically, this will be used as decorator.
INPUT:
cls
– a new-style class
OUTPUT:
cls
Warning
instancedoc
mutates the given class. So you are not supposed to use it asnewcls = instancedoc(cls)
because that would mutatecls
(andnewcls
would be the same object ascls
)