coding guide

But in the process of making that pass, I ran into a small

    > worm can: in the collections the kwargs and the setters
    > don't match, so kwdocd['PatchCollection'], for example, is
    > not quite right. The collection setter names are singular
    > (set_color) to mirror the corresponding non-collection
    > objects, but the kwargs are plural (colors). Although I see
    > the (grammatical) logic of the plural form I like the
    > singular form because I see little gain and considerable

When I was doing the kwdocd stuff I noticed the same but was focused
on getting the documentation infrastructure working and didn't want to
get distracted. But this is in part what I was alluding to in an
earlier email about the need for a cleanup. Eg, in Axes we have
axisbg in the init function and the axis_bgcolor property, both of
which do the same thing; ditto for frameon and frame_on

I think we should handle all properties in __init__ methods with
**kwargs and artist.update, rather than using explicitly named
keywords. artist init methods can take explicit keyword args, but
these will not be properties. When I wrote some of these methods, I
put named keyword args in the __init__ methods because it made them
more readable, eg with "help", and because some of these did not exist
as properties. As properties were added, apparently sometimes bad
names were chosen. Now that we have a system for documenting keywords
automatically, the docstring aspect is not so important so we should
remove the bad or inconsistent names.

For deprecated kwargs (eg axisbg) we could something like the
following, eg for Axes:

OLD:
    def __init__(self, fig, rect,
                 axisbg = None, # defaults to rc axes.facecolor
                 frameon = True,
                 sharex=None, # use Axes instance's xaxis info
                 sharey=None, # use Axes instance's yaxis info
                 label='',
                 **kwargs
                 ):
        """

New:
    def __init__(self, fig, rect,
                 sharex=None, # use Axes instance's xaxis info
                 sharey=None, # use Axes instance's yaxis info
                 **kwargs
                 ):
        """
        # check for deprecated usage:
        kwargs = kwargs.copy()
        frame_on = kwargs.get(frameon)
        if frame_on is not None:
            #deprecation warning
            kwargs['frame_on'] = frame_on

        axis_bgcolor = kwargs.get(axisbg)
        if axis_bgcolor is not None:
            #deprecation warning; use axis_bgcolor rather than axisbg
            kwargs['axis_bgcolor'] = axis_bgcolor
        ....
        self.update(kwargs)

Alternatively, we can raise a helpful exception, eg 'Use axis_bgcolor
rather than axisbg'

Another approach is to support these alternate names through aliases
like we do in Line2D: lw for linewidth, etc.... I don't feel strongly
about any of the three approaches, but we can agree on something and
both fix them as we find them. It should go pretty quickly.

    > loss in having different names for the same functionality in
    > LineCollection as compared to Line2D, for example. We could
    > get around the problem by allowing the singular forms of the
    > kwargs as well and deprecating the plural forms.

Or use aliases. Again, if you have a preference I am happy to go with
it. I guess simplicity should rule the day rather than having an ever
growing number of ways to specify what you want.

    > Another small glitch: it looks like you used the inspector
    > to assemble the kwargs list for the Axes docstring, but some
    > of these, like figure and position, duplicate required
    > arguments so they don't really makes sense as kwargs--even
    > though they would work. Did you edit out other such
    > examples? Is that the reason the Axes.__init__ kwargs list
    > is not being generated automatically?

No, the reason here is that you can't mutate the docstring outside the
class, and you can't use the inspector until the class is defined. So
init methods are special cases. There may be some sophisticated way
to do it but the naive way

class C:
    def somefunc():
       'a test %d'
       pass

C.somefunc.__doc__ = C.somefunc.__doc__%1

Traceback (most recent call last):
  File "<ipython console>", line 1, in ?
TypeError: attribute '__doc__' of 'instancemethod' objects is not
  writable

Absent something sophisticated, this morning while I was thinking
about the need to systematize the __init__ method kwarg handling, I
considered that maybe we should build a kwdocd module using the analog
of boilerplate.py. Eg we would manually build the file which defines
the kwdocd dictionary in a separate file. Something like:

import matplotlib.artist
import matplotlib.patches
for o in dir(matplotlib.patches):
     if not isinstance(o, Patch): continue
     name = o.__name__
     s = matplotlib.artist.kwdoc(o)
     # now write a dictionary entry to kwdoc.py with key=name and val=s

and ditto for all other artists. We could then use this dict in
__init__ methods and class methods.

Not terribly elegant, but neither is boilerplate.py, but it would
generate readable code, and having the kwdocd strings in a file would
have some utility for developers and users. There is a bit of a
bootstrapping problem here but it could be solved w/o too much
difficulty.

But if we can solve the problem of outside class docstring
interpolation, this will be moot. This looks like a job for c.l.py.
I googled a bit and it looks like their are some approaches using
metaclasses:

  http://groups.google.com/group/comp.lang.python/browse_frm/thread/80a529a7ed6e239e/f77e00ffefadf223?lnk=st&q=__doc__+"not+writable"+group%3A*python*&rnum=1#f77e00ffefadf223

  http://groups.google.com/group/comp.lang.python/browse_frm/thread/a25b1ec9478c1cfb/af19c967ab0a87eb?lnk=st&q=__doc__+"not+writable"+group%3A*python*&rnum=2#af19c967ab0a87eb

Both of these discuss generating a new class with a modified class
docstring rather than with a modified class method docstring, but
perhaps there is an analog.

I confess this metaclass stuff makes me feel queezy for reasons I
don't fully understand, but I like to avoid python black magic when
possible.

JDH