8000 Merge pull request #1945 from pelson/pep8_testing · matplotlib/matplotlib@d5071f4 · GitHub
[go: up one dir, main page]

Skip to content

Commit d5071f4

Browse files
committed
Merge pull request #1945 from pelson/pep8_testing
PEP8 testing
2 parents b239626 + bd4f6fd commit d5071f4

File tree

14 files changed

+299
-43
lines changed

14 files changed

+299
-43
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ python:
77
- 3.3
88

99
install:
10-
- pip -q install --use-mirrors nose python-dateutil numpy
10+
- pip install -q --use-mirrors nose python-dateutil numpy pep8
1111
# This is a workaround to install the latest versions of pyparsing,
1212
# which are not yet available on PyPI
1313
- 'if [ ${TRAVIS_PYTHON_VERSION:0:1} == "3" ]; then pip -q install http://sourceforge.net/projects/pyparsing/files/pyparsing/pyparsing-2.0.0/pyparsing-2.0.0.tar.gz; fi'

lib/matplotlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,7 @@ def tk_window_focus():
11771177
'matplotlib.tests.test_basic',
11781178
'matplotlib.tests.test_bbox_tight',
11791179
'matplotlib.tests.test_cbook',
1180+
'matplotlib.tests.test_coding_standards',
11801181
'matplotlib.tests.test_collections',
11811182
'matplotlib.tests.test_colorbar',
11821183
'matplotlib.tests.test_colors',

lib/matplotlib/cm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def __init__(self, norm=None, cmap=None):
188188
if norm is None:
189189
norm = colors.Normalize()
190190

191-
self._A = None;
191+
self._A = None
192192
#: The Normalization instance of this ScalarMappable.
193193
self.norm = norm
194194
#: The Colormap instance of this ScalarMappable.

lib/matplotlib/colorbar.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -501,12 +501,10 @@ def _add_solids(self, X, Y, C):
501501
self.dividers.remove()
502502
self.dividers = None
503503
if self.drawedges:
504-
self.dividers = collections.LineCollection(
505-
self._edges(X, Y),
504+
linewidths = (0.5 * mpl.rcParams['axes.linewidth'],)
505+
self.dividers = collections.LineCollection(self._edges(X, Y),
506506
colors=(mpl.rcParams['axes.edgecolor'],),
507-
linewidths=(
508-
0.5 * mpl.rcParams['axes.linewidth'],)
509-
)
507+
linewidths=linewidths)
510508
self.ax.add_collection(self.dividers)
511509

