File: //usr/lib/python2.7/dist-packages/matplotlib/tests/test_coding_standards.py
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from fnmatch import fnmatch
import os
from nose.tools import assert_equal
from nose.plugins.skip import SkipTest
from matplotlib.testing.noseclasses import KnownFailureTest
try:
import pep8
except ImportError:
HAS_PEP8 = False
else:
HAS_PEP8 = pep8.__version__ > '1.4.5'
import matplotlib
PEP8_ADDITIONAL_IGNORE = ['E111',
'E114',
'E115',
'E116',
'E121',
'E122',
'E123',
'E124',
'E125',
'E126',
'E127',
'E128',
'E129',
'E131',
'E265',
'E266',
'W503']
EXTRA_EXCLUDE_FILE = os.path.join(os.path.dirname(__file__),
'.pep8_test_exclude.txt')
if HAS_PEP8:
class StandardReportWithExclusions(pep8.StandardReport):
#: A class attribute to store the exception exclusion file patterns.
expected_bad_files = []
#: A class attribute to store the lines of failing tests.
_global_deferred_print = []
#: 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 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
# mirror the content of StandardReport, only storing the output to
# file rather than printing. This could be a feature request for
# the PEP8 tool.
self._deferred_print.sort()
for line_number, offset, code, text, _ in self._deferred_print:
self._global_deferred_print.append(
self._fmt % {'path': self.filename,
'row': self.line_offset + line_number,
'col': offset + 1, 'code': code,
'text': text})
return self.file_errors
def assert_pep8_conformance(module=matplotlib, exclude_files=None,
extra_exclude_file=EXTRA_EXCLUDE_FILE,
pep8_additional_ignore=PEP8_ADDITIONAL_IGNORE,
dirname=None, expected_bad_files=None,
extra_exclude_directories=None):
"""
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.
"""
if not HAS_PEP8:
raise SkipTest('The pep8 tool is required for this test')
# 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)
reporter = pep8style.options.reporter
if expected_bad_files is not None:
reporter.expected_bad_files = expected_bad_files
# Extend the number of PEP8 guidelines which are not checked.
pep8style.options.ignore = (pep8style.options.ignore +
tuple(pep8_additional_ignore))
# 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.
if exclude_files is not None:
pep8style.options.exclude.extend(exclude_files)
# Allow users to add their own exclude list.
if extra_exclude_file is not None and 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)
if extra_exclude_directories:
pep8style.options.exclude.extend(extra_exclude_directories)
if dirname is None:
dirname = os.path.dirname(module.__file__)
result = pep8style.check_files([dirname])
if reporter is StandardReportWithExclusions:
msg = ("Found code syntax errors (and warnings):\n"
"{0}".format('\n'.join(reporter._global_deferred_print)))
else:
msg = "Found code syntax errors (and warnings)."
assert_equal(result.total_errors, 0, msg)
# 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 '
'{0}'.format('\n '.join(unexpectedly_good)))
def test_pep8_conformance_installed_files():
exclude_files = ['_delaunay.py',
'_image.py',
'_tri.py',
'_backend_agg.py',
'_tkagg.py',
'ft2font.py',
'_cntr.py',
'_contour.py',
'_png.py',
'_path.py',
'ttconv.py',
'_gtkagg.py',
'_backend_gdk.py',
'pyparsing*',
'_qhull.py',
'_macosx.py']
expected_bad_files = ['_cm.py',
'_mathtext_data.py',
'backend_bases.py',
'cbook.py',
'collections.py',
'dviread.py',
'font_manager.py',
'fontconfig_pattern.py',
'gridspec.py',
'legend_handler.py',
'mathtext.py',
'patheffects.py',
'pylab.py',
'pyplot.py',
'rcsetup.py',
'stackplot.py',
'texmanager.py',
'transforms.py',
'type1font.py',
'widgets.py',
'testing/decorators.py',
'testing/jpl_units/Duration.py',
'testing/jpl_units/Epoch.py',
'testing/jpl_units/EpochConverter.py',
'testing/jpl_units/StrConverter.py',
'testing/jpl_units/UnitDbl.py',
'testing/jpl_units/UnitDblConverter.py',
'testing/jpl_units/UnitDblFormatter.py',
'testing/jpl_units/__init__.py',
'tri/triinterpolate.py',
'tests/test_axes.py',
'tests/test_bbox_tight.py',
'tests/test_delaunay.py',
'tests/test_dviread.py',
'tests/test_image.py',
'tests/test_legend.py',
'tests/test_lines.py',
'tests/test_mathtext.py',
'tests/test_rcparams.py',
'tests/test_simplification.py',
'tests/test_streamplot.py',
'tests/test_subplots.py',
'tests/test_tightlayout.py',
'tests/test_triangulation.py',
'compat/subprocess.py',
'backends/__init__.py',
'backends/backend_agg.py',
'backends/backend_cairo.py',
'backends/backend_cocoaagg.py',
'backends/backend_gdk.py',
'backends/backend_gtk.py',
'backends/backend_gtk3.py',
'backends/backend_gtk3cairo.py',
'backends/backend_gtkagg.py',
'backends/backend_gtkcairo.py',
'backends/backend_macosx.py',
'backends/backend_mixed.py',
'backends/backend_pgf.py',
'backends/backend_ps.py',
'backends/backend_svg.py',
'backends/backend_template.py',
'backends/backend_tkagg.py',
'backends/tkagg.py',
'backends/windowing.py',
'backends/qt_editor/formlayout.py',
'sphinxext/mathmpl.py',
'sphinxext/only_directives.py',
'sphinxext/plot_directive.py',
'projections/__init__.py',
'projections/geo.py',
'projections/polar.py',
'externals/six.py']
expected_bad_files = ['*/matplotlib/' + s for s in expected_bad_files]
assert_pep8_conformance(module=matplotlib,
exclude_files=exclude_files,
expected_bad_files=expected_bad_files)
def test_pep8_conformance_examples():
mpldir = os.environ.get('MPL_REPO_DIR', None)
if mpldir is None:
# try and guess!
fp = os.getcwd()
while len(fp) > 2:
if os.path.isdir(os.path.join(fp, 'examples')):
mpldir = fp
break
fp, tail = os.path.split(fp)
if mpldir is None:
raise KnownFailureTest("can not find the examples, set env "
"MPL_REPO_DIR to point to the top-level path "
"of the source tree")
exdir = os.path.join(mpldir, 'examples')
blacklist = ()
expected_bad_files = ['*/pylab_examples/table_demo.py',
'*/pylab_examples/tricontour_demo.py',
'*/pylab_examples/tripcolor_demo.py',
'*/pylab_examples/triplot_demo.py',
'*/shapes_and_collections/artist_reference.py']
assert_pep8_conformance(dirname=exdir,
extra_exclude_directories=blacklist,
pep8_additional_ignore=PEP8_ADDITIONAL_IGNORE +
['E116', 'E501', 'E402'],
expected_bad_files=expected_bad_files)
if __name__ == '__main__':
import nose
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)