Subject: [Fenics] FEniCS Documentation -- PyDOLFIN doc-strings

From: Kristian Oelgaard <[email-masked]>
Date: Tue, 22 Jun 2010 17:28:37 +0200

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).

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.

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-method-to-automatically-overwrite-that-of-another-me

Kristian

---

From: Johan Hake <[email-masked]>
Date: Tue, 22 Jun 2010 10:03:07 -0700

> a script to check if all functions are documented or if any docs are

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.
 
> 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.

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.

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

> http://stackoverflow.com/questions/71817/using-the-docstring-from-one-metho
> d-to-automatically-overwrite-that-of-another-me
> 
> 
> Kristian
> 
> _______________________________________________
> Mailing list: https://launchpad.net/~fenics
> Post to     : [email-masked]
> Unsubscribe : https://launchpad.net/~fenics
> More help   : https://help.launchpad.net/ListHelp

---

From: Hans Petter Langtangen <[email-masked]>
Date: Tue, 22 Jun 2010 23:10:35 +0200

> maybe we can do it in a completely different way.

I use to dynamically create a lot of doc strings. The thing is to
assign to __doc__ between the doc string and the methods in the class.
Here is a test case:

def generate():
    return ', with more text'

class A:
    'This is A'
    pass

class B(object):
    'This is B'
    __doc__ += generate()
    pass

A.__doc__ += generate()
print A.__doc__
print B.__doc__
B.__doc__ += generate()

unix> run tmp.py
This is A, with more text
This is B, with more text
Traceback (most recent call last):
  File "tmp.py", line 16, in <module>
    B.__doc__ += generate()
AttributeError: attribute '__doc__' of 'type' objects is not writable

The first assignment to __doc__ in class B went fine.

Hans Petter

---

From: Anders Logg <[email-masked]>
Date: Tue, 22 Jun 2010 23:30:23 +0200

> The first assignment to __doc__ in class B went fine.

Why does it work for A and not for B? Does it only work once?

--
Anders

---

From: Johan Hake <[email-masked]>
Date: Tue, 22 Jun 2010 14:33:32 -0700

> Why does it work for A and not for B? Does it only work once?

A is an old style class and B is a new style class. 

You can assign to B's __doc__ as many times as you want as long as you do it 
within the class definition.

Johan

---

From: Anders Logg <[email-masked]>
Date: Tue, 22 Jun 2010 23:58:05 +0200

> A is an old style class and B is a new style class.

Ah, I didn't see that. Or rather I saw it but had forgotten about it
10 seconds later when I looked at the rest of the code... :-)

--
Anders

---

From: Kristian Oelgaard <[email-masked]>
Date: Wed, 23 Jun 2010 10:08:45 +0200

>    return ', with more text'

The problem with this approach though is that we need to put the call
to the 'doc function' in the SWIG generated cpp.py module.
For the hand written modules in PyDOLFIN it is no problem to do this.

Kristian

---

From: Kristian Oelgaard <[email-masked]>
Date: Wed, 23 Jun 2010 10:17:27 +0200

> suggests and it is probably as easy as anything else.

Yes, I thought about using a simple nested dict, but then realised
that with a module I could test for missing documentation both ways
more easily.

> the docstrings), I suggest two things we can do:

I'll dig a bit into NumPy and see what I can find out. If it is easy
I'll prefer this approach since it looks cleaner than doing 1) and 2)
below.

> where docstrings is the generated module containing the docstrings.

We should do both 1) and 2) at the same time right?
It should definitely be possible to do 1), when building the
documentation, we can run a script that creates the docstrings.i file
which DOLFIN can simply copy.
The second part looks really good, I guess the docstrings module can
just be copied to DOLFIN on build too.

For both 1) and 2) we can still use the pseudo module, for 1) we just
need to have a manually updated list of classes/functions for which
the documentation should be written to docstings.i or is it possible
(perhaps better) to just dump all docstrings in docstrings.i and let
SWIG copy whatever it needs?

Kristian

---

From: Kristian Oelgaard <[email-masked]>
Date: Wed, 23 Jun 2010 10:55:39 +0200

> 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

---

From: Kristian Oelgaard <[email-masked]>
Date: Wed, 23 Jun 2010 16:35:56 +0200

>> 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.

Kristian

---

From: Johan Hake <[email-masked]>
Date: Wed, 23 Jun 2010 08:57:21 -0700

