summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArt Hall <arthall@gmail.com>2016-06-02 11:46:08 -0400
committerArt Hall <arthall@gmail.com>2016-06-02 11:46:08 -0400
commit5cf3c7a5d32ed4fbe4fcb09b67a967fcdd6fa786 (patch)
tree4d46c82c55a3ec8dcb06e15b436930bb6250f826
parentbbefb19a036e1048dbdd460432dc1f973be63504 (diff)
parentfd4f1c286cdc4e0bc25822e10742adbc9062af15 (diff)
downloadpep8-5cf3c7a5d32ed4fbe4fcb09b67a967fcdd6fa786.tar.gz
Merge latest master into issue-314
-rw-r--r--.travis.yml18
-rw-r--r--CHANGES.txt91
-rw-r--r--CONTRIBUTING.rst4
-rw-r--r--LICENSE1
-rw-r--r--Makefile6
-rw-r--r--README.rst41
-rw-r--r--docs/Makefile8
-rw-r--r--docs/advanced.rst55
-rw-r--r--docs/api.rst10
-rw-r--r--docs/conf.py30
-rw-r--r--docs/developer.rst44
-rw-r--r--docs/index.rst16
-rw-r--r--docs/intro.rst471
-rw-r--r--docs/make.bat4
-rwxr-xr-xpycodestyle.py (renamed from pep8.py)289
-rw-r--r--setup.py14
-rw-r--r--testsuite/E12.py6
-rw-r--r--testsuite/E25.py9
-rw-r--r--testsuite/E27.py14
-rw-r--r--testsuite/E40.py25
-rw-r--r--testsuite/E50.py14
-rw-r--r--testsuite/E71.py18
-rw-r--r--testsuite/W19.py2
-rw-r--r--testsuite/support.py7
-rw-r--r--testsuite/test_all.py19
-rw-r--r--testsuite/test_api.py151
-rw-r--r--testsuite/test_parser.py61
-rw-r--r--testsuite/test_shell.py26
-rw-r--r--testsuite/test_util.py20
-rw-r--r--tox.ini10
30 files changed, 968 insertions, 516 deletions
diff --git a/.travis.yml b/.travis.yml
index b188325..ee069e8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,25 +1,29 @@
language: python
+sudo: false
python:
- 2.6
- 2.7
- 3.2
- 3.3
- 3.4
+ - 3.5
+ - nightly
- pypy
- pypy3
install:
- pip install -e .
- pip list
script:
- - python pep8.py --testsuite testsuite
- - python pep8.py --statistics pep8.py
- - python pep8.py --doctest
+ - python pycodestyle.py --testsuite testsuite
+ - python pycodestyle.py --statistics pycodestyle.py
+ - python pycodestyle.py --doctest
- python setup.py test
-matrix:
- allow_failures:
- - python: pypy
- - python: pypy3
notifications:
email:
- IanLee1521@gmail.com
+ irc:
+ channels:
+ - "irc.freenode.org##python-code-quality"
+ use_notice: true
+ skip_join: true
diff --git a/CHANGES.txt b/CHANGES.txt
index d53fb70..e129dc8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -2,8 +2,73 @@ Changelog
=========
-1.x (unreleased)
-----------------
+2.0.0 (2016-05-31)
+------------------
+
+Announcements:
+
+* Repository renamed to `pycodestyle`; Issue #466 / #481.
+* Added joint Code of Conduct as member of PyCQA; #483
+
+Changes:
+
+* Added tox test support for Python 3.5 and pypy3
+* Added check E275 for whitespace on `from ... import ...` lines; #489 / #491
+* Added W503 to the list of codes ignored by default ignore list; #498
+* Removed use of project level `.pep8` configuration file; #364
+
+Bugs:
+
+* Fixed bug with treating `~` operator as binary; #383 / #384
+* Identify binary operators as unary; #484 / #485
+
+1.7.0 (2016-01-12)
+------------------
+
+Announcements:
+
+* Repository moved to PyCQA Organization on GitHub:
+ https://github.com/pycqa/pep8
+
+Changes:
+
+* Reverted the fix in #368, "options passed on command line are only ones
+ accepted" feature. This has many unintended consequences in pep8 and flake8
+ and needs to be reworked when I have more time.
+* Added support for Python 3.5. (Issue #420 & #459)
+* Added support for multi-line config_file option parsing. (Issue #429)
+* Improved parameter parsing. (Issues #420 & #456)
+
+Bugs:
+
+* Fixed BytesWarning on Python 3. (Issue #459)
+
+1.6.2 (2015-02-15)
+------------------
+
+Changes:
+
+* Added check for breaking around a binary operator. (Issue #197, Pull #305)
+
+Bugs:
+
+* Restored config_file parameter in process_options(). (Issue #380)
+
+
+1.6.1 (2015-02-08)
+------------------
+
+Changes:
+
+* Assign variables before referenced. (Issue #287)
+
+Bugs:
+
+* Exception thrown due to unassigned ``local_dir`` variable. (Issue #377)
+
+
+1.6.0 (2015-02-06)
+------------------
News:
@@ -32,6 +97,15 @@ Changes:
* Add ``.tox/`` to default excludes. (Issue #335)
+* Do not report E121 or E126 in the default configuration. (Issues #256 / #316)
+
+* Allow spaces around the equals sign in an annotated function. (Issue #357)
+
+* Allow trailing backslash if in an inline comment. (Issue #374)
+
+* If ``--config`` is used, only that configuration is processed. Otherwise,
+ merge the user and local configurations are merged. (Issue #368 / #369)
+
Bug fixes:
* Don't crash if Checker.build_tokens_line() returns None. (Issue #306)
@@ -43,6 +117,11 @@ Bug fixes:
* Fix false positive E711/E712/E713. (Issues #330 and #336)
+* Do not skip physical checks if the newline is escaped. (Issue #319)
+
+* Flush sys.stdout to avoid race conditions with printing. See flake8 bug:
+ https://gitlab.com/pycqa/flake8/issues/17 for more details. (Issue #363)
+
1.5.7 (2014-05-29)
------------------
@@ -274,7 +353,7 @@ Bug fixes:
* Initiate a graceful shutdown on ``Control+C``.
-* Allow to change the ``checker_class`` for the ``StyleGuide``.
+* Allow changing the ``checker_class`` for the ``StyleGuide``.
1.4.2 (2013-02-10)
@@ -284,7 +363,7 @@ Bug fixes:
* Register new checkers with ``register_check(func_or_cls, codes)``.
-* Allow to construct a ``StyleGuide`` with a custom parser.
+* Allow constructing a ``StyleGuide`` with a custom parser.
* Accept visual indentation without parenthesis after the ``if``
statement. (Issue #151)
@@ -330,7 +409,7 @@ Bug fixes:
(Issue #93 and #141)
* Add the Sphinx-based documentation, and publish it
- on http://pep8.readthedocs.org/. (Issue #105)
+ on https://pycodestyle.readthedocs.io/. (Issue #105)
1.3.4 (2012-12-18)
@@ -493,7 +572,7 @@ Bug fixes:
The ``--repeat`` flag becomes obsolete because it is the default
behaviour. (Issue #6)
-* Allow to specify ``--max-line-length``. (Issue #36)
+* Allow specifying ``--max-line-length``. (Issue #36)
* Make the shebang more flexible. (Issue #26)
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..9771176
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,4 @@
+Contributing to ``pycodestyle``
+===============================
+
+Please see the `developer notes <https://pycodestyle.readthedocs.io/en/latest/developer.html>`_
diff --git a/LICENSE b/LICENSE
index 70242b8..302779d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,6 @@
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
+Copyright © 2014-2016 Ian Lee <IanLee1521@gmail.com>
Licensed under the terms of the Expat License
diff --git a/Makefile b/Makefile
index 29b243d..366f580 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
test :
- python pep8.py --testsuite testsuite
+ python pycodestyle.py --testsuite testsuite
selftest :
- python pep8.py --statistics pep8.py
+ python pycodestyle.py --statistics pycodestyle.py
doctest :
- python pep8.py --doctest
+ python pycodestyle.py --doctest
unittest :
python -m testsuite.test_all
diff --git a/README.rst b/README.rst
index d842f05..466509b 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,16 @@
-pep8 - Python style guide checker
-=================================
+pycodestyle (formerly called pep8) - Python style guide checker
+===============================================================
-pep8 is a tool to check your Python code against some of the style
+pycodestyle is a tool to check your Python code against some of the style
conventions in `PEP 8`_.
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
+.. note::
+
+ This package used to be called ``pep8`` but was renamed to ``pycodestyle``
+ to reduce confusion. Further discussion `here
+ <https://github.com/PyCQA/pycodestyle/issues/466>`_.
Features
--------
@@ -15,18 +20,18 @@ Features
* Parseable output: Jump to error location in your editor.
* Small: Just one Python file, requires only stdlib. You can use just
- the pep8.py file for this purpose.
+ the ``pycodestyle.py`` file for this purpose.
* Comes with a comprehensive test suite.
Installation
------------
-You can install, upgrade, uninstall pep8.py with these commands::
+You can install, upgrade, uninstall ``pycodestyle.py`` with these commands::
- $ pip install pep8
- $ pip install --upgrade pep8
- $ pip uninstall pep8
+ $ pip install pycodestyle
+ $ pip install --upgrade pycodestyle
+ $ pip uninstall pycodestyle
There's also a package for Debian/Ubuntu, but it's not always the
latest version.
@@ -36,7 +41,7 @@ Example usage and output
::
- $ pep8 --first optparse.py
+ $ pycodestyle --first optparse.py
optparse.py:69:11: E401 multiple imports on one line
optparse.py:77:1: E302 expected 2 blank lines, found 1
optparse.py:88:5: E301 expected 1 blank line, found 0
@@ -46,10 +51,10 @@ Example usage and output
optparse.py:472:29: E221 multiple spaces before operator
optparse.py:544:21: W601 .has_key() is deprecated, use 'in'
-You can also make pep8.py show the source code for each error, and
+You can also make ``pycodestyle.py`` show the source code for each error, and
even the relevant text from PEP 8::
- $ pep8 --show-source --show-pep8 testsuite/E40.py
+ $ pycodestyle --show-source --show-pep8 testsuite/E40.py
testsuite/E40.py:2:10: E401 multiple imports on one line
import os, sys
^
@@ -61,7 +66,7 @@ even the relevant text from PEP 8::
Or you can display how often each error was found::
- $ pep8 --statistics -qq Python-2.5/Lib
+ $ pycodestyle --statistics -qq Python-2.5/Lib
232 E201 whitespace after '['
599 E202 whitespace before ')'
631 E203 whitespace before ','
@@ -78,14 +83,14 @@ Or you can display how often each error was found::
Links
-----
-.. image:: https://api.travis-ci.org/jcrocholl/pep8.png?branch=master
- :target: https://travis-ci.org/jcrocholl/pep8
+.. image:: https://api.travis-ci.org/PyCQA/pycodestyle.png?branch=master
+ :target: https://travis-ci.org/PyCQA/pycodestyle
:alt: Build status
-.. image:: https://pypip.in/wheel/pep8/badge.png?branch=master
- :target: https://pypi.python.org/pypi/pep8
+.. image:: https://pypip.in/wheel/pycodestyle/badge.png?branch=master
+ :target: https://pypi.python.org/pypi/pycodestyle
:alt: Wheel Status
-* `Read the documentation <http://pep8.readthedocs.org/>`_
+* `Read the documentation <https://pycodestyle.readthedocs.io/>`_
-* `Fork me on GitHub <http://github.com/jcrocholl/pep8>`_
+* `Fork me on GitHub <http://github.com/PyCQA/pycodestyle>`_
diff --git a/docs/Makefile b/docs/Makefile
index 1952db4..96c920f 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -77,17 +77,17 @@ qthelp:
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pep8.qhcp"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pycodestyle.qhcp"
@echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pep8.qhc"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pycodestyle.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/pep8"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pep8"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/pycodestyle"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pycodestyle"
@echo "# devhelp"
epub:
diff --git a/docs/advanced.rst b/docs/advanced.rst
index 2bce2e0..fd3cf3e 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -1,4 +1,4 @@
-.. currentmodule:: pep8
+.. currentmodule:: pycodestyle
==============
Advanced usage
@@ -8,64 +8,81 @@ Advanced usage
Automated tests
---------------
-You can also execute `pep8` tests from Python code. For example, this
+You can also execute ``pycodestyle`` tests from Python code. For example, this
can be highly useful for automated testing of coding style conformance
in your project::
import unittest
- import pep8
+ import pycodestyle
class TestCodeFormat(unittest.TestCase):
- def test_pep8_conformance(self):
- """Test that we conform to PEP8."""
- pep8style = pep8.StyleGuide(quiet=True)
- result = pep8style.check_files(['file1.py', 'file2.py'])
+ def test_conformance(self):
+ """Test that we conform to PEP-8."""
+ style = pycodestyle.StyleGuide(quiet=True)
+ result = style.check_files(['file1.py', 'file2.py'])
self.assertEqual(result.total_errors, 0,
"Found code style errors (and warnings).")
-If you are using `nosetests` for running tests, remove `quiet=True`
+If you are using ``nosetests`` for running tests, remove ``quiet=True``
since Nose suppresses stdout.
There's also a shortcut for checking a single file::
- import pep8
+ import pycodestyle
- fchecker = pep8.Checker('testsuite/E27.py', show_source=True)
+ fchecker = pycodestyle.Checker('testsuite/E27.py', show_source=True)
file_errors = fchecker.check_all()
print("Found %s errors (and warnings)" % file_errors)
+Configuring tests
+-----------------
+
+You can configure automated ``pycodestyle`` tests in a variety of ways.
+
+For example, you can pass in a path to a configuration file that ``pycodestyle``
+should use::
+
+ import pycodestyle
+
+ style = pycodestyle.StyleGuide(config_file='/path/to/tox.ini')
+
+You can also set specific options explicitly::
+
+ style = pycodestyle.StyleGuide(ignore=['E501'])
+
+
Skip file header
----------------
Another example is related to the `feature request #143
-<https://github.com/jcrocholl/pep8/issues/143>`_: skip a number of lines
+<https://github.com/pycqa/pycodestyle/issues/143>`_: skip a number of lines
at the beginning and the end of a file. This use case is easy to implement
through a custom wrapper for the PEP 8 library::
#!python
- import pep8
+ import pycodestyle
LINES_SLICE = slice(14, -20)
- class PEP8(pep8.StyleGuide):
- """This subclass of pep8.StyleGuide will skip the first and last lines
+ class StyleGuide(pycodestyle.StyleGuide):
+ """This subclass of pycodestyle.StyleGuide will skip the first and last lines
of each file."""
def input_file(self, filename, lines=None, expected=None, line_offset=0):
if lines is None:
assert line_offset == 0
line_offset = LINES_SLICE.start or 0
- lines = pep8.readlines(filename)[LINES_SLICE]
- return super(PEP8, self).input_file(
+ lines = pycodestyle.readlines(filename)[LINES_SLICE]
+ return super(StyleGuide, self).input_file(
filename, lines=lines, expected=expected, line_offset=line_offset)
if __name__ == '__main__':
- pep8style = PEP8(parse_argv=True, config_file=True)
- report = pep8style.check_files()
+ style = StyleGuide(parse_argv=True, config_file=True)
+ report = style.check_files()
if report.total_errors:
raise SystemExit(1)
@@ -74,4 +91,4 @@ and 20 lines at the end. If there's no line to skip at the end, it could be
changed with ``LINES_SLICE = slice(14, None)`` for example.
You can save it in a file and use it with the same options as the
-original ``pep8``.
+original ``pycodestyle``.
diff --git a/docs/api.rst b/docs/api.rst
index b346aba..f9c7066 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -1,8 +1,8 @@
-========
-pep8 API
-========
+===============
+pycodestyle API
+===============
-.. module:: pep8
+.. module:: pycodestyle
The library provides classes which are usable by third party tools.
@@ -84,5 +84,5 @@ Utilities
.. autofunction:: stdin_get_value()
.. autofunction:: parse_udiff(diff, patterns=None, parent='.')
.. autofunction:: filename_match(filename, patterns, default=True)
- .. autofunction:: get_parser(prog='pep8', version=pep8.__version__)
+ .. autofunction:: get_parser(prog='pycodestyle', version=pycodestyle.__version__)
.. autofunction:: init_checks_registry()
diff --git a/docs/conf.py b/docs/conf.py
index d1dca3c..7935b0b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# pep8 documentation build configuration file, created by
+# pycodestyle documentation build configuration file, created by
# sphinx-quickstart on Tue Aug 21 09:47:49 2012.
#
# This file is execfile()d with the current directory set to its
@@ -44,20 +44,20 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
-project = u'pep8'
+project = u'pycodestyle'
authors = u'Johann C. Rocholl, Florent Xicluna, Ian Lee'
-copyright = u'2006-2014, %s' % (authors)
+copyright = u'2006-2016, %s' % (authors)
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
-pep8_version = __import__('pep8').__version__.split('.')
+pkg_version = __import__('pycodestyle').__version__.split('.')
# The short X.Y version.
-version = '.'.join(pep8_version[:2])
+version = '.'.join(pkg_version[:2])
# The full version, including alpha/beta/rc tags.
-release = '.'.join(pep8_version)
+release = '.'.join(pkg_version)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -99,7 +99,11 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'default'
+on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
+if not on_rtd: # only import and set the theme if we're building docs locally
+ import sphinx_rtd_theme
+ html_theme = 'sphinx_rtd_theme'
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -128,7 +132,7 @@ html_theme = 'default'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
@@ -172,7 +176,7 @@ html_static_path = ['_static']
#html_file_suffix = None
# Output file base name for HTML help builder.
-htmlhelp_basename = 'pep8doc'
+htmlhelp_basename = 'pycodestyledoc'
# -- Options for LaTeX output -------------------------------------------------
@@ -192,7 +196,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'pep8.tex', u'pep8 documentation',
+ ('index', 'pycodestyle.tex', u'pycodestyle documentation',
authors, 'manual'),
]
@@ -222,7 +226,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- ('index', 'pep8', u'pep8 documentation',
+ ('index', 'pycodestyle', u'pycodestyle documentation',
[authors], 1)
]
@@ -236,8 +240,8 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ('index', 'pep8', u'pep8 documentation', authors,
- 'pep8', 'One line description of project.',
+ ('index', 'pycodestyle', u'pycodestyle documentation', authors,
+ 'pycodestyle', 'One line description of project.',
'Miscellaneous'),
]
diff --git a/docs/developer.rst b/docs/developer.rst
index 4725acd..3acf2a6 100644
--- a/docs/developer.rst
+++ b/docs/developer.rst
@@ -1,4 +1,4 @@
-.. currentmodule:: pep8
+.. currentmodule:: pycodestyle
=================
Developer's notes
@@ -11,13 +11,28 @@ Source code
The source code is currently `available on GitHub`_ under the terms and
conditions of the :ref:`Expat license <license>`. Fork away!
-* `Source code <https://github.com/jcrocholl/pep8>`_ and
- `issue tracker <https://github.com/jcrocholl/pep8/issues>`_ on GitHub.
-* `Continuous tests <http://travis-ci.org/jcrocholl/pep8>`_ against Python
+* `Source code <https://github.com/pycqa/pycodestyle>`_ and
+ `issue tracker <https://github.com/pycqa/pycodestyle/issues>`_ on GitHub.
+* `Continuous tests <http://travis-ci.org/pycqa/pycodestyle>`_ against Python
2.6 through 3.4 and PyPy, on `Travis-CI platform
<http://about.travis-ci.org/>`_.
-.. _available on GitHub: https://github.com/jcrocholl/pep8
+.. _available on GitHub: https://github.com/pycqa/pycodestyle
+
+
+Direction
+~~~~~~~~~
+
+Some high-level aims and directions to bear in mind for contributions:
+
+* ``pycodestyle`` is intended to be as fast as possible.
+ Using the ``ast`` module defeats that purpose.
+ The `pep8-naming <https://github.com/flintwork/pep8-naming>`_ plugin exists for this sort of functionality.
+* If you want to provide extensibility / plugins,
+ please see `flake8 <https://gitlab.com/pycqa/flake8>`_ -
+ ``pycodestyle`` doesn't want or need a plugin architecture.
+* Python 2.6 support is still deemed important.
+* ``pycodestyle`` aims to have no external dependencies.
Contribute
@@ -74,19 +89,22 @@ Several docstrings contain examples directly from the `PEP 8`_ document.
Okay: spam(ham[1], {eggs: 2})
E201: spam( ham[1], {eggs: 2})
-These examples are verified automatically when pep8.py is run with the
-``--doctest`` option. You can add examples for your own check functions.
-The format is simple: ``"Okay"`` or error/warning code followed by colon
-and space, the rest of the line is example source code. If you put ``'r'``
-before the docstring, you can use ``\n`` for newline and ``\t`` for tab.
+These examples are verified automatically when ``pycodestyle.py`` is run with
+the ``--doctest`` option. You can add examples for your own check functions.
+The format is simple: ``"Okay"`` or error/warning code followed by colon and
+space, the rest of the line is example source code. If you put ``'r'`` before
+the docstring, you can use ``\n`` for newline and ``\t`` for tab.
Then be sure to pass the tests::
- $ python pep8.py --testsuite testsuite
- $ python pep8.py --doctest
- $ python pep8.py --verbose pep8.py
+ $ python pycodestyle.py --testsuite testsuite
+ $ python pycodestyle.py --doctest
+ $ python pycodestyle.py --verbose pycodestyle.py
+
+When contributing to pycodestyle, please observe our `Code of Conduct`_.
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
+.. _Code of Conduct: http://meta.pycqa.org/en/latest/code-of-conduct.html
Changes
diff --git a/docs/index.rst b/docs/index.rst
index 5500e0d..0764e9f 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,12 +1,12 @@
-.. pep8 documentation master file
+.. pycodestyle documentation master file
-pep8's documentation
-====================
+pycodestyle's documentation
+===========================
*Python style guide checker*
-pep8 is a tool to check your Python code against some of the style
-conventions in `PEP 8`_.
+pycodestyle (formerly pep8) is a tool to check your Python code against some of
+the style conventions in `PEP 8`_.
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
@@ -21,8 +21,8 @@ Contents:
API <api>
developer
-* Online documentation: http://pep8.readthedocs.org/
-* Source code and issue tracker: https://github.com/jcrocholl/pep8
+* Online documentation: https://pycodestyle.readthedocs.io/
+* Source code and issue tracker: https://github.com/pycqa/pycodestyle
Indices and tables
@@ -45,7 +45,7 @@ Maintained by Florent Xicluna and Ian Lee.
License
=======
-The ``pep8`` library is provided under the terms and conditions of the
+The ``pycodestyle`` library is provided under the terms and conditions of the
Expat license::
# Permission is hereby granted, free of charge, to any person
diff --git a/docs/intro.rst b/docs/intro.rst
index 1bcafe8..12f67d7 100644
--- a/docs/intro.rst
+++ b/docs/intro.rst
@@ -1,9 +1,9 @@
-.. currentmodule:: pep8
+.. currentmodule:: pycodestyle
Introduction
============
-pep8 is a tool to check your Python code against some of the style
+pycodestyle is a tool to check your Python code against some of the style
conventions in `PEP 8`_.
.. contents::
@@ -18,7 +18,7 @@ Features
* Parseable output: Jump to error location in your editor.
* Small: Just one Python file, requires only stdlib. You can use just
- the pep8.py file for this purpose.
+ the ``pycodestyle.py`` file for this purpose.
* Comes with a comprehensive test suite.
@@ -40,14 +40,14 @@ Always remember this statement from `PEP 8`_:
Among other things, these features are currently not in the scope of
-the ``pep8`` library:
+the ``pycodestyle`` library:
* **naming conventions**: this kind of feature is supported through plugins.
Install `flake8 <https://pypi.python.org/pypi/flake8>`_ and the
`pep8-naming extension <https://pypi.python.org/pypi/pep8-naming>`_ to use
this feature.
* **docstring conventions**: they are not in the scope of this library;
- see the `pep257 project <https://github.com/GreenSteam/pep257>`_.
+ see the `pydocstyle project <https://github.com/PyCQA/pydocstyle>`_.
* **automatic fixing**: see the section *PEP8 Fixers* in the
:ref:`related tools <related-tools>` page.
@@ -55,16 +55,11 @@ the ``pep8`` library:
Installation
------------
-You can install, upgrade, uninstall pep8.py with these commands::
+You can install, upgrade, uninstall ``pycodestyle.py`` with these commands::
- $ pip install pep8
- $ pip install --upgrade pep8
- $ pip uninstall pep8
-
-There's also a package for Debian/Ubuntu, but it's not always the
-latest version::
-
- $ sudo apt-get install pep8
+ $ pip install pycodestyle
+ $ pip install --upgrade pycodestyle
+ $ pip uninstall pycodestyle
Example usage and output
@@ -72,7 +67,7 @@ Example usage and output
::
- $ pep8 --first optparse.py
+ $ pycodestyle --first optparse.py
optparse.py:69:11: E401 multiple imports on one line
optparse.py:77:1: E302 expected 2 blank lines, found 1
optparse.py:88:5: E301 expected 1 blank line, found 0
@@ -82,10 +77,10 @@ Example usage and output
optparse.py:472:29: E221 multiple spaces before operator
optparse.py:544:21: W601 .has_key() is deprecated, use 'in'
-You can also make pep8.py show the source code for each error, and
+You can also make ``pycodestyle.py`` show the source code for each error, and
even the relevant text from PEP 8::
- $ pep8 --show-source --show-pep8 testsuite/E40.py
+ $ pycodestyle --show-source --show-pep8 testsuite/E40.py
testsuite/E40.py:2:10: E401 multiple imports on one line
import os, sys
^
@@ -97,7 +92,7 @@ even the relevant text from PEP 8::
Or you can display how often each error was found::
- $ pep8 --statistics -qq Python-2.5/Lib
+ $ pycodestyle --statistics -qq Python-2.5/Lib
232 E201 whitespace after '['
599 E202 whitespace before ')'
631 E203 whitespace before ','
@@ -111,15 +106,16 @@ Or you can display how often each error was found::
612 W601 .has_key() is deprecated, use 'in'
1188 W602 deprecated form of raising exception
-You can also make pep8.py show the error text in different formats by using --format having options default/pylint/custom::
+You can also make ``pycodestyle.py`` show the error text in different formats by
+using ``--format`` having options default/pylint/custom::
- $ pep8 testsuite/E40.py --format=default
+ $ pycodestyle testsuite/E40.py --format=default
testsuite/E40.py:2:10: E401 multiple imports on one line
- $ pep8 testsuite/E40.py --format=pylint
+ $ pycodestyle testsuite/E40.py --format=pylint
testsuite/E40.py:2: [E401] multiple imports on one line
- $ pep8 testsuite/E40.py --format='%(path)s|%(row)d|%(col)d| %(code)s %(text)s'
+ $ pycodestyle testsuite/E40.py --format='%(path)s|%(row)d|%(col)d| %(code)s %(text)s'
testsuite/E40.py|2|10| E401 multiple imports on one line
Variables in the ``custom`` format option
@@ -140,8 +136,8 @@ Variables in the ``custom`` format option
Quick help is available on the command line::
- $ pep8 -h
- Usage: pep8 [options] input ...
+ $ pycodestyle -h
+ Usage: pycodestyle [options] input ...
Options:
--version show program's version number and exit
@@ -183,24 +179,28 @@ Quick help is available on the command line::
Configuration
-------------
-The behaviour may be configured at two levels.
+The behaviour may be configured at two levels, the user and project levels.
+
+At the user level, settings are read from the following locations:
+
+If on Windows:
+ ``~\.pep8``
+
+Otherwise, if the :envvar:`XDG_CONFIG_HOME` environment variable is defined:
+ ``XDG_CONFIG_HOME/pep8``
+
+Else if :envvar:`XDG_CONFIG_HOME` is not defined:
+ ``~/.config/pep8``
-The user settings are read from the ``~/.config/pep8`` file and
-for Windows from the ``~\.pep8`` file.
Example::
[pep8]
ignore = E226,E302,E41
max-line-length = 160
-At the project level, a ``tox.ini`` file or a ``setup.cfg`` file is read if
-present (``.pep8`` file is also supported, but it is deprecated). If none of
-these files have a ``[pep8]`` section, no project specific configuration is
-loaded.
-
-If the ``ignore`` option is not in the configuration and not in the arguments,
-only the error codes ``E123/E133``, ``E226`` and ``E241/E242`` are ignored
-(see below).
+At the project level, a ``setup.cfg`` file or a ``tox.ini`` file is read if
+present. If none of these files have a ``[pep8]`` section, no project specific
+configuration is loaded.
Error codes
@@ -208,198 +208,205 @@ Error codes
This is the current list of error and warning codes:
-+----------+----------------------------------------------------------------------+
-| code | sample message |
-+==========+======================================================================+
-| **E1** | *Indentation* |
-+----------+----------------------------------------------------------------------+
-| E101 | indentation contains mixed spaces and tabs |
-+----------+----------------------------------------------------------------------+
-| E111 | indentation is not a multiple of four |
-+----------+----------------------------------------------------------------------+
-| E112 | expected an indented block |
-+----------+----------------------------------------------------------------------+
-| E113 | unexpected indentation |
-+----------+----------------------------------------------------------------------+
-| E114 | indentation is not a multiple of four (comment) |
-+----------+----------------------------------------------------------------------+
-| E115 | expected an indented block (comment) |
-+----------+----------------------------------------------------------------------+
-| E116 | unexpected indentation (comment) |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E121 (^) | continuation line under-indented for hanging indent |
-+----------+----------------------------------------------------------------------+
-| E122 (^) | continuation line missing indentation or outdented |
-+----------+----------------------------------------------------------------------+
-| E123 (*) | closing bracket does not match indentation of opening bracket's line |
-+----------+----------------------------------------------------------------------+
-| E124 (^) | closing bracket does not match visual indentation |
-+----------+----------------------------------------------------------------------+
-| E125 (^) | continuation line with same indent as next logical line |
-+----------+----------------------------------------------------------------------+
-| E126 (^) | continuation line over-indented for hanging indent |
-+----------+----------------------------------------------------------------------+
-| E127 (^) | continuation line over-indented for visual indent |
-+----------+----------------------------------------------------------------------+
-| E128 (^) | continuation line under-indented for visual indent |
-+----------+----------------------------------------------------------------------+
-| E129 (^) | visually indented line with same indent as next logical line |
-+----------+----------------------------------------------------------------------+
-| E131 (^) | continuation line unaligned for hanging indent |
-+----------+----------------------------------------------------------------------+
-| E133 (*) | closing bracket is missing indentation |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **E2** | *Whitespace* |
-+----------+----------------------------------------------------------------------+
-| E201 | whitespace after '(' |
-+----------+----------------------------------------------------------------------+
-| E202 | whitespace before ')' |
-+----------+----------------------------------------------------------------------+
-| E203 | whitespace before ':' |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E211 | whitespace before '(' |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E221 | multiple spaces before operator |
-+----------+----------------------------------------------------------------------+
-| E222 | multiple spaces after operator |
-+----------+----------------------------------------------------------------------+
-| E223 | tab before operator |
-+----------+----------------------------------------------------------------------+
-| E224 | tab after operator |
-+----------+----------------------------------------------------------------------+
-| E225 | missing whitespace around operator |
-+----------+----------------------------------------------------------------------+
-| E226 (*) | missing whitespace around arithmetic operator |
-+----------+----------------------------------------------------------------------+
-| E227 | missing whitespace around bitwise or shift operator |
-+----------+----------------------------------------------------------------------+
-| E228 | missing whitespace around modulo operator |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E231 | missing whitespace after ',' |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E241 (*) | multiple spaces after ',' |
-+----------+----------------------------------------------------------------------+
-| E242 (*) | tab after ',' |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E251 | unexpected spaces around keyword / parameter equals |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E261 | at least two spaces before inline comment |
-+----------+----------------------------------------------------------------------+
-| E262 | inline comment should start with '# ' |
-+----------+----------------------------------------------------------------------+
-| E265 | block comment should start with '# ' |
-+----------+----------------------------------------------------------------------+
-| E266 | too many leading '#' for block comment |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| E271 | multiple spaces after keyword |
-+----------+----------------------------------------------------------------------+
-| E272 | multiple spaces before keyword |
-+----------+----------------------------------------------------------------------+
-| E273 | tab after keyword |
-+----------+----------------------------------------------------------------------+
-| E274 | tab before keyword |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **E3** | *Blank line* |
-+----------+----------------------------------------------------------------------+
-| E301 | expected 1 blank line, found 0 |
-+----------+----------------------------------------------------------------------+
-| E302 | expected 2 blank lines, found 0 |
-+----------+----------------------------------------------------------------------+
-| E303 | too many blank lines (3) |
-+----------+----------------------------------------------------------------------+
-| E304 | blank lines found after function decorator |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **E4** | *Import* |
-+----------+----------------------------------------------------------------------+
-| E401 | multiple imports on one line |
-+----------+----------------------------------------------------------------------+
-| E402 | module level import not at top of file |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **E5** | *Line length* |
-+----------+----------------------------------------------------------------------+
-| E501 (^) | line too long (82 > 79 characters) |
-+----------+----------------------------------------------------------------------+
-| E502 | the backslash is redundant between brackets |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **E7** | *Statement* |
-+----------+----------------------------------------------------------------------+
-| E701 | multiple statements on one line (colon) |
-+----------+----------------------------------------------------------------------+
-| E702 | multiple statements on one line (semicolon) |
-+----------+----------------------------------------------------------------------+
-| E703 | statement ends with a semicolon |
-+----------+----------------------------------------------------------------------+
-| E704 (*) | multiple statements on one line (def) |
-+----------+----------------------------------------------------------------------+
-| E711 (^) | comparison to None should be 'if cond is None:' |
-+----------+----------------------------------------------------------------------+
-| E712 (^) | comparison to True should be 'if cond is True:' or 'if cond:' |
-+----------+----------------------------------------------------------------------+
-| E713 | test for membership should be 'not in' |
-+----------+----------------------------------------------------------------------+
-| E714 | test for object identity should be 'is not' |
-+----------+----------------------------------------------------------------------+
-| E721 | do not compare types, use 'isinstance()' |
-+----------+----------------------------------------------------------------------+
-| E731 | do not assign a lambda expression, use a def |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **E9** | *Runtime* |
-+----------+----------------------------------------------------------------------+
-| E901 | SyntaxError or IndentationError |
-+----------+----------------------------------------------------------------------+
-| E902 | IOError |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **W1** | *Indentation warning* |
-+----------+----------------------------------------------------------------------+
-| W191 | indentation contains tabs |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **W2** | *Whitespace warning* |
-+----------+----------------------------------------------------------------------+
-| W291 | trailing whitespace |
-+----------+----------------------------------------------------------------------+
-| W292 | no newline at end of file |
-+----------+----------------------------------------------------------------------+
-| W293 | blank line contains whitespace |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **W3** | *Blank line warning* |
-+----------+----------------------------------------------------------------------+
-| W391 | blank line at end of file |
-+----------+----------------------------------------------------------------------+
-+----------+----------------------------------------------------------------------+
-| **W6** | *Deprecation warning* |
-+----------+----------------------------------------------------------------------+
-| W601 | .has_key() is deprecated, use 'in' |
-+----------+----------------------------------------------------------------------+
-| W602 | deprecated form of raising exception |
-+----------+----------------------------------------------------------------------+
-| W603 | '<>' is deprecated, use '!=' |
-+----------+----------------------------------------------------------------------+
-| W604 | backticks are deprecated, use 'repr()' |
-+----------+----------------------------------------------------------------------+
-
-
-**(*)** In the default configuration, the checks **E123**, **E133**, **E226**,
-**E241**, **E242** and **E704** are ignored because they are not rules unanimously
-accepted, and `PEP 8`_ does not enforce them. The check **E133** is mutually
-exclusive with check **E123**. Use switch ``--hang-closing`` to report **E133**
-instead of **E123**.
++------------+----------------------------------------------------------------------+
+| code | sample message |
++============+======================================================================+
+| **E1** | *Indentation* |
++------------+----------------------------------------------------------------------+
+| E101 | indentation contains mixed spaces and tabs |
++------------+----------------------------------------------------------------------+
+| E111 | indentation is not a multiple of four |
++------------+----------------------------------------------------------------------+
+| E112 | expected an indented block |
++------------+----------------------------------------------------------------------+
+| E113 | unexpected indentation |
++------------+----------------------------------------------------------------------+
+| E114 | indentation is not a multiple of four (comment) |
++------------+----------------------------------------------------------------------+
+| E115 | expected an indented block (comment) |
++------------+----------------------------------------------------------------------+
+| E116 | unexpected indentation (comment) |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E121 (\*^) | continuation line under-indented for hanging indent |
++------------+----------------------------------------------------------------------+
+| E122 (^) | continuation line missing indentation or outdented |
++------------+----------------------------------------------------------------------+
+| E123 (*) | closing bracket does not match indentation of opening bracket's line |
++------------+----------------------------------------------------------------------+
+| E124 (^) | closing bracket does not match visual indentation |
++------------+----------------------------------------------------------------------+
+| E125 (^) | continuation line with same indent as next logical line |
++------------+----------------------------------------------------------------------+
+| E126 (\*^) | continuation line over-indented for hanging indent |
++------------+----------------------------------------------------------------------+
+| E127 (^) | continuation line over-indented for visual indent |
++------------+----------------------------------------------------------------------+
+| E128 (^) | continuation line under-indented for visual indent |
++------------+----------------------------------------------------------------------+
+| E129 (^) | visually indented line with same indent as next logical line |
++------------+----------------------------------------------------------------------+
+| E131 (^) | continuation line unaligned for hanging indent |
++------------+----------------------------------------------------------------------+
+| E133 (*) | closing bracket is missing indentation |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **E2** | *Whitespace* |
++------------+----------------------------------------------------------------------+
+| E201 | whitespace after '(' |
++------------+----------------------------------------------------------------------+
+| E202 | whitespace before ')' |
++------------+----------------------------------------------------------------------+
+| E203 | whitespace before ':' |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E211 | whitespace before '(' |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E221 | multiple spaces before operator |
++------------+----------------------------------------------------------------------+
+| E222 | multiple spaces after operator |
++------------+----------------------------------------------------------------------+
+| E223 | tab before operator |
++------------+----------------------------------------------------------------------+
+| E224 | tab after operator |
++------------+----------------------------------------------------------------------+
+| E225 | missing whitespace around operator |
++------------+----------------------------------------------------------------------+
+| E226 (*) | missing whitespace around arithmetic operator |
++------------+----------------------------------------------------------------------+
+| E227 | missing whitespace around bitwise or shift operator |
++------------+----------------------------------------------------------------------+
+| E228 | missing whitespace around modulo operator |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E231 | missing whitespace after ',', ';', or ':' |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E241 (*) | multiple spaces after ',' |
++------------+----------------------------------------------------------------------+
+| E242 (*) | tab after ',' |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E251 | unexpected spaces around keyword / parameter equals |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E261 | at least two spaces before inline comment |
++------------+----------------------------------------------------------------------+
+| E262 | inline comment should start with '# ' |
++------------+----------------------------------------------------------------------+
+| E265 | block comment should start with '# ' |
++------------+----------------------------------------------------------------------+
+| E266 | too many leading '#' for block comment |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| E271 | multiple spaces after keyword |
++------------+----------------------------------------------------------------------+
+| E272 | multiple spaces before keyword |
++------------+----------------------------------------------------------------------+
+| E273 | tab after keyword |
++------------+----------------------------------------------------------------------+
+| E274 | tab before keyword |
++------------+----------------------------------------------------------------------+
+| E275 | missing whitespace after keyword |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **E3** | *Blank line* |
++------------+----------------------------------------------------------------------+
+| E301 | expected 1 blank line, found 0 |
++------------+----------------------------------------------------------------------+
+| E302 | expected 2 blank lines, found 0 |
++------------+----------------------------------------------------------------------+
+| E303 | too many blank lines (3) |
++------------+----------------------------------------------------------------------+
+| E304 | blank lines found after function decorator |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **E4** | *Import* |
++------------+----------------------------------------------------------------------+
+| E401 | multiple imports on one line |
++------------+----------------------------------------------------------------------+
+| E402 | module level import not at top of file |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **E5** | *Line length* |
++------------+----------------------------------------------------------------------+
+| E501 (^) | line too long (82 > 79 characters) |
++------------+----------------------------------------------------------------------+
+| E502 | the backslash is redundant between brackets |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **E7** | *Statement* |
++------------+----------------------------------------------------------------------+
+| E701 | multiple statements on one line (colon) |
++------------+----------------------------------------------------------------------+
+| E702 | multiple statements on one line (semicolon) |
++------------+----------------------------------------------------------------------+
+| E703 | statement ends with a semicolon |
++------------+----------------------------------------------------------------------+
+| E704 (*) | multiple statements on one line (def) |
++------------+----------------------------------------------------------------------+
+| E711 (^) | comparison to None should be 'if cond is None:' |
++------------+----------------------------------------------------------------------+
+| E712 (^) | comparison to True should be 'if cond is True:' or 'if cond:' |
++------------+----------------------------------------------------------------------+
+| E713 | test for membership should be 'not in' |
++------------+----------------------------------------------------------------------+
+| E714 | test for object identity should be 'is not' |
++------------+----------------------------------------------------------------------+
+| E721 (^) | do not compare types, use 'isinstance()' |
++------------+----------------------------------------------------------------------+
+| E731 | do not assign a lambda expression, use a def |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **E9** | *Runtime* |
++------------+----------------------------------------------------------------------+
+| E901 | SyntaxError or IndentationError |
++------------+----------------------------------------------------------------------+
+| E902 | IOError |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **W1** | *Indentation warning* |
++------------+----------------------------------------------------------------------+
+| W191 | indentation contains tabs |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **W2** | *Whitespace warning* |
++------------+----------------------------------------------------------------------+
+| W291 | trailing whitespace |
++------------+----------------------------------------------------------------------+
+| W292 | no newline at end of file |
++------------+----------------------------------------------------------------------+
+| W293 | blank line contains whitespace |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **W3** | *Blank line warning* |
++------------+----------------------------------------------------------------------+
+| W391 | blank line at end of file |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **W5** | *Line break warning* |
++------------+----------------------------------------------------------------------+
+| W503 (*) | line break occurred before a binary operator |
++------------+----------------------------------------------------------------------+
++------------+----------------------------------------------------------------------+
+| **W6** | *Deprecation warning* |
++------------+----------------------------------------------------------------------+
+| W601 | .has_key() is deprecated, use 'in' |
++------------+----------------------------------------------------------------------+
+| W602 | deprecated form of raising exception |
++------------+----------------------------------------------------------------------+
+| W603 | '<>' is deprecated, use '!=' |
++------------+----------------------------------------------------------------------+
+| W604 | backticks are deprecated, use 'repr()' |
++------------+----------------------------------------------------------------------+
+
+
+**(*)** In the default configuration, the checks **E121**, **E123**, **E126**,
+**E133**, **E226**, **E241**, **E242**, **E704** and **W503** are ignored because
+they are not rules unanimously accepted, and `PEP 8`_ does not enforce them. The
+check **E133** is mutually exclusive with check **E123**. Use switch ``--hang-
+closing`` to report **E133** instead of **E123**.
**(^)** These checks can be disabled at the line level using the ``# noqa``
special comment. This possibility should be reserved for special cases.
@@ -409,7 +416,7 @@ special comment. This possibility should be reserved for special cases.
Note: most errors can be listed with such one-liner::
- $ python pep8.py --first --select E,W testsuite/ --format '%(code)s: %(text)s'
+ $ python pycodestyle.py --first --select E,W testsuite/ --format '%(code)s: %(text)s'
.. _related-tools:
@@ -417,10 +424,10 @@ Note: most errors can be listed with such one-liner::
Related tools
-------------
-The `flake8 checker <https://flake8.readthedocs.org>`_ is a wrapper around
-``pep8`` and similar tools. It supports plugins.
+The `flake8 checker <https://flake8.readthedocs.io>`_ is a wrapper around
+``pycodestyle`` and similar tools. It supports plugins.
-Other tools which use ``pep8`` are referenced in the Wiki: `list of related tools
-<https://github.com/jcrocholl/pep8/wiki/RelatedTools>`_.
+Other tools which use ``pycodestyle`` are referenced in the Wiki: `list of related
+tools <https://github.com/pycqa/pycodestyle/wiki/RelatedTools>`_.
.. _PEP 8: http://www.python.org/dev/peps/pep-0008/
diff --git a/docs/make.bat b/docs/make.bat
index efa0e94..1ecae62 100644
--- a/docs/make.bat
+++ b/docs/make.bat
@@ -99,9 +99,9 @@ if "%1" == "qthelp" (
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pep8.qhcp
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pycodestyle.qhcp
echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pep8.ghc
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pycodestyle.ghc
goto end
)
diff --git a/pep8.py b/pycodestyle.py
index 79a81ed..e033547 100755
--- a/pep8.py
+++ b/pycodestyle.py
@@ -1,8 +1,9 @@
#!/usr/bin/env python
-# pep8.py - Check Python source code formatting, according to PEP 8
+# pycodestyle.py - Check Python source code formatting, according to PEP 8
+#
# Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
# Copyright (C) 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
-# Copyright (C) 2014 Ian Lee <ianlee1521@gmail.com>
+# Copyright (C) 2014-2016 Ian Lee <ianlee1521@gmail.com>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -28,10 +29,10 @@ r"""
Check Python source code formatting, according to PEP 8.
For usage and a list of options, try this:
-$ python pep8.py -h
+$ python pycodestyle.py -h
This program and its regression test suite live here:
-http://github.com/jcrocholl/pep8
+https://github.com/pycqa/pycodestyle
Groups of errors and warnings:
E errors
@@ -47,8 +48,6 @@ W warnings
"""
from __future__ import with_statement
-__version__ = '1.6.0a0'
-
import os
import sys
import re
@@ -56,6 +55,7 @@ import time
import inspect
import keyword
import tokenize
+import warnings
from optparse import OptionParser
from fnmatch import fnmatch
try:
@@ -64,18 +64,22 @@ try:
except ImportError:
from ConfigParser import RawConfigParser
+__version__ = '2.0.0'
+
DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
-DEFAULT_IGNORE = 'E123,E226,E24,E704'
+DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503'
try:
if sys.platform == 'win32':
- DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
+ USER_CONFIG = os.path.expanduser(r'~\.pep8')
else:
- DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or
- os.path.expanduser('~/.config'), 'pep8')
+ USER_CONFIG = os.path.join(
+ os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
+ 'pep8'
+ )
except ImportError:
- DEFAULT_CONFIG = None
+ USER_CONFIG = None
-PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')
+PROJECT_CONFIG = ('setup.cfg', 'tox.ini')
TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
MAX_LINE_LENGTH = 79
REPORT_FORMAT = {
@@ -106,7 +110,7 @@ ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
DOCSTRING_REGEX = re.compile(r'u?r?["\']')
EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
-COMPARE_SINGLETON_REGEX = re.compile(r'\b(None|False|True)?\s*([=!]=)'
+COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
r'\s*(?(1)|(None|False|True))\b')
COMPARE_NEGATIVE_REGEX = re.compile(r'\b(not)\s+[^][)(}{ ]+\s+(in|is)\s')
COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
@@ -323,6 +327,23 @@ def whitespace_around_keywords(logical_line):
yield match.start(2), "E271 multiple spaces after keyword"
+def missing_whitespace_after_import_keyword(logical_line):
+ r"""Multiple imports in form from x import (a, b, c) should have space
+ between import statement and parenthesised name list.
+
+ Okay: from foo import (bar, baz)
+ E275: from foo import(bar, baz)
+ E275: from importable.module import(bar, baz)
+ """
+ line = logical_line
+ indicator = ' import('
+ if line.startswith('from '):
+ found = line.find(indicator)
+ if -1 < found:
+ pos = found + len(indicator) - 1
+ yield pos, "E275 missing whitespace after keyword"
+
+
def missing_whitespace(logical_line):
r"""Each comma, semicolon or colon should be followed by whitespace.
@@ -433,6 +454,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
indent_chances = {}
last_indent = tokens[0][2]
visual_indent = None
+ last_token_multiline = False
# for each depth, memorize the visual indent column
indent = [last_indent[1]]
if verbose >= 3:
@@ -512,8 +534,9 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
yield start, "%s continuation line %s" % error
# look for visual indenting
- if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)
- and not indent[depth]):
+ if (parens[row] and
+ token_type not in (tokenize.NL, tokenize.COMMENT) and
+ not indent[depth]):
indent[depth] = start[1]
indent_chances[start[1]] = True
if verbose >= 4:
@@ -561,7 +584,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
break
assert len(indent) == depth + 1
if start[1] not in indent_chances:
- # allow to line up tokens
+ # allow lining up tokens
indent_chances[start[1]] = text
last_token_multiline = (start[0] != end[0])
@@ -754,6 +777,8 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
Okay: boolean(a != b)
Okay: boolean(a <= b)
Okay: boolean(a >= b)
+ Okay: def foo(arg: int = 42):
+ Okay: async def foo(arg: int = 42):
E251: def complex(real, imag = 0.0):
E251: return magic(r = real, i = imag)
@@ -761,6 +786,8 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
parens = 0
no_space = False
prev_end = None
+ annotated_func_arg = False
+ in_def = logical_line.startswith(('def', 'async def'))
message = "E251 unexpected spaces around keyword / parameter equals"
for token_type, text, start, end, line in tokens:
if token_type == tokenize.NL:
@@ -770,14 +797,21 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
if start != prev_end:
yield (prev_end, message)
if token_type == tokenize.OP:
- if text == '(':
+ if text in '([':
parens += 1
- elif text == ')':
+ elif text in ')]':
parens -= 1
- elif parens and text == '=':
+ elif in_def and text == ':' and parens == 1:
+ annotated_func_arg = True
+ elif parens and text == ',' and parens == 1:
+ annotated_func_arg = False
+ elif parens and text == '=' and not annotated_func_arg:
no_space = True
if start != prev_end:
yield (prev_end, message)
+ if not parens:
+ annotated_func_arg = False
+
prev_end = end
@@ -823,7 +857,7 @@ def whitespace_before_comment(logical_line, tokens):
def imports_on_separate_lines(logical_line):
- r"""Imports should usually be on separate lines.
+ r"""Place imports on separate lines.
Okay: import os\nimport sys
E401: import sys, os
@@ -843,14 +877,17 @@ def imports_on_separate_lines(logical_line):
def module_imports_on_top_of_file(
logical_line, indent_level, checker_state, noqa):
- r"""Imports are always put at the top of the file, just after any module
- comments and docstrings, and before module globals and constants.
+ r"""Place imports at the top of the file.
+
+ Always put imports at the top of the file, just after any module comments
+ and docstrings, and before module globals and constants.
Okay: import os
Okay: # this is a comment\nimport os
Okay: '''this is a module docstring'''\nimport os
Okay: r'''this is a module docstring'''\nimport os
- Okay: __version__ = "123"\nimport os
+ Okay: try:\n import x\nexcept:\n pass\nelse:\n pass\nimport y
+ Okay: try:\n import x\nexcept:\n pass\nfinally:\n pass\nimport y
E402: a=1\nimport os
E402: 'One string'\n"Two string"\nimport os
E402: a=1\nfrom sys import x
@@ -864,6 +901,8 @@ def module_imports_on_top_of_file(
line = line[1:]
return line and (line[0] == '"' or line[0] == "'")
+ allowed_try_keywords = ('try', 'except', 'else', 'finally')
+
if indent_level: # Allow imports in conditional statements or functions
return
if not logical_line: # Allow empty lines or comments
@@ -873,10 +912,10 @@ def module_imports_on_top_of_file(
line = logical_line
if line.startswith('import ') or line.startswith('from '):
if checker_state.get('seen_non_imports', False):
- yield 0, "E402 import not at top of file"
- elif line.startswith('__version__ '):
- # These lines should be included after the module's docstring, before
- # any other code, separated by a blank line above and below.
+ yield 0, "E402 module level import not at top of file"
+ elif any(line.startswith(kw) for kw in allowed_try_keywords):
+ # Allow try, except, else, finally keywords intermixed with imports in
+ # order to support conditional importing
return
elif is_string_literal(line):
# The first literal is a docstring, allow it. Otherwise, report error.
@@ -958,10 +997,15 @@ def explicit_line_join(logical_line, tokens):
Okay: aaa = [123,\n 123]
Okay: aaa = ("bbb "\n "ccc")
Okay: aaa = "bbb " \\n "ccc"
+ Okay: aaa = 123 # \\
"""
prev_start = prev_end = parens = 0
+ comment = False
+ backslash = None
for token_type, text, start, end, line in tokens:
- if start[0] != prev_start and parens and backslash:
+ if token_type == tokenize.COMMENT:
+ comment = True
+ if start[0] != prev_start and parens and backslash and not comment:
yield backslash, "E502 the backslash is redundant between brackets"
if end[0] != prev_end:
if line.rstrip('\r\n').endswith('\\'):
@@ -978,6 +1022,55 @@ def explicit_line_join(logical_line, tokens):
parens -= 1
+def break_around_binary_operator(logical_line, tokens):
+ r"""
+ Avoid breaks before binary operators.
+
+ The preferred place to break around a binary operator is after the
+ operator, not before it.
+
+ W503: (width == 0\n + height == 0)
+ W503: (width == 0\n and height == 0)
+
+ Okay: (width == 0 +\n height == 0)
+ Okay: foo(\n -x)
+ Okay: foo(x\n [])
+ Okay: x = '''\n''' + ''
+ Okay: foo(x,\n -y)
+ Okay: foo(x, # comment\n -y)
+ Okay: var = (1 &\n ~2)
+ Okay: var = (1 /\n -2)
+ Okay: var = (1 +\n -1 +\n -2)
+ """
+ def is_binary_operator(token_type, text):
+ # The % character is strictly speaking a binary operator, but the
+ # common usage seems to be to put it next to the format parameters,
+ # after a line break.
+ return ((token_type == tokenize.OP or text in ['and', 'or']) and
+ text not in "()[]{},:.;@=%~")
+
+ line_break = False
+ unary_context = True
+ # Previous non-newline token types and text
+ previous_token_type = None
+ previous_text = None
+ for token_type, text, start, end, line in tokens:
+ if token_type == tokenize.COMMENT:
+ continue
+ if ('\n' in text or '\r' in text) and token_type != tokenize.STRING:
+ line_break = True
+ else:
+ if (is_binary_operator(token_type, text) and line_break and
+ not unary_context and
+ not is_binary_operator(previous_token_type,
+ previous_text)):
+ yield start, "W503 line break before binary operator"
+ unary_context = text in '([{,;'
+ line_break = False
+ previous_token_type = token_type
+ previous_text = text
+
+
def comparison_to_singleton(logical_line, noqa):
r"""Comparison to singletons should use "is" or "is not".
@@ -1033,7 +1126,7 @@ def comparison_negative(logical_line):
yield pos, "E714 test for object identity should be 'is not'"
-def comparison_type(logical_line):
+def comparison_type(logical_line, noqa):
r"""Object type comparisons should always use isinstance().
Do not compare types directly.
@@ -1049,7 +1142,7 @@ def comparison_type(logical_line):
Okay: if type(a1) is type(b1):
"""
match = COMPARE_TYPE_REGEX.search(logical_line)
- if match:
+ if match and not noqa:
inst = match.group(1)
if inst and isidentifier(inst) and inst not in SINGLETONS:
return # Allow comparison for types which are not obvious
@@ -1094,7 +1187,7 @@ def python_3000_not_equal(logical_line):
def python_3000_backticks(logical_line):
- r"""Backticks are removed in Python 3: use repr() instead.
+ r"""Use repr() instead of backticks in Python 3.
Okay: val = repr(1 + 2)
W604: val = `1 + 2`
@@ -1109,7 +1202,7 @@ def python_3000_backticks(logical_line):
##############################################################################
-if '' == ''.encode():
+if sys.version_info < (3,):
# Python 2: implicit encoding.
def readlines(filename):
"""Read the source code."""
@@ -1133,7 +1226,9 @@ else:
isidentifier = str.isidentifier
def stdin_get_value():
+ """Read the value from stdin."""
return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
+
noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
@@ -1245,15 +1340,15 @@ def update_counts(s, counts):
counts[char] += 1
-if COMMENT_WITH_NL:
- def _is_eol_token(token):
- return (token[0] in NEWLINE or
- (token[0] == tokenize.COMMENT and token[1] == token[4]))
-else:
- def _is_eol_token(token):
- return token[0] in NEWLINE
+def _is_eol_token(token):
+ return token[0] in NEWLINE or token[4][token[3][1]:].lstrip() == '\\\n'
+if COMMENT_WITH_NL:
+ def _is_eol_token(token, _eol_token=_is_eol_token):
+ return _eol_token(token) or (token[0] == tokenize.COMMENT and
+ token[1] == token[4])
+
##############################################################################
# Framework to run all checks
##############################################################################
@@ -1262,6 +1357,16 @@ else:
_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
+def _get_parameters(function):
+ if sys.version_info >= (3, 3):
+ return [parameter.name
+ for parameter
+ in inspect.signature(function).parameters.values()
+ if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
+ else:
+ return inspect.getargspec(function)[0]
+
+
def register_check(check, codes=None):
"""Register a new check object."""
def _add_check(check, kind, codes, args):
@@ -1270,13 +1375,13 @@ def register_check(check, codes=None):
else:
_checks[kind][check] = (codes or [''], args)
if inspect.isfunction(check):
- args = inspect.getargspec(check)[0]
+ args = _get_parameters(check)
if args and args[0] in ('physical_line', 'logical_line'):
if codes is None:
codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
_add_check(check, args[0], codes, args)
elif inspect.isclass(check):
- if inspect.getargspec(check.__init__)[0][:2] == ['self', 'tree']:
+ if _get_parameters(check.__init__)[:2] == ['self', 'tree']:
_add_check(check, 'tree', codes, None)
@@ -1367,7 +1472,7 @@ class Checker(object):
return check(*arguments)
def init_checker_state(self, name, argument_names):
- """ Prepares a custom state for the specific checker plugin."""
+ """Prepare custom state for the specific checker plugin."""
if 'checker_state' in argument_names:
self.checker_state = self._checker_states.setdefault(name, {})
@@ -1403,8 +1508,8 @@ class Checker(object):
(start_row, start_col) = start
if prev_row != start_row: # different row
prev_text = self.lines[prev_row - 1][prev_col - 1]
- if prev_text == ',' or (prev_text not in '{[('
- and text not in '}])'):
+ if prev_text == ',' or (prev_text not in '{[(' and
+ text not in '}])'):
text = ' ' + text
elif prev_col != start_col: # different column
text = line[prev_col:start_col] + text
@@ -1452,7 +1557,7 @@ class Checker(object):
"""Build the file's AST and run all AST checks."""
try:
tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
- except (SyntaxError, TypeError):
+ except (ValueError, SyntaxError, TypeError):
return self.report_invalid_syntax()
for name, cls, __ in self._ast_checks:
checker = cls(tree, self.filename)
@@ -1649,6 +1754,7 @@ class BaseReport(object):
class FileReport(BaseReport):
"""Collect the results of the checks and print only the filenames."""
+
print_filename = True
@@ -1696,6 +1802,14 @@ class StandardReport(BaseReport):
print(re.sub(r'\S', ' ', line[:offset]) + '^')
if self._show_pep8 and doc:
print(' ' + doc.strip())
+
+ # stdout is block buffered when not stdout.isatty().
+ # line can be broken where buffer boundary since other processes
+ # write to same file.
+ # flush() after print() to avoid buffer boundary.
+ # Typical buffer size is 8192. line written safely when
+ # len(line) < 8192.
+ sys.stdout.flush()
return self.file_errors
@@ -1719,7 +1833,7 @@ class StyleGuide(object):
# build options from the command line
self.checker_class = kwargs.pop('checker_class', Checker)
parse_argv = kwargs.pop('parse_argv', False)
- config_file = kwargs.pop('config_file', None)
+ config_file = kwargs.pop('config_file', False)
parser = kwargs.pop('parser', None)
# build options from dict
options_dict = dict(*args, **kwargs)
@@ -1848,6 +1962,7 @@ class StyleGuide(object):
def get_parser(prog='pep8', version=__version__):
+ """Create the parser for the program."""
parser = OptionParser(prog=prog, version=version,
usage="%prog [options] input ...")
parser.config_options = [
@@ -1872,7 +1987,8 @@ def get_parser(prog='pep8', version=__version__):
parser.add_option('--select', metavar='errors', default='',
help="select errors and warnings (e.g. E,W6)")
parser.add_option('--ignore', metavar='errors', default='',
- help="skip errors and warnings (e.g. E4,W)")
+ help="skip errors and warnings (e.g. E4,W) "
+ "(default: %s)" % DEFAULT_IGNORE)
parser.add_option('--show-source', action='store_true',
help="show source code for each error")
parser.add_option('--show-pep8', action='store_true',
@@ -1894,8 +2010,8 @@ def get_parser(prog='pep8', version=__version__):
parser.add_option('--format', metavar='format', default='default',
help="set the error format [default|pylint|<custom>]")
parser.add_option('--diff', action='store_true',
- help="report only lines changed according to the "
- "unified diff received on STDIN")
+ help="report changes only within line number ranges in "
+ "the unified diff received on STDIN")
group = parser.add_option_group("Testing Options")
if os.path.exists(TESTSUITE_PATH):
group.add_option('--testsuite', metavar='dir',
@@ -1908,25 +2024,40 @@ def get_parser(prog='pep8', version=__version__):
def read_config(options, args, arglist, parser):
- """Read both user configuration and local configuration."""
+ """Read and parse configurations.
+
+ If a config file is specified on the command line with the "--config"
+ option, then only it is used for configuration.
+
+ Otherwise, the user configuration (~/.config/pep8) and any local
+ configurations in the current directory or above will be merged together
+ (in that order) using the read method of ConfigParser.
+ """
config = RawConfigParser()
- user_conf = options.config
- if user_conf and os.path.isfile(user_conf):
- if options.verbose:
- print('user configuration: %s' % user_conf)
- config.read(user_conf)
+ cli_conf = options.config
local_dir = os.curdir
+
+ if USER_CONFIG and os.path.isfile(USER_CONFIG):
+ if options.verbose:
+ print('user configuration: %s' % USER_CONFIG)
+ config.read(USER_CONFIG)
+
parent = tail = args and os.path.abspath(os.path.commonprefix(args))
while tail:
- if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):
+ if config.read(os.path.join(parent, fn) for fn in PROJECT_CONFIG):
local_dir = parent
if options.verbose:
print('local configuration: in %s' % parent)
break
(parent, tail) = os.path.split(parent)
+ if cli_conf and os.path.isfile(cli_conf):
+ if options.verbose:
+ print('cli configuration: %s' % cli_conf)
+ config.read(cli_conf)
+
pep8_section = parser.prog
if config.has_section(pep8_section):
option_list = dict([(o.dest, o.type or o.action)
@@ -1963,19 +2094,21 @@ def read_config(options, args, arglist, parser):
def process_options(arglist=None, parse_argv=False, config_file=None,
parser=None):
- """Process options passed either via arglist or via command line args."""
+ """Process options passed either via arglist or via command line args.
+
+ Passing in the ``config_file`` parameter allows other tools, such as flake8
+ to specify their own options to be processed in pep8.
+ """
if not parser:
parser = get_parser()
if not parser.has_option('--config'):
- if config_file is True:
- config_file = DEFAULT_CONFIG
group = parser.add_option_group("Configuration", description=(
"The project options are read from the [%s] section of the "
"tox.ini file or the setup.cfg file located in any parent folder "
"of the path(s) being processed. Allowed options are: %s." %
(parser.prog, ', '.join(parser.config_options))))
group.add_option('--config', metavar='path', default=config_file,
- help="user config file location (default: %default)")
+ help="user config file location")
# Don't read the command line if the module is used as a library.
if not arglist and not parse_argv:
arglist = []
@@ -1996,10 +2129,10 @@ def process_options(arglist=None, parse_argv=False, config_file=None,
options = read_config(options, args, arglist, parser)
options.reporter = parse_argv and options.quiet == 1 and FileReport
- options.filename = options.filename and options.filename.split(',')
+ options.filename = _parse_multi_options(options.filename)
options.exclude = normalize_paths(options.exclude)
- options.select = options.select and options.select.split(',')
- options.ignore = options.ignore and options.ignore.split(',')
+ options.select = _parse_multi_options(options.select)
+ options.ignore = _parse_multi_options(options.ignore)
if options.diff:
options.reporter = DiffReport
@@ -2010,6 +2143,22 @@ def process_options(arglist=None, parse_argv=False, config_file=None,
return options, args
+def _parse_multi_options(options, split_token=','):
+ r"""Split and strip and discard empties.
+
+ Turns the following:
+
+ A,
+ B,
+
+ into ["A", "B"]
+ """
+ if options:
+ return [o.strip() for o in options.split(split_token) if o.strip()]
+ else:
+ return options
+
+
def _main():
"""Parse options and run checks on Python source."""
import signal
@@ -2020,23 +2169,29 @@ def _main():
except AttributeError:
pass # not supported on Windows
- pep8style = StyleGuide(parse_argv=True, config_file=True)
- options = pep8style.options
+ style_guide = StyleGuide(parse_argv=True)
+ options = style_guide.options
+
if options.doctest or options.testsuite:
from testsuite.support import run_tests
- report = run_tests(pep8style)
+ report = run_tests(style_guide)
else:
- report = pep8style.check_files()
+ report = style_guide.check_files()
+
if options.statistics:
report.print_statistics()
+
if options.benchmark:
report.print_benchmark()
+
if options.testsuite and not options.quiet:
report.print_results()
+
if report.total_errors:
if options.count:
sys.stderr.write(str(report.total_errors) + '\n')
sys.exit(1)
+
if __name__ == '__main__':
_main()
diff --git a/setup.py b/setup.py
index 29182c6..b77770e 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ from setuptools import setup
def get_version():
- with open('pep8.py') as f:
+ with open('pycodestyle.py') as f:
for line in f:
if line.startswith('__version__'):
return eval(line.split('=')[-1])
@@ -19,16 +19,18 @@ def get_long_description():
setup(
- name='pep8',
+ name='pycodestyle',
version=get_version(),
description="Python style guide checker",
long_description=get_long_description(),
- keywords='pep8',
+ keywords='pycodestyle, pep8, PEP 8, PEP-8, PEP8',
author='Johann C. Rocholl',
author_email='johann@rocholl.net',
- url='http://pep8.readthedocs.org/',
+ maintainer='Ian Lee',
+ maintainer_email='IanLee1521@gmail.com',
+ url='https://pycodestyle.readthedocs.io/',
license='Expat license',
- py_modules=['pep8'],
+ py_modules=['pycodestyle'],
namespace_packages=[],
include_package_data=True,
zip_safe=False,
@@ -38,7 +40,7 @@ setup(
],
entry_points={
'console_scripts': [
- 'pep8 = pep8:_main',
+ 'pycodestyle = pycodestyle:_main',
],
},
classifiers=[
diff --git a/testsuite/E12.py b/testsuite/E12.py
index 6ebd44e..a995c95 100644
--- a/testsuite/E12.py
+++ b/testsuite/E12.py
@@ -323,14 +323,14 @@ if line_removed:
rv.update(d=('a', 'b', 'c'),
e=42)
#
-#: E127
+#: E127 W503
rv.update(d=('a' + 'b', 'c'),
e=42, f=42
+ 42)
-#: E127
+#: E127 W503
input1 = {'a': {'calc': 1 + 2}, 'b': 1
+ 42}
-#: E128
+#: E128 W503
rv.update(d=('a' + 'b', 'c'),
e=42, f=(42
+ 42))
diff --git a/testsuite/E25.py b/testsuite/E25.py
index 9b7ff69..7a536b5 100644
--- a/testsuite/E25.py
+++ b/testsuite/E25.py
@@ -29,3 +29,12 @@ foo(bar=(1 >= 1))
foo(bar=(1 <= 1))
(options, args) = parser.parse_args()
d[type(None)] = _deepcopy_atomic
+
+# Annotated Function Definitions
+#: Okay
+def munge(input: AnyStr, sep: AnyStr = None, limit=1000,
+ extra: Union[str, dict] = None) -> AnyStr:
+ pass
+#: Okay
+async def add(a: int = 0, b: int = 0) -> int:
+ return a + b
diff --git a/testsuite/E27.py b/testsuite/E27.py
index f9d3e8e..888b3a8 100644
--- a/testsuite/E27.py
+++ b/testsuite/E27.py
@@ -28,3 +28,17 @@ a and b
a and b
#: E273 E274
this and False
+#: Okay
+from u import (a, b)
+from v import c, d
+#: E271
+from w import (e, f)
+#: E275
+from w import(e, f)
+#: E275
+from importable.module import(e, f)
+#: E275
+try:
+ from importable.module import(e, f)
+except ImportError:
+ pass
diff --git a/testsuite/E40.py b/testsuite/E40.py
index d921c25..1051e32 100644
--- a/testsuite/E40.py
+++ b/testsuite/E40.py
@@ -11,3 +11,28 @@ from foo.bar.yourclass import YourClass
import myclass
import foo.bar.yourclass
+#: E402
+__all__ = ['abc']
+
+import foo
+#: Okay
+try:
+ import foo
+except:
+ pass
+else:
+ print('imported foo')
+finally:
+ print('made attempt to import foo')
+
+import bar
+#: E402
+VERSION = '1.2.3'
+
+import foo
+#: E402
+import foo
+
+a = 1
+
+import bar
diff --git a/testsuite/E50.py b/testsuite/E50.py
index 31ad6b9..f60f389 100644
--- a/testsuite/E50.py
+++ b/testsuite/E50.py
@@ -1,5 +1,19 @@
#: E501
a = '12345678901234567890123456789012345678901234567890123456789012345678901234567890'
+#: E501
+a = '1234567890123456789012345678901234567890123456789012345678901234567890' or \
+ 6
+#: E501
+a = 7 or \
+ '1234567890123456789012345678901234567890123456789012345678901234567890' or \
+ 6
+#: E501 E501
+a = 7 or \
+ '1234567890123456789012345678901234567890123456789012345678901234567890' or \
+ '1234567890123456789012345678901234567890123456789012345678901234567890' or \
+ 6
+#: E501
+a = '1234567890123456789012345678901234567890123456789012345678901234567890' # \
#: E502
a = ('123456789012345678901234567890123456789012345678901234567890123456789' \
'01234567890')
diff --git a/testsuite/E71.py b/testsuite/E71.py
index ea870e5..7464da9 100644
--- a/testsuite/E71.py
+++ b/testsuite/E71.py
@@ -10,6 +10,18 @@ if None == res:
#: E711
if None != res:
pass
+#: E711
+if res[1] == None:
+ pass
+#: E711
+if res[1] != None:
+ pass
+#: E711
+if None != res[1]:
+ pass
+#: E711
+if None == res[1]:
+ pass
#
#: E712
@@ -24,6 +36,12 @@ if True != res:
#: E712
if False == res:
pass
+#: E712
+if res[1] == True:
+ pass
+#: E712
+if res[1] != False:
+ pass
#
#: E713
diff --git a/testsuite/W19.py b/testsuite/W19.py
index edbb1f0..afdfb76 100644
--- a/testsuite/W19.py
+++ b/testsuite/W19.py
@@ -86,7 +86,7 @@ if (a == 2 or
b == """abc def ghi
jkl mno"""):
return True
-#: E101 W191
+#: W191:2:1 W191:3:1 E101:3:2
if length > options.max_line_length:
return options.max_line_length, \
"E501 line too long (%d characters)" % length
diff --git a/testsuite/support.py b/testsuite/support.py
index 5185005..003f181 100644
--- a/testsuite/support.py
+++ b/testsuite/support.py
@@ -3,7 +3,7 @@ import os.path
import re
import sys
-from pep8 import Checker, BaseReport, StandardReport, readlines
+from pycodestyle import Checker, BaseReport, StandardReport, readlines
SELFTEST_REGEX = re.compile(r'\b(Okay|[EW]\d{3}):\s(.*)')
ROOT_DIR = os.path.dirname(os.path.dirname(__file__))
@@ -16,6 +16,9 @@ class PseudoFile(list):
def getvalue(self):
return ''.join(self)
+ def flush(self):
+ pass
+
class TestReport(StandardReport):
"""Collect the results for the tests."""
@@ -116,7 +119,7 @@ def selftest(options):
print("%s: %s" % (code, source))
else:
count_failed += 1
- print("pep8.py: %s:" % error)
+ print("pycodestyle.py: %s:" % error)
for line in checker.lines:
print(line.rstrip())
return count_failed, count_all
diff --git a/testsuite/test_all.py b/testsuite/test_all.py
index 50e2cb9..bd18943 100644
--- a/testsuite/test_all.py
+++ b/testsuite/test_all.py
@@ -4,24 +4,26 @@ import os.path
import sys
import unittest
-import pep8
+import pycodestyle
from testsuite.support import init_tests, selftest, ROOT_DIR
# Note: please only use a subset of unittest methods which were present
# in Python 2.5: assert(True|False|Equal|NotEqual|Raises)
-class Pep8TestCase(unittest.TestCase):
+class PycodestyleTestCase(unittest.TestCase):
"""Test the standard errors and warnings (E and W)."""
def setUp(self):
- self._style = pep8.StyleGuide(
+ self._style = pycodestyle.StyleGuide(
paths=[os.path.join(ROOT_DIR, 'testsuite')],
select='E,W', quiet=True)
def test_doctest(self):
import doctest
- fail_d, done_d = doctest.testmod(pep8, verbose=False, report=False)
+ fail_d, done_d = doctest.testmod(
+ pycodestyle, verbose=False, report=False
+ )
self.assertTrue(done_d, msg='tests not found')
self.assertFalse(fail_d, msg='%s failure(s)' % fail_d)
@@ -37,20 +39,21 @@ class Pep8TestCase(unittest.TestCase):
msg='%s failure(s)' % report.total_errors)
def test_own_dog_food(self):
- files = [pep8.__file__.rstrip('oc'), __file__.rstrip('oc'),
+ files = [pycodestyle.__file__.rstrip('oc'), __file__.rstrip('oc'),
os.path.join(ROOT_DIR, 'setup.py')]
- report = self._style.init_report(pep8.StandardReport)
+ report = self._style.init_report(pycodestyle.StandardReport)
report = self._style.check_files(files)
self.assertFalse(report.total_errors,
msg='Failures: %s' % report.messages)
def suite():
- from testsuite import test_api, test_shell, test_util
+ from testsuite import test_api, test_parser, test_shell, test_util
suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(Pep8TestCase))
+ suite.addTest(unittest.makeSuite(PycodestyleTestCase))
suite.addTest(unittest.makeSuite(test_api.APITestCase))
+ suite.addTest(unittest.makeSuite(test_parser.ParserTestCase))
suite.addTest(unittest.makeSuite(test_shell.ShellTestCase))
suite.addTest(unittest.makeSuite(test_util.UtilTestCase))
return suite
diff --git a/testsuite/test_api.py b/testsuite/test_api.py
index de7bc7b..6549a46 100644
--- a/testsuite/test_api.py
+++ b/testsuite/test_api.py
@@ -4,7 +4,7 @@ import shlex
import sys
import unittest
-import pep8
+import pycodestyle
from testsuite.support import ROOT_DIR, PseudoFile
E11 = os.path.join(ROOT_DIR, 'testsuite', 'E11.py')
@@ -25,17 +25,18 @@ class APITestCase(unittest.TestCase):
def setUp(self):
self._saved_stdout = sys.stdout
self._saved_stderr = sys.stderr
- self._saved_checks = pep8._checks
+ self._saved_checks = pycodestyle._checks
sys.stdout = PseudoFile()
sys.stderr = PseudoFile()
- pep8._checks = dict((k, dict((f, (vals[0][:], vals[1]))
- for (f, vals) in v.items()))
- for (k, v) in self._saved_checks.items())
+ pycodestyle._checks = dict(
+ (k, dict((f, (vals[0][:], vals[1])) for (f, vals) in v.items()))
+ for (k, v) in self._saved_checks.items()
+ )
def tearDown(self):
sys.stdout = self._saved_stdout
sys.stderr = self._saved_stderr
- pep8._checks = self._saved_checks
+ pycodestyle._checks = self._saved_checks
def reset(self):
del sys.stdout[:], sys.stderr[:]
@@ -44,14 +45,14 @@ class APITestCase(unittest.TestCase):
def check_dummy(physical_line, line_number):
if False:
yield
- pep8.register_check(check_dummy, ['Z001'])
+ pycodestyle.register_check(check_dummy, ['Z001'])
- self.assertTrue(check_dummy in pep8._checks['physical_line'])
- codes, args = pep8._checks['physical_line'][check_dummy]
+ self.assertTrue(check_dummy in pycodestyle._checks['physical_line'])
+ codes, args = pycodestyle._checks['physical_line'][check_dummy]
self.assertTrue('Z001' in codes)
self.assertEqual(args, ['physical_line', 'line_number'])
- options = pep8.StyleGuide().options
+ options = pycodestyle.StyleGuide().options
self.assertTrue(any(func == check_dummy
for name, func, args in options.physical_checks))
@@ -59,32 +60,32 @@ class APITestCase(unittest.TestCase):
def check_dummy(logical_line, tokens):
if False:
yield
- pep8.register_check(check_dummy, ['Z401'])
+ pycodestyle.register_check(check_dummy, ['Z401'])
- self.assertTrue(check_dummy in pep8._checks['logical_line'])
- codes, args = pep8._checks['logical_line'][check_dummy]
+ self.assertTrue(check_dummy in pycodestyle._checks['logical_line'])
+ codes, args = pycodestyle._checks['logical_line'][check_dummy]
self.assertTrue('Z401' in codes)
self.assertEqual(args, ['logical_line', 'tokens'])
- pep8.register_check(check_dummy, [])
- pep8.register_check(check_dummy, ['Z402', 'Z403'])
- codes, args = pep8._checks['logical_line'][check_dummy]
+ pycodestyle.register_check(check_dummy, [])
+ pycodestyle.register_check(check_dummy, ['Z402', 'Z403'])
+ codes, args = pycodestyle._checks['logical_line'][check_dummy]
self.assertEqual(codes, ['Z401', 'Z402', 'Z403'])
self.assertEqual(args, ['logical_line', 'tokens'])
- options = pep8.StyleGuide().options
+ options = pycodestyle.StyleGuide().options
self.assertTrue(any(func == check_dummy
for name, func, args in options.logical_checks))
def test_register_ast_check(self):
- pep8.register_check(DummyChecker, ['Z701'])
+ pycodestyle.register_check(DummyChecker, ['Z701'])
- self.assertTrue(DummyChecker in pep8._checks['tree'])
- codes, args = pep8._checks['tree'][DummyChecker]
+ self.assertTrue(DummyChecker in pycodestyle._checks['tree'])
+ codes, args = pycodestyle._checks['tree'][DummyChecker]
self.assertTrue('Z701' in codes)
self.assertTrue(args is None)
- options = pep8.StyleGuide().options
+ options = pycodestyle.StyleGuide().options
self.assertTrue(any(cls == DummyChecker
for name, cls, args in options.ast_checks))
@@ -96,23 +97,23 @@ class APITestCase(unittest.TestCase):
def check_dummy(logical, tokens):
if False:
yield
- pep8.register_check(InvalidChecker, ['Z741'])
- pep8.register_check(check_dummy, ['Z441'])
+ pycodestyle.register_check(InvalidChecker, ['Z741'])
+ pycodestyle.register_check(check_dummy, ['Z441'])
- for checkers in pep8._checks.values():
+ for checkers in pycodestyle._checks.values():
self.assertTrue(DummyChecker not in checkers)
self.assertTrue(check_dummy not in checkers)
- self.assertRaises(TypeError, pep8.register_check)
+ self.assertRaises(TypeError, pycodestyle.register_check)
def test_styleguide(self):
- report = pep8.StyleGuide().check_files()
+ report = pycodestyle.StyleGuide().check_files()
self.assertEqual(report.total_errors, 0)
self.assertFalse(sys.stdout)
self.assertFalse(sys.stderr)
self.reset()
- report = pep8.StyleGuide().check_files(['missing-file'])
+ report = pycodestyle.StyleGuide().check_files(['missing-file'])
stdout = sys.stdout.getvalue().splitlines()
self.assertEqual(len(stdout), report.total_errors)
self.assertEqual(report.total_errors, 1)
@@ -121,7 +122,7 @@ class APITestCase(unittest.TestCase):
self.assertFalse(sys.stderr)
self.reset()
- report = pep8.StyleGuide().check_files([E11])
+ report = pycodestyle.StyleGuide().check_files([E11])
stdout = sys.stdout.getvalue().splitlines()
self.assertEqual(len(stdout), report.total_errors)
self.assertEqual(report.total_errors, 17)
@@ -129,7 +130,7 @@ class APITestCase(unittest.TestCase):
self.reset()
# Passing the paths in the constructor gives same result
- report = pep8.StyleGuide(paths=[E11]).check_files()
+ report = pycodestyle.StyleGuide(paths=[E11]).check_files()
stdout = sys.stdout.getvalue().splitlines()
self.assertEqual(len(stdout), report.total_errors)
self.assertEqual(report.total_errors, 17)
@@ -138,10 +139,10 @@ class APITestCase(unittest.TestCase):
def test_styleguide_options(self):
# Instanciate a simple checker
- pep8style = pep8.StyleGuide(paths=[E11])
+ pep8style = pycodestyle.StyleGuide(paths=[E11])
# Check style's attributes
- self.assertEqual(pep8style.checker_class, pep8.Checker)
+ self.assertEqual(pep8style.checker_class, pycodestyle.Checker)
self.assertEqual(pep8style.paths, [E11])
self.assertEqual(pep8style.runner, pep8style.input_file)
self.assertEqual(pep8style.options.ignore_code, pep8style.ignore_code)
@@ -173,13 +174,16 @@ class APITestCase(unittest.TestCase):
_saved_argv = sys.argv
sys.argv = shlex.split('pep8 %s /dev/null' % argstring)
try:
- return pep8.StyleGuide(parse_argv=True)
+ return pycodestyle.StyleGuide(parse_argv=True)
finally:
sys.argv = _saved_argv
options = parse_argv('').options
self.assertEqual(options.select, ())
- self.assertEqual(options.ignore, ('E123', 'E226', 'E24', 'E704'))
+ self.assertEqual(
+ options.ignore,
+ ('E121', 'E123', 'E126', 'E226', 'E24', 'E704', 'W503')
+ )
options = parse_argv('--doctest').options
self.assertEqual(options.select, ())
@@ -205,22 +209,22 @@ class APITestCase(unittest.TestCase):
self.assertEqual(options.select, ('E24',))
self.assertEqual(options.ignore, ('',))
- pep8style = pep8.StyleGuide(paths=[E11])
+ pep8style = pycodestyle.StyleGuide(paths=[E11])
self.assertFalse(pep8style.ignore_code('E112'))
self.assertFalse(pep8style.ignore_code('W191'))
self.assertTrue(pep8style.ignore_code('E241'))
- pep8style = pep8.StyleGuide(select='E', paths=[E11])
+ pep8style = pycodestyle.StyleGuide(select='E', paths=[E11])
self.assertFalse(pep8style.ignore_code('E112'))
self.assertTrue(pep8style.ignore_code('W191'))
self.assertFalse(pep8style.ignore_code('E241'))
- pep8style = pep8.StyleGuide(select='W', paths=[E11])
+ pep8style = pycodestyle.StyleGuide(select='W', paths=[E11])
self.assertTrue(pep8style.ignore_code('E112'))
self.assertFalse(pep8style.ignore_code('W191'))
self.assertTrue(pep8style.ignore_code('E241'))
- pep8style = pep8.StyleGuide(select=('F401',), paths=[E11])
+ pep8style = pycodestyle.StyleGuide(select=('F401',), paths=[E11])
self.assertEqual(pep8style.options.select, ('F401',))
self.assertEqual(pep8style.options.ignore, ('',))
self.assertFalse(pep8style.ignore_code('F'))
@@ -228,7 +232,7 @@ class APITestCase(unittest.TestCase):
self.assertTrue(pep8style.ignore_code('F402'))
def test_styleguide_excluded(self):
- pep8style = pep8.StyleGuide(paths=[E11])
+ pep8style = pycodestyle.StyleGuide(paths=[E11])
self.assertFalse(pep8style.excluded('./foo/bar'))
self.assertFalse(pep8style.excluded('./foo/bar/main.py'))
@@ -245,7 +249,7 @@ class APITestCase(unittest.TestCase):
self.assertFalse(pep8style.excluded('./CVS/subdir'))
def test_styleguide_checks(self):
- pep8style = pep8.StyleGuide(paths=[E11])
+ pep8style = pycodestyle.StyleGuide(paths=[E11])
# Default lists of checkers
self.assertTrue(len(pep8style.options.physical_checks) > 4)
@@ -261,49 +265,51 @@ class APITestCase(unittest.TestCase):
self.assertEqual(args[0], 'logical_line')
# Do run E11 checks
- options = pep8.StyleGuide().options
- self.assertTrue(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide().options
+ self.assertTrue(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
- options = pep8.StyleGuide(select=['E']).options
- self.assertTrue(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide(select=['E']).options
+ self.assertTrue(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
- options = pep8.StyleGuide(ignore=['W']).options
- self.assertTrue(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide(ignore=['W']).options
+ self.assertTrue(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
- options = pep8.StyleGuide(ignore=['E12']).options
- self.assertTrue(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide(ignore=['E12']).options
+ self.assertTrue(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
# Do not run E11 checks
- options = pep8.StyleGuide(select=['W']).options
- self.assertFalse(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide(select=['W']).options
+ self.assertFalse(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
- options = pep8.StyleGuide(ignore=['E']).options
- self.assertFalse(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide(ignore=['E']).options
+ self.assertFalse(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
- options = pep8.StyleGuide(ignore=['E11']).options
- self.assertFalse(any(func == pep8.indentation
+ options = pycodestyle.StyleGuide(ignore=['E11']).options
+ self.assertFalse(any(func == pycodestyle.indentation
for name, func, args in options.logical_checks))
def test_styleguide_init_report(self):
- pep8style = pep8.StyleGuide(paths=[E11])
+ style = pycodestyle.StyleGuide(paths=[E11])
+
+ standard_report = pycodestyle.StandardReport
- self.assertEqual(pep8style.options.reporter, pep8.StandardReport)
- self.assertEqual(type(pep8style.options.report), pep8.StandardReport)
+ self.assertEqual(style.options.reporter, standard_report)
+ self.assertEqual(type(style.options.report), standard_report)
- class MinorityReport(pep8.BaseReport):
+ class MinorityReport(pycodestyle.BaseReport):
pass
- report = pep8style.init_report(MinorityReport)
- self.assertEqual(pep8style.options.report, report)
+ report = style.init_report(MinorityReport)
+ self.assertEqual(style.options.report, report)
self.assertEqual(type(report), MinorityReport)
- pep8style = pep8.StyleGuide(paths=[E11], reporter=MinorityReport)
- self.assertEqual(type(pep8style.options.report), MinorityReport)
- self.assertEqual(pep8style.options.reporter, MinorityReport)
+ style = pycodestyle.StyleGuide(paths=[E11], reporter=MinorityReport)
+ self.assertEqual(type(style.options.report), MinorityReport)
+ self.assertEqual(style.options.reporter, MinorityReport)
def test_styleguide_check_files(self):
- pep8style = pep8.StyleGuide(paths=[E11])
+ pep8style = pycodestyle.StyleGuide(paths=[E11])
report = pep8style.check_files()
self.assertTrue(report.total_errors)
@@ -314,12 +320,12 @@ class APITestCase(unittest.TestCase):
def test_check_unicode(self):
# Do not crash if lines are Unicode (Python 2.x)
- pep8.register_check(DummyChecker, ['Z701'])
+ pycodestyle.register_check(DummyChecker, ['Z701'])
source = '#\n'
if hasattr(source, 'decode'):
source = source.decode('ascii')
- pep8style = pep8.StyleGuide()
+ pep8style = pycodestyle.StyleGuide()
count_errors = pep8style.input_file('stdin', lines=[source])
self.assertFalse(sys.stdout)
@@ -327,15 +333,18 @@ class APITestCase(unittest.TestCase):
self.assertEqual(count_errors, 0)
def test_check_nullbytes(self):
- pep8.register_check(DummyChecker, ['Z701'])
+ pycodestyle.register_check(DummyChecker, ['Z701'])
- pep8style = pep8.StyleGuide()
+ pep8style = pycodestyle.StyleGuide()
count_errors = pep8style.input_file('stdin', lines=['\x00\n'])
stdout = sys.stdout.getvalue()
if 'SyntaxError' in stdout:
# PyPy 2.2 returns a SyntaxError
expected = "stdin:1:2: E901 SyntaxError"
+ elif 'ValueError' in stdout:
+ # Python 3.5.
+ expected = "stdin:1:1: E901 ValueError"
else:
expected = "stdin:1:1: E901 TypeError"
self.assertTrue(stdout.startswith(expected),
@@ -345,13 +354,13 @@ class APITestCase(unittest.TestCase):
self.assertEqual(count_errors, 1)
def test_styleguide_unmatched_triple_quotes(self):
- pep8.register_check(DummyChecker, ['Z701'])
+ pycodestyle.register_check(DummyChecker, ['Z701'])
lines = [
'def foo():\n',
' """test docstring""\'\n',
]
- pep8style = pep8.StyleGuide()
+ pep8style = pycodestyle.StyleGuide()
pep8style.input_file('stdin', lines=lines)
stdout = sys.stdout.getvalue()
@@ -359,7 +368,7 @@ class APITestCase(unittest.TestCase):
self.assertTrue(expected in stdout)
def test_styleguide_continuation_line_outdented(self):
- pep8.register_check(DummyChecker, ['Z701'])
+ pycodestyle.register_check(DummyChecker, ['Z701'])
lines = [
'def foo():\n',
' pass\n',
@@ -370,7 +379,7 @@ class APITestCase(unittest.TestCase):
' pass\n',
]
- pep8style = pep8.StyleGuide()
+ pep8style = pycodestyle.StyleGuide()
count_errors = pep8style.input_file('stdin', lines=lines)
self.assertEqual(count_errors, 2)
stdout = sys.stdout.getvalue()
diff --git a/testsuite/test_parser.py b/testsuite/test_parser.py
new file mode 100644
index 0000000..26a45fc
--- /dev/null
+++ b/testsuite/test_parser.py
@@ -0,0 +1,61 @@
+import os
+import tempfile
+import unittest
+
+import pycodestyle
+
+
+def _process_file(contents):
+ with tempfile.NamedTemporaryFile(delete=False) as f:
+ f.write(contents)
+
+ options, args = pycodestyle.process_options(config_file=f.name)
+ os.remove(f.name)
+
+ return options, args
+
+
+class ParserTestCase(unittest.TestCase):
+
+ def test_vanilla_ignore_parsing(self):
+ contents = b"""
+[pep8]
+ignore = E226,E24
+ """
+ options, args = _process_file(contents)
+
+ self.assertEqual(options.ignore, ["E226", "E24"])
+
+ def test_multiline_ignore_parsing(self):
+ contents = b"""
+[pep8]
+ignore =
+ E226,
+ E24
+ """
+
+ options, args = _process_file(contents)
+
+ self.assertEqual(options.ignore, ["E226", "E24"])
+
+ def test_trailing_comma_ignore_parsing(self):
+ contents = b"""
+[pep8]
+ignore = E226,
+ """
+
+ options, args = _process_file(contents)
+
+ self.assertEqual(options.ignore, ["E226"])
+
+ def test_multiline_trailing_comma_ignore_parsing(self):
+ contents = b"""
+[pep8]
+ignore =
+ E226,
+ E24,
+ """
+
+ options, args = _process_file(contents)
+
+ self.assertEqual(options.ignore, ["E226", "E24"])
diff --git a/testsuite/test_shell.py b/testsuite/test_shell.py
index e536852..760c228 100644
--- a/testsuite/test_shell.py
+++ b/testsuite/test_shell.py
@@ -3,7 +3,7 @@ import os.path
import sys
import unittest
-import pep8
+import pycodestyle
from testsuite.support import ROOT_DIR, PseudoFile
@@ -14,9 +14,9 @@ class ShellTestCase(unittest.TestCase):
self._saved_argv = sys.argv
self._saved_stdout = sys.stdout
self._saved_stderr = sys.stderr
- self._saved_pconfig = pep8.PROJECT_CONFIG
- self._saved_cpread = pep8.RawConfigParser._read
- self._saved_stdin_get_value = pep8.stdin_get_value
+ self._saved_pconfig = pycodestyle.PROJECT_CONFIG
+ self._saved_cpread = pycodestyle.RawConfigParser._read
+ self._saved_stdin_get_value = pycodestyle.stdin_get_value
self._config_filenames = []
self.stdin = ''
sys.argv = ['pep8']
@@ -25,16 +25,16 @@ class ShellTestCase(unittest.TestCase):
def fake_config_parser_read(cp, fp, filename):
self._config_filenames.append(filename)
- pep8.RawConfigParser._read = fake_config_parser_read
- pep8.stdin_get_value = self.stdin_get_value
+ pycodestyle.RawConfigParser._read = fake_config_parser_read
+ pycodestyle.stdin_get_value = self.stdin_get_value
def tearDown(self):
sys.argv = self._saved_argv
sys.stdout = self._saved_stdout
sys.stderr = self._saved_stderr
- pep8.PROJECT_CONFIG = self._saved_pconfig
- pep8.RawConfigParser._read = self._saved_cpread
- pep8.stdin_get_value = self._saved_stdin_get_value
+ pycodestyle.PROJECT_CONFIG = self._saved_pconfig
+ pycodestyle.RawConfigParser._read = self._saved_cpread
+ pycodestyle.stdin_get_value = self._saved_stdin_get_value
def stdin_get_value(self):
return self.stdin
@@ -43,7 +43,7 @@ class ShellTestCase(unittest.TestCase):
del sys.stdout[:], sys.stderr[:]
sys.argv[1:] = args
try:
- pep8._main()
+ pycodestyle._main()
errorcode = None
except SystemExit:
errorcode = sys.exc_info()[1].code
@@ -88,7 +88,7 @@ class ShellTestCase(unittest.TestCase):
self.assertTrue('setup.cfg' in config_filenames)
def test_check_stdin(self):
- pep8.PROJECT_CONFIG = ()
+ pycodestyle.PROJECT_CONFIG = ()
stdout, stderr, errcode = self.pep8('-')
self.assertFalse(errcode)
self.assertFalse(stderr)
@@ -111,7 +111,7 @@ class ShellTestCase(unittest.TestCase):
def test_check_noarg(self):
# issue #170: do not read stdin by default
- pep8.PROJECT_CONFIG = ()
+ pycodestyle.PROJECT_CONFIG = ()
stdout, stderr, errcode = self.pep8()
self.assertEqual(errcode, 2)
self.assertEqual(stderr.splitlines(),
@@ -120,7 +120,7 @@ class ShellTestCase(unittest.TestCase):
self.assertFalse(self._config_filenames)
def test_check_diff(self):
- pep8.PROJECT_CONFIG = ()
+ pycodestyle.PROJECT_CONFIG = ()
diff_lines = [
"--- testsuite/E11.py 2006-06-01 08:49:50 +0500",
"+++ testsuite/E11.py 2008-04-06 17:36:29 +0500",
diff --git a/testsuite/test_util.py b/testsuite/test_util.py
index 11395cc..8eaba7e 100644
--- a/testsuite/test_util.py
+++ b/testsuite/test_util.py
@@ -3,21 +3,21 @@
import os
import unittest
-import pep8
+from pycodestyle import normalize_paths
class UtilTestCase(unittest.TestCase):
def test_normalize_paths(self):
cwd = os.getcwd()
- self.assertEqual(pep8.normalize_paths(''), [])
- self.assertEqual(pep8.normalize_paths([]), [])
- self.assertEqual(pep8.normalize_paths(None), [])
- self.assertEqual(pep8.normalize_paths(['foo']), ['foo'])
- self.assertEqual(pep8.normalize_paths('foo'), ['foo'])
- self.assertEqual(pep8.normalize_paths('foo,bar'), ['foo', 'bar'])
- self.assertEqual(pep8.normalize_paths('foo, bar '), ['foo', 'bar'])
- self.assertEqual(pep8.normalize_paths('/foo/bar,baz/../bat'),
+ self.assertEqual(normalize_paths(''), [])
+ self.assertEqual(normalize_paths([]), [])
+ self.assertEqual(normalize_paths(None), [])
+ self.assertEqual(normalize_paths(['foo']), ['foo'])
+ self.assertEqual(normalize_paths('foo'), ['foo'])
+ self.assertEqual(normalize_paths('foo,bar'), ['foo', 'bar'])
+ self.assertEqual(normalize_paths('foo, bar '), ['foo', 'bar'])
+ self.assertEqual(normalize_paths('/foo/bar,baz/../bat'),
['/foo/bar', cwd + '/bat'])
- self.assertEqual(pep8.normalize_paths(".pyc,\n build/*"),
+ self.assertEqual(normalize_paths(".pyc,\n build/*"),
['.pyc', cwd + '/build/*'])
diff --git a/tox.ini b/tox.ini
index 50a0d00..a4992e9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,15 +1,15 @@
-# Tox (http://codespeak.net/~hpk/tox/) is a tool for running tests
+# Tox (https://testrun.org/tox/latest/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
[tox]
-envlist = py26, py27, py32, py33, py34, pypy, jython
+envlist = py26, py27, py32, py33, py34, py35, pypy, pypy3, jython
[testenv]
commands =
{envpython} setup.py install
- {envpython} pep8.py --testsuite testsuite
- {envpython} pep8.py --statistics pep8.py
- {envpython} pep8.py --doctest
+ {envpython} pycodestyle.py --testsuite testsuite
+ {envpython} pycodestyle.py --statistics pycodestyle.py
+ {envpython} pycodestyle.py --doctest
{envpython} -m testsuite.test_all