← Back to team overview

fenics team mailing list archive

Re: FEniCS Documentation -- PyDOLFIN doc-strings

 

On 23 June 2010 17:57, Johan Hake <johan.hake@xxxxxxxxx> wrote:
> On Wednesday June 23 2010 07:35:56 Kristian Oelgaard wrote:
>> On 23 June 2010 10:55, Kristian Oelgaard <k.b.oelgaard@xxxxxxxxx> wrote:
>> > On 22 June 2010 19:03, Johan Hake <johan.hake@xxxxxxxxx> wrote:
>> >> On Tuesday June 22 2010 08:28:37 Kristian Oelgaard wrote:
>> >>> I've started writing the programmer's reference for FEniCS.
>> >>> One of the features that we decided on was that doc-strings for
>> >>> PyDOLFIN should be written and maintained as part of the documentation
>> >>> project and then added to the dolfin module on import.
>> >>>
>> >>> I thought about doing this in the following way:
>> >>>
>> >>> 1) Create a pseudo module 'dolfin-doc' which is a copy of the classes
>> >>> and functions in the 'real' dolfin module only it contains no code at
>> >>> all, just doc-strings. (This approach will also make it easy to create
>> >>> a script to check if all functions are documented or if any docs are
>> >>> obsolete).
>> >>
>> >> Sounds good. I first thought of a structure (other than a dummy class)
>> >> that just mimics the class hierarchy, but in some way that is what you
>> >> actually suggests and it is probably as easy as anything else.
>> >>
>> >>> 2) Use the autodoc functionality of Sphinx to create parts of the
>> >>> documentation for functions and classes
>> >>>
>> >>> 3) Manually add additional information (in the reST file) and links to
>> >>> other parts of the documentation like demos etc. This will not be
>> >>> available using help() in the Python interpreter.
>> >>>
>> >>> 4) In the dolfin.__init__.py function import the 'dolfin-doc' module
>> >>> and copy the doc-strings from all classes and functions to the classes
>> >>> and functions in the real dolfin module as was suggested by Johan
>> >>> Hake.
>> >>>
>> >>> The problem with this approach is that assigning to __doc__ is not
>> >>> permitted for objects of 'type' type.
>> >>>
>> >> :(
>> >>
>> >> I did not anticipate this. Not sure why this is. I have got the
>> >> impression that numpy get around this. They use numpydoc to dynamically
>> >> add their documentation. It makes heavy use of sphinx, but I couldn't
>> >> figure how they get around that __doc__ is read-only.
>> >
>> > To me it looks like numpydoc is a Sphinx extension that translates the
>> > Numpy docstrings into something that Sphinx can understand, not the
>> > other way around which is what we want.
>> >
>> > http://projects.scipy.org/numpy/browser/trunk/doc/sphinxext/README.txt
>> >
>> > So I think our best bet is to proceed with your suggestions below.
>> >
>> > Kristian
>> >
>> >> While it might be cool to look into what NumPy have done, (they also
>> >> define a pseudo classes, which they populate with docstrings, (look
>> >> into phantom_import.py), and they also define some nice format for the
>> >> reST used in the docstrings), I suggest two things we can do:
>> >>
>> >> 1) SWIG can generate docstrings. We do that allready using parsed
>> >> doxygen documentation. All of this is gathered in docstrings.i. I
>> >> suggest generating such a file from our documentation. We need to turn
>> >> of %feature("autodoc","1") in dolfin.i to get rid of the long and
>> >> sometimes faulty generated signatures.
>>
>> I turns out that it's only the __doc__ of the class I can't assign to,
>> not the __doc__ of member functions (and regular functions).
>> A simpler solution (at least for me) is to parse the cpp.py module
>> once generated and substitute all docstrings of classes with the
>> docstrings from the dolfindoc module rather than creating the
>> docstrings.i file.
>>
>> Then for the classes that we manually add we use the method you
>> described below, but only for class.__doc__ .
>>
>> class Foo(object):
>>     __doc__ = dolfindoc.Foo.__doc__
>>     def bar(self):
>>         "this doc string will be substituted with the
>> dolfindoc.Foo.__dict__["bar"].__doc__."
>>         pass
>>
>> then in dolfin/__init__.py we load the classes as we do now from the
>> dolfin module, and then iterate over all functions and member
>> functions and substitute docstrings from the dolfindoc module.
>
> Sounds good to me. And remember that we only need to use the SWIG docstring
> feature for classes that we do not extend in our own Python layer.
>
> Have we landed on a unified way of expressing parameters to methods, functions
> and class initialization? NumPy relies on reST and they have defined what
> should go into a docstring. Their example is quite extensive and we should
> probably cut it down, but I think it is a nice reference:

