Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

PEP8 testing #1945

Merged
merged 5 commits into from

4 participants

@pelson
Collaborator

Added a coding_standards test module. Currently checks PEP8 compliance on all files except those explicitly excluded.

@NelleV's work on getting PEP8 compliance has been really valuable - this test makes sure that that work is being carried on by all of us in our development efforts.

@mdboom mdboom commented on the diff
lib/matplotlib/tests/test_coding_standards.py
((183 lines not shown))
+ self.total_errors -= 1
+ return self.file_errors
+
+ # Otherwise call the superclass' method to print the bad results.
+ return super(StandardReportWithExclusions,
+ self).get_file_results()
+
+
+def test_pep8_conformance():
+# Tests the matplotlib codebase against the "pep8" tool.
+#
+# Users can add their own excluded files (should files exist in the
+# local directory which is not in the repository) by adding a
+# ".pep8_test_exclude.txt" file in the same directory as this test.
+# The file should be a line separated list of filenames/directories
+# as can be passed to the "pep8" tool's exclude list.
@mdboom Owner
mdboom added a note

Shouldn't this comment above just be a docstring? Also, it seems out of date with what's actually here.

@pelson Collaborator
pelson added a note

I don't think its out of date (I suppose there is more going on in the method than the comment suggests?). Is there a specific part which is out of date?

