diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..f5c602c0d7b8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,2 @@ +Please refer to the [Coding +Guidelines](http://matplotlib.org/devel/coding_guide.html). diff --git a/MANIFEST.in b/MANIFEST.in index c54d71b42dfb..9838df35c44b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ include CHANGELOG KNOWN_BUGS INSTALL -include INTERACTIVE TODO +include INTERACTIVE TODO CONTRIBUTING.md include Makefile make.osx MANIFEST.in MANIFEST include matplotlibrc.template setup.cfg.template include __init__.py setupext.py setup.py setupegg.py diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst index c49a59c04b6e..a796d57afce2 100644 --- a/doc/devel/coding_guide.rst +++ b/doc/devel/coding_guide.rst @@ -4,136 +4,111 @@ Coding guide ************ -Committing changes -================== +.. _pull-request-checklist: -When committing changes to matplotlib, there are a few things to bear -in mind. +Pull request checklist +====================== -* if your changes are non-trivial, please make an entry in the - :file:`CHANGELOG` +This checklist should be consulted when creating pull requests to make +sure they are complete before merging. These are not intended to be +rigidly followed---it's just an attempt to list in one place all of +the items that are necessary for a good pull request. Of course, some +items will not always apply. -* if you change the API, please document it in :file:`doc/api/api_changes.rst`, - and consider posting to `matplotlib-devel - `_ +Branch selection +---------------- -* Are your changes python2.6 compatible? We support python2.6 and later +* In general, simple bugfixes that are unlikely to introduce new bugs + of their own should be merged onto the maintenance branch. New + features, or anything that changes the API, should be made against + master. The rules are fuzzy here -- when in doubt, try to get some + consensus. -* Can you pass :file:`examples/tests/backend_driver.py`? This is our - poor man's unit test. + * Once changes are merged into the maintenance branch, they should + be merged into master. -* Can you add a test to :file:`lib/matplotlib/tests` to test your changes? +Style +----- -* If you have altered extension code, do you pass - :file:`unit/memleak_hawaii3.py`? +* Formatting should follow `PEP8 + `_. Exceptions to these + rules are acceptable if it makes the code objectively more readable. -* if you have added new files or directories, or reorganized existing - ones, are the new files included in the match patterns in - :file:`MANIFEST.in`. This file determines what goes into the source - distribution of the mpl build. + - You may want to consider installing automatic PEP8 checking in + your editor. -* Keep the maintenance branches and master in sync where it makes sense. +* No tabs (only spaces). No trailing whitespace. -Style guide -=========== - -Importing and name spaces -------------------------- - -For `numpy `_, use:: - - import numpy as np - a = np.array([1,2,3]) + - Configuring your editor to remove these things upon saving will + save a lot of trouble. -For masked arrays, use:: +* Import the following modules using the standard scipy conventions:: - import numpy.ma as ma - -For matplotlib main module, use:: - - import matplotlib as mpl - mpl.rcParams['xtick.major.pad'] = 6 - -For matplotlib modules (or any other modules), use:: + import numpy as np + import numpy.ma as ma + import matplotlib as mpl + from matplotlib import pyplot as plt + import matplotlib.cbook as cbook + import matplotlib.collections as mcol + import matplotlib.patches as mpatches - import matplotlib.cbook as cbook +* See below for additional points about + :ref:`keyword-argument-processing`, if code in your pull request + does that. - if cbook.iterable(z): - pass +* Adding a new pyplot function involves generating code. See + :ref:`new-pyplot-function` for more information. -We prefer this over the equivalent ``from matplotlib import cbook`` -because the latter is ambiguous as to whether ``cbook`` is a module or a -function. The former makes it explicit that you -are importing a module or package. There are some modules with names -that match commonly used local variable names, eg -:mod:`matplotlib.lines` or :mod:`matplotlib.colors`. To avoid the clash, -use the prefix 'm' with the ``import some.thing as -mthing`` syntax, eg:: +Documentation +------------- - import matplotlib.lines as mlines - import matplotlib.transforms as transforms # OK - import matplotlib.transforms as mtransforms # OK, if you want to disambiguate - import matplotlib.transforms as mtrans # OK, if you want to abbreviate +* Every new feature should be documented. If it's a new module, don't + forget to add it to the API docs. -Naming, spacing, and formatting conventions -------------------------------------------- +* Build the docs and make sure all formatting warnings are addressed. -In general, we want to hew as closely as possible to the standard -coding guidelines for python written by Guido in `PEP 0008 -`_, though we do not do this -throughout. +* See :ref:`documenting-matplotlib` for our documentation style guide. -* functions and class methods: ``lower`` or - ``lower_underscore_separated`` +* If your changes are non-trivial, please make an entry in the + :file:`CHANGELOG`. -* attributes and variables: ``lower`` or ``lowerUpper`` +* If your change is a major new feature, add an entry to + :file:`doc/users/whats_new.rst`. -* classes: ``Upper`` or ``MixedCase`` +* If you change the API in a backward-incompatible way, please + document it in :file:`doc/api/api_changes.rst`. -Prefer the shortest names that are still readable. +Testing +------- -Configure your editor to use spaces, not hard tabs. The standard -indentation unit is always four spaces; -if there is a file with -tabs or a different number of spaces it is a bug -- please fix it. -To detect and fix these and other whitespace errors (see below), -use `reindent.py -`_ as -a command-line script. Unless you are sure your editor always -does the right thing, please use reindent.py before committing your -changes in git. +Using the test framework is discussed in detail in the section +:ref:`testing`. -Keep docstrings_ uniformly indented as in the example below, with -nothing to the left of the triple quotes. The -:func:`matplotlib.cbook.dedent` function is needed to remove excess -indentation only if something will be interpolated into the docstring, -again as in the example below. +* If the PR is a bugfix, add a test that fails prior to the change and + passes with the change. Include any relevant issue numbers in the + docstring of the test. -Limit line length to 80 characters. If a logical line needs to be -longer, use parentheses to break it; do not use an escaped newline. -It may be preferable to use a temporary variable to replace a single -long line with two shorter and more readable lines. +* If this is a new feature, add a test that exercises as much of the + new feature as possible. (The `--with-coverage` option may be + useful here). -Please do not commit lines with trailing white space, as it causes -noise in git diffs. Tell your editor to strip whitespace from line -ends when saving a file. If you are an emacs user, the following in -your ``.emacs`` will cause emacs to strip trailing white space upon -saving for python, C and C++: +* Make sure the Travis tests are passing before merging. -.. code-block:: cl + - The Travis tests automatically test on all of the Python versions + matplotlib supports whenever a pull request is created or updated. + The `tox` support in matplotlib may be useful for testing locally. - ; and similarly for c++-mode-hook and c-mode-hook - (add-hook 'python-mode-hook - (lambda () - (add-hook 'write-file-functions 'delete-trailing-whitespace))) +Installation +------------ -for older versions of emacs (emacs<22) you need to do: +* If you have added new files or directories, or reorganized existing + ones, make sure the new files included in the match patterns in + :file:`MANIFEST.in`, and/or in `package_data` in `setup.py`. -.. code-block:: cl +Style guide +=========== - (add-hook 'python-mode-hook - (lambda () - (add-hook 'local-write-file-hooks 'delete-trailing-whitespace))) +.. _keyword-argument-processing: Keyword argument processing --------------------------- @@ -216,85 +191,16 @@ forced to use ``**kwargs``. An example is elif len(args) == 1: ...etc... -.. _docstrings: - -Documentation and docstrings -============================ - -Matplotlib uses artist introspection 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 :class:`~matplotlib.artist.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 :class:`matplotlib.lines.Line2D`:: - - # in lines.py - 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 (:func:`~matplotlib.pyplot.plot`, -:func:`~matplotlib.pyplot.semilogx`, -:func:`~matplotlib.pyplot.semilogy`, etc...), it can be difficult for -the new user to know which ``kwargs`` are supported. Matplotlib uses -a docstring interpolation scheme to support documentation of every -function that takes a ``**kwargs``. The requirements are: +Hints +===== -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. - -The functions :attr:`matplotlib.artist.kwdocd` and -:func:`matplotlib.artist.kwdoc` to facilitate this. They combine -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 from -:mod:`matplotlib.lines`:: - - # in lines.py - artist.kwdocd['Line2D'] = artist.kwdoc(Line2D) - -Then in any function accepting :class:`~matplotlib.lines.Line2D` -pass-through ``kwargs``, eg. :meth:`matplotlib.axes.Axes.plot`:: - - # in axes.py - 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__ = cbook.dedent(plot.__doc__) % artist.kwdocd - -Note there is a problem for :class:`~matplotlib.artist.Artist` -``__init__`` methods, eg. :meth:`matplotlib.patches.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. -There are some some manual hacks in this case, violating the -"single entry point" requirement above -- see the -``artist.kwdocd['Patch']`` setting in :mod:`matplotlib.patches`. +This section describes how to add certain kinds of new features to +matplotlib. .. _custom_backend: Developing a new backend -======================== +------------------------ If you are working on a custom backend, the *backend* setting in :file:`matplotlibrc` (:ref:`customizing-matplotlib`) supports an @@ -316,331 +222,33 @@ external backend via the ``module`` directive. if > python simple_plot.py -d module://my_backend - .. _sample-data: Writing examples -================ +---------------- We have hundreds of examples in subdirectories of :file:`matplotlib/examples`, and these are automatically generated when the website is built to show up both in the `examples `_ and `gallery -`_ sections of the website. Many -people find these examples from the website, and do not have ready -access to the file:`examples` directory in which they reside. Thus -any example data that is required for the example should be added to -the `sample_data `_ git -repository. Then in your example code you can load it into a file -handle with:: - - import matplotlib.cbook as cbook - fh = cbook.get_sample_data('mydata.dat') - -The file will be fetched from the git repo using urllib and updated -when the revision number changes. +`_ sections of the website. - -If you prefer just to get the full path to the file instead of a file -object:: +Any sample data that the example uses should be kept small and +distributed with matplotlib in the +`lib/matplotlib/mpl-data/sample_data/` directory. Then in your +example code you can load it into a file handle with:: import matplotlib.cbook as cbook - datafile = cbook.get_sample_data('mydata.dat', asfileobj=False) - print 'datafile', datafile + fh = cbook.get_sample_data('mydata.dat') +.. _new-pyplot-function: Writing a new pyplot function -============================= +----------------------------- + A large portion of the pyplot interface is automatically generated by the `boilerplate.py` script (in the root of the source tree). To add or remove a plotting method from pyplot, edit the appropriate list in `boilerplate.py` and then run the script which will update the content in `lib/matplotlib/pyplot.py`. Both the changes in `boilerplate.py` and `lib/matplotlib/pyplot.py` should be checked into the repository. - -Testing -======= - -Matplotlib has a testing infrastructure based on nose_, making it easy -to write new tests. The tests are in :mod:`matplotlib.tests`, and -customizations to the nose testing infrastructure are in -:mod:`matplotlib.testing`. (There is other old testing cruft around, -please ignore it while we consolidate our testing to these locations.) - -.. _nose: http://somethingaboutorange.com/mrl/projects/nose/ - -Requirements ------------- - -The following software is required to run the tests: - - - nose_, version 1.0 or later - - - `Ghostscript `_ (to render PDF - files) - - - `Inkscape `_ (to render SVG files) - -Running the tests ------------------ - -Running the tests is simple. Make sure you have nose installed and run -the script :file:`tests.py` in the root directory of the distribution. -The script can take any of the usual `nosetest arguments`_, such as - -=================== =========== -``-v`` increase verbosity -``-d`` detailed error messages -``--with-coverage`` enable collecting coverage information -=================== =========== - -To run a single test from the command line, you can provide a -dot-separated path to the module followed by the function separated by -a colon, eg. (this is assuming the test is installed):: - - python tests.py matplotlib.tests.test_simplification:test_clipping - -An alternative implementation that does not look at command line -arguments works from within Python:: - - import matplotlib - matplotlib.test() - - -.. _`nosetest arguments`: http://somethingaboutorange.com/mrl/projects/nose/1.0.0/usage.html - - -Running tests by any means other than `matplotlib.test()` -does not load the nose "knownfailureif" (Known failing tests) plugin, -causing known-failing tests to fail for real. - -Writing a simple test ---------------------- - -Many elements of Matplotlib can be tested using standard tests. For -example, here is a test from :mod:`matplotlib.tests.test_basic`:: - - from nose.tools import assert_equal - - def test_simple(): - '''very simple example test''' - assert_equal(1+1,2) - -Nose determines which functions are tests by searching for functions -beginning with "test" in their name. - -Writing an image comparison test --------------------------------- - -Writing an image based test is only slightly more difficult than a -simple test. The main consideration is that you must specify the -"baseline", or expected, images in the -:func:`~matplotlib.testing.decorators.image_comparison` decorator. For -example, this test generates a single image and automatically tests -it:: - - import numpy as np - import matplotlib - from matplotlib.testing.decorators import image_comparison - import matplotlib.pyplot as plt - - @image_comparison(baseline_images=['spines_axes_positions']) - def test_spines_axes_positions(): - # SF bug 2852168 - fig = plt.figure() - x = np.linspace(0,2*np.pi,100) - y = 2*np.sin(x) - ax = fig.add_subplot(1,1,1) - ax.set_title('centered spines') - ax.plot(x,y) - ax.spines['right'].set_position(('axes',0.1)) - ax.yaxis.set_ticks_position('right') - ax.spines['top'].set_position(('axes',0.25)) - ax.xaxis.set_ticks_position('top') - ax.spines['left'].set_color('none') - ax.spines['bottom'].set_color('none') - -The first time this test is run, there will be no baseline image to -compare against, so the test will fail. Copy the output images (in -this case `result_images/test_category/spines_axes_positions.*`) to -the `baseline_images` tree in the source directory (in this case -`lib/matplotlib/tests/baseline_images/test_category`) and put them -under source code revision control (with `git add`). When rerunning -the tests, they should now pass. - -There are two optional keyword arguments to the `image_comparison` -decorator: - - - `extensions`: If you only wish to test some of the image formats - (rather than the default `png`, `svg` and `pdf` formats), pass a - list of the extensions to test. - - - `tol`: This is the image matching tolerance, the default `1e-3`. - If some variation is expected in the image between runs, this - value may be adjusted. - -Known failing tests -------------------- - -If you're writing a test, you may mark it as a known failing test with -the :func:`~matplotlib.testing.decorators.knownfailureif` -decorator. This allows the test to be added to the test suite and run -on the buildbots without causing undue alarm. For example, although -the following test will fail, it is an expected failure:: - - from nose.tools import assert_equal - from matplotlib.testing.decorators import knownfailureif - - @knownfailureif(True) - def test_simple_fail(): - '''very simple example test that should fail''' - assert_equal(1+1,3) - -Note that the first argument to the -:func:`~matplotlib.testing.decorators.knownfailureif` decorator is a -fail condition, which can be a value such as True, False, or -'indeterminate', or may be a dynamically evaluated expression. - -Creating a new module in matplotlib.tests ------------------------------------------ - -Let's say you've added a new module named -``matplotlib.tests.test_whizbang_features``. To add this module to -the list of default tests, append its name to ``default_test_modules`` -in :file:`lib/matplotlib/__init__.py`. - -Using tox ---------- - -`Tox `_ is a tool for running tests against multiple -Python environments, including multiple versions of Python (e.g.: 2.6, 2.7, -3.2, etc.) and even different Python implementations altogether (e.g.: CPython, -PyPy, Jython, etc.) - -Testing all 4 versions of Python (2.6, 2.7, 3.1, and 3.2) requires having four -versions of Python installed on your system and on the PATH. Depending on your -operating system, you may want to use your package manager (such as apt-get, -yum or MacPorts) to do this, or use `pythonbrew -`_. - -tox makes it easy to determine if your working copy introduced any regressions -before submitting a pull request. Here's how to use it: - -.. code-block:: bash - - $ pip install tox - $ tox - -You can also run tox on a subset of environments: - -.. code-block:: bash - - $ tox -e py26,py27 - -Tox processes everything serially so it can take a long time to test several -environments. To speed it up, you might try using a new, parallelized version -of tox called ``detox``. Give this a try: - -.. code-block:: bash - - $ pip install -U -i http://pypi.testrun.org detox - $ detox - -Tox is configured using a file called ``tox.ini``. You may need to edit this -file if you want to add new environments to test (e.g.: ``py33``) or if you -want to tweak the dependencies or the way the tests are run. For more info on -the ``tox.ini`` file, see the `Tox Configuration Specification -`_. - -Using Travis CI ---------------- - -`Travis CI `_ is a hosted CI system "in the cloud". - -Travis is configured to receive notifications of new commits to GitHub repos -(via GitHub "service hooks") and to run builds or tests when it sees these new -commits. It looks for a YAML file called ``.travis.yml`` in the root of the -repository to see how to test the project. - -Travis CI is already enabled for the `main matplotlib GitHub repository -`_ -- for example, see `its Travis -page `_. - -If you want to enable Travis CI for your personal matplotlib GitHub repo, -simply enable the repo to use Travis CI in either the Travis CI UI or the -GitHub UI (Admin | Service Hooks). For details, see `the Travis CI Getting -Started page `_. - -Once this is configured, you can see the Travis CI results at -http://travis-ci.org/#!/your_GitHub_user_name/matplotlib -- here's `an example -`_. - -.. _license-discussion: - -Licenses -======== - -Matplotlib only uses BSD compatible code. If you bring in code from -another project make sure it has a PSF, BSD, MIT or compatible license -(see the Open Source Initiative `licenses page -`_ for details on individual -licenses). If it doesn't, you may consider contacting the author and -asking them to relicense it. GPL and LGPL code are not acceptable in -the main code base, though we are considering an alternative way of -distributing L/GPL code through an separate channel, possibly a -toolkit. If you include code, make sure you include a copy of that -code's license in the license directory if the code's license requires -you to distribute the license with it. Non-BSD compatible licenses -are acceptable in matplotlib toolkits (eg basemap), but make sure you -clearly state the licenses you are using. - -Why BSD compatible? -------------------- - -The two dominant license variants in the wild are GPL-style and -BSD-style. There are countless other licenses that place specific -restrictions on code reuse, but there is an important difference to be -considered in the GPL and BSD variants. The best known and perhaps -most widely used license is the GPL, which in addition to granting you -full rights to the source code including redistribution, carries with -it an extra obligation. If you use GPL code in your own code, or link -with it, your product must be released under a GPL compatible -license. I.e., you are required to give the source code to other -people and give them the right to redistribute it as well. Many of the -most famous and widely used open source projects are released under -the GPL, including linux, gcc, emacs and sage. - -The second major class are the BSD-style licenses (which includes MIT -and the python PSF license). These basically allow you to do whatever -you want with the code: ignore it, include it in your own open source -project, include it in your proprietary product, sell it, -whatever. python itself is released under a BSD compatible license, in -the sense that, quoting from the PSF license page:: - - There is no GPL-like "copyleft" restriction. Distributing - binary-only versions of Python, modified or not, is allowed. There - is no requirement to release any of your source code. You can also - write extension modules for Python and provide them only in binary - form. - -Famous projects released under a BSD-style license in the permissive -sense of the last paragraph are the BSD operating system, python and -TeX. - -There are several reasons why early matplotlib developers selected a -BSD compatible license. matplotlib is a python extension, and we -choose a license that was based on the python license (BSD -compatible). Also, we wanted to attract as many users and developers -as possible, and many software companies will not use GPL code in -software they plan to distribute, even those that are highly committed -to open source development, such as `enthought -`_, out of legitimate concern that use of the -GPL will "infect" their code base by its viral nature. In effect, they -want to retain the right to release some proprietary code. Companies -and institutions who use matplotlib often make significant -contributions, because they have the resources to get a job done, even -a boring one. Two of the matplotlib backends (FLTK and WX) were -contributed by private companies. The final reason behind the -licensing choice is compatibility with the other python extensions for -scientific computing: ipython, numpy, scipy, the enthought tool suite -and python itself are all distributed under BSD compatible licenses. diff --git a/doc/devel/documenting_mpl.rst b/doc/devel/documenting_mpl.rst index 4bfb21d9506f..24c3c0341b06 100644 --- a/doc/devel/documenting_mpl.rst +++ b/doc/devel/documenting_mpl.rst @@ -46,6 +46,84 @@ statement, such as:: .. include:: ../../TODO +docstrings +---------- + +In addition to the "narrative" documentation described above, +matplotlib also defines its API reference documentation in docstrings. +For the most part, these are standard Python docstrings, but +matplotlib also includes some features to better support documenting +getters and setters. + +Matplotlib uses artist introspection 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 :class:`~matplotlib.artist.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 :class:`matplotlib.lines.Line2D`:: + + # in lines.py + 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 (:func:`~matplotlib.pyplot.plot`, +:func:`~matplotlib.pyplot.semilogx`, +:func:`~matplotlib.pyplot.semilogy`, etc...), it can be difficult for +the new user to know which ``kwargs`` are supported. Matplotlib uses +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. + +The functions :attr:`matplotlib.artist.kwdocd` and +:func:`matplotlib.artist.kwdoc` to facilitate this. They combine +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 from +:mod:`matplotlib.lines`:: + + # in lines.py + artist.kwdocd['Line2D'] = artist.kwdoc(Line2D) + +Then in any function accepting :class:`~matplotlib.lines.Line2D` +pass-through ``kwargs``, eg. :meth:`matplotlib.axes.Axes.plot`:: + + # in axes.py + 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__ = cbook.dedent(plot.__doc__) % artist.kwdocd + +Note there is a problem for :class:`~matplotlib.artist.Artist` +``__init__`` methods, eg. :meth:`matplotlib.patches.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. +There are some some manual hacks in this case, violating the +"single entry point" requirement above -- see the +``artist.kwdocd['Patch']`` setting in :mod:`matplotlib.patches`. .. _formatting-mpl-docs: @@ -181,11 +259,6 @@ working with Sphinx in general. Here are a few additional things to keep in mind .. _`inline markup`: http://sphinx.pocoo.org/markup/inline.html .. _index: http://sphinx.pocoo.org/markup/para.html#index-generating-markup -Docstrings ----------- - -In addition to the aforementioned formatting suggestions: - * Please limit the text width of docstrings to 70 characters. * Keyword arguments should be described using a definition list. @@ -195,7 +268,6 @@ In addition to the aforementioned formatting suggestions: arguments, there are a many cases where a table is used in place of a definition list for autogenerated sections of docstrings. - Figures ======= diff --git a/doc/devel/gitwash/development_workflow.rst b/doc/devel/gitwash/development_workflow.rst index ef2429082a3a..147d94f9e6ba 100644 --- a/doc/devel/gitwash/development_workflow.rst +++ b/doc/devel/gitwash/development_workflow.rst @@ -134,6 +134,9 @@ without interfering with the output from the comparison. More detail? Note the three dots in the URL above (``master...my-new-feature``) and see :ref:`dot2-dot3`. +It's a good idea to consult the :ref:`pull-request-checklist` to make +sure your pull request is ready for merging. + Asking for your changes to be merged into the main repo ======================================================= diff --git a/doc/devel/index.rst b/doc/devel/index.rst index 16f072b2529a..bc7661660196 100644 --- a/doc/devel/index.rst +++ b/doc/devel/index.rst @@ -13,9 +13,10 @@ :maxdepth: 2 coding_guide.rst + license.rst gitwash/index.rst + testing.rst documenting_mpl.rst release_guide.rst transformations.rst add_new_projection.rst - outline.rst diff --git a/doc/devel/license.rst b/doc/devel/license.rst new file mode 100644 index 000000000000..aea9d7c4f4b7 --- /dev/null +++ b/doc/devel/license.rst @@ -0,0 +1,69 @@ +.. _license-discussion: + +Licenses +======== + +Matplotlib only uses BSD compatible code. If you bring in code from +another project make sure it has a PSF, BSD, MIT or compatible license +(see the Open Source Initiative `licenses page +`_ for details on individual +licenses). If it doesn't, you may consider contacting the author and +asking them to relicense it. GPL and LGPL code are not acceptable in +the main code base, though we are considering an alternative way of +distributing L/GPL code through an separate channel, possibly a +toolkit. If you include code, make sure you include a copy of that +code's license in the license directory if the code's license requires +you to distribute the license with it. Non-BSD compatible licenses +are acceptable in matplotlib toolkits (eg basemap), but make sure you +clearly state the licenses you are using. + +Why BSD compatible? +------------------- + +The two dominant license variants in the wild are GPL-style and +BSD-style. There are countless other licenses that place specific +restrictions on code reuse, but there is an important difference to be +considered in the GPL and BSD variants. The best known and perhaps +most widely used license is the GPL, which in addition to granting you +full rights to the source code including redistribution, carries with +it an extra obligation. If you use GPL code in your own code, or link +with it, your product must be released under a GPL compatible +license. I.e., you are required to give the source code to other +people and give them the right to redistribute it as well. Many of the +most famous and widely used open source projects are released under +the GPL, including linux, gcc, emacs and sage. + +The second major class are the BSD-style licenses (which includes MIT +and the python PSF license). These basically allow you to do whatever +you want with the code: ignore it, include it in your own open source +project, include it in your proprietary product, sell it, +whatever. python itself is released under a BSD compatible license, in +the sense that, quoting from the PSF license page:: + + There is no GPL-like "copyleft" restriction. Distributing + binary-only versions of Python, modified or not, is allowed. There + is no requirement to release any of your source code. You can also + write extension modules for Python and provide them only in binary + form. + +Famous projects released under a BSD-style license in the permissive +sense of the last paragraph are the BSD operating system, python and +TeX. + +There are several reasons why early matplotlib developers selected a +BSD compatible license. matplotlib is a python extension, and we +choose a license that was based on the python license (BSD +compatible). Also, we wanted to attract as many users and developers +as possible, and many software companies will not use GPL code in +software they plan to distribute, even those that are highly committed +to open source development, such as `enthought +`_, out of legitimate concern that use of the +GPL will "infect" their code base by its viral nature. In effect, they +want to retain the right to release some proprietary code. Companies +and institutions who use matplotlib often make significant +contributions, because they have the resources to get a job done, even +a boring one. Two of the matplotlib backends (FLTK and WX) were +contributed by private companies. The final reason behind the +licensing choice is compatibility with the other python extensions for +scientific computing: ipython, numpy, scipy, the enthought tool suite +and python itself are all distributed under BSD compatible licenses. diff --git a/doc/devel/outline.rst b/doc/devel/outline.rst deleted file mode 100644 index d79ccb8bb99f..000000000000 --- a/doc/devel/outline.rst +++ /dev/null @@ -1,222 +0,0 @@ -.. _outline: - -************ -Docs outline -************ - -Proposed chapters for the docs, who has responsibility for them, and -who reviews them. The "unit" doesn't have to be a full chapter -(though in some cases it will be), it may be a chapter or a section in -a chapter. - -======================== ================== ========== =================== -User's guide unit Author Status Reviewer -======================== ================== ========== =================== -plotting 2-D arrays Eric has author Perry ? Darren -colormapping Eric has author ? -quiver plots Eric has author ? -histograms Manuel ? no author Erik Tollerud ? -bar / errorbar ? no author ? -x-y plots ? no author Darren -time series plots ? no author ? -date plots John has author ? -working with data John has author Darren -custom ticking ? no author ? -masked data Eric has author ? -patches ? no author ? -legends ? no author ? -animation John has author ? -collections ? no author ? -text - mathtext Michael accepted John -text - usetex Darren accepted John -text - annotations John submitted ? -fonts et al Michael ? no author Darren -pyplot tut John submitted Eric -configuration Darren submitted ? -win32 install Charlie ? no author Darren -os x install Charlie ? no author ? -linux install Darren has author ? -artist api John submitted ? -event handling John submitted ? -navigation John submitted ? -interactive usage ? no author ? -widgets ? no author ? -ui - gtk ? no author ? -ui - wx ? no author ? -ui - tk ? no author ? -ui - qt Darren has author ? -backend - pdf Jouni ? no author ? -backend - ps Darren has author ? -backend - svg ? no author ? -backend - agg ? no author ? -backend - cairo ? no author ? -======================== ================== ========== =================== - -Here is the ouline for the dev guide, much less fleshed out - -========================== =============== =========== ================== -Developer's guide unit Author Status Reviewer -========================== =============== =========== ================== -the renderer John has author Michael ? -the canvas John has author ? -the artist John has author ? -transforms Michael submitted John -documenting mpl Darren submitted John, Eric, Mike? -coding guide John complete Eric -and_much_more ? ? ? -========================== =============== =========== ================== - -We also have some work to do converting docstrings to ReST for the API -Reference. Please be sure to follow the few guidelines described in -:ref:`formatting-mpl-docs`. Once it is converted, please include the module in -the API documentation and update the status in the table to "converted". Once -docstring conversion is complete and all the modules are available in the docs, -we can figure out how best to organize the API Reference and continue from -there. - -==================== =========== =================== -Module Author Status -==================== =========== =================== -backend_agg needs conversion -backend_cairo needs conversion -backend_cocoa needs conversion -backend_emf needs conversion -backend_fltkagg needs conversion -backend_gdk needs conversion -backend_gtk needs conversion -backend_gtkagg needs conversion -backend_gtkcairo needs conversion -backend_mixed needs conversion -backend_pdf needs conversion -backend_ps Darren needs conversion -backend_qt Darren needs conversion -backend_qtagg Darren needs conversion -backend_qt4 Darren needs conversion -backend_qt4agg Darren needs conversion -backend_svg needs conversion -backend_template needs conversion -backend_tkagg needs conversion -backend_wx needs conversion -backend_wxagg needs conversion -backends/tkagg needs conversion -config/checkdep Darren needs conversion -config/cutils Darren needs conversion -config/mplconfig Darren needs conversion -config/mpltraits Darren needs conversion -config/rcparams Darren needs conversion -config/rcsetup Darren needs conversion -config/tconfig Darren needs conversion -config/verbose Darren needs conversion -projections/__init__ Mike converted -projections/geo Mike converted (not included--experimental) -projections/polar Mike converted -afm converted -artist converted -axes converted -axis converted -backend_bases converted -cbook converted -cm converted -collections converted -colorbar converted -colors converted -contour needs conversion -dates Darren needs conversion -dviread Darren needs conversion -figure Darren needs conversion -finance Darren needs conversion -font_manager Mike converted -fontconfig_pattern Mike converted -image needs conversion -legend needs conversion -lines Mike & ??? converted -mathtext Mike converted -mlab John/Mike converted -mpl N/A -patches Mike converted -path Mike converted -pylab N/A -pyplot converted -quiver needs conversion -rcsetup needs conversion -scale Mike converted -table needs conversion -texmanager Darren needs conversion -text Mike converted -ticker John converted -transforms Mike converted -type1font needs conversion -units needs conversion -widgets needs conversion -==================== =========== =================== - -And we might want to do a similar table for the FAQ, but that may also be overkill... - -If you agree to author a unit, remove the question mark by your name -(or add your name if there is no candidate), and change the status to -"has author". Once you have completed draft and checked it in, you -can change the status to "submitted" and try to find a reviewer if you -don't have one. The reviewer should read your chapter, test it for -correctness (eg try your examples) and change the status to "complete" -when done. - -You are free to lift and convert as much material from the web site or -the existing latex user's guide as you see fit. The more the better. - -The UI chapters should give an example or two of using mpl with your -GUI and any relevant info, such as version, installation, config, -etc... The backend chapters should cover backend specific -configuration (eg PS only options), what features are missing, etc... - -Please feel free to add units, volunteer to review or author a -chapter, etc... - -It is probably easiest to be an editor. Once you have signed up to be -an editor, if you have an author pester the author for a submission -every so often. If you don't have an author, find one, and then pester -them! Your only two responsibilities are getting your author to -produce and checking their work, so don't be shy. You *do not* need -to be an expert in the subject you are editing -- you should know -something about it and be willing to read, test, give feedback and -pester! - -Reviewer notes -============== - -If you want to make notes for the authorwhen you have reviewed a -submission, you can put them here. As the author cleans them up or -addresses them, they should be removed. - -mathtext user's guide-- reviewed by JDH ---------------------------------------- - -This looks good (see :ref:`mathtext-tutorial`) -- there are a few -minor things to close the book on this chapter: - -#. The main thing to wrap this up is getting the mathtext module - ported over to rest and included in the API so the links from the - user's guide tutorial work. - - - There's nothing in the mathtext module that I really consider a - "public" API (i.e. that would be useful to people just doing - plots). If mathtext.py were to be documented, I would put it in - the developer's docs. Maybe I should just take the link in the - user's guide out. - MGD - -#. This section might also benefit from a little more detail on the - customizations that are possible (eg an example fleshing out the rc - options a little bit). Admittedly, this is pretty clear from - readin ghte rc file, but it might be helpful to a newbie. - - - The only rcParam that is currently useful is mathtext.fontset, - which is documented here. The others only apply when - mathtext.fontset == 'custom', which I'd like to declare - "unsupported". It's really hard to get a good set of math fonts - working that way, though it might be useful in a bind when - someone has to use a specific wacky font for mathtext and only - needs basics, like sub/superscripts. - MGD - -#. There is still a TODO in the file to include a complete list of symbols - - - Done. It's pretty extensive, thanks to STIX... - MGD - diff --git a/doc/devel/release_guide.rst b/doc/devel/release_guide.rst index 8823e34d7095..e38ba7072c7c 100644 --- a/doc/devel/release_guide.rst +++ b/doc/devel/release_guide.rst @@ -8,10 +8,6 @@ A guide for developers who are doing a matplotlib release * Edit :file:`__init__.py` and bump the version number - - -When doing a release - .. _release-testing: Testing @@ -35,7 +31,7 @@ Testing .. _release-branching: Branching -============ +========= Once all the tests are passing and you are ready to do a release, you need to create a release branch:: @@ -61,13 +57,16 @@ release after the fact, just track down the commit hash, and:: Tags allow developers to quickly checkout different releases by name, and also provides source download via zip and tarball on github. +Then push the tags to the main repository:: + + git push upstream v1.0.1 + .. _release-packaging: Packaging ========= - -* Make sure the :file:`MANIFEST.in` us up to date and remove +* Make sure the :file:`MANIFEST.in` is up to date and remove :file:`MANIFEST` so it will be rebuilt by MANIFEST.in * run `git clean` in the mpl git directory before building the sdist @@ -102,6 +101,32 @@ there. .. _release-announcing: +Documentation updates +===================== + +The built documentation exists in the `matplotlib.github.com +`_ repository. +Pushing changes to master automatically updates the website. + +In the matplotlib source repository, build the documentation:: + + cd doc + python make.py html + python make.py latex + +Then copy the build products into your local checkout of the +`matplotlib.github.com` repository (assuming here to be checked out in +`~/matplotlib.github.com`:: + + cp -r build/html/* ~/matplotlib.github.com + cp build/latex/Matplotlib.pdf ~/matplotlib.github.com + +Then, from the `matplotlib.github.com` directory, commit and push the +changes upstream:: + + git commit -m "Updating for v1.0.1" + git push upstream master + Announcing ========== diff --git a/doc/devel/testing.rst b/doc/devel/testing.rst new file mode 100644 index 000000000000..0f8ba4346837 --- /dev/null +++ b/doc/devel/testing.rst @@ -0,0 +1,246 @@ +.. _testing: + +Testing +======= + +Matplotlib has a testing infrastructure based on nose_, making it easy +to write new tests. The tests are in :mod:`matplotlib.tests`, and +customizations to the nose testing infrastructure are in +:mod:`matplotlib.testing`. (There is other old testing cruft around, +please ignore it while we consolidate our testing to these locations.) + +.. _nose: http://somethingaboutorange.com/mrl/projects/nose/ + +Requirements +------------ + +The following software is required to run the tests: + + - nose_, version 1.0 or later + + - `Ghostscript `_ (to render PDF + files) + + - `Inkscape `_ (to render SVG files) + +Running the tests +----------------- + +Running the tests is simple. Make sure you have nose installed and run +the script :file:`tests.py` in the root directory of the distribution. +The script can take any of the usual `nosetest arguments`_, such as + +=================== =========== +``-v`` increase verbosity +``-d`` detailed error messages +``--with-coverage`` enable collecting coverage information +=================== =========== + +To run a single test from the command line, you can provide a +dot-separated path to the module followed by the function separated by +a colon, eg. (this is assuming the test is installed):: + + python tests.py matplotlib.tests.test_simplification:test_clipping + +An alternative implementation that does not look at command line +arguments works from within Python:: + + import matplotlib + matplotlib.test() + + +.. _`nosetest arguments`: http://somethingaboutorange.com/mrl/projects/nose/1.0.0/usage.html + + +Running tests by any means other than `matplotlib.test()` +does not load the nose "knownfailureif" (Known failing tests) plugin, +causing known-failing tests to fail for real. + +Writing a simple test +--------------------- + +Many elements of Matplotlib can be tested using standard tests. For +example, here is a test from :mod:`matplotlib.tests.test_basic`:: + + from nose.tools import assert_equal + + def test_simple(): + """ + very simple example test + """ + assert_equal(1+1,2) + +Nose determines which functions are tests by searching for functions +beginning with "test" in their name. + +If the test as side effects that need to be cleaned up, such as +creating figures using the pyplot interface, use the ``@cleanup`` +decorator:: + + from matplotlib.testing.decorators import cleanup + + @cleanup + def test_create_figure(): + """ + very simple example test that creates a figure using pyplot. + """ + fig = figure() + ... + + +Writing an image comparison test +-------------------------------- + +Writing an image based test is only slightly more difficult than a +simple test. The main consideration is that you must specify the +"baseline", or expected, images in the +:func:`~matplotlib.testing.decorators.image_comparison` decorator. For +example, this test generates a single image and automatically tests +it:: + + import numpy as np + import matplotlib + from matplotlib.testing.decorators import image_comparison + import matplotlib.pyplot as plt + + @image_comparison(baseline_images=['spines_axes_positions']) + def test_spines_axes_positions(): + # SF bug 2852168 + fig = plt.figure() + x = np.linspace(0,2*np.pi,100) + y = 2*np.sin(x) + ax = fig.add_subplot(1,1,1) + ax.set_title('centered spines') + ax.plot(x,y) + ax.spines['right'].set_position(('axes',0.1)) + ax.yaxis.set_ticks_position('right') + ax.spines['top'].set_position(('axes',0.25)) + ax.xaxis.set_ticks_position('top') + ax.spines['left'].set_color('none') + ax.spines['bottom'].set_color('none') + +The first time this test is run, there will be no baseline image to +compare against, so the test will fail. Copy the output images (in +this case `result_images/test_category/spines_axes_positions.*`) to +the `baseline_images` tree in the source directory (in this case +`lib/matplotlib/tests/baseline_images/test_category`) and put them +under source code revision control (with `git add`). When rerunning +the tests, they should now pass. + +There are two optional keyword arguments to the `image_comparison` +decorator: + + - `extensions`: If you only wish to test some of the image formats + (rather than the default `png`, `svg` and `pdf` formats), pass a + list of the extensions to test. + + - `tol`: This is the image matching tolerance, the default `1e-3`. + If some variation is expected in the image between runs, this + value may be adjusted. + +Known failing tests +------------------- + +If you're writing a test, you may mark it as a known failing test with +the :func:`~matplotlib.testing.decorators.knownfailureif` +decorator. This allows the test to be added to the test suite and run +on the buildbots without causing undue alarm. For example, although +the following test will fail, it is an expected failure:: + + from nose.tools import assert_equal + from matplotlib.testing.decorators import knownfailureif + + @knownfailureif(True) + def test_simple_fail(): + '''very simple example test that should fail''' + assert_equal(1+1,3) + +Note that the first argument to the +:func:`~matplotlib.testing.decorators.knownfailureif` decorator is a +fail condition, which can be a value such as True, False, or +'indeterminate', or may be a dynamically evaluated expression. + +Creating a new module in matplotlib.tests +----------------------------------------- + +We try to keep the tests categorized by the primary module they are +testing. For example, the tests related to the ``mathtext.py`` module +are in ``test_mathtext.py``. + +Let's say you've added a new module named ``whizbang.py`` and you want +to add tests for it in ``matplotlib.tests.test_whizbang``. To add +this module to the list of default tests, append its name to +``default_test_modules`` in :file:`lib/matplotlib/__init__.py`. + +Using tox +--------- + +`Tox `_ is a tool for running tests against +multiple Python environments, including multiple versions of Python +(e.g.: 2.6, 2.7, 3.2, etc.) and even different Python implementations +altogether (e.g.: CPython, PyPy, Jython, etc.) + +Testing all 4 versions of Python (2.6, 2.7, 3.1, and 3.2) requires +having four versions of Python installed on your system and on the +PATH. Depending on your operating system, you may want to use your +package manager (such as apt-get, yum or MacPorts) to do this, or use +`pythonbrew `_. + +tox makes it easy to determine if your working copy introduced any +regressions before submitting a pull request. Here's how to use it: + +.. code-block:: bash + + $ pip install tox + $ tox + +You can also run tox on a subset of environments: + +.. code-block:: bash + + $ tox -e py26,py27 + +Tox processes everything serially so it can take a long time to test +several environments. To speed it up, you might try using a new, +parallelized version of tox called ``detox``. Give this a try: + +.. code-block:: bash + + $ pip install -U -i http://pypi.testrun.org detox + $ detox + +Tox is configured using a file called ``tox.ini``. You may need to +edit this file if you want to add new environments to test (e.g.: +``py33``) or if you want to tweak the dependencies or the way the +tests are run. For more info on the ``tox.ini`` file, see the `Tox +Configuration Specification +`_. + +Using Travis CI +--------------- + +`Travis CI `_ is a hosted CI system "in the +cloud". + +Travis is configured to receive notifications of new commits to GitHub +repos (via GitHub "service hooks") and to run builds or tests when it +sees these new commits. It looks for a YAML file called +``.travis.yml`` in the root of the repository to see how to test the +project. + +Travis CI is already enabled for the `main matplotlib GitHub +repository `_ -- for +example, see `its Travis page +`_. + +If you want to enable Travis CI for your personal matplotlib GitHub +repo, simply enable the repo to use Travis CI in either the Travis CI +UI or the GitHub UI (Admin | Service Hooks). For details, see `the +Travis CI Getting Started page +`_. This +generally isn't necessary, since any pull request submitted against +the main matplotlib repository will be tested. + +Once this is configured, you can see the Travis CI results at +http://travis-ci.org/#!/your_GitHub_user_name/matplotlib -- here's `an +example `_.