On Wednesday June 23 2010 07:35:56 Kristian Oelgaard wrote:
> >> 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.
> >> 
> >> 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.
> > 
> >> 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.
> 

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:

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

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):
> >>> http://stackoverflow.com/questions/71817/using-the-docstring-from-one-m
> >>> etho d-to-automatically-overwrite-that-of-another-me
> >>> 
> >>> 
> >>> Kristian
> >>>

---

From: Kristian Oelgaard <[email-masked]>
Date: Wed, 23 Jun 2010 18:29:30 +0200

> 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.

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

---

From: Johan Hake <[email-masked]>
Date: Wed, 23 Jun 2010 10:04:46 -0700

On Wednesday June 23 2010 09:29:30 Kristian Oelgaard wrote:
> >> >>> PyDOLFIN should be written and maintained as part of the
> >> >>> documentation project and then added to the dolfin module on
> >> >>> import.
> >> >>> 
> >> >>> 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.
> >> >> 
> >> >>> 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.
> >> >>> 
> >> >>> 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.
> >> >>> 
> >> >> 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.
> >> > 
> >> >> 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:
> >> >> 
> >> >> 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.
> >> 
> > 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
> 
> http://docs.scipy.org/doc/numpy-1.3.x/reference/generated/numpy.random.mult
> ivariate_normal.html#numpy.random.multivariate_normal
> 

I think it looks good, and importantly not too complicated. I think the NumPy 
guys have put quite a lot of thoughts into this and it is good to not reinvent 
the wheel.

> having everything available from

I am not sure what that means, probably because I have not been able to follow 
your work closely.

> (The two should, however, look very similar in structure in my opinion).

It would be nice to follow the docstring example from above for the C++ 
methods. We probably need to rearange the Parameters section to fit the 
different C++ types though.

Johan

> >> >>> 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-on
> >> >>> e-m etho d-to-automatically-overwrite-that-of-another-me
> >> >>> 
> >> >>> 
> >> >>> Kristian
> >> >>>

---

From: Kristian Oelgaard <[email-masked]>
Date: Mon, 19 Jul 2010 20:54:44 +0100

> dolfindoc.Foo.__dict__["bar"].__doc__."

Unfortunately it turned out I was too quick to make this conclusion.
For instance,
for the Swig generated class Mesh in the module cpp I can't assign to

Mesh.__doc__

because it is a 'type' object as pointed our earlier, I can assign to:

Mesh.__dict__["__init__"].__doc__

but not

Mesh.__dict__["size"].__doc__

along with practically all other member functions.

The reason is that Swig, after the class definitions does this:

Mesh.size = new_instancemethod(_cpp.Mesh_size,None,Mesh)

to which no assignment is possible.
'AttributeError: attribute '__doc__' of 'instancemethod' objects is
not writable'
The code in Mesh.size is already

    def size(self, *args):
        return _cpp.Mesh_size(self, *args)

so why Swig overrides the method I don't know. If it didn't I could
assign to the docstring.

Recall that my initial plan was to simply parse the cpp.py file and
substitute the docstrings of all classes with what the pseudo module
dolfindoc would define. However, that doesn't seem so practical
anymore since I would need to also comment out all lines where
instancemethods are being assigned to class members such that on
import (in dolfin/__init__.py) I can loop classes and assign to
function docstrings. This is of course possible but seems a bit
awkward and I don't know what implications the commenting out of
instancemethod assignment will have.
As I see it, two solutions remain.

1) Take the pseudo module dolfindoc from the FEniCS documentation and
create a docstring.i generator. The script
dolfin/dolfin/swig/generator.py should then try to import the
dolfindoc module, if successful use that to create docstring.i,
otherwise use the Doxy2SWIG generator.
One question w.r.t this approach, when is docstrings.i being
generated? I see it is distributed with DOLFIN but shouldn't it be
generated everytime DOLFIN is rebuild with enablePython, or does
enableDocs have to be switched on as well?

2) Extend our Python layer with all functions and classes that we want
to use the dolfindoc docstrings for.
These should just be empty and redirect calls to classes and functions
of the cpp. In dolfin/mesh/mesh.py:

class Mesh(cpp.Mesh):
    def size(self):
        try:
            import dolfindoc.mesh.mesh
            __doc__ = dolfindoc.mesh.mesh.Mesh.__doc__
        except:
            __doc__ = cpp.Mesh.__doc__
        return cpp.Mesh.size()

An additional benefit of this approach is that the module structure
can be identical to what we have in the _real_ DOLFIN, not as it is
now where everything is dumped in the dolfin.cpp module.
I don't know how much overhead this will create, alternatively we can
skip the try/except clause and simply have the documentation as a
dependency, or not add the docstrings for memberfunctions and add them
later on import as was the original idea.

Suggestions and comments are more than welcome!

Kristian

---

From: Johan Hake <[email-masked]>
Date: Thu, 22 Jul 2010 12:10:29 -0700

On Monday July 19 2010 12:54:44 Kristian Oelgaard wrote:
> >>> dynamically add their documentation. It makes heavy use of sphinx, but
> >>> I couldn't figure how they get around that __doc__ is read-only.
> >> 

I thought that you landed on this alternative. The point is to generate a 
dosctrings.i file from the FEniCS documentation. Then for the extended Python 
layer we can use a generated Python module to assign the docstrings:

  class VariationalProblem(...):
     ...
     __doc__ generated_docstring_module.VariationalProblem.__doc__

> enableDocs have to be switched on as well?

It is generated by running dolfin/swig/generate.py. It takes quite a long time 
so I think it is good to pre-generate this in the distribution.

> later on import as was the original idea.

This sounds cumbersome and in the example above will the try: except clause be 
called everytime size is called.
 
Johan

> >>>> http://stackoverflow.com/questions/71817/using-the-docstring-from-one-
> >>>> metho d-to-automatically-overwrite-that-of-another-me
> >>>> 
> >>>> 
> >>>> Kristian
> >>>>

---

From: Kristian Ølgaard <[email-masked]>
Date: Thu, 22 Jul 2010 20:37:26 +0100

> layer we can use a generated Python module to assign the docstrings:

I landed on a slightly modified version of that yes. OK, the
docstrings.i part should be relatively easy to generate and probably
very fast too since I don't have to generate the html pages and parse.

>     __doc__ generated_docstring_module.VariationalProblem.__doc__

This I don't understand, if we generate a module which we will
distribute with DOLFIN why not simply distribute the module from the
FEniCS documentation?

> so I think it is good to pre-generate this in the distribution.

OK, so if a developer actually happens to update or even write
docstrings, the docstrings.i should be updated before commit.
(at least in theory ;))

> called everytime size is called.

Yes, I thought about having no docstrings as default (just need them
for the class docstring) and the dynamically add them on import for
all member functions.
I know it's a bit more work, but we will have the same layout of
modules as we have for the directories in DOLFIN.

Kristian

---

From: Johan Hake <[email-masked]>
Date: Thu, 22 Jul 2010 22:10:01 -0700

On Thursday July 22 2010 12:37:26 Kristian Ølgaard wrote:
> >> >>>> easy to create a script to check if all functions are documented
> >> >>>> or if any docs are obsolete).
> >> >>> 
> >> >>> 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.
> >> >>> 
> >> >>>> 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.
> >> >>>> 
> >> >> 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.
> >> >> 

Ok.
 
> distribute with DOLFIN why not simply distribute the module from the

Yes, this should be the generated_docstring_module, which is imported before 
the statement above.

> > It is generated by running dolfin/swig/generate.py. It takes quite a long
> > time so I think it is good to pre-generate this in the distribution.
> 

This has been the procedure for now. It is probably possible to change this 
workflow, to a more automatic one.

Johan

> > This sounds cumbersome and in the example above will the try: except
> > clause be called everytime size is called.
> 
> >> >>>> http://stackoverflow.com/questions/71817/using-the-docstring-from-o
> >> >>>> ne- metho d-to-automatically-overwrite-that-of-another-me
> >> >>>> 
> >> >>>> 
> >> >>>> Kristian
> >> >>>>

---

From: Kristian Ølgaard <[email-masked]>
Date: Sat, 24 Jul 2010 17:48:44 +0100

>     __doc__ generated_docstring_module.VariationalProblem.__doc__

This approach is getting more and more complicated; it turns out we
also need to generate all the
_post.i files to get the docstrings correct. At this point it seems a
lot easier to me to simply extend the Python layer with everything we
want to have detailed documentation for and distribute the
dolfindocstrings module with DOLFIN so we can do:

this way we handle the docstrings in a uniform way, else we need to
generate docstrings.i for some functions, *_post.i files for other
functions and STILL do the assign to __doc__ trick.

For functions that we don't extend in the Python layer we still have
the oneliner docs from the header files extended with some random
output from Swig.

Kristian

---

From: Johan Hake <[email-masked]>
Date: Sun, 25 Jul 2010 12:29:57 -0700

On Saturday July 24 2010 09:48:44 Kristian Ølgaard wrote:
> > dosctrings.i file from the FEniCS documentation. Then for the extended
> > Python layer we can use a generated Python module to assign the
> > docstrings:
> > 
> _post.i files to get the docstrings correct. 

Do yo meen the extended python functions that resides in these files?

> At this point it seems a

How do we handle the documentation of the pure cpp classes, for example 
cpp.Mesh?

Johan

---

From: Kristian Ølgaard <[email-masked]>
Date: Sun, 25 Jul 2010 21:25:25 +0100

> Do yo meen the extended python functions that resides in these files?

Yes, they will need a docstring too. But since Swig doesn't mess with
these particular (member-) functions, it is actually possible to
assign to __doc__ dynamically (on import) so maybe that would be an
easier option.

> How do we handle the documentation of the pure cpp classes, for example

For all functions/classes we put a docstring in the docstringsmodule
and distribute this module with DOLFIN.

The current approach that we're pursuing is:
For the classes in cpp, we generate the docstrings.i,
For add on functions in *_post.i we need to either generate *_post.i
or assign to __doc__ of those particular functions on import.
For classes functions in the Python layer we just assign to __doc__ in
the definition of classes/functions.

or as I suggested:

Extend the Python layer with whatever classes/functions that we want
to have documented in detail and assign to __doc__ in the definitions.

Kristian

---

From: Anders Logg <[email-masked]>
Date: Wed, 28 Jul 2010 20:15:13 +0200

On Thu, Jul 22, 2010 at 10:10:01PM -0700, Johan Hake wrote:
> > > Python

Would it be possible to integrate it in the build system? Or too much
noise every time we build?

It should at least be integrated in the release script. I have added
it to the pre-release hook of the release script now. We might want to
have a top-level script that does all the import/autogeneration magic
Kristian is working on, including calling generate.py in dolfin/swig.
Look at the file release.conf.

--
Anders

---

From: Johan Hake <[email-masked]>
Date: Wed, 28 Jul 2010 12:08:30 -0700

[snip]

> > 
> > This has been the procedure for now. It is probably possible to change
> > this workflow, to a more automatic one.
> 

I think it takes too much time now. It is especially the doxygen part of the 
docstring generation that takes time. This will of course change when we 
integrate the new documentation efforts.

> Look at the file release.conf.

This is probably better than nothing, but DOLFIN should be ready for release 
when this script is run. If the script has not been called before release has 
been decided it might produce a different release which need to be tested, at 
least the PyDOLFIN part. 

Johan

> 
> --
> Anders
> 
> > Johan
> > 
> > > >> 2) Extend our Python layer with all functions and classes that we
> > > >> want to use the dolfindoc docstrings for.
> > > >> These should just be empty and redirect calls to classes and
> > > >> functions of the cpp. In dolfin/mesh/mesh.py:
> > > >> 
> > > >> class Mesh(cpp.Mesh):
> > > >>     def size(self):
> > > >>         try:
> > > >> I don't know how much overhead this will create, alternatively we
> > > >> can skip the try/except clause and simply have the documentation as
> > > >> a dependency, or not add the docstrings for memberfunctions and add
> > > >> them later on import as was the original idea.
> > > > 
> > > >> > 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
> > > >> >>> 2) The added python classes and methods can be documented using
> > > >> >>> your suggested approach, but instead of adding the docstring
> > > >> >>> after class
> > > >> >>> 
> > > >> >>>> 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-fr
> > > >> >>>> om-o ne- metho d-to-automatically-overwrite-that-of-another-me
> > > >> >>>> 
> > > >> >>>> 
> > > >> >>>> Kristian
> > > >> >>>>

---

From: Johan Hake <[email-masked]>
Date: Wed, 28 Jul 2010 12:14:23 -0700

