Eric Firing had the excellent idea of making a CODING_GUIDE which
summarizes the conventions used in matplotlib development, and I've
added this to svn.  Feel free to make changes, additions and
comments.  I think we could add a lot here, including an overview of
the API.  Here  is the document I just committed::

Devs, feel free to edit this document.  This is meant to be a guide to
developers on the mpl coding practices and standards


== Committing Changes ==

When committing changes to matplotlib, there are a few things to bear
in mind.  

  * if your changes are nontrivial, please make an entry in the
    CHANGELOG

  * if you change the API, please document it in API_CHANGES, and
    consider posing to mpl-devel

  * Are your changes python2.3 compatible?  We are still trying to
    support 2.3, so avoid 2.4 only features like decorators until we
    remove 2.3 support

  * Are your changes Numeric, numarray and numpy compatible?  Try
    running simple_plot.py or image_demo.py with --Numeric, --numarray
    and --numpy (Note, someone should add examples to
    backend_driver.py which explicitly require numpy, numarray and
    Numeric so we can automatically catch these)

  * Can you pass examples/backend_driver.py?  This is our poor man's
    unit test.

  * If you have altered extension code, do you pass
    unit/memleak_hawaii.py?


== Naming conventions ==

  functions and class methods  : lower or lower_underscore_separated

  attributes and variables     : lower or lowerUpper

  classes                      : Upper or MixedCase

Personally, I prefer the shortest names that are still readable.

== kwargs processing == 

Matplotlib makes extensive use of **kwargs for pass through
customizations from one function to another, eg the pylab plot ->
Axes.plot pass through.  As a general rule, the use of **kwargs should
be reserved for pass-through keyword arguments, eg

  def somefunc(x, k1='something', **kwargs):
      # do some thing with x, k1
      return some_other_func(..., **kwargs)

If I intend for all the keyword args to be used in somefunc alone, I
just use the key/value keyword args in the function definition rather
than the **kwargs idiom.  In some cases I want to consume some keys
and pass through the others, in which case I pop the ones I want to
use locally and pass on the rest, eg I pop scalex and scaley in
Axes.plot and assume the rest are Line2D keyword arguments.  Whenever
you mutate a kwargs dictionary (eg by popping it), you must first copy
it since the user may be explitly passing in a dictionary which is
used across many function calls.  As an example of a copy, pop,
passthrough usage, see Axes.plot:

    def plot(self, *args, **kwargs):
        kwargs = kwargs.copy()
        scalex = popd(kwargs, 'scalex', True)
        scaley = popd(kwargs, 'scaley', True)
        if not self._hold: self.cla()
        lines = []
        for line in self._get_lines(*args, **kwargs):
            self.add_line(line)
            lines.append(line)

popd is a matplotlib.cbook function to pop an item from a dictionary
with a default value if the item doesn't exist

Note there is a use case when kwargs are meant to be used locally in
the function (not passed on), but you still need the **kwargs idiom.
That is when you want to use *args to allow variable numbers of
non-keyword args.  In this case, python will not allow you to use
named keyword args after the *args usage, so you will be forced to use
**kwargs.  An example is matplotlib.contour.ContourLabeler.clabel

    def clabel(self, *args, **kwargs):
        fontsize = kwargs.get('fontsize', None)
        inline = kwargs.get('inline', 1)
        self.fmt = kwargs.get('fmt', '%1.3f')
        colors = kwargs.get('colors', None)
        if len(args) == 0:
            levels = self.levels
            indices = range(len(self.levels))
        elif len(args) == 1:
           ...etc...



== class documentation ==

matplotlib uses artist instrospection of docstrings to support
properties.  All properties that you want to support through setp and
getp should have a set_property and get_property method in the Artist
class.  Yes this is not ideal given python properties or enthought
traits, but it is a historical legacy for now.  The setter methods use
the docstring with the ACCEPTS token to indicate the type of argument
the method accepts.  Eg in matplotlib.lines.Line2D

    def set_linestyle(self, linestyle):
        """
        Set the linestyle of the line

        ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' | ' ' | '' ]
        """


Since matplotlib uses a lot of pass through kwargs, eg in every
function that creates a line (plot, semilogx, semilogy, etc...), it
can be difficult for the new user to know which kwargs are supported.
I have developed a docstring interpolation scheme to support
documentation of every function that takes a **kwargs.  The
requirements are:

  1) single point of configuration so changes to the properties don't
     require multiple docstring edits

  2) as automated as possible so that as properties change the docs
     are updated automagically.

I have added a matplotlib.artist.kwdocd to faciliate this.  This
combines python string interpolation in the docstring with the
matplotlib artist introspection facility that underlies setp and getp.
The kwdocd is a single dictionary that maps class name to a docstring
of kwargs.  Here is an example at the bottom of matplotlib.lines

artist.kwdocd['Line2D'] = 
'\n'.join(artist.ArtistInspector(Line2D).pprint_setters(leadingspace=12))

Then in any function accepting Line2D passthrough kwargs, eg
matplotlib.axes.Axes.plot

    def plot(self, *args, **kwargs):
        """
        Some stuff omitted

        The kwargs are Line2D properties:
%(Line2D)s

        kwargs scalex and scaley, if defined, are passed on
        to autoscale_view to determine whether the x and y axes are
        autoscaled; default True.  See Axes.autoscale_view for more
        information
        """
        pass
    plot.__doc__ = plot.__doc__ % artist.kwdocd

Note there is a problem for Artist __init__ methods, eg
Patch.__init__ which supports Patch kwargs, since the artist inspector
cannot work until the class is fully defined and we can't modify the
Patch.__init__.__doc__ docstring outside the class definition.  I have
made some manual hacks in this case which violates the "single entry
point" requirement above; hopefully we'll find a more elegant solution
before too long


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to