docstrings, help(), and __name__
I've recently been implementing docstring support for Boost.Python extension classes (and in particular, their methods). I have a callable type which wraps all C++ functions and member functions -- it basically looks like a minimal subset of Python's function type, with a tp_descr_get slot which does the same thing that funcobject.c's func_descr_get() does: static PyObject * function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) { if (obj == Py_None) obj = NULL; return PyMethod_New(func, obj, type_); } So I just recently added a descriptor for the "__doc__" string attribute, and I thought I'd try help() on one of these methods: ***************************************************************** Failure in example: help(X) from line #2 of __main__ Exception raised: Traceback (most recent call last): File "doctest.py", line 430, in _run_examples_inner compileflags, 1) in globs File "<string>", line 1, in ? File "c:\tools\python-2.2.1\lib\site.py", line 279, in __call__ return pydoc.help(*args, **kwds) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1510, in __call__ self.help(request) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1546, in help else: doc(request, 'Help on %s:') File "c:\tools\python-2.2.1\lib\pydoc.py", line 1341, in doc pager(title % (desc + suffix) + '\n\n' + text.document(thing, name)) File "c:\tools\python-2.2.1\lib\pydoc.py", line 268, in document if inspect.isclass(object): return apply(self.docclass, args) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1093, in docclass lambda t: t[1] == 'method') File "c:\tools\python-2.2.1\lib\pydoc.py", line 1035, in spill name, mod, object)) File "c:\tools\python-2.2.1\lib\pydoc.py", line 269, in document if inspect.isroutine(object): return apply(self.docroutine, args) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1116, in docroutine realname = object.__name__ AttributeError: 'Boost.Python.function' object has no attribute '__name__' ***************************************************************** It seems I'm breaking some protocol. It's easy enough to add a '__name__' attribute to my function objects, but I'd like to be sure that I'm adding everything I really /should/ add. Just how much like a regular Python function does my function have to be in order to make the help system (and other standard systems with such expectations) happy? TIA, Dave ----------------------------------------------------------- David Abrahams * Boost Consulting dave@boost-consulting.com * http://www.boost-consulting.com
I've recently been implementing docstring support for Boost.Python extension classes (and in particular, their methods). I have a callable type which wraps all C++ functions and member functions -- it basically looks like a minimal subset of Python's function type, with a tp_descr_get slot which does the same thing that funcobject.c's func_descr_get() does:
static PyObject * function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) { if (obj == Py_None) obj = NULL; return PyMethod_New(func, obj, type_); }
So I just recently added a descriptor for the "__doc__" string attribute, and I thought I'd try help() on one of these methods:
***************************************************************** Failure in example: help(X) from line #2 of __main__ Exception raised: Traceback (most recent call last): File "doctest.py", line 430, in _run_examples_inner compileflags, 1) in globs File "<string>", line 1, in ? File "c:\tools\python-2.2.1\lib\site.py", line 279, in __call__ return pydoc.help(*args, **kwds) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1510, in __call__ self.help(request) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1546, in help else: doc(request, 'Help on %s:') File "c:\tools\python-2.2.1\lib\pydoc.py", line 1341, in doc pager(title % (desc + suffix) + '\n\n' + text.document(thing, name)) File "c:\tools\python-2.2.1\lib\pydoc.py", line 268, in document if inspect.isclass(object): return apply(self.docclass, args) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1093, in docclass lambda t: t[1] == 'method') File "c:\tools\python-2.2.1\lib\pydoc.py", line 1035, in spill name, mod, object)) File "c:\tools\python-2.2.1\lib\pydoc.py", line 269, in document if inspect.isroutine(object): return apply(self.docroutine, args) File "c:\tools\python-2.2.1\lib\pydoc.py", line 1116, in docroutine realname = object.__name__ AttributeError: 'Boost.Python.function' object has no attribute '__name__' *****************************************************************
It seems I'm breaking some protocol. It's easy enough to add a '__name__' attribute to my function objects, but I'd like to be sure that I'm adding everything I really /should/ add. Just how much like a regular Python function does my function have to be in order to make the help system (and other standard systems with such expectations) happy?
It's hard to say. The pydoc code makes up protocols as it goes. I think __name__ is probably the only one you're missing in practice. --Guido van Rossum (home page: http://www.python.org/~guido/)
From: "Guido van Rossum" <guido@python.org>
It seems I'm breaking some protocol. It's easy enough to add a '__name__' attribute to my function objects, but I'd like to be sure that I'm adding everything I really /should/ add. Just how much like a regular Python function does my function have to be in order to make the help system (and other standard systems with such expectations) happy?
It's hard to say. The pydoc code makes up protocols as it goes. I think __name__ is probably the only one you're missing in practice.
That appears to be correct. Interestingly, these methods seem to be treated differently from ordinary ones. My methods get shown like this: | __init__ = __init__(...) | this is the __init__ function | its documentation has two lines. Where the 2nd instance of __init__ is given by the value of the __name__ attribute, while built-in methods get shown as follows:
class X(object): ... def __init__(self): pass ... help(X) Help on class X in module __main__:
class X(__builtin__.object) | Methods defined here: | | __init__(self) Does anyone know why the difference? Is it perhaps the missing 'im_class' attribute in my case? These are the sorts of things I want to know about... Thanks, Dave ----------------------------------------------------------- David Abrahams * Boost Consulting dave@boost-consulting.com * http://www.boost-consulting.com
That appears to be correct. Interestingly, these methods seem to be treated differently from ordinary ones. My methods get shown like this:
| __init__ = __init__(...) | this is the __init__ function | its documentation has two lines.
Where the 2nd instance of __init__ is given by the value of the __name__ attribute, while built-in methods get shown as follows:
class X(object): ... def __init__(self): pass ... help(X) Help on class X in module __main__:
class X(__builtin__.object) | Methods defined here: | | __init__(self)
Does anyone know why the difference? Is it perhaps the missing 'im_class' attribute in my case? These are the sorts of things I want to know about...
Who knows. As I said, pydoc is a mess of underdocumented heuristics... --Guido van Rossum (home page: http://www.python.org/~guido/)
On Wed, 7 Aug 2002, Guido van Rossum wrote:
It seems I'm breaking some protocol. It's easy enough to add a '__name__' attribute to my function objects, but I'd like to be sure that I'm adding everything I really /should/ add. Just how much like a regular Python function does my function have to be in order to make the help system (and other standard systems with such expectations) happy?
It's hard to say. The pydoc code makes up protocols as it goes. I think __name__ is probably the only one you're missing in practice.
pydoc does not "make up protocols as it goes". It does its best to utilize the protocols exposed by the Python core. The attribute protocols on Python built-in objects vary from type to type, and pydoc tries to accommodate them. Part of the purpose of pydoc and inspect was to document and provide a more uniform interface to some of these protocols. All the built-in objects that are declared with a name have a __name__ attribute, so you'll want to provide that. Beyond that, it depends on the type of object you want to emulate; the various protocols are documented in the 'inspect' module. For example, see pydoc inspect.isfunction for details on function objects. -- ?!ng
From: "Ka-Ping Yee" <python-dev@zesty.ca>
The attribute protocols on Python built-in objects vary from type to type, and pydoc tries to accommodate them. Part of the purpose of pydoc and inspect was to document and provide a more uniform interface to some of these protocols.
All the built-in objects that are declared with a name have a __name__ attribute, so you'll want to provide that. Beyond that, it depends on the type of object you want to emulate; the various protocols are documented in the 'inspect' module. For example, see
pydoc inspect.isfunction
Do you mean help(inspect.isfunction), or am I clueless about the environment which accepts the above command?
for details on function objects.
It appears that ismethod is the one that's relevant to me, since the doc system gets my functions through my descriptor, which is wrapping them with PyMethod_New. So far I'm getting away with not adding an im_class attribute to my function objects, but it does result in that odd "__init__ = __init__" output (unless I've misdiagnosed). My function objects will certainly never have func_code, as help(inspect.isfunction) implies they should, and I'm a little reluctant to load up functions with a lot more attributes just so they can be like Python's functions... though I'm certain the penalty would be lost in the noise. The main question is this: which attributes do I absolutely /need/ in order to avoid raising an exception or giving nonsensical output from help()? Thanks again, Dave
participants (3)
-
David Abrahams
-
Guido van Rossum
-
Ka-Ping Yee