If I convert it to a docstring, you end up with annoying output when running the tests. This can be avoided though (see http://stackoverflow.com/questions/12962772/how-to-stop-python-unittest-from-printing-test-docstring)

@mdboom Owner
mdboom added a note

Ah, I see. Let's leave it as a comment then.

I was confused by the list of exclusions in this file and the mention of .pep8_test_exclude. Why are there two different methods for defining exclusions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mdboom
Owner

I think this is a great idea. My only worry is that some PEP8 warning categories can and should be reasonably broken in certain contexts (some of the whitespace ones for example). I wonder if there's any warning categories that if we turned off, more files would become compliant...?

@NelleV
Collaborator

@mdboom We can filter warnings from PEP8. I would suggest filtering the following (which are a bit strict):
E121,E122,E123,E124,E125,E126,E127,E128

I think the most important is not to check whether the file is pep8, but more whether the file is more and more pep8, but I'm not sure how we could do this automatically in the tests (on scikit-learn, we have a jenkins tests for this, which is just here to plot how much warnings we have - the goal is to have less and less warnings. It would be the same with test coverage: we want it to increase).

@NelleV
Collaborator

Maybe we could add a pyflakes check also? I've spotted and fixed a lot of small bugs thanks to it.

@mdboom
Owner

@NelleV: I agree that tracking PEP8 compliance would be useful. There's sort of two use cases here: 1) to make sure new code in a PR is PEP8 compliant by having the Travis build fail, 2) to just track that PEP8 compliance is getting better. I plan to have a ShiningPanda (Jenkins) instance up soon for matplotlib (we just got the payment sent), so we can should definitely run these kinds of graphs there.

As for pyflakes, I'm a huge fan as well. I have it automatically run in my editor (emacs) and find it to be a life saver. However, there are certain false positives there, too, that we probably would want to disable. The one that jumps to mind is the "x is imported, but not used in this module"... Occasionally one wants to do that to include something in a namespace that is then used from outside the module. As long as we can find and turn those off, I'd be in favor of adding that, too.

@NelleV
Collaborator

@mdboom I don't know about pyflakes, but we can turn this off when using flake8 (pyflakes + pep8) the same way can filter pep8 warnings out.

@pelson
Collaborator

I think the most important is not to check whether the file is pep8, but more whether the file is more and more pep8

This is achievable if we kept a log of the pep8 output and ran a diff each time we run the tests (this could be automated). The only problem with that is that we would need to update the results every time we make a minor PEP8 fix...

Given how much work you've done @NelleV I was hopeful we could start to rattle off some of the files on the list pretty quickly. Once they are pep8-d (and tested), they should stay pep8-d with this test...

@pwuertz
Collaborator

The error E225 (missing whitespace around operator) should also be blacklisted. The operator expression examples in PEP8 were just plain wrong for quite some time and many people and PEP8 check-tools picked up that error. I recently filed a bug (http://bugs.python.org/issue16239) and the examples were changed, but I guess it will take some time until this change is reflected in checking-tools.

@NelleV
Collaborator

It has already been fixed.

@pwuertz
Collaborator

Ah sorry, the pep8 package in Ubuntu 13.04 was outdated of course. Pep8 1.4.5 indeed doesn't complain about that anymore.

@pelson
Collaborator

Thanks for your comments.

@mdboom - I think this is a case of Merge or Close - I'm fine either way, but I don't think there is much point this sitting here if collectively we aren't keen to have this in the codebase.

@mdboom
Owner

I'm :+1: on the idea. At the moment, there are some PEP8 failures, and we should fix those before merging this.

Can you clarify the comment to address my question from before? The only concern I have is that there appear to be two different ways to define exclusions and I'm not sure why one would choose one over the other.

@pelson
Collaborator

At the moment, there are some PEP8 failures, and we should fix those before merging this.

Hmmm. They weren't failing on my machine. I'll investigate.

Why are there two different methods for defining exclusions?

The important list - the modules which are enumerated in the test itself are obviously the modules which are not compliant. The second list of exclusions comes from a file which is not under version control (you the user has control of what goes in there) - this is for files which are in your clone, but not in the repository itself. I'm not adverse to removing the second exclusions - it was useful to me when I wrote a similar test for cartopy, but I'm not currently using it in matplotlib...

@mdboom
Owner

Travis tests the PR branch merged with the destination branch. So in this case, I wouldn't be surprised if there's something on master that broke PEP8 conformance. Try rebasing your branch on the current master and tetsing that.

@pelson
Collaborator

Travis tests the PR branch merged with the destination branch.

Turns out that when you install a package with setuptools which has shared objects as an egg, you get extra "wrapper" .py files. This is what is not PEP8 compliant. The bootstrap file for _cntr.so:

def __bootstrap__():
   global __bootstrap__, __loader__, __file__
   import sys, pkg_resources, imp
   __file__ = pkg_resources.resource_filename(__name__,'_cntr.so')
   __loader__ = None; del __bootstrap__, __loader__
   imp.load_dynamic(__name__,__file__)
__bootstrap__()

I'm going to put in a patch to setuptools to make the output PEP8 compliant.

@mdboom
Owner

Ok. In the meantime, I suspect we can just ignore the bootstrap files.

EDIT:

By that, I mean have this system ignore them.

@pelson
Collaborator

Ok. In the meantime, I suspect we can just ignore the bootstrap files.

Its a bit harder than that. Generally we don't want to list files in the exclusions if they are not part of the repository. I've submitted the PR https://bitbucket.org/tarek/distribute/pull-request/40 and will now work on the workaround...

@mdboom
Owner

I guess I just meant that if there's a way that we could automatically detect that something is a bootstrap file, we wouldn't PEP8 check it. I'm not sure I follow what the objection to that is.

Even if your patch is accepted upstream, it will be a while until it trickles down and everyone has the fix to distribute (and distribute is soon to be replaced, so it could be quite some time).

@pelson
Collaborator

I've just rebased again. pep8 testing on python3 is a no-go - 2to3 is producing some non-compliant output.

Hopefully this will be the last commit...

@pelson
Collaborator

The tests are passing on python2.6, and an unrelated failure has occured on the python2.7 build.

I think this PR is good to go.

@pelson
Collaborator

I've logged the failure in #2046.

@pelson
Collaborator

@mdboom - once this is merged, I'm planning to reduce the number of files which are explicitly excluded by fixing up some of the more simple PEP8 problems.

@NelleV
Collaborator

I'll help on that too on my (almost non existing) free time.

@pelson
Collaborator

I'll help on that too on my (almost non existing) free time.

To be fair @NelleV you've already done all of the hard work - I'd just be sweeping up any remaining issues that have been introduced since your work, and having the satisfaction of knowing that the code will continue to remain compliant once the filename is struck off the list :smile:

@pelson
Collaborator

Bump. Sorry to pester @mdboom but this is one I don't want to go stale...

@mdboom
Owner

Looks good, now that all tests are passing.

@mdboom mdboom merged commit d5071f4 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
2  .travis.yml
@@ -7,7 +7,7 @@ python:
- 3.3
install:
- - pip -q install --use-mirrors nose python-dateutil numpy
+ - pip install -q --use-mirrors nose python-dateutil numpy pep8
# This is a workaround to install the latest versions of pyparsing,
# which are not yet available on PyPI
- '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'
View
1  lib/matplotlib/__init__.py
@@ -1177,6 +1177,7 @@ def tk_window_focus():
'matplotlib.tests.test_basic',
'matplotlib.tests.test_bbox_tight',
'matplotlib.tests.test_cbook',
+ 'matplotlib.tests.test_coding_standards',
'matplotlib.tests.test_collections',
'matplotlib.tests.test_colorbar',
'matplotlib.tests.test_colors',
View
2  lib/matplotlib/cm.py
@@ -188,7 +188,7 @@ def __init__(self, norm=None, cmap=None):
if norm is None:
norm = colors.Normalize()
- self._A = None;
+ self._A = None
#: The Normalization instance of this ScalarMappable.
self.norm = norm
#: The Colormap instance of this ScalarMappable.
View
39 lib/matplotlib/colorbar.py
@@ -501,12 +501,10 @@ def _add_solids(self, X, Y, C):
self.dividers.remove()
self.dividers = None
if self.drawedges:
- self.dividers = collections.LineCollection(
- self._edges(X, Y),
+ linewidths = (0.5 * mpl.rcParams['axes.linewidth'],)
+ self.dividers = collections.LineCollection(self._edges(X, Y),
colors=(mpl.rcParams['axes.edgecolor'],),
- linewidths=(
- 0.5 * mpl.rcParams['axes.linewidth'],)
- )
+ linewidths=linewidths)
self.ax.add_collection(self.dividers)
def add_lines(self, levels, colors, linewidths, erase=True):
@@ -725,9 +723,9 @@ def _uniform_y(self, N):
y = np.linspace(0, 1, N)
else:
automin = automax = 1. / (N - 1.)
- extendlength = self._get_extension_lengths(
- self.extendfrac,
- automin, automax, default=0.05)
+ extendlength = self._get_extension_lengths(self.extendfrac,
+ automin, automax,
+ default=0.05)
if self.extend == 'both':
y = np.zeros(N + 2, 'd')
y[0] = 0. - extendlength[0]
@@ -986,19 +984,23 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
'''
locations = ["left", "right", "top", "bottom"]
if orientation is not None and location is not None:
- raise TypeError('position and orientation are mutually exclusive. Consider ' \
- 'setting the position to any of %s' % ', '.join(locations))
+ msg = ('position and orientation are mutually exclusive. '
+ 'Consider setting the position to any of '
+ '{0}'.format(', '.join(locations)))
+ raise TypeError(msg)
# provide a default location
if location is None and orientation is None:
location = 'right'
- # allow the user to not specify the location by specifying the orientation instead
+ # allow the user to not specify the location by specifying the
+ # orientation instead
if location is None:
location = 'right' if orientation == 'vertical' else 'bottom'
if location not in locations:
- raise ValueError('Invalid colorbar location. Must be one of %s' % ', '.join(locations))
+ raise ValueError('Invalid colorbar location. Must be one '
+ 'of %s' % ', '.join(locations))
default_location_settings = {'left': {'anchor': (1.0, 0.5),
'panchor': (0.0, 0.5),
@@ -1014,7 +1016,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
'orientation': 'horizontal'},
'bottom': {'anchor': (0.5, 1.0),
'panchor': (0.5, 0.0),
- 'pad': 0.15, # backwards compat
+ 'pad': 0.15, # backwards compat
'orientation': 'horizontal'},
}
@@ -1029,19 +1031,18 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
parent_anchor = kw.pop('panchor', loc_settings['panchor'])
pad = kw.pop('pad', loc_settings['pad'])
-
# turn parents into a list if it is not already
if not isinstance(parents, (list, tuple)):
parents = [parents]
fig = parents[0].get_figure()
if not all(fig is ax.get_figure() for ax in parents):
- raise ValueError('Unable to create a colorbar axes as not all ' + \
+ raise ValueError('Unable to create a colorbar axes as not all '
'parents share the same figure.')
# take a bounding box around all of the given axes
- parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen() \
- for ax in parents])
+ parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen()
+ for ax in parents])
pb = parents_bbox
if location in ('left', 'right'):
@@ -1054,11 +1055,11 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
if location == 'bottom':
pbcb, _, pb1 = pb.splity(fraction, fraction + pad)
else:
- pb1, _, pbcb = pb.splity(1 - fraction - pad, 1 - fraction)
+ pb1, _, pbcb = pb.splity(1 - fraction - pad, 1 - fraction)
pbcb = pbcb.shrunk(shrink, 1.0).anchored(anchor, pbcb)
# define the aspect ratio in terms of y's per x rather than x's per y
- aspect = 1.0/aspect
+ aspect = 1.0 / aspect
# define a transform which takes us from old axes coordinates to
# new axes coordinates
View
11 lib/matplotlib/lines.py
@@ -613,12 +613,13 @@ def draw(self, renderer):
if self.get_path_effects():
affine_frozen = affine.frozen()
for pe in self.get_path_effects():
- pe.draw_markers(renderer, gc, marker_path, marker_trans,
- subsampled, affine_frozen, rgbaFace)
+ pe.draw_markers(renderer, gc, marker_path,
+ marker_trans, subsampled,
+ affine_frozen, rgbaFace)
else:
- renderer.draw_markers(
- gc, marker_path, marker_trans, subsampled, affine.frozen(),
- rgbaFace)
+ renderer.draw_markers(gc, marker_path, marker_trans,
+ subsampled, affine.frozen(),
+ rgbaFace)
alt_marker_path = marker.get_alt_path()
if alt_marker_path:
View
1  lib/matplotlib/scale.py
@@ -359,6 +359,7 @@ def inverted(self):
return InvertedSymmetricalLogTransform(self.base, self.linthresh,
self.linscale)
+
class InvertedSymmetricalLogTransform(Transform):
input_dims = 1
output_dims = 1
View
235 lib/matplotlib/tests/test_coding_standards.py
@@ -0,0 +1,235 @@
+from fnmatch import fnmatch
+import os
+import sys
+
+from nose.tools import assert_equal
+import pep8
+
+import matplotlib
+
+
+class StandardReportWithExclusions(pep8.StandardReport):
+ #; A class attribute to store the exception exclusion file patterns.
+ expected_bad_files = [
+ '*/matplotlib/__init__.py',
+ '*/matplotlib/_cm.py',
+ '*/matplotlib/_mathtext_data.py',
+ '*/matplotlib/_pylab_helpers.py',
+ '*/matplotlib/afm.py',
+ '*/matplotlib/animation.py',
+ '*/matplotlib/artist.py',
+ '*/matplotlib/axes.py',
+ '*/matplotlib/axis.py',
+ '*/matplotlib/backend_bases.py',
+ '*/matplotlib/bezier.py',
+ '*/matplotlib/cbook.py',
+ '*/matplotlib/collections.py',
+ '*/matplotlib/docstring.py',
+ '*/matplotlib/dviread.py',
+ '*/matplotlib/finance.py',
+ '*/matplotlib/font_manager.py',
+ '*/matplotlib/fontconfig_pattern.py',
+ '*/matplotlib/gridspec.py',
+ '*/matplotlib/legend.py',
+ '*/matplotlib/legend_handler.py',
+ '*/matplotlib/mathtext.py',
+ '*/matplotlib/mlab.py',
+ '*/matplotlib/path.py',
+ '*/matplotlib/patheffects.py',
+ '*/matplotlib/pylab.py',
+ '*/matplotlib/pyplot.py',
+ '*/matplotlib/rcsetup.py',
+ '*/matplotlib/stackplot.py',
+ '*/matplotlib/texmanager.py',
+ '*/matplotlib/text.py',
+ '*/matplotlib/transforms.py',
+ '*/matplotlib/type1font.py',
+ '*/matplotlib/widgets.py',
+ '*/matplotlib/testing/compare.py',
+ '*/matplotlib/testing/decorators.py',
+ '*/matplotlib/testing/image_util.py',
+ '*/matplotlib/testing/noseclasses.py',
+ '*/matplotlib/testing/jpl_units/Duration.py',
+ '*/matplotlib/testing/jpl_units/Epoch.py',
+ '*/matplotlib/testing/jpl_units/EpochConverter.py',
+ '*/matplotlib/testing/jpl_units/StrConverter.py',
+ '*/matplotlib/testing/jpl_units/UnitDbl.py',
+ '*/matplotlib/testing/jpl_units/UnitDblConverter.py',
+ '*/matplotlib/testing/jpl_units/UnitDblFormatter.py',
+ '*/matplotlib/testing/jpl_units/__init__.py',
+ '*/matplotlib/tri/tricontour.py',
+ '*/matplotlib/tri/triinterpolate.py',
+ '*/matplotlib/tri/tripcolor.py',
+ '*/matplotlib/tri/triplot.py',
+ '*/matplotlib/tests/__init__.py',
+ '*/matplotlib/tests/test_agg.py',
+ '*/matplotlib/tests/test_animation.py',
+ '*/matplotlib/tests/test_arrow_patches.py',
+ '*/matplotlib/tests/test_artist.py',
+ '*/matplotlib/tests/test_axes.py',
+ '*/matplotlib/tests/test_backend_pdf.py',
+ '*/matplotlib/tests/test_backend_pgf.py',
+ '*/matplotlib/tests/test_backend_svg.py',
+ '*/matplotlib/tests/test_basic.py',
+ '*/matplotlib/tests/test_bbox_tight.py',
+ '*/matplotlib/tests/test_cbook.py',
+ '*/matplotlib/tests/test_colorbar.py',
+ '*/matplotlib/tests/test_colors.py',
+ '*/matplotlib/tests/test_compare_images.py',
+ '*/matplotlib/tests/test_contour.py',
+ '*/matplotlib/tests/test_dates.py',
+ '*/matplotlib/tests/test_delaunay.py',
+ '*/matplotlib/tests/test_dviread.py',
+ '*/matplotlib/tests/test_image.py',
+ '*/matplotlib/tests/test_legend.py',
+ '*/matplotlib/tests/test_lines.py',
+ '*/matplotlib/tests/test_mathtext.py',
+ '*/matplotlib/tests/test_patches.py',
+ '*/matplotlib/tests/test_pickle.py',
+ '*/matplotlib/tests/test_png.py',
+ '*/matplotlib/tests/test_rcparams.py',
+ '*/matplotlib/tests/test_simplification.py',
+ '*/matplotlib/tests/test_spines.py',
+ '*/matplotlib/tests/test_streamplot.py',
+ '*/matplotlib/tests/test_subplots.py',
+ '*/matplotlib/tests/test_text.py',
+ '*/matplotlib/tests/test_tightlayout.py',
+ '*/matplotlib/tests/test_transforms.py',
+ '*/matplotlib/tests/test_triangulation.py',
+ '*/matplotlib/compat/subprocess.py',
+ '*/matplotlib/backends/__init__.py',
+ '*/matplotlib/backends/backend_agg.py',
+ '*/matplotlib/backends/backend_cairo.py',
+ '*/matplotlib/backends/backend_cocoaagg.py',
+ '*/matplotlib/backends/backend_gdk.py',
+ '*/matplotlib/backends/backend_gtk.py',
+ '*/matplotlib/backends/backend_gtk3.py',
+ '*/matplotlib/backends/backend_gtk3cairo.py',
+ '*/matplotlib/backends/backend_gtkagg.py',
+ '*/matplotlib/backends/backend_gtkcairo.py',
+ '*/matplotlib/backends/backend_macosx.py',
+ '*/matplotlib/backends/backend_mixed.py',
+ '*/matplotlib/backends/backend_pdf.py',
+ '*/matplotlib/backends/backend_pgf.py',
+ '*/matplotlib/backends/backend_ps.py',
+ '*/matplotlib/backends/backend_qt4.py',
+ '*/matplotlib/backends/backend_qt4agg.py',
+ '*/matplotlib/backends/backend_svg.py',
+ '*/matplotlib/backends/backend_template.py',
+ '*/matplotlib/backends/backend_tkagg.py',
+ '*/matplotlib/backends/backend_webagg.py',
+ '*/matplotlib/backends/backend_wx.py',
+ '*/matplotlib/backends/backend_wxagg.py',
+ '*/matplotlib/backends/qt4_compat.py',
+ '*/matplotlib/backends/tkagg.py',
+ '*/matplotlib/backends/windowing.py',
+ '*/matplotlib/backends/qt4_editor/figureoptions.py',
+ '*/matplotlib/backends/qt4_editor/formlayout.py',
+ '*/matplotlib/sphinxext/__init__.py',
+ '*/matplotlib/sphinxext/ipython_console_highlighting.py',
+ '*/matplotlib/sphinxext/ipython_directive.py',
+ '*/matplotlib/sphinxext/mathmpl.py',
+ '*/matplotlib/sphinxext/only_directives.py',
+ '*/matplotlib/sphinxext/plot_directive.py',
+ '*/matplotlib/projections/__init__.py',
+ '*/matplotlib/projections/geo.py',
+ '*/matplotlib/projections/polar.py']
+
+ #: A class attribute to store patterns which have seen exceptions.
+ matched_exclusions = set()
+
+ def get_file_results(self):
+ # If the file had no errors, return self.file_errors (which will be 0)
+ if not self._deferred_print:
+ return self.file_errors
+
+ # Iterate over all of the patterns, to find a possible exclusion. If we
+ # the filename is to be excluded, go ahead and remove the counts that
+ # self.error added.
+ for pattern in self.expected_bad_files:
+ if fnmatch(self.filename, pattern):
+ self.matched_exclusions.add(pattern)
+ # invert the error method's counters.
+ for _, _, code, _, _ in self._deferred_print:
+ self.counters[code] -= 1
+ if self.counters[code] == 0:
+ self.counters.pop(code)
+ self.messages.pop(code)
+ self.file_errors -= 1
+ self.total_errors -= 1
+ return self.file_errors
+
+ # Otherwise call the superclass' method to print the bad results.
+ return super(StandardReportWithExclusions,
+ self).get_file_results()
+
+
+def test_pep8_conformance():
+# Tests the matplotlib codebase against the "pep8" tool.
+#
+# Users can add their own excluded files (should files exist in the
+# local directory which is not in the repository) by adding a
+# ".pep8_test_exclude.txt" file in the same directory as this test.
+# The file should be a line separated list of filenames/directories
+# as can be passed to the "pep8" tool's exclude list.
@mdboom Owner
mdboom added a note

Shouldn't this comment above just be a docstring? Also, it seems out of date with what's actually here.

@pelson Collaborator
pelson added a note

I don't think its out of date (I suppose there is more going on in the method than the comment suggests?). Is there a specific part which is out of date?

If I convert it to a docstring, you end up with annoying output when running the tests. This can be avoided though (see http://stackoverflow.com/questions/12962772/how-to-stop-python-unittest-from-printing-test-docstring)

@mdboom Owner
mdboom added a note

Ah, I see. Let's leave it as a comment then.

I was confused by the list of exclusions in this file and the mention of .pep8_test_exclude. Why are there two different methods for defining exclusions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ # Only run this test with Python 2 - the 2to3 tool generates non pep8
+ # compliant code.
+ if sys.version_info[0] != 2:
+ return
+
+ # to get a list of bad files, rather than the specific errors, add
+ # "reporter=pep8.FileReport" to the StyleGuide constructor.
+ pep8style = pep8.StyleGuide(quiet=False,
+ reporter=StandardReportWithExclusions)
+
+ # Extend the number of PEP8 guidelines which are not checked.
+ pep8style.options.ignore = pep8style.options.ignore + ('E121', 'E122',
+ 'E123', 'E124', 'E125', 'E126', 'E127',
+ 'E128')
+
+ # Support for egg shared object wrappers, which are not PEP8 compliant,
+ # nor part of the matplotlib repository.
+ # DO NOT ADD FILES *IN* THE REPOSITORY TO THIS LIST.
+ pep8style.options.exclude.extend(
+ ['_delaunay.py',
+ '_image.py',
+ '_tri.py',
+ '_backend_agg.py',
+ '_tkagg.py',
+ 'ft2font.py',
+ '_cntr.py',
+ '_png.py',
+ '_path.py',
+ 'ttconv.py',
+ 'pyparsing*'])
+
+ # Allow users to add their own exclude list.
+ extra_exclude_file = os.path.join(os.path.dirname(__file__),
+ '.pep8_test_exclude.txt')
+ if os.path.exists(extra_exclude_file):
+ with open(extra_exclude_file, 'r') as fh:
+ extra_exclude = [line.strip() for line in fh if line.strip()]
+ pep8style.options.exclude.extend(extra_exclude)
+
+ result = pep8style.check_files([os.path.dirname(matplotlib.__file__)])
+ assert_equal(result.total_errors, 0, "Found code syntax "
+ "errors (and warnings).")
+
+ reporter = pep8style.options.reporter
+ # If we've been using the exclusions reporter, check that we didn't
+ # exclude files unnecessarily.
+ if reporter is StandardReportWithExclusions:
+ unexpectedly_good = sorted(set(reporter.expected_bad_files) -
+ reporter.matched_exclusions)
+
+ if unexpectedly_good:
+ raise ValueError('Some exclude patterns were unnecessary as the '
+ 'files they pointed to either passed the PEP8 '
+ 'tests or do not point to a file:\n '
+ '{}'.format('\n '.join(unexpectedly_good)))
+
+
+if __name__ == '__main__':
+ import nose
+ nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
View
4 lib/matplotlib/tests/test_figure.py
@@ -78,7 +78,8 @@ def test_suptitle():
# only test png and svg. The PDF output appears correct,
# but Ghostscript does not preserve the background color.
extensions=['png', 'svg'],
- savefig_kwarg={'facecolor': (0, 1, 0.4), 'edgecolor': 'none'})
+ savefig_kwarg={'facecolor': (0, 1, 0.4),
+ 'edgecolor': 'none'})
def test_alpha():
# We want an image which has a background color and an
# alpha of 0.4.
@@ -92,6 +93,7 @@ def test_alpha():
alpha=0.6,
facecolor='red'))
+
@cleanup
def test_too_many_figures():
import warnings
View
6 lib/matplotlib/tests/test_path.py
@@ -1,6 +1,7 @@
from matplotlib.path import Path
from nose.tools import assert_raises
+
def test_readonly_path():
path = Path.unit_circle()
@@ -8,3 +9,8 @@ def modify_vertices():
path.vertices = path.vertices * 2.0
assert_raises(AttributeError, modify_vertices)
+
+
+if __name__ == '__main__':
+ import nose
+ nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
View
10 lib/matplotlib/tests/test_patheffects.py
@@ -9,7 +9,7 @@
@image_comparison(baseline_images=['patheffect1'], remove_text=True)
def test_patheffect1():
ax1 = plt.subplot(111)
- ax1.imshow([[1,2],[2,3]])
+ ax1.imshow([[1, 2], [2, 3]])
txt = ax1.annotate("test", (1., 1.), (0., 0),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle3", lw=2),
@@ -31,14 +31,13 @@ def test_patheffect1():
def test_patheffect2():
ax2 = plt.subplot(111)
- arr = np.arange(25).reshape((5,5))
+ arr = np.arange(25).reshape((5, 5))
ax2.imshow(arr)
cntr = ax2.contour(arr, colors="k")
plt.setp(cntr.collections,
path_effects=[withStroke(linewidth=3, foreground="w")])
-
clbls = ax2.clabel(cntr, fmt="%2.0f", use_clabeltext=True)
plt.setp(clbls,
path_effects=[withStroke(linewidth=3, foreground="w")])
@@ -51,3 +50,8 @@ def test_patheffect3():
p1, = ax3.plot([0, 1], [0, 1])
leg = ax3.legend([p1], ["Line 1"], fancybox=True, loc=2)
leg.legendPatch.set_path_effects([withSimplePatchShadow()])
+
+
+if __name__ == '__main__':
+ import nose
+ nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
View
8 lib/matplotlib/tests/test_ticker.py
@@ -26,7 +26,8 @@ def test_LinearLocator():
def test_MultipleLocator():
loc = mticker.MultipleLocator(base=3.147)
- test_value = np.array([-9.441, -6.294, -3.147, 0., 3.147, 6.294, 9.441, 12.588])
+ test_value = np.array([-9.441, -6.294, -3.147, 0., 3.147, 6.294,
+ 9.441, 12.588])
assert_almost_equal(loc.tick_values(-7, 10), test_value)
@@ -35,8 +36,9 @@ def test_LogLocator():
assert_raises(ValueError, loc.tick_values, 0, 1000)
- test_value = np.array([1.00000000e-05, 1.00000000e-03, 1.00000000e-01, 1.00000000e+01,
- 1.00000000e+03, 1.00000000e+05, 1.00000000e+07, 1.000000000e+09])
+ test_value = np.array([1.00000000e-05, 1.00000000e-03, 1.00000000e-01,
+ 1.00000000e+01, 1.00000000e+03, 1.00000000e+05,
+ 1.00000000e+07, 1.000000000e+09])
assert_almost_equal(loc.tick_values(0.001, 1.1e5), test_value)
loc = mticker.LogLocator(base=2)
View
1  lib/matplotlib/tests/test_ttconv.py
@@ -4,6 +4,7 @@
import matplotlib.pyplot as plt
import os.path
+
@image_comparison(baseline_images=["truetype-conversion"],
extensions=["pdf"])
def test_truetype_conversion():
View
15 lib/matplotlib/ticker.py
@@ -205,10 +205,11 @@ def fix_minus(self, s):
"""
some classes may want to replace a hyphen for minus with the
proper unicode symbol as described `here
- <http://sourceforge.net/tracker/index.php?func=detail&aid=1962574&group_id=80706&atid=560720>`_.
+ <http://sourceforge.net/tracker/index.php?func=detail&aid=1962574&
+group_id=80706&atid=560720>`_.
The default is to do nothing
- Note, if you use this method, eg in :meth`format_data` or
+ Note, if you use this method, e.g., in :meth:`format_data` or
call, you probably don't want to use it for
:meth:`format_data_short` since the toolbar uses this for
interactive coord reporting and I doubt we can expect GUIs
@@ -794,7 +795,7 @@ class EngFormatter(Formatter):
18: "E",
21: "Z",
24: "Y"
- }
+ }
def __init__(self, unit="", places=None):
self.unit = unit
@@ -865,12 +866,10 @@ class Locator(TickHelper):
the Axis data and view limits
"""
- # some automatic tick locators can generate so many ticks they
- # kill the machine when you try and render them, see eg sf bug
- # report
- # https://sourceforge.net/tracker/index.php?func=detail&aid=2715172&group_id=80706&atid=560720.
+ # Some automatic tick locators can generate so many ticks they
+ # kill the machine when you try and render them.
# This parameter is set to cause locators to raise an error if too
- # many ticks are generated
+ # many ticks are generated.
MAXTICKS = 1000
def tick_values(self, vmin, vmax):
View
7 setup.py
@@ -29,9 +29,12 @@
os.remove('MANIFEST')
try:
- from setuptools.core import setup
+ from setuptools import setup
except ImportError:
- from distutils.core import setup
+ try:
+ from setuptools.core import setup
+ except ImportError:
+ from distutils.core import setup
import setupext
from setupext import print_line, print_raw, print_message, print_status
Something went wrong with that request. Please try again.