We have not yet decided on a format mainly because I didn't know what
was possible and how we should go about things so suggestions are
welcome.

>  http://projects.scipy.org/numpy/browser/trunk/doc/EXAMPLE_DOCSTRING.txt

This looks OK to me, also compare to:

>>> import numpy
>>> help(numpy.random.multivariate_normal)

and finally:

http://docs.scipy.org/doc/numpy-1.3.x/reference/generated/numpy.random.multivariate_normal.html#numpy.random.multivariate_normal

It looks like the string from help() is just the raw reST docstring,
if we want to do this too we should definitely just put everything in
the dolfindoc pseudo module and let Sphinx do its magic.

Initially, I thought about mixing some manually written reST intput
with some autodoc from Sphinx from the module docstring but I guess
having everything available from

>>> help()

is a good idea?

For the C++ interface we don't have to worry, we simply write
everything manually in the reST files in the documentation source.
(The two should, however, look very similar in structure in my opinion).

Kristian

> Johan
>
>
>> Kristian
>>
>> >> 2) The added python classes and methods can be documented using your
>> >> suggested approach, but instead of adding the docstring after class
>> >> creation, do it during class (method or function) creation, a la:
>> >>
>> >>  class Foo(object):
>> >>      __doc__ = docstrings.Foo.__doc__
>> >>      ...
>> >>
>> >> where docstrings is the generated module containing the docstrings.
>> >>
>> >> Johan
>> >>
>> >>> In other words we can't assign to the __doc__ of
>> >>>
>> >>> class Foo(object):
>> >>>     "Foo doc"
>> >>>     pass
>> >>>
>> >>> Which is a new-style class and found in UFL and the SWIG code in
>> >>> DOLFIN.
>> >>>
>> >>> It works fine for
>> >>>
>> >>> def some_function(v):
>> >>>     "function doc"
>> >>>     return 2*v
>> >>>
>> >>> and
>> >>>
>> >>> class Bar:
>> >>>     "Bar doc"
>> >>>     pass
>> >>>
>> >>> which is the old-style class often found in FFC.
>> >>>
>> >>> Does anyone have a solution or comments to the above approach, or
>> >>> maybe we can do it in a completely different way.
>> >>>
>> >>> I read about some workaround for the 'assign to __doc__' problem, but
>> >>> it doesn't seem that nice and it might be a problem to incorporate in
>> >>> the SWIG generated code?
>> >>>
>> >>> http://stackoverflow.com/questions/71817/using-the-docstring-from-one-m
>> >>> etho d-to-automatically-overwrite-that-of-another-me
>> >>>
>> >>>
>> >>> Kristian
>> >>>
>> >>> _______________________________________________
>> >>> Mailing list: https://launchpad.net/~fenics
>> >>> Post to     : fenics@xxxxxxxxxxxxxxxxxxx
>> >>> Unsubscribe : https://launchpad.net/~fenics
>> >>> More help   : https://help.launchpad.net/ListHelp
>>
>> _______________________________________________
>> Mailing list: https://launchpad.net/~fenics
>> Post to     : fenics@xxxxxxxxxxxxxxxxxxx
>> Unsubscribe : https://launchpad.net/~fenics
>> More help   : https://help.launchpad.net/ListHelp
>



Follow ups

References