forked from matplotlib/matplotlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCODING_GUIDE
293 lines (213 loc) · 10.3 KB
/
CODING_GUIDE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
= The matplotlib developer's guide =
This is meant to be a guide to developers on the mpl coding practices
and standards. Please edit and extend this document.
== svn checkouts ==
# checking out everything (toolkits, user's guide, htdocs, etc..)
svn co https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/trunk matplotlib --username=youruser --password=yourpass
# checking out the main src
svn co https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/trunk/matplotlib matplotlib --username=youruser --password=yourpass
# branch checkouts, eg the transforms branch
svn co https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/transforms transbranch
== Committing changes ==
When committing changes to matplotlib, there are a few things to bear
in mind.
* if your changes are non-trivial, please make an entry in the
CHANGELOG
* if you change the API, please document it in API_CHANGES, and
consider posting 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
* 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?
* if you have added new files or directories, or reorganized
existing ones, are the new files included in the match patterns in
MANIFEST.in. This file determines what goes into the src
distribution of the mpl build.
== Importing and name spaces ==
For numpy, use:
import numpy as npy
a = npy.array([1,2,3])
For masked arrays, use:
import matplotlib.numerix.npyma as ma
(This is needed to support the maskedarray module as an
alternative to the original numpy ma module; eventually,
the maskedarray implementation is likely to replace the
ma implementation.)
For matplotlib main module, use:
import matplotlib as mpl
mpl.rcParams['xtick.major.pad'] = 6
For matplotlib modules (or any other modules), use:
import matplotlib.cbook as cbook
if cbook.iterable(z):
pass
We prefer this over the equivalent 'from matplotlib import cbook'
because the latter is ambiguous whether cbook is a module or a
function to the new developer. The former makes it explcit that
you are importing a module or package.
== Naming, spacing, and formatting conventions ==
In general, we want to hew as closely as possible to the standard
coding guidelines for python written by Guido in
http://www.python.org/dev/peps/pep-0008, though we do not do this
throughout.
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.
Also, use an editor that does not put tabs in files. Four spaces
should be used for indentation everywhere and if there is a file with
tabs or more or less spaces it is a bug -- please fix it.
Please avoid spurious invisible spaces at the ends of lines.
(Tell your editor to strip whitespace from line ends when saving
a file.)
Keep docstrings uniformly indented as in the example below, with
nothing to the left of the triple quotes. The dedent() function
is needed to remove excess indentation only if something will be
interpolated into the docstring, again as in the example above.
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.
Please do not commit lines with trailing white space, as it causes
noise in svn diffs. If you are an emacs user, the following in your
.emacs will cause emacs to strip trailing white space on save for
python, C and C++
; and similarly for c++-mode-hook and c-mode-hook
(add-hook 'python-mode-hook
(lambda ()
(add-hook 'write-file-functions 'delete-trailing-whitespace)))
for older versions of emacs (emacs<22) you need to do
(add-hook 'python-mode-hook
(lambda ()
(add-hook 'local-write-file-hooks 'delete-trailing-whitespace)))
== 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. If not, you may consider contacting the author and asking
them to relicense it. GPL and LGPL code are not acceptible 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.
== Keyword argument processing ==
Matplotlib makes extensive use of **kwargs for pass through
customizations from one function to another. A typical example is in
pylab.text, The definition of the pylab text function is a simple
pass-through to axes.Axes.text
# in pylab.py
def text(*args, **kwargs):
ret = gca().text(*args, **kwargs)
draw_if_interactive()
return ret
axes.Axes.text in simplified form looks like this, ie it just passes
them on to text.Text.__init__
# in axes.py
def text(self, x, y, s, fontdict=None, withdash=False, **kwargs):
t = Text(x=x, y=y, text=s, **kwargs)
and Text.__init__ (again with liberties for illustration) just passes
them on to the artist.Artist.update method
# in text.py
def __init__(self, x=0, y=0, text='', **kwargs):
Artist.__init__(self)
self.update(kwargs)
'update' does the work looking for methods named like 'set_property'
if 'property' is a keyword argument. Ie, noone looks at the keywords,
they just get passed through the API to the artist constructor which
looks for suitably named methods and calls them with the value.
As a general rule, the use of **kwargs should be reserved for
pass-through keyword arguments, as in the examaple above. If I intend
for all the keyword args to be used in some function and not passed
on, 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. As an example of a pop, passthrough
usage, see Axes.plot:
# in axes.py
def plot(self, *args, **kwargs):
scalex = kwargs.pop('scalex', True)
scaley = kwargs.pop('scaley', True)
if not self._hold: self.cla()
lines = []
for line in self._get_lines(*args, **kwargs):
self.add_line(line)
lines.append(line)
The matplotlib.cbook function popd() is rendered
obsolete by the pop() dictionary method introduced in Python 2.3,
so it should not be used for new code.
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
# in contour.py
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
# 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 (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 and kwdoc() to faciliate this.
They 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 from matplotlib.lines
# in lines.py
artist.kwdocd['Line2D'] = artist.kwdoc(Line2D)
Then in any function accepting Line2D passthrough kwargs, eg
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 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