512510
def add_lines(self, levels, colors, linewidths, erase=True):
@@ -725,9 +723,9 @@ def _uniform_y(self, N):
725723
y = np.linspace(0, 1, N)
726724
else:
727725
automin = automax = 1. / (N - 1.)
728-
extendlength = self._get_extension_lengths(
729-
self.extendfrac,
730-
automin, automax, default=0.05)
726+
extendlength = self._get_extension_lengths(self.extendfrac,
727+
automin, automax,
728+
default=0.05)
731729
if self.extend == 'both':
732730
y = np.zeros(N + 2, 'd')
733731
y[0] = 0. - extendlength[0]
@@ -986,19 +984,23 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
986984
'''
987985
locations = ["left", "right", "top", "bottom"]
988986
if orientation is not None and location is not None:
989-
raise TypeError('position and orientation are mutually exclusive. Consider ' \
990-
'setting the position to any of %s' % ', '.join(locations))
987+
msg = ('position and orientation are mutually exclusive. '
988+
'Consider setting the position to any of '
989+
'{0}'.format(', '.join(locations)))
990+
raise TypeError(msg)
991991

992992
# provide a default location
993993
if location is None and orientation is None:
994994
location = 'right'
995995

996-
# allow the user to not specify the location by specifying the orientation instead
996+
# allow the user to not specify the location by specifying the
997+
# orientation instead
997998
if location is None:
998999
location = 'right' if orientation == 'vertical' else 'bottom'
9991000

10001001
if location not in locations:
1001-
raise ValueError('Invalid colorbar location. Must be one of %s' % ', '.join(locations))
1002+
raise ValueError('Invalid colorbar location. Must be one '
1003+
'of %s' % ', '.join(locations))
10021004

10031005
default_location_settings = {'left': {'anchor': (1.0, 0.5),
10041006
'panchor': (0.0, 0.5),
@@ -1014,7 +1016,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
10141016
'orientation': 'horizontal'},
10151017
'bottom': {'anchor': (0.5, 1.0),
10161018
'panchor': (0.5, 0.0),
1017-
'pad': 0.15, # backwards compat
1019+
'pad': 0.15, # backwards compat
10181020
'orientation': 'horizontal'},
10191021
}
10201022

@@ -1029,19 +1031,18 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
10291031
parent_anchor = kw.pop('panchor', loc_settings['panchor'])
10301032
pad = kw.pop('pad', loc_settings['pad'])
10311033

1032-
10331034
# turn parents into a list if it is not already
10341035
if not isinstance(parents, (list, tuple)):
10351036
parents = [parents]
10361037

10371038
fig = parents[0].get_figure()
10381039
if not all(fig is ax.get_figure() for ax in parents):
1039-
raise ValueError('Unable to create a colorbar axes as not all ' + \
1040+
raise ValueError('Unable to create a colorbar axes as not all '
10401041
'parents share the same figure.')
10411042

10421043
# take a bounding box around all of the given axes
1043-
parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen() \
1044-
for ax in parents])
1044+
parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen()
1045+
for ax in parents])
10451046

10461047
pb = parents_bbox
10471048
if location in ('left', 'right'):
@@ -1054,11 +1055,11 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
10541055
if location == 'bottom':
10551056
pbcb, _, pb1 = pb.splity(fraction, fraction + pad)
10561057
else:
1057-
pb1, _, pbcb = pb.splity(1 - fraction - pad, 1 - fraction)
1058+
pb1, _, pbcb = pb.splity(1 - fraction - pad, 1 - fraction)
10581059
pbcb = pbcb.shrunk(shrink, 1.0).anchored(anchor, pbcb)
10591060

10601061
# define the aspect ratio in terms of y's per x rather than x's per y
1061-
aspect = 1.0/aspect
1062+
aspect = 1.0 / aspect
10621063

10631064
# define a transform which takes us from old axes coordinates to
10641065
# new axes coordinates

lib/matplotlib/lines.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -613,12 +613,13 @@ def draw(self, renderer):
613613
if self.get_path_effects():
614614
affine_frozen = affine.frozen()
615615
for pe in self.get_path_effects():
616-
pe.draw_markers(renderer, gc, marker_path, marker_trans,
617-
subsampled, affine_frozen, rgbaFace)
616+
pe.draw_markers(renderer, gc, marker_path,
617+
marker_trans, subsampled,
618+
affine_frozen, rgbaFace)
618619
else:
619-
renderer.draw_markers(
620-
gc, marker_path, marker_trans, subsampled, affine.frozen(),
621-
rgbaFace)
620+
renderer.draw_markers(gc, marker_path, marker_trans,
621+
subsampled, affine.frozen(),
622+
rgbaFace)
622623

623624
alt_marker_path = marker.get_alt_path()
624625
if alt_marker_path:

lib/matplotlib/scale.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ def inverted(self):
359359
return InvertedSymmetricalLogTransform(self.base, self.linthresh,
360360
self.linscale)
361361

362+
362363
class InvertedSymmetricalLogTransform(Transform):
363364
input_dims = 1
364365
output_dims = 1
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
from fnmatch import fnmatch
2+
import os
3+
import sys
4+
5+
from nose.tools import assert_equal
6+
import pep8
7+
8+
import matplotlib
9+
10+
11+
class StandardReportWithExclusions(pep8.StandardReport):
12+
#; A class attribute to store the exception exclusion file patterns.
13+
expected_bad_files = [
14+
'*/matplotlib/__init__.py',
15+
'*/matplotlib/_cm.py',
16+
'*/matplotlib/_mathtext_data.py',
17+
'*/matplotlib/_pylab_helpers.py',
18+
'*/matplotlib/afm.py',
19+
'*/matplotlib/animation.py',
20+
'*/matplotlib/artist.py',
21+
'*/matplotlib/axes.py',
22+
'*/matplotlib/axis.py',
23+
'*/matplotlib/backend_bases.py',
24+
'*/matplotlib/bezier.py',
25+
'*/matplotlib/cbook.py',
26+
'*/matplotlib/collections.py',
27+
'*/matplotlib/docstring.py',
28+
'*/matplotlib/dviread.py',
29+
'*/matplotlib/finance.py',
30+
'*/matplotlib/font_manager.py',
31+
'*/matplotlib/fontconfig_pattern.py',
32+
'*/matplotlib/gridspec.py',
33+
'*/matplotlib/legend.py',
34+
'*/matplotlib/legend_handler.py',
35+
'*/matplotlib/mathtext.py',
36+
'*/matplotlib/mlab.py',
37+
'*/matplotlib/path.py',
38+
'*/matplotlib/patheffects.py',
39+
'*/matplotlib/pylab.py',
40+
'*/matplotlib/pyplot.py',
41+
'*/matplotlib/rcsetup.py',
42+
'*/matplotlib/stackplot.py',
43+
'*/matplotlib/texmanager.py',
44+
'*/matplotlib/text.py',
45+
'*/matplotlib/transforms.py',
46+
'*/matplotlib/type1font.py',
47+
'*/matplotlib/widgets.py',
48+
'*/matplotlib/testing/compare.py',
49+
'*/matplotlib/testing/decorators.py',
50+
'*/matplotlib/testing/image_util.py',
51+
'*/matplotlib/testing/noseclasses.py',
52+
'*/matplotlib/testing/jpl_units/Duration.py',
53+
'*/matplotlib/testing/jpl_units/Epoch.py',
54+
'*/matplotlib/testing/jpl_units/EpochConverter.py',
55+
'*/matplotlib/testing/jpl_units/StrConverter.py',
56+
'*/matplotlib/testing/jpl_units/UnitDbl.py',
57+
'*/matplotlib/testing/jpl_units/UnitDblConverter.py',
58+
'*/matplotlib/testing/jpl_units/UnitDblFormatter.py',
59+
'*/matplotlib/testing/jpl_units/__init__.py',
60+
'*/matplotlib/tri/tricontour.py',
61+
'*/matplotlib/tri/triinterpolate.py',
62+
'*/matplotlib/tri/tripcolor.py',
63+
'*/matplotlib/tri/triplot.py',
64+
'*/matplotlib/tests/__init__.py',
65+
'*/matplotlib/tests/test_agg.py',
66+
'*/matplotlib/tests/test_animation.py',
67+
'*/matplotlib/tests/test_arrow_patches.py',
68+
'*/matplotlib/tests/test_artist.py',
69+
'*/matplotlib/tests/test_axes.py',
70+
'*/matplotlib/tests/test_backend_pdf.py',
71+
'*/matplotlib/tests/test_backend_pgf.py',
72+
'*/matplotlib/tests/test_backend_svg.py',
73+
'*/matplotlib/tests/test_basic.py',
74+
'*/matplotlib/tests/test_bbox_tight.py',
75+
'*/matplotlib/tests/test_cbook.py',
76+
'*/matplotlib/tests/test_colorbar.py',
77+
'*/matplotlib/tests/test_colors.py',
78+
'*/matplotlib/tests/test_compare_images.py',
79+
'*/matplotlib/tests/test_contour.py',
80+
'*/matplotlib/tests/test_dates.py',
81+
'*/matplotlib/tests/test_delaunay.py',
82+
'*/matplotlib/tests/test_dviread.py',
83+
'*/matplotlib/tests/test_image.py',
84+
'*/matplotlib/tests/test_legend.py',
85+
'*/matplotlib/tests/test_lines.py',
86+
'*/matplotlib/tests/test_mathtext.py',
87+
'*/matplotlib/tests/test_patches.py',
88+
'*/matplotlib/tests/test_pickle.py',
89+
'*/matplotlib/tests/test_png.py',
90+
'*/matplotlib/tests/test_rcparams.py',
91+
'*/matplotlib/tests/test_simplification.py',
92+
'*/matplotlib/tests/test_spines.py',
93+
'*/matplotlib/tests/test_streamplot.py',
94+
'*/matplotlib/tests/test_subplots.py',
95+
'*/matplotlib/tests/test_text.py',
96+
'*/matplotlib/tests/test_tightlayout.py',
97+
'*/matplotlib/tests/test_transforms.py',
98+
'*/matplotlib/tests/test_triangulation.py',
99+
'*/matplotlib/compat/subprocess.py',
100+
'*/matplotlib/backends/__init__.py',
101+
'*/matplotlib/backends/backend_agg.py',
102+
'*/matplotlib/backends/backend_cairo.py',
103+
'*/matplotlib/backends/backend_cocoaagg.py',
104+
'*/matplotlib/backends/backend_gdk.py',
105+
'*/matplotlib/backends/backend_gtk.py',
106+
'*/matplotlib/backends/backend_gtk3.py',
107+
'*/matplotlib/backends/backend_gtk3cairo.py',
108+
'*/matplotlib/backends/backend_gtkagg.py',
109+
'*/matplotlib/backends/backend_gtkcairo.py',
110+
'*/matplotlib/backends/backend_macosx.py',
111+
'*/matplotlib/backends/backend_mixed.py',
112+
'*/matplotlib/backends/backend_pdf.py',
113+
'*/matplotlib/backends/backend_pgf.py',
114+
'*/matplotlib/backends/backend_ps.py',
115+
'*/matplotlib/backends/backend_qt4.py',
116+
'*/matplotlib/backends/backend_qt4agg.py',
117+
'*/matplotlib/backends/backend_svg.py',
118+
'*/matplotlib/backends/backend_template.py',
119+
'*/matplotlib/backends/backend_tkagg.py',
120+
'*/matplotlib/backends/backend_webagg.py',
121+
'*/matplotlib/backends/backend_wx.py',
122+
'*/matplotlib/backends/backend_wxagg.py',
123+
'*/matplotlib/backends/qt4_compat.py',
124+
'*/matplotlib/backends/tkagg.py',
125+
'*/matplotlib/backends/windowing.py',
126+
'*/matplotlib/backends/qt4_editor/figureoptions.py',
127+
'*/matplotlib/backends/qt4_editor/formlayout.py',
128+
'*/matplotlib/sphinxext/__init__.py',
129+
'*/matplotlib/sphinxext/ipython_console_highlighting.py',
130+
'*/matplotlib/sphinxext/ipython_directive.py',
131+
'*/matplotlib/sphinxext/mathmpl.py',
132+
'*/matplotlib/sphinxext/only_directives.py',
133+
'*/matplotlib/sphinxext/plot_directive.py',
134+
'*/matplotlib/projections/__init__.py',
135+
'*/matplotlib/projections/geo.py',
136+
'*/matplotlib/projections/polar.py']
137+
138+
#: A class attribute to store patterns which have seen exceptions.
139+
matched_exclusions = set()
140+
141+
def get_file_results(self):
142+
# If the file had no errors, return self.file_errors (which will be 0)
143+
if not self._deferred_print:
144+
return self.file_errors
145+
146+
# Iterate over all of the patterns, to find a possible exclusion. If we
147+
# the filename is to be excluded, go ahead and remove the counts that
148+
# self.error added.
149+
for pattern in self.expected_bad_files:
150+
if fnmatch(self.filename, pattern):
151+
self.matched_exclusions.add(pattern)
152+
# invert the error method's counters.
153+
for _, _, code, _, _ in self._deferred_print:
154+
self.counters[code] -= 1
155+
if self.counters[code] == 0:
156+
self.counters.pop(code)
157+
self.messages.pop(code)
158+
self.file_errors -= 1
159+
self.total_errors -= 1
160+
return self.file_errors
161+
162+
# Otherwise call the superclass' method to print the bad results.
163+
return super(StandardReportWithExclusions,
164+
self).get_file_results()
165+
166+
167+
def test_pep8_conformance():
168+
# Tests the matplotlib codebase against the "pep8" tool.
169+
#
170+
# Users can add their own excluded files (should files exist in the
171+
# local directory which is not in the repository) by adding a
172+
# ".pep8_test_exclude.txt" file in the same directory as this test.
173+
# The file should be a line separated list of filenames/directories
174+
# as can be passed to the "pep8" tool's exclude list.
175+
176+
# Only run this test with Python 2 - the 2to3 tool generates non pep8
177+
# compliant code.
178+
if sys.version_info[0] != 2:
179+
return
180+
181+
# to get a list of bad files, rather than the specific errors, add
182+
# "reporter=pep8.FileReport" to the StyleGuide constructor.
183+
pep8style = pep8.StyleGuide(quiet=False,
184+
reporter=StandardReportWithExclusions)
185+
186+
# Extend the number of PEP8 guidelines which are not checked.
187+
pep8style.options.ignore = pep8style.options.ignore + ('E121', 'E122',
188+
'E123', 'E124', 'E125', 'E126', 'E127',
189+
'E128')
190+
191+
# Support for egg shared object wrappers, which are not PEP8 compliant,
192+
# nor part of the matplotlib repository.
193+
# DO NOT ADD FILES *IN* THE REPOSITORY TO THIS LIST.
194+
pep8style.options.exclude.extend(
195+
['_delaunay.py',
196+
'_image.py',
197+
'_tri.py',
198+
'_backend_agg.py',
199+
'_tkagg.py',
200+
'ft2font.py',
201+
'_cntr.py',
202+
'_png.py',
203+
'_path.py',
204+
'ttconv.py',
205+
'pyparsing*'])
206+
207+
# Allow users to add their own exclude list.
208+
extra_exclude_file = os.path.join(os.path.dirname(__file__),
209+
'.pep8_test_exclude.txt')
210+
if os.path.exists(extra_exclude_file):
211+
with open(extra_exclude_file, 'r') as fh:
212+
extra_exclude = [line.strip() for line in fh if line.strip()]
213+
pep8style.options.exclude.extend(extra_exclude)
214+
215+
result = pep8style.check_files([os.path.dirname(matplotlib.__file__)])
216+
assert_equal(result.total_errors, 0, "Found code syntax "
217+
"errors (and warnings).")
218+
219+
reporter = pep8style.options.reporter
220+
# If we've been using the exclusions reporter, check that we didn't
221+
# exclude files unnecessarily.
222+
if reporter is StandardReportWithExclusions:
223+
unexpectedly_good = sorted(set(reporter.expected_bad_files) -
224+
reporter.matched_exclusions)
225+
226+
if unexpectedly_good:
227+
raise ValueError('Some exclude patterns were unnecessary as the '
228+
'files they pointed to either passed the PEP8 '
229+
'tests or do not point to a file:\n '
230+
'{}'.format('\n '.join(unexpectedly_good)))
231+
232+
233+
if __name__ == '__main__':
234+
import nose
235+
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

0 commit comments

Comments
 (0)
0