On Sunday July 25 2010 13:25:25 Kristian Ølgaard wrote:
> >> >> > On 23 June 2010 10:55, Kristian Oelgaard <[email-masked]>
> > 
> > wrote:
> >> >> >>>> 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).
> >> >> >>> 
> >> >> >>>> 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.
> >> >> >>>> 
> >> >> >>>> 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.
> >> >> >>>> 
> >> >> >>> :(
> >> >> >>> 
> >> >> >>> dynamically add their documentation. It makes heavy use of
> >> >> >>> sphinx, but I couldn't figure how they get around that __doc__
> >> >> >>> is read-only.
> >> >> >> 
> >> >> >> 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
> >> >> >> .tx t
> >> >> >> 
> >> >> >>> 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:
> >> >> >>> 
> >> >> >>> 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
> >> > I thought that you landed on this alternative. The point is to
> >> > generate a dosctrings.i file from the FEniCS documentation. Then for
> >> > the extended Python layer we can use a generated Python module to
> >> > assign the docstrings:
> >> > 

How would you do that? I tried 

%extend dolfin::GenericVector
{
  %pythoncode
  %{
    def data(self):
        generated_docstring_module.GenericVector.data.__doc__
        return self._data()
  %}
}

But it was only possible to have a "real" string, not a variable that was a 
str. Not sure why...

> and distribute this module with DOLFIN.

Ok
 
> the definition of classes/functions.

Ok
 
> to have documented in detail and assign to __doc__ in the definitions.

Ok

Johan

> >> > It is generated by running dolfin/swig/generate.py. It takes quite a
> >> > long time so I think it is good to pre-generate this in the
> >> > distribution.
> >> > 
> >> >> dependency, or not add the docstrings for memberfunctions and add
> >> >> >>> after class creation, do it during class (method or function)
> >> >> >>> creation, a la:
> >> >> >>> 
> >> >> >>>  class Foo(object):
> >> >> >>>> http://stackoverflow.com/questions/71817/using-the-docstring-fro
> >> >> >>>> m-o ne- metho d-to-automatically-overwrite-that-of-another-me
> >> >> >>>> 
> >> >> >>>> 
> >> >> >>>> Kristian
> >> >> >>>>

---

From: Kristian Ølgaard <[email-masked]>
Date: Wed, 28 Jul 2010 21:09:40 +0100

> But it was only possible to have a "real" string, not a variable that was a

Me neither, what I thought about doing was to generate the contents of
the *_post.i files from some source and then insert the docstring as a
literal string in the *_post.i file. But I decided that was too much
work.

So what I will end up doing is to assign to the __doc__ members of
these functions in the dolfin/__init__.py (on import). This is
possible because Swig doesn't mess around with these functions but
just adds them to the module. If the *_post.i contains other than
simple functions/member functions we'll have to generate the *_post.i
files from some source.

Kristian

---

From: Johan Hake <[email-masked]>
Date: Wed, 28 Jul 2010 13:20:36 -0700

[snip]

> > But it was only possible to have a "real" string, not a variable that was
> > a str. Not sure why...
> 

Would this work? I tried:

  class A(object):
      def jada(self):pass
  
  A.jada.__doc__ = "jada"

but I got

  attribute '__doc__' of 'instancemethod' objects is not writable

I am still on vacation, which mean that I have been away from coding a bit so 
my Python is a bit rusty ;)
 
Johan

---

From: Kristian Ølgaard <[email-masked]>
Date: Wed, 28 Jul 2010 21:30:38 +0100

>  attribute '__doc__' of 'instancemethod' objects is not writable

Yes, the trick is to do:

A.__dict__["jada"].__doc__ = "jada"

So we just loop all classes in cpp and their dicts and try to assign
to __doc__, if we can't we'll assume that it is handled by the
docstrings.i. All other classes and functions in our Python layer have
correct docstrings by construction.

> my Python is a bit rusty ;)

You're not much help then are you? ;)
Enjoy whatever remains of you holiday, looking forward to seeing you
back, more frequently, on the list.

Kristian

---

From: Johan Hake <[email-masked]>
Date: Wed, 28 Jul 2010 13:59:32 -0700

On Wednesday July 28 2010 13:30:38 Kristian Ølgaard wrote:
> >> > But it was only possible to have a "real" string, not a variable that
> >> > was a str. Not sure why...
> >> 
> > I am still on vacation, which mean that I have been away from coding a
> > bit so my Python is a bit rusty ;)
> 

Obviously not! :D

> back, more frequently, on the list.

I'll be back!

Johan