├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── CHANGES.txt ├── CONTRIBUTING.rst ├── LICENSE ├── Makefile ├── README.rst ├── dev-requirements.txt ├── docs ├── Makefile ├── advanced.rst ├── api.rst ├── conf.py ├── developer.rst ├── index.rst ├── intro.rst └── make.bat ├── pycodestyle.py ├── setup.cfg ├── setup.py ├── testing ├── __init__.py ├── data │ ├── E10.py │ ├── E11.py │ ├── E12.py │ ├── E12not.py │ ├── E20.py │ ├── E21.py │ ├── E22.py │ ├── E23.py │ ├── E24.py │ ├── E25.py │ ├── E26.py │ ├── E27.py │ ├── E30.py │ ├── E30not.py │ ├── E40.py │ ├── E50.py │ ├── E70.py │ ├── E71.py │ ├── E72.py │ ├── E73.py │ ├── E74.py │ ├── E90.py │ ├── W19.py │ ├── W29.py │ ├── W39.py │ ├── W60.py │ ├── crlf.py │ ├── latin-1.py │ ├── noqa.py │ ├── python3.py │ ├── python310.py │ ├── python311.py │ ├── python312.py │ ├── python313.py │ ├── python314.py │ ├── python35.py │ ├── python36.py │ ├── python38.py │ ├── python39.py │ ├── utf-8-bom.py │ └── utf-8.py └── support.py ├── tests ├── __init__.py ├── test_E101.py ├── test_E901.py ├── test_all.py ├── test_api.py ├── test_blank_lines.py ├── test_data.py ├── test_parser.py ├── test_pycodestyle.py ├── test_self_doctests.py ├── test_shell.py └── test_util.py └── tox.ini /.gitattributes: -------------------------------------------------------------------------------- 1 | testing/data/E90.py -text 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: main 2 | on: 3 | pull_request: 4 | push: 5 | branches: [master, main, 'test-me-*'] 6 | tags: ['*'] 7 | 8 | jobs: 9 | main: 10 | strategy: 11 | matrix: 12 | include: 13 | - os: windows-latest 14 | py: 3.9 15 | toxenv: py 16 | - os: ubuntu-latest 17 | py: pypy3.10 18 | toxenv: py 19 | - os: ubuntu-latest 20 | py: 3.9 21 | toxenv: py 22 | - os: ubuntu-latest 23 | py: '3.10' 24 | toxenv: py 25 | - os: ubuntu-latest 26 | py: '3.11' 27 | toxenv: py 28 | - os: ubuntu-latest 29 | py: '3.12' 30 | toxenv: py 31 | - os: ubuntu-latest 32 | py: '3.13' 33 | toxenv: py 34 | - os: ubuntu-latest 35 | py: '3.14-dev' 36 | toxenv: py 37 | - os: ubuntu-latest 38 | py: 3.9 39 | toxenv: flake8 40 | runs-on: ${{ matrix.os }} 41 | steps: 42 | - uses: actions/checkout@v3 43 | - uses: actions/setup-python@v4 44 | with: 45 | python-version: ${{ matrix.py }} 46 | if: matrix.py != '3.14-dev' 47 | - uses: deadsnakes/action@v3.0.1 48 | with: 49 | python-version: ${{ matrix.py }} 50 | if: matrix.py == '3.14-dev' 51 | - run: pip install tox 52 | - run: tox -e ${{ matrix.toxenv }} 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg 2 | *.egg-info 3 | *.pyc 4 | /.coverage* 5 | /.tox 6 | /build/ 7 | /dist 8 | /venv*/ 9 | docs/_build 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: ^testing/data/ 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v5.0.0 5 | hooks: 6 | - id: check-yaml 7 | - id: debug-statements 8 | - id: end-of-file-fixer 9 | - id: trailing-whitespace 10 | - repo: https://github.com/asottile/reorder-python-imports 11 | rev: v3.15.0 12 | hooks: 13 | - id: reorder-python-imports 14 | args: [--py39-plus] 15 | - repo: https://github.com/asottile/pyupgrade 16 | rev: v3.20.0 17 | hooks: 18 | - id: pyupgrade 19 | args: [--py39-plus] 20 | - repo: https://github.com/asottile/setup-cfg-fmt 21 | rev: v2.8.0 22 | hooks: 23 | - id: setup-cfg-fmt 24 | - repo: https://github.com/pycqa/flake8 25 | rev: 7.2.0 26 | hooks: 27 | - id: flake8 28 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.11" 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing to pycodestyle 2 | =========================== 3 | 4 | When contributing to pycodestyle, please observe our `Code of Conduct`_. 5 | 6 | Step 1: Forking pycodestyle for editing 7 | --------------------------------------- 8 | 9 | Fork the pycodestyle repository on GitHub. This will add 10 | pycodestyle to your GitHub account. You will push your changes to your 11 | fork and then make pull requests into the official pycodestyle repository. 12 | 13 | GitHub has an excellent `guide`_ that has screenshots on how to do this. 14 | 15 | Next, clone your fork of the pycodestyle repository to your system for 16 | editing:: 17 | 18 | $ git clone https://www.github.com//pycodestyle 19 | 20 | Now you have a copy of the pycodestyle codebase that is almost ready for 21 | edits. Next we will setup `virtualenv`_ which will help create an isolated 22 | environment to manage dependencies. 23 | 24 | 25 | Step 2: Use virtualenv when developing 26 | -------------------------------------- 27 | 28 | `virtualenv`_ is a tool to create isolated python environments. 29 | First, install virtualenv with:: 30 | 31 | $ pip install virtualenv 32 | 33 | Next, ``cd`` to the pycodestyle repository that you cloned earlier and 34 | create, then activate a virtualenv:: 35 | 36 | $ cd pycodestyle 37 | $ virtualenv venv-pycodestyle 38 | $ source venv-pycodestyle/bin/activate 39 | 40 | Note that ``venv*/`` is ignored via ``.gitignore``. 41 | 42 | Now you can install the pycodestyle requirements:: 43 | 44 | $ pip install -r dev-requirements.txt 45 | 46 | To deactivate the virtualenv you can type:: 47 | 48 | $ deactivate 49 | 50 | For more information see `virtualenv`_'s documentation. 51 | 52 | 53 | Step 3: Run tests 54 | ----------------- 55 | 56 | Before creating a pull request you should run the tests to make sure that the 57 | changes that have been made haven't caused any regressions in functionality. 58 | To run the tests, the core developer team and GitHub Actions use `tox`_:: 59 | 60 | $ pip install -r dev-requirements.txt 61 | $ tox 62 | 63 | All the tests should pass for all available interpreters, with the summary of:: 64 | 65 | congratulations :) 66 | 67 | At this point you can create a pull request back to the official pycodestyle 68 | repository for review! For more information on how to make a pull request, 69 | GitHub has an excellent `guide`_. 70 | 71 | The current tests are written in 2 styles: 72 | 73 | * pytest tests 74 | * functional test using a custom framework 75 | 76 | 77 | Running tests 78 | ~~~~~~~~~~~~~ 79 | 80 | The tests are written using ``pytest``, the existing tests 81 | include unit, integration and functional tests. 82 | 83 | To run the tests:: 84 | 85 | $ pytest tests 86 | 87 | Running functional 88 | ~~~~~~~~~~~~~~~~~~ 89 | 90 | $ pip install -e . 91 | $ # Run all tests. 92 | $ pytest tests/test_data.py 93 | $ # Run a subset of the tests. 94 | $ pytest tests/tests_data.py -k testing/data/E30.py 95 | 96 | 97 | .. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/ 98 | .. _guide: https://guides.github.com/activities/forking/ 99 | .. _tox: https://tox.readthedocs.io/en/latest/ 100 | .. _Code of Conduct: http://meta.pycqa.org/en/latest/code-of-conduct.html 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2006-2009 Johann C. Rocholl 2 | Copyright © 2009-2014 Florent Xicluna 3 | Copyright © 2014-2020 Ian Lee 4 | 5 | Licensed under the terms of the Expat License 6 | 7 | Permission is hereby granted, free of charge, to any person 8 | obtaining a copy of this software and associated documentation files 9 | (the "Software"), to deal in the Software without restriction, 10 | including without limitation the rights to use, copy, modify, merge, 11 | publish, distribute, sublicense, and/or sell copies of the Software, 12 | and to permit persons to whom the Software is furnished to do so, 13 | subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 22 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | release: 2 | umask 022 && chmod -R a+rX . && python setup.py sdist bdist_wheel 3 | # twine upload dist/* 4 | 5 | test: 6 | tox 7 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | pycodestyle (formerly called pep8) - Python style guide checker 2 | =============================================================== 3 | 4 | .. image:: https://github.com/PyCQA/pycodestyle/actions/workflows/main.yml/badge.svg 5 | :target: https://github.com/PyCQA/pycodestyle/actions/workflows/main.yml 6 | :alt: Build status 7 | 8 | .. image:: https://readthedocs.org/projects/pycodestyle/badge/?version=latest 9 | :target: https://pycodestyle.pycqa.org 10 | :alt: Documentation Status 11 | 12 | .. image:: https://img.shields.io/pypi/wheel/pycodestyle.svg 13 | :target: https://pypi.org/project/pycodestyle/ 14 | :alt: Wheel Status 15 | 16 | .. image:: https://badges.gitter.im/PyCQA/pycodestyle.svg 17 | :alt: Join the chat at https://gitter.im/PyCQA/pycodestyle 18 | :target: https://gitter.im/PyCQA/pycodestyle?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge 19 | 20 | pycodestyle is a tool to check your Python code against some of the style 21 | conventions in `PEP 8`_. 22 | 23 | .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ 24 | 25 | .. note:: 26 | 27 | This package used to be called ``pep8`` but was renamed to ``pycodestyle`` 28 | to reduce confusion. Further discussion can be found `in the issue where 29 | Guido requested this 30 | change `_, or in the 31 | lightning talk at PyCon 2016 by @IanLee1521: 32 | `slides `_ 33 | `video `_. 34 | 35 | Features 36 | -------- 37 | 38 | * Plugin architecture: Adding new checks is easy. 39 | 40 | * Parseable output: Jump to error location in your editor. 41 | 42 | * Small: Just one Python file, requires only stdlib. You can use just 43 | the ``pycodestyle.py`` file for this purpose. 44 | 45 | * Comes with a comprehensive test suite. 46 | 47 | Installation 48 | ------------ 49 | 50 | You can install, upgrade, and uninstall ``pycodestyle.py`` with these commands:: 51 | 52 | $ pip install pycodestyle 53 | $ pip install --upgrade pycodestyle 54 | $ pip uninstall pycodestyle 55 | 56 | There's also a package for Debian/Ubuntu, but it's not always the 57 | latest version. 58 | 59 | Example usage and output 60 | ------------------------ 61 | 62 | :: 63 | 64 | $ pycodestyle --first optparse.py 65 | optparse.py:69:11: E401 multiple imports on one line 66 | optparse.py:77:1: E302 expected 2 blank lines, found 1 67 | optparse.py:88:5: E301 expected 1 blank line, found 0 68 | optparse.py:347:31: E211 whitespace before '(' 69 | optparse.py:357:17: E201 whitespace after '{' 70 | optparse.py:472:29: E221 multiple spaces before operator 71 | 72 | You can also make ``pycodestyle.py`` show the source code for each error, and 73 | even the relevant text from PEP 8:: 74 | 75 | $ pycodestyle --show-source --show-pep8 testing/data/E40.py 76 | testing/data/E40.py:2:10: E401 multiple imports on one line 77 | import os, sys 78 | ^ 79 | Imports should usually be on separate lines. 80 | 81 | Okay: import os\nimport sys 82 | E401: import sys, os 83 | 84 | 85 | Or you can display how often each error was found:: 86 | 87 | $ pycodestyle --statistics -qq Python-2.5/Lib 88 | 232 E201 whitespace after '[' 89 | 599 E202 whitespace before ')' 90 | 631 E203 whitespace before ',' 91 | 842 E211 whitespace before '(' 92 | 2531 E221 multiple spaces before operator 93 | 4473 E301 expected 1 blank line, found 0 94 | 4006 E302 expected 2 blank lines, found 1 95 | 165 E303 too many blank lines (4) 96 | 325 E401 multiple imports on one line 97 | 3615 E501 line too long (82 characters) 98 | 99 | Links 100 | ----- 101 | 102 | * `Read the documentation `_ 103 | 104 | * `Fork me on GitHub `_ 105 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | tox 2 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pycodestyle.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pycodestyle.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/pycodestyle" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pycodestyle" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/advanced.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pycodestyle 2 | 3 | ============== 4 | Advanced usage 5 | ============== 6 | 7 | 8 | Automated tests 9 | --------------- 10 | 11 | You can also execute ``pycodestyle`` tests from Python code. For example, this 12 | can be highly useful for automated testing of coding style conformance 13 | in your project:: 14 | 15 | import unittest 16 | import pycodestyle 17 | 18 | 19 | class TestCodeFormat(unittest.TestCase): 20 | 21 | def test_conformance(self): 22 | """Test that we conform to PEP-8.""" 23 | style = pycodestyle.StyleGuide(quiet=True) 24 | result = style.check_files(['file1.py', 'file2.py']) 25 | self.assertEqual(result.total_errors, 0, 26 | "Found code style errors (and warnings).") 27 | 28 | There's also a shortcut for checking a single file:: 29 | 30 | import pycodestyle 31 | 32 | fchecker = pycodestyle.Checker('testing/data/E27.py', show_source=True) 33 | file_errors = fchecker.check_all() 34 | 35 | print("Found %s errors (and warnings)" % file_errors) 36 | 37 | 38 | Configuring tests 39 | ----------------- 40 | 41 | You can configure automated ``pycodestyle`` tests in a variety of ways. 42 | 43 | For example, you can pass in a path to a configuration file that ``pycodestyle`` 44 | should use:: 45 | 46 | import pycodestyle 47 | 48 | style = pycodestyle.StyleGuide(config_file='/path/to/tox.ini') 49 | 50 | You can also set specific options explicitly:: 51 | 52 | style = pycodestyle.StyleGuide(ignore=['E501']) 53 | 54 | 55 | Skip file header 56 | ---------------- 57 | 58 | Another example is related to the `feature request #143 59 | `_: skip a number of lines 60 | at the beginning and the end of a file. This use case is easy to implement 61 | through a custom wrapper for the PEP 8 library:: 62 | 63 | #!python 64 | import pycodestyle 65 | 66 | LINES_SLICE = slice(14, -20) 67 | 68 | class StyleGuide(pycodestyle.StyleGuide): 69 | """This subclass of pycodestyle.StyleGuide will skip the first and last lines 70 | of each file.""" 71 | 72 | def input_file(self, filename, lines=None, expected=None, line_offset=0): 73 | if lines is None: 74 | assert line_offset == 0 75 | line_offset = LINES_SLICE.start or 0 76 | lines = pycodestyle.readlines(filename)[LINES_SLICE] 77 | return super(StyleGuide, self).input_file( 78 | filename, lines=lines, expected=expected, line_offset=line_offset) 79 | 80 | if __name__ == '__main__': 81 | style = StyleGuide(parse_argv=True, config_file=True) 82 | report = style.check_files() 83 | if report.total_errors: 84 | raise SystemExit(1) 85 | 86 | This module declares a lines' window which skips 14 lines at the beginning 87 | and 20 lines at the end. If there's no line to skip at the end, it could be 88 | changed with ``LINES_SLICE = slice(14, None)`` for example. 89 | 90 | You can save it in a file and use it with the same options as the 91 | original ``pycodestyle``. 92 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | pycodestyle API 3 | =============== 4 | 5 | .. module:: pycodestyle 6 | 7 | The library provides classes which are usable by third party tools. 8 | 9 | .. contents:: 10 | :local: 11 | 12 | 13 | .. _main_classes: 14 | 15 | Checker Classes 16 | --------------- 17 | 18 | The :class:`StyleGuide` class is used to configure a style guide checker 19 | instance to check multiple files. 20 | 21 | The :class:`Checker` class can be used to check a single file. 22 | 23 | 24 | .. autoclass:: StyleGuide(parse_argv=False, config_file=None, parser=None, paths=None, report=None, **kwargs) 25 | 26 | .. automethod:: init_report(reporter=None) 27 | .. automethod:: check_files(paths=None) 28 | .. automethod:: input_file(filename, lines=None, expected=None, line_offset=0) 29 | .. automethod:: input_dir(dirname) 30 | .. automethod:: excluded(filename, parent=None) 31 | .. automethod:: ignore_code(code) 32 | .. automethod:: get_checks(argument_name) 33 | 34 | .. autoclass:: Checker(filename=None, lines=None, report=None, **kwargs) 35 | 36 | .. automethod:: readline 37 | .. automethod:: run_check(check, argument_names) 38 | .. automethod:: check_physical(line) 39 | .. automethod:: build_tokens_line 40 | .. automethod:: check_logical 41 | .. automethod:: check_ast 42 | .. automethod:: generate_tokens 43 | .. automethod:: check_all(expected=None, line_offset=0) 44 | 45 | 46 | .. _report_classes: 47 | 48 | Report Classes 49 | -------------- 50 | 51 | .. autoclass:: BaseReport(options) 52 | 53 | .. automethod:: start 54 | .. automethod:: stop 55 | .. automethod:: init_file(filename, lines, expected, line_offset) 56 | .. automethod:: increment_logical_line 57 | .. automethod:: error(line_number, offset, text, check) 58 | .. automethod:: get_file_results 59 | .. automethod:: get_count(prefix='') 60 | .. automethod:: get_statistics(prefix='') 61 | .. automethod:: print_statistics(prefix='') 62 | .. automethod:: print_benchmark 63 | 64 | .. autoclass:: FileReport 65 | 66 | .. autoclass:: StandardReport 67 | 68 | .. autoclass:: DiffReport 69 | 70 | 71 | Utilities 72 | --------- 73 | 74 | .. autofunction:: expand_indent(line) 75 | .. autofunction:: mute_string(text) 76 | .. autofunction:: read_config(options, args, arglist, parser) 77 | .. autofunction:: process_options(arglist=None, parse_argv=False, config_file=None) 78 | .. autofunction:: register_check(func_or_cls, codes=None) 79 | 80 | .. 81 | These ones are used internally, but they don't need advertising 82 | .. autofunction:: readlines(filename) 83 | .. autofunction:: isidentifier(word) 84 | .. autofunction:: stdin_get_value() 85 | .. autofunction:: parse_udiff(diff, patterns=None, parent='.') 86 | .. autofunction:: filename_match(filename, patterns, default=True) 87 | .. autofunction:: get_parser(prog='pycodestyle', version=pycodestyle.__version__) 88 | .. autofunction:: init_checks_registry() 89 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # 2 | # pycodestyle documentation build configuration file, created by 3 | # sphinx-quickstart on Tue Aug 21 09:47:49 2012. 4 | # 5 | # This file is execfile()d with the current directory set to its 6 | # containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | import os 14 | import sys 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # sys.path.insert(0, os.path.abspath('.')) 20 | sys.path.insert(0, os.path.abspath('..')) 21 | 22 | # -- General configuration ---------------------------------------------------- 23 | 24 | # If your documentation needs a minimal Sphinx version, state it here. 25 | # needs_sphinx = '1.0' 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 29 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 30 | 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] 31 | 32 | # Add any paths that contain templates here, relative to this directory. 33 | templates_path = ['_templates'] 34 | 35 | # The suffix of source filenames. 36 | source_suffix = '.rst' 37 | 38 | # The encoding of source files. 39 | # source_encoding = 'utf-8-sig' 40 | 41 | # The master toctree document. 42 | master_doc = 'index' 43 | 44 | # General information about the project. 45 | project = 'pycodestyle' 46 | authors = 'Johann C. Rocholl, Florent Xicluna, Ian Lee' 47 | copyright = '2006-2016, %s' % (authors) 48 | 49 | # The version info for the project you're documenting, acts as replacement for 50 | # |version| and |release|, also used in various other places throughout the 51 | # built documents. 52 | # 53 | 54 | pkg_version = __import__('pycodestyle').__version__.split('.') 55 | # The short X.Y version. 56 | version = '.'.join(pkg_version[:2]) 57 | # The full version, including alpha/beta/rc tags. 58 | release = '.'.join(pkg_version) 59 | 60 | # The language for content autogenerated by Sphinx. Refer to documentation 61 | # for a list of supported languages. 62 | # language = None 63 | 64 | # There are two options for replacing |today|: either, you set today to some 65 | # non-false value, then it is used: 66 | # today = '' 67 | # Else, today_fmt is used as the format for a strftime call. 68 | # today_fmt = '%B %d, %Y' 69 | 70 | # List of patterns, relative to source directory, that match files and 71 | # directories to ignore when looking for source files. 72 | exclude_patterns = ['_build'] 73 | 74 | # The reST default role (used for this markup: `text`) to use for 75 | # all documents. 76 | # default_role = None 77 | 78 | # If true, '()' will be appended to :func: etc. cross-reference text. 79 | # add_function_parentheses = True 80 | 81 | # If true, the current module name will be prepended to all description 82 | # unit titles (such as .. function::). 83 | # add_module_names = True 84 | 85 | # If true, sectionauthor and moduleauthor directives will be shown in the 86 | # output. They are ignored by default. 87 | # show_authors = False 88 | 89 | # The name of the Pygments (syntax highlighting) style to use. 90 | pygments_style = 'sphinx' 91 | 92 | # A list of ignored prefixes for module index sorting. 93 | # modindex_common_prefix = [] 94 | 95 | 96 | # -- Options for HTML output -------------------------------------------------- 97 | 98 | # The theme to use for HTML and HTML Help pages. See the documentation for 99 | # a list of builtin themes. 100 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 101 | if not on_rtd: # only import and set the theme if we're building docs locally 102 | import sphinx_rtd_theme 103 | html_theme = 'sphinx_rtd_theme' 104 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 105 | 106 | # Theme options are theme-specific and customize the look and feel of a theme 107 | # further. For a list of options available for each theme, see the 108 | # documentation. 109 | # html_theme_options = {} 110 | 111 | # Add any paths that contain custom themes here, relative to this directory. 112 | # html_theme_path = [] 113 | 114 | # The name for this set of Sphinx documents. If None, it defaults to 115 | # " v documentation". 116 | # html_title = None 117 | 118 | # A shorter title for the navigation bar. Default is the same as html_title. 119 | # html_short_title = None 120 | 121 | # The name of an image file (relative to this directory) to place at the top 122 | # of the sidebar. 123 | # html_logo = None 124 | 125 | # The name of an image file (within the static path) to use as favicon of the 126 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 127 | # pixels large. 128 | # html_favicon = None 129 | 130 | # Add any paths that contain custom static files (such as style sheets) here, 131 | # relative to this directory. They are copied after the builtin static files, 132 | # so a file named "default.css" will overwrite the builtin "default.css". 133 | # html_static_path = ['_static'] 134 | 135 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 136 | # using the given strftime format. 137 | # html_last_updated_fmt = '%b %d, %Y' 138 | 139 | # If true, SmartyPants will be used to convert quotes and dashes to 140 | # typographically correct entities. 141 | # html_use_smartypants = True 142 | 143 | # Custom sidebar templates, maps document names to template names. 144 | # html_sidebars = {} 145 | 146 | # Additional templates that should be rendered to pages, maps page names to 147 | # template names. 148 | # html_additional_pages = {} 149 | 150 | # If false, no module index is generated. 151 | # html_domain_indices = True 152 | 153 | # If false, no index is generated. 154 | # html_use_index = True 155 | 156 | # If true, the index is split into individual pages for each letter. 157 | # html_split_index = False 158 | 159 | # If true, links to the reST sources are added to the pages. 160 | # html_show_sourcelink = True 161 | 162 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 163 | # html_show_sphinx = True 164 | 165 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 166 | # html_show_copyright = True 167 | 168 | # If true, an OpenSearch description file will be output, and all pages will 169 | # contain a tag referring to it. The value of this option must be the 170 | # base URL from which the finished HTML is served. 171 | # html_use_opensearch = '' 172 | 173 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 174 | # html_file_suffix = None 175 | 176 | # Output file base name for HTML help builder. 177 | htmlhelp_basename = 'pycodestyledoc' 178 | 179 | 180 | # -- Options for LaTeX output ------------------------------------------------- 181 | 182 | latex_elements = { 183 | # The paper size ('letterpaper' or 'a4paper'). 184 | # 'papersize': 'letterpaper', 185 | 186 | # The font size ('10pt', '11pt' or '12pt'). 187 | # 'pointsize': '10pt', 188 | 189 | # Additional stuff for the LaTeX preamble. 190 | # 'preamble': '', 191 | } 192 | 193 | # Grouping the document tree into LaTeX files. List of tuples 194 | # (source start file, target name, title, 195 | # author, documentclass [howto/manual]). 196 | latex_documents = [ 197 | ('index', 'pycodestyle.tex', 'pycodestyle documentation', 198 | authors, 'manual'), 199 | ] 200 | 201 | # The name of an image file (relative to this directory) to place at the top of 202 | # the title page. 203 | # latex_logo = None 204 | 205 | # For "manual" documents, if this is true, then toplevel headings are parts, 206 | # not chapters. 207 | # latex_use_parts = False 208 | 209 | # If true, show page references after internal links. 210 | # latex_show_pagerefs = False 211 | 212 | # If true, show URL addresses after external links. 213 | # latex_show_urls = False 214 | 215 | # Documents to append as an appendix to all manuals. 216 | # latex_appendices = [] 217 | 218 | # If false, no module index is generated. 219 | # latex_domain_indices = True 220 | 221 | 222 | # -- Options for manual page output ------------------------------------------- 223 | 224 | # One entry per manual page. List of tuples 225 | # (source start file, name, description, authors, manual section). 226 | man_pages = [ 227 | ('index', 'pycodestyle', 'pycodestyle documentation', 228 | [authors], 1) 229 | ] 230 | 231 | # If true, show URL addresses after external links. 232 | # man_show_urls = False 233 | 234 | 235 | # -- Options for Texinfo output ----------------------------------------------- 236 | 237 | # Grouping the document tree into Texinfo files. List of tuples 238 | # (source start file, target name, title, author, 239 | # dir menu entry, description, category) 240 | texinfo_documents = [ 241 | ('index', 'pycodestyle', 'pycodestyle documentation', authors, 242 | 'pycodestyle', 'One line description of project.', 243 | 'Miscellaneous'), 244 | ] 245 | 246 | # Documents to append as an appendix to all manuals. 247 | # texinfo_appendices = [] 248 | 249 | # If false, no module index is generated. 250 | # texinfo_domain_indices = True 251 | 252 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 253 | # texinfo_show_urls = 'footnote' 254 | -------------------------------------------------------------------------------- /docs/developer.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pycodestyle 2 | 3 | ================= 4 | Developer's notes 5 | ================= 6 | 7 | 8 | Source code 9 | ~~~~~~~~~~~ 10 | 11 | The source code is currently `available on GitHub`_ under the terms and 12 | conditions of the :ref:`Expat license `. Fork away! 13 | 14 | * `Source code `_ and 15 | `issue tracker `_ on GitHub. 16 | * `Continuous tests `_ against 17 | Python 2.7 and 3.5+ as well as the nightly Python build and PyPy, on GitHub 18 | Actions. 19 | 20 | .. _available on GitHub: https://github.com/pycqa/pycodestyle 21 | 22 | 23 | Direction 24 | ~~~~~~~~~ 25 | 26 | Some high-level aims and directions to bear in mind for contributions: 27 | 28 | * ``pycodestyle`` is intended to be as fast as possible. 29 | Using the ``ast`` module defeats that purpose. 30 | The `pep8-naming `_ plugin exists 31 | for this sort of functionality. 32 | * If you want to provide extensibility / plugins, 33 | please see `flake8 `_ - 34 | ``pycodestyle`` doesn't want or need a plugin architecture. 35 | * ``pycodestyle`` aims to have no external dependencies. 36 | 37 | 38 | Contribute 39 | ~~~~~~~~~~ 40 | 41 | You can add checks to this program by writing plugins. Each plugin is 42 | a simple function that is called for each line of source code, either 43 | physical or logical. 44 | 45 | Physical line: 46 | 47 | * Raw line of text from the input file. 48 | 49 | Logical line: 50 | 51 | * Multi-line statements converted to a single line. 52 | * Stripped left and right. 53 | * Contents of strings replaced with ``"xxx"`` of same length. 54 | * Comments removed. 55 | 56 | The check function requests physical or logical lines by the name of 57 | the first argument:: 58 | 59 | def maximum_line_length(physical_line) 60 | def extraneous_whitespace(logical_line) 61 | def blank_lines(logical_line, blank_lines, indent_level, line_number) 62 | 63 | The last example above demonstrates how check plugins can request 64 | additional information with extra arguments. All attributes of the 65 | :class:`Checker` object are available. Some examples: 66 | 67 | * ``lines``: a list of the raw lines from the input file 68 | * ``tokens``: the tokens that contribute to this logical line 69 | * ``line_number``: line number in the input file 70 | * ``total_lines``: number of lines in the input file 71 | * ``blank_lines``: blank lines before this one 72 | * ``indent_char``: indentation character in this file (``" "`` or ``"\t"``) 73 | * ``indent_level``: indentation (with tabs expanded to multiples of 8) 74 | * ``previous_indent_level``: indentation on previous line 75 | * ``previous_logical``: previous logical line 76 | 77 | Check plugins can also maintain per-file state. If you need this, declare 78 | a parameter named ``checker_state``. You will be passed a dict, which will be 79 | the same one for all lines in the same file but a different one for different 80 | files. Each check plugin gets its own dict, so you don't need to worry about 81 | clobbering the state of other plugins. 82 | 83 | The docstring of each check function shall be the relevant part of 84 | text from `PEP 8`_. It is printed if the user enables ``--show-pep8``. 85 | Several docstrings contain examples directly from the `PEP 8`_ document. 86 | 87 | :: 88 | 89 | Okay: spam(ham[1], {eggs: 2}) 90 | E201: spam( ham[1], {eggs: 2}) 91 | 92 | These examples are verified automatically by ``test_self_doctest.py``. 93 | You can add examples for your own check functions. 94 | The format is simple: ``"Okay"`` or error/warning code followed by colon and 95 | space, the rest of the line is example source code. If you put ``'r'`` before 96 | the docstring, you can use ``\n`` for newline and ``\t`` for tab. 97 | 98 | Then be sure to pass the tests:: 99 | 100 | $ pytest tests 101 | $ python pycodestyle.py --verbose pycodestyle.py 102 | 103 | When contributing to pycodestyle, please observe our `Code of Conduct`_. 104 | 105 | To run the tests, the core developer team and GitHub Actions use tox:: 106 | 107 | $ pip install -r dev-requirements.txt 108 | $ tox 109 | 110 | All the tests should pass for all available interpreters, with the summary of:: 111 | 112 | congratulations :) 113 | 114 | .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ 115 | .. _Code of Conduct: http://meta.pycqa.org/en/latest/code-of-conduct.html 116 | 117 | 118 | Changes 119 | ~~~~~~~ 120 | 121 | .. include:: ../CHANGES.txt 122 | :start-line: 3 123 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. pycodestyle documentation master file 2 | 3 | pycodestyle's documentation 4 | =========================== 5 | 6 | *Python style guide checker* 7 | 8 | pycodestyle (formerly pep8) is a tool to check your Python code against some of 9 | the style conventions in `PEP 8`_. 10 | 11 | .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ 12 | 13 | 14 | Contents: 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | intro 20 | advanced 21 | API 22 | developer 23 | 24 | * Online documentation: https://pycodestyle.pycqa.org/ 25 | * Source code and issue tracker: https://github.com/pycqa/pycodestyle 26 | 27 | 28 | Indices and tables 29 | ================== 30 | 31 | * :ref:`genindex` 32 | * :ref:`search` 33 | 34 | 35 | Credits 36 | ======= 37 | 38 | Created by Johann C. Rocholl. 39 | 40 | Maintained by Florent Xicluna and Ian Lee. 41 | 42 | 43 | .. _license: 44 | 45 | License 46 | ======= 47 | 48 | The ``pycodestyle`` library is provided under the terms and conditions of the 49 | Expat license:: 50 | 51 | # Permission is hereby granted, free of charge, to any person 52 | # obtaining a copy of this software and associated documentation files 53 | # (the "Software"), to deal in the Software without restriction, 54 | # including without limitation the rights to use, copy, modify, merge, 55 | # publish, distribute, sublicense, and/or sell copies of the Software, 56 | # and to permit persons to whom the Software is furnished to do so, 57 | # subject to the following conditions: 58 | # 59 | # The above copyright notice and this permission notice shall be 60 | # included in all copies or substantial portions of the Software. 61 | # 62 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 63 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 64 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 65 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 66 | # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 67 | # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 68 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 69 | # SOFTWARE. 70 | -------------------------------------------------------------------------------- /docs/intro.rst: -------------------------------------------------------------------------------- 1 | .. currentmodule:: pycodestyle 2 | 3 | Introduction 4 | ============ 5 | 6 | pycodestyle is a tool to check your Python code against some of the style 7 | conventions in `PEP 8`_. 8 | 9 | .. contents:: 10 | :local: 11 | 12 | 13 | Features 14 | -------- 15 | 16 | * Plugin architecture: Adding new checks is easy. 17 | 18 | * Parseable output: Jump to error location in your editor. 19 | 20 | * Small: Just one Python file, requires only stdlib. You can use just 21 | the ``pycodestyle.py`` file for this purpose. 22 | 23 | * Comes with a comprehensive test suite. 24 | 25 | 26 | Disclaimer 27 | ---------- 28 | 29 | This utility does not enforce every single rule of PEP 8. It helps to 30 | verify that some coding conventions are applied but it does not intend 31 | to be exhaustive. Some rules cannot be expressed with a simple algorithm, 32 | and other rules are only guidelines which you could circumvent when you 33 | need to. 34 | 35 | Always remember this statement from `PEP 8`_: 36 | 37 | *A style guide is about consistency. Consistency with this style guide is 38 | important. Consistency within a project is more important. Consistency 39 | within one module or function is most important.* 40 | 41 | 42 | Among other things, these features are currently not in the scope of 43 | the ``pycodestyle`` library: 44 | 45 | * **naming conventions**: this kind of feature is supported through plugins. 46 | Install `flake8 `_ and the 47 | `pep8-naming extension `_ to use 48 | this feature. 49 | * **docstring conventions**: they are not in the scope of this library; 50 | see the `pydocstyle project `_. 51 | * **automatic fixing**: see the section *PEP8 Fixers* in the 52 | :ref:`related tools ` page. 53 | 54 | 55 | Installation 56 | ------------ 57 | 58 | You can install, upgrade, uninstall ``pycodestyle.py`` with these commands:: 59 | 60 | $ pip install pycodestyle 61 | $ pip install --upgrade pycodestyle 62 | $ pip uninstall pycodestyle 63 | 64 | 65 | Example usage and output 66 | ------------------------ 67 | 68 | :: 69 | 70 | $ pycodestyle --first optparse.py 71 | optparse.py:69:11: E401 multiple imports on one line 72 | optparse.py:77:1: E302 expected 2 blank lines, found 1 73 | optparse.py:88:5: E301 expected 1 blank line, found 0 74 | optparse.py:347:31: E211 whitespace before '(' 75 | optparse.py:357:17: E201 whitespace after '{' 76 | optparse.py:472:29: E221 multiple spaces before operator 77 | 78 | You can also make ``pycodestyle.py`` show the source code for each error, and 79 | even the relevant text from PEP 8:: 80 | 81 | $ pycodestyle --show-source --show-pep8 testing/data/E40.py 82 | testing/data/E40.py:2:10: E401 multiple imports on one line 83 | import os, sys 84 | ^ 85 | Imports should usually be on separate lines. 86 | 87 | Okay: import os\nimport sys 88 | E401: import sys, os 89 | 90 | 91 | Or you can display how often each error was found:: 92 | 93 | $ pycodestyle --statistics -qq Python-2.5/Lib 94 | 232 E201 whitespace after '[' 95 | 599 E202 whitespace before ')' 96 | 631 E203 whitespace before ',' 97 | 842 E211 whitespace before '(' 98 | 2531 E221 multiple spaces before operator 99 | 4473 E301 expected 1 blank line, found 0 100 | 4006 E302 expected 2 blank lines, found 1 101 | 165 E303 too many blank lines (4) 102 | 325 E401 multiple imports on one line 103 | 3615 E501 line too long (82 characters) 104 | 105 | You can also make ``pycodestyle.py`` show the error text in different formats by 106 | using ``--format`` having options default/pylint/custom:: 107 | 108 | $ pycodestyle testing/data/E40.py --format=default 109 | testing/data/E40.py:2:10: E401 multiple imports on one line 110 | 111 | $ pycodestyle testing/data/E40.py --format=pylint 112 | testing/data/E40.py:2: [E401] multiple imports on one line 113 | 114 | $ pycodestyle testing/data/E40.py --format='%(path)s|%(row)d|%(col)d| %(code)s %(text)s' 115 | testing/data/E40.py|2|10| E401 multiple imports on one line 116 | 117 | Variables in the ``custom`` format option 118 | 119 | +----------------+------------------+ 120 | | Variable | Significance | 121 | +================+==================+ 122 | | ``path`` | File name | 123 | +----------------+------------------+ 124 | | ``row`` | Row number | 125 | +----------------+------------------+ 126 | | ``col`` | Column number | 127 | +----------------+------------------+ 128 | | ``code`` | Error code | 129 | +----------------+------------------+ 130 | | ``text`` | Error text | 131 | +----------------+------------------+ 132 | 133 | Quick help is available on the command line:: 134 | 135 | $ pycodestyle -h 136 | Usage: pycodestyle [options] input ... 137 | 138 | Options: 139 | --version show program's version number and exit 140 | -h, --help show this help message and exit 141 | -v, --verbose print status messages, or debug with -vv 142 | -q, --quiet report only file names, or nothing with -qq 143 | --first show first occurrence of each error 144 | --exclude=patterns exclude files or directories which match these comma 145 | separated patterns (default: .svn,CVS,.bzr,.hg,.git) 146 | --filename=patterns when parsing directories, only check filenames matching 147 | these comma separated patterns (default: *.py) 148 | --select=errors select errors and warnings (e.g. E,W6) 149 | --ignore=errors skip errors and warnings (e.g. E4,W) 150 | --show-source show source code for each error 151 | --show-pep8 show text of PEP 8 for each error (implies --first) 152 | --statistics count errors and warnings 153 | --count print total number of errors and warnings to standard 154 | error and set exit code to 1 if total is not null 155 | --max-line-length=n set maximum allowed line length (default: 79) 156 | --max-doc-length=n set maximum allowed doc line length and perform these 157 | checks (unchecked if not set) 158 | --indent-size=n set how many spaces make up an indent (default: 4) 159 | --hang-closing hang closing bracket instead of matching indentation of 160 | opening bracket's line 161 | --format=format set the error format [default|pylint|] 162 | --diff report only lines changed according to the unified diff 163 | received on STDIN 164 | 165 | Testing Options: 166 | --benchmark measure processing speed 167 | 168 | Configuration: 169 | The project options are read from the [pycodestyle] section of the 170 | tox.ini file or the setup.cfg file located in any parent folder of the 171 | path(s) being processed. Allowed options are: exclude, filename, 172 | select, ignore, max-line-length, max-doc-length, hang-closing, count, 173 | format, quiet, show-pep8, show-source, statistics, verbose. 174 | 175 | --config=path user config file location 176 | (default: ~/.config/pycodestyle) 177 | 178 | 179 | Configuration 180 | ------------- 181 | 182 | The behaviour may be configured at two levels, the user and project levels. 183 | 184 | At the user level, settings are read from the following locations: 185 | 186 | If on Windows: 187 | ``~\.pycodestyle`` 188 | 189 | Otherwise, if the :envvar:`XDG_CONFIG_HOME` environment variable is defined: 190 | ``XDG_CONFIG_HOME/pycodestyle`` 191 | 192 | Else if :envvar:`XDG_CONFIG_HOME` is not defined: 193 | ``~/.config/pycodestyle`` 194 | 195 | Example:: 196 | 197 | [pycodestyle] 198 | count = False 199 | ignore = E226,E302,E71 200 | max-line-length = 160 201 | statistics = True 202 | 203 | At the project level, a ``setup.cfg`` file or a ``tox.ini`` file is read if 204 | present. If none of these files have a ``[pycodestyle]`` section, no project 205 | specific configuration is loaded. 206 | 207 | 208 | Error codes 209 | ----------- 210 | 211 | This is the current list of error and warning codes: 212 | 213 | +------------+----------------------------------------------------------------------+ 214 | | code | sample message | 215 | +============+======================================================================+ 216 | | **E1** | *Indentation* | 217 | +------------+----------------------------------------------------------------------+ 218 | | E101 | indentation contains mixed spaces and tabs | 219 | +------------+----------------------------------------------------------------------+ 220 | | E111 | indentation is not a multiple of four | 221 | +------------+----------------------------------------------------------------------+ 222 | | E112 | expected an indented block | 223 | +------------+----------------------------------------------------------------------+ 224 | | E113 | unexpected indentation | 225 | +------------+----------------------------------------------------------------------+ 226 | | E114 | indentation is not a multiple of four (comment) | 227 | +------------+----------------------------------------------------------------------+ 228 | | E115 | expected an indented block (comment) | 229 | +------------+----------------------------------------------------------------------+ 230 | | E116 | unexpected indentation (comment) | 231 | +------------+----------------------------------------------------------------------+ 232 | | E117 | over-indented | 233 | +------------+----------------------------------------------------------------------+ 234 | | E121 (\*^) | continuation line under-indented for hanging indent | 235 | +------------+----------------------------------------------------------------------+ 236 | | E122 (^) | continuation line missing indentation or outdented | 237 | +------------+----------------------------------------------------------------------+ 238 | | E123 (*) | closing bracket does not match indentation of opening bracket's line | 239 | +------------+----------------------------------------------------------------------+ 240 | | E124 (^) | closing bracket does not match visual indentation | 241 | +------------+----------------------------------------------------------------------+ 242 | | E125 (^) | continuation line with same indent as next logical line | 243 | +------------+----------------------------------------------------------------------+ 244 | | E126 (\*^) | continuation line over-indented for hanging indent | 245 | +------------+----------------------------------------------------------------------+ 246 | | E127 (^) | continuation line over-indented for visual indent | 247 | +------------+----------------------------------------------------------------------+ 248 | | E128 (^) | continuation line under-indented for visual indent | 249 | +------------+----------------------------------------------------------------------+ 250 | | E129 (^) | visually indented line with same indent as next logical line | 251 | +------------+----------------------------------------------------------------------+ 252 | | E131 (^) | continuation line unaligned for hanging indent | 253 | +------------+----------------------------------------------------------------------+ 254 | | E133 (*) | closing bracket is missing indentation | 255 | +------------+----------------------------------------------------------------------+ 256 | +------------+----------------------------------------------------------------------+ 257 | | **E2** | *Whitespace* | 258 | +------------+----------------------------------------------------------------------+ 259 | | E201 | whitespace after '(' | 260 | +------------+----------------------------------------------------------------------+ 261 | | E202 | whitespace before ')' | 262 | +------------+----------------------------------------------------------------------+ 263 | | E203 | whitespace before ',', ';', or ':' | 264 | +------------+----------------------------------------------------------------------+ 265 | | E204 | whitespace after decorator '@' | 266 | +------------+----------------------------------------------------------------------+ 267 | +------------+----------------------------------------------------------------------+ 268 | | E211 | whitespace before '(' | 269 | +------------+----------------------------------------------------------------------+ 270 | +------------+----------------------------------------------------------------------+ 271 | | E221 | multiple spaces before operator | 272 | +------------+----------------------------------------------------------------------+ 273 | | E222 | multiple spaces after operator | 274 | +------------+----------------------------------------------------------------------+ 275 | | E223 | tab before operator | 276 | +------------+----------------------------------------------------------------------+ 277 | | E224 | tab after operator | 278 | +------------+----------------------------------------------------------------------+ 279 | | E225 | missing whitespace around operator | 280 | +------------+----------------------------------------------------------------------+ 281 | | E226 (*) | missing whitespace around arithmetic operator | 282 | +------------+----------------------------------------------------------------------+ 283 | | E227 | missing whitespace around bitwise or shift operator | 284 | +------------+----------------------------------------------------------------------+ 285 | | E228 | missing whitespace around modulo operator | 286 | +------------+----------------------------------------------------------------------+ 287 | +------------+----------------------------------------------------------------------+ 288 | | E231 | missing whitespace after ',', ';', or ':' | 289 | +------------+----------------------------------------------------------------------+ 290 | +------------+----------------------------------------------------------------------+ 291 | | E241 (*) | multiple spaces after ',' | 292 | +------------+----------------------------------------------------------------------+ 293 | | E242 (*) | tab after ',' | 294 | +------------+----------------------------------------------------------------------+ 295 | +------------+----------------------------------------------------------------------+ 296 | | E251 | unexpected spaces around keyword / parameter equals | 297 | +------------+----------------------------------------------------------------------+ 298 | +------------+----------------------------------------------------------------------+ 299 | | E261 | at least two spaces before inline comment | 300 | +------------+----------------------------------------------------------------------+ 301 | | E262 | inline comment should start with '# ' | 302 | +------------+----------------------------------------------------------------------+ 303 | | E265 | block comment should start with '# ' | 304 | +------------+----------------------------------------------------------------------+ 305 | | E266 | too many leading '#' for block comment | 306 | +------------+----------------------------------------------------------------------+ 307 | +------------+----------------------------------------------------------------------+ 308 | | E271 | multiple spaces after keyword | 309 | +------------+----------------------------------------------------------------------+ 310 | | E272 | multiple spaces before keyword | 311 | +------------+----------------------------------------------------------------------+ 312 | | E273 | tab after keyword | 313 | +------------+----------------------------------------------------------------------+ 314 | | E274 | tab before keyword | 315 | +------------+----------------------------------------------------------------------+ 316 | | E275 | missing whitespace after keyword | 317 | +------------+----------------------------------------------------------------------+ 318 | +------------+----------------------------------------------------------------------+ 319 | | **E3** | *Blank line* | 320 | +------------+----------------------------------------------------------------------+ 321 | | E301 | expected 1 blank line, found 0 | 322 | +------------+----------------------------------------------------------------------+ 323 | | E302 | expected 2 blank lines, found 0 | 324 | +------------+----------------------------------------------------------------------+ 325 | | E303 | too many blank lines (3) | 326 | +------------+----------------------------------------------------------------------+ 327 | | E304 | blank lines found after function decorator | 328 | +------------+----------------------------------------------------------------------+ 329 | | E305 | expected 2 blank lines after end of function or class | 330 | +------------+----------------------------------------------------------------------+ 331 | | E306 | expected 1 blank line before a nested definition | 332 | +------------+----------------------------------------------------------------------+ 333 | +------------+----------------------------------------------------------------------+ 334 | | **E4** | *Import* | 335 | +------------+----------------------------------------------------------------------+ 336 | | E401 | multiple imports on one line | 337 | +------------+----------------------------------------------------------------------+ 338 | | E402 | module level import not at top of file | 339 | +------------+----------------------------------------------------------------------+ 340 | +------------+----------------------------------------------------------------------+ 341 | | **E5** | *Line length* | 342 | +------------+----------------------------------------------------------------------+ 343 | | E501 (^) | line too long (82 > 79 characters) | 344 | +------------+----------------------------------------------------------------------+ 345 | | E502 | the backslash is redundant between brackets | 346 | +------------+----------------------------------------------------------------------+ 347 | +------------+----------------------------------------------------------------------+ 348 | | **E7** | *Statement* | 349 | +------------+----------------------------------------------------------------------+ 350 | | E701 | multiple statements on one line (colon) | 351 | +------------+----------------------------------------------------------------------+ 352 | | E702 | multiple statements on one line (semicolon) | 353 | +------------+----------------------------------------------------------------------+ 354 | | E703 | statement ends with a semicolon | 355 | +------------+----------------------------------------------------------------------+ 356 | | E704 (*) | multiple statements on one line (def) | 357 | +------------+----------------------------------------------------------------------+ 358 | | E711 (^) | comparison to None should be 'if cond is None:' | 359 | +------------+----------------------------------------------------------------------+ 360 | | E712 (^) | comparison to True should be 'if cond is True:' or 'if cond:' | 361 | +------------+----------------------------------------------------------------------+ 362 | | E713 | test for membership should be 'not in' | 363 | +------------+----------------------------------------------------------------------+ 364 | | E714 | test for object identity should be 'is not' | 365 | +------------+----------------------------------------------------------------------+ 366 | | E721 (^) | do not compare types, use 'isinstance()' | 367 | +------------+----------------------------------------------------------------------+ 368 | | E722 | do not use bare except, specify exception instead | 369 | +------------+----------------------------------------------------------------------+ 370 | | E731 | do not assign a lambda expression, use a def | 371 | +------------+----------------------------------------------------------------------+ 372 | | E741 | do not use variables named 'l', 'O', or 'I' | 373 | +------------+----------------------------------------------------------------------+ 374 | | E742 | do not define classes named 'l', 'O', or 'I' | 375 | +------------+----------------------------------------------------------------------+ 376 | | E743 | do not define functions named 'l', 'O', or 'I' | 377 | +------------+----------------------------------------------------------------------+ 378 | +------------+----------------------------------------------------------------------+ 379 | | **E9** | *Runtime* | 380 | +------------+----------------------------------------------------------------------+ 381 | | E901 | SyntaxError or IndentationError | 382 | +------------+----------------------------------------------------------------------+ 383 | | E902 | IOError | 384 | +------------+----------------------------------------------------------------------+ 385 | +------------+----------------------------------------------------------------------+ 386 | | **W1** | *Indentation warning* | 387 | +------------+----------------------------------------------------------------------+ 388 | | W191 | indentation contains tabs | 389 | +------------+----------------------------------------------------------------------+ 390 | +------------+----------------------------------------------------------------------+ 391 | | **W2** | *Whitespace warning* | 392 | +------------+----------------------------------------------------------------------+ 393 | | W291 | trailing whitespace | 394 | +------------+----------------------------------------------------------------------+ 395 | | W292 | no newline at end of file | 396 | +------------+----------------------------------------------------------------------+ 397 | | W293 | blank line contains whitespace | 398 | +------------+----------------------------------------------------------------------+ 399 | +------------+----------------------------------------------------------------------+ 400 | | **W3** | *Blank line warning* | 401 | +------------+----------------------------------------------------------------------+ 402 | | W391 | blank line at end of file | 403 | +------------+----------------------------------------------------------------------+ 404 | +------------+----------------------------------------------------------------------+ 405 | | **W5** | *Line break warning* | 406 | +------------+----------------------------------------------------------------------+ 407 | | W503 (*) | line break before binary operator | 408 | +------------+----------------------------------------------------------------------+ 409 | | W504 (*) | line break after binary operator | 410 | +------------+----------------------------------------------------------------------+ 411 | | W505 (\*^) | doc line too long (82 > 79 characters) | 412 | +------------+----------------------------------------------------------------------+ 413 | +------------+----------------------------------------------------------------------+ 414 | | **W6** | *Deprecation warning* | 415 | +------------+----------------------------------------------------------------------+ 416 | | W605 | invalid escape sequence '\x' | 417 | +------------+----------------------------------------------------------------------+ 418 | 419 | 420 | **(*)** In the default configuration, the checks **E121**, **E123**, **E126**, **E133**, 421 | **E226**, **E241**, **E242**, **E704**, **W503**, **W504** and **W505** are ignored 422 | because they are not rules unanimously accepted, and `PEP 8`_ does not enforce them. 423 | Please note that if the option ``--ignore=errors`` is used, 424 | the default configuration will be overridden and ignore only the check(s) you skip. 425 | The check **W503** is mutually exclusive with check **W504**. 426 | The check **E133** is mutually exclusive with check **E123**. Use switch 427 | ``--hang-closing`` to report **E133** instead of **E123**. Use switch 428 | ``--max-doc-length=n`` to report **W505**. 429 | 430 | **(^)** These checks can be disabled at the line level using the ``# noqa`` 431 | special comment. This possibility should be reserved for special cases. 432 | 433 | *Special cases aren't special enough to break the rules.* 434 | 435 | 436 | Note: most errors can be listed with such one-liner:: 437 | 438 | $ python pycodestyle.py --first --select E,W testing/data --format '%(code)s: %(text)s' 439 | 440 | 441 | .. _related-tools: 442 | 443 | Related tools 444 | ------------- 445 | 446 | The `flake8 checker `_ is a wrapper around 447 | ``pycodestyle`` and similar tools. It supports plugins. 448 | 449 | Other tools which use ``pycodestyle`` are referenced in the Wiki: `list of related 450 | tools `_. 451 | 452 | .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ 453 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pycodestyle.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pycodestyle.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = pycodestyle 3 | version = attr: pycodestyle.__version__ 4 | description = Python style guide checker 5 | long_description = file: README.rst 6 | long_description_content_type = text/x-rst 7 | url = https://pycodestyle.pycqa.org/ 8 | author = Johann C. Rocholl 9 | author_email = johann@rocholl.net 10 | maintainer = Ian Lee 11 | maintainer_email = IanLee1521@gmail.com 12 | license = MIT 13 | license_files = LICENSE 14 | classifiers = 15 | Development Status :: 5 - Production/Stable 16 | Environment :: Console 17 | Intended Audience :: Developers 18 | Operating System :: OS Independent 19 | Programming Language :: Python 20 | Programming Language :: Python :: 3 21 | Programming Language :: Python :: 3 :: Only 22 | Programming Language :: Python :: Implementation :: CPython 23 | Programming Language :: Python :: Implementation :: PyPy 24 | Topic :: Software Development :: Libraries :: Python Modules 25 | keywords = pycodestyle, pep8, PEP 8, PEP-8, PEP8 26 | project_urls = 27 | Changes=https://pycodestyle.pycqa.org/en/latest/developer.html#changes 28 | 29 | [options] 30 | py_modules = pycodestyle 31 | python_requires = >=3.9 32 | include_package_data = True 33 | zip_safe = False 34 | 35 | [options.entry_points] 36 | console_scripts = 37 | pycodestyle = pycodestyle:_main 38 | 39 | [bdist_wheel] 40 | universal = 1 41 | 42 | [pycodestyle] 43 | ignore = E226,E24,W504 44 | max_line_length = 79 45 | max_doc_length = 72 46 | 47 | [coverage:run] 48 | plugins = covdefaults 49 | omit = testing/data 50 | 51 | [coverage:report] 52 | fail_under = 93 53 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | setup() 3 | -------------------------------------------------------------------------------- /testing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCQA/pycodestyle/a98638490e3c799efeebf0af638940d5a581b3c9/testing/__init__.py -------------------------------------------------------------------------------- /testing/data/E10.py: -------------------------------------------------------------------------------- 1 | #: E101 E122 W191 W191 2 | if True: 3 | pass 4 | 5 | change_2_log = \ 6 | """Change 2 by slamb@testclient on 2006/04/13 21:46:23 7 | 8 | creation 9 | """ 10 | 11 | p4change = { 12 | 2: change_2_log, 13 | } 14 | 15 | 16 | class TestP4Poller(unittest.TestCase): 17 | def setUp(self): 18 | self.setUpGetProcessOutput() 19 | return self.setUpChangeSource() 20 | 21 | def tearDown(self): 22 | pass 23 | 24 | # 25 | #: E101 W191 W191 26 | if True: 27 | foo(1, 28 | 2) 29 | #: E101 E101 W191 W191 30 | def test_keys(self): 31 | """areas.json - All regions are accounted for.""" 32 | expected = set([ 33 | u'Norrbotten', 34 | u'V\xe4sterbotten', 35 | ]) 36 | #: E101 W191 37 | if True: 38 | print(""" 39 | tab at start of this line 40 | """) 41 | -------------------------------------------------------------------------------- /testing/data/E11.py: -------------------------------------------------------------------------------- 1 | #: E111 2 | if x > 2: 3 | print x 4 | #: E111 E117 5 | if True: 6 | print 7 | #: E112 8 | if False: 9 | print 10 | #: E113 11 | print 12 | print 13 | #: E114 E116 14 | mimetype = 'application/x-directory' 15 | # 'httpd/unix-directory' 16 | create_date = False 17 | #: E116 E116 E116 18 | def start(self): 19 | if True: 20 | self.master.start() 21 | # try: 22 | # self.master.start() 23 | # except MasterExit: 24 | # self.shutdown() 25 | # finally: 26 | # sys.exit() 27 | #: E115 E115 E115 E115 E115 E115 28 | def start(self): 29 | if True: 30 | # try: 31 | # self.master.start() 32 | # except MasterExit: 33 | # self.shutdown() 34 | # finally: 35 | # sys.exit() 36 | self.master.start() 37 | #: E117 38 | def start(): 39 | print 40 | #: E117 W191 41 | def start(): 42 | print 43 | -------------------------------------------------------------------------------- /testing/data/E12.py: -------------------------------------------------------------------------------- 1 | #: E121 2 | print "E121", ( 3 | "dent") 4 | #: E122 5 | print "E122", ( 6 | "dent") 7 | #: E123 8 | my_list = [ 9 | 1, 2, 3, 10 | 4, 5, 6, 11 | ] 12 | #: E124 13 | print "E124", ("visual", 14 | "indent_two" 15 | ) 16 | #: E124 17 | print "E124", ("visual", 18 | "indent_five" 19 | ) 20 | #: E124 21 | a = (123, 22 | ) 23 | #: E129 W503 24 | if (row < 0 or self.moduleCount <= row 25 | or col < 0 or self.moduleCount <= col): 26 | raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) 27 | #: E126 28 | print "E126", ( 29 | "dent") 30 | #: E126 31 | print "E126", ( 32 | "dent") 33 | #: E127 34 | print "E127", ("over-", 35 | "over-indent") 36 | #: E128 37 | print "E128", ("visual", 38 | "hanging") 39 | #: E128 40 | print "E128", ("under-", 41 | "under-indent") 42 | #: 43 | 44 | 45 | #: E126 46 | my_list = [ 47 | 1, 2, 3, 48 | 4, 5, 6, 49 | ] 50 | #: E121 51 | result = { 52 | 'key1': 'value', 53 | 'key2': 'value', 54 | } 55 | #: E126 E126 56 | rv.update(dict.fromkeys(( 57 | 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 58 | 'reasonComment_de', 'reasonComment_it'), 59 | '?'), 60 | "foo") 61 | #: E126 62 | abricot = 3 + \ 63 | 4 + \ 64 | 5 + 6 65 | #: E131 66 | print "hello", ( 67 | 68 | "there", 69 | # "john", 70 | "dude") 71 | #: E126 72 | part = set_mimetype(( 73 | a.get('mime_type', 'text')), 74 | 'default') 75 | #: 76 | 77 | 78 | #: E122 79 | if True: 80 | result = some_function_that_takes_arguments( 81 | 'a', 'b', 'c', 82 | 'd', 'e', 'f', 83 | ) 84 | #: E122 85 | if some_very_very_very_long_variable_name or var \ 86 | or another_very_long_variable_name: 87 | raise Exception() 88 | #: E122 89 | if some_very_very_very_long_variable_name or var[0] \ 90 | or another_very_long_variable_name: 91 | raise Exception() 92 | #: E122 93 | if True: 94 | if some_very_very_very_long_variable_name or var \ 95 | or another_very_long_variable_name: 96 | raise Exception() 97 | #: E122 98 | if True: 99 | if some_very_very_very_long_variable_name or var[0] \ 100 | or another_very_long_variable_name: 101 | raise Exception() 102 | #: E122 103 | dictionary = [ 104 | "is": { 105 | "nested": yes(), 106 | }, 107 | ] 108 | #: E122 109 | setup('', 110 | scripts=[''], 111 | classifiers=[ 112 | 'Development Status :: 4 - Beta', 113 | 'Environment :: Console', 114 | 'Intended Audience :: Developers', 115 | ]) 116 | #: 117 | 118 | 119 | #: E123 W291 120 | print "E123", ( 121 | "bad", "hanging", "close" 122 | ) 123 | # 124 | #: E123 E123 E123 125 | result = { 126 | 'foo': [ 127 | 'bar', { 128 | 'baz': 'frop', 129 | } 130 | ] 131 | } 132 | #: E123 133 | result = some_function_that_takes_arguments( 134 | 'a', 'b', 'c', 135 | 'd', 'e', 'f', 136 | ) 137 | #: E124 138 | my_list = [1, 2, 3, 139 | 4, 5, 6, 140 | ] 141 | #: E124 142 | my_list = [1, 2, 3, 143 | 4, 5, 6, 144 | ] 145 | #: E124 146 | result = some_function_that_takes_arguments('a', 'b', 'c', 147 | 'd', 'e', 'f', 148 | ) 149 | #: E124 150 | fooff(aaaa, 151 | cca( 152 | vvv, 153 | dadd 154 | ), fff, 155 | ) 156 | #: E124 157 | fooff(aaaa, 158 | ccaaa( 159 | vvv, 160 | dadd 161 | ), 162 | fff, 163 | ) 164 | #: E124 165 | d = dict('foo', 166 | help="exclude files or directories which match these " 167 | "comma separated patterns (default: %s)" % DEFAULT_EXCLUDE 168 | ) 169 | #: E124 E128 E128 170 | if line_removed: 171 | self.event(cr, uid, 172 | name="Removing the option for contract", 173 | description="contract line has been removed", 174 | ) 175 | #: 176 | 177 | 178 | #: E125 179 | if foo is None and bar is "frop" and \ 180 | blah == 'yeah': 181 | blah = 'yeahnah' 182 | #: E125 183 | # Further indentation required as indentation is not distinguishable 184 | 185 | 186 | def long_function_name( 187 | var_one, var_two, var_three, 188 | var_four): 189 | print(var_one) 190 | # 191 | #: E125 192 | 193 | 194 | def qualify_by_address( 195 | self, cr, uid, ids, context=None, 196 | params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): 197 | """ This gets called by the web server """ 198 | #: E129 W503 199 | if (a == 2 200 | or b == "abc def ghi" 201 | "jkl mno"): 202 | return True 203 | #: 204 | 205 | 206 | #: E126 207 | my_list = [ 208 | 1, 2, 3, 209 | 4, 5, 6, 210 | ] 211 | #: E126 212 | abris = 3 + \ 213 | 4 + \ 214 | 5 + 6 215 | #: E126 216 | fixed = re.sub(r'\t+', ' ', target[c::-1], 1)[::-1] + \ 217 | target[c + 1:] 218 | #: E126 E126 219 | rv.update(dict.fromkeys(( 220 | 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 221 | 'reasonComment_de', 'reasonComment_it'), 222 | '?'), 223 | "foo") 224 | #: E126 225 | eat_a_dict_a_day({ 226 | "foo": "bar", 227 | }) 228 | #: E126 W503 229 | if ( 230 | x == ( 231 | 3 232 | ) 233 | or y == 4): 234 | pass 235 | #: E126 W503 W503 236 | if ( 237 | x == ( 238 | 3 239 | ) 240 | or x == ( 241 | 3) 242 | or y == 4): 243 | pass 244 | #: E131 245 | troublesome_hash = { 246 | "hash": "value", 247 | "long": "the quick brown fox jumps over the lazy dog before doing a " 248 | "somersault", 249 | } 250 | #: 251 | 252 | 253 | #: E128 254 | # Arguments on first line forbidden when not using vertical alignment 255 | foo = long_function_name(var_one, var_two, 256 | var_three, var_four) 257 | # 258 | #: E128 259 | print('l.%s\t%s\t%s\t%r' % 260 | (token[2][0], pos, tokenize.tok_name[token[0]], token[1])) 261 | #: E128 262 | 263 | 264 | def qualify_by_address(self, cr, uid, ids, context=None, 265 | params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): 266 | """ This gets called by the web server """ 267 | #: 268 | 269 | 270 | #: E128 271 | foo(1, 2, 3, 272 | 4, 5, 6) 273 | #: E128 274 | foo(1, 2, 3, 275 | 4, 5, 6) 276 | #: E128 277 | foo(1, 2, 3, 278 | 4, 5, 6) 279 | #: E128 280 | foo(1, 2, 3, 281 | 4, 5, 6) 282 | #: E127 283 | foo(1, 2, 3, 284 | 4, 5, 6) 285 | #: E127 286 | foo(1, 2, 3, 287 | 4, 5, 6) 288 | #: E127 289 | foo(1, 2, 3, 290 | 4, 5, 6) 291 | #: E127 292 | foo(1, 2, 3, 293 | 4, 5, 6) 294 | #: E127 295 | foo(1, 2, 3, 296 | 4, 5, 6) 297 | #: E127 298 | foo(1, 2, 3, 299 | 4, 5, 6) 300 | #: E127 301 | foo(1, 2, 3, 302 | 4, 5, 6) 303 | #: E127 304 | foo(1, 2, 3, 305 | 4, 5, 6) 306 | #: E127 307 | foo(1, 2, 3, 308 | 4, 5, 6) 309 | #: E128 E128 310 | if line_removed: 311 | self.event(cr, uid, 312 | name="Removing the option for contract", 313 | description="contract line has been removed", 314 | ) 315 | #: E124 E127 E127 316 | if line_removed: 317 | self.event(cr, uid, 318 | name="Removing the option for contract", 319 | description="contract line has been removed", 320 | ) 321 | #: E127 322 | rv.update(d=('a', 'b', 'c'), 323 | e=42) 324 | # 325 | #: E127 W503 326 | rv.update(d=('a' + 'b', 'c'), 327 | e=42, f=42 328 | + 42) 329 | #: E127 W503 330 | input1 = {'a': {'calc': 1 + 2}, 'b': 1 331 | + 42} 332 | #: E128 W503 333 | rv.update(d=('a' + 'b', 'c'), 334 | e=42, f=(42 335 | + 42)) 336 | #: E123 337 | if True: 338 | def example_issue254(): 339 | return [node.copy( 340 | ( 341 | replacement 342 | # First, look at all the node's current children. 343 | for child in node.children 344 | # Replace them. 345 | for replacement in replace(child) 346 | ), 347 | dict(name=token.undefined) 348 | )] 349 | #: E125:2:5 E125:8:5 350 | if (""" 351 | """): 352 | pass 353 | 354 | for foo in """ 355 | abc 356 | 123 357 | """.strip().split(): 358 | print(foo) 359 | #: E122:6:5 E122:7:5 E122:8:1 360 | print dedent( 361 | ''' 362 | mkdir -p ./{build}/ 363 | mv ./build/ ./{build}/%(revision)s/ 364 | '''.format( 365 | build='build', 366 | # more stuff 367 | ) 368 | ) 369 | #: E701:1:8 E231:1:8 E122:2:1 E203:4:8 E128:5:1 370 | if True:\ 371 | print(True) 372 | 373 | print(a 374 | , end=' ') 375 | #: E127:4:12 376 | def foo(): 377 | pass 378 | raise 123 + \ 379 | 123 380 | #: E127:4:13 381 | class Eggs: 382 | pass 383 | assert 123456 == \ 384 | 123456 385 | #: E127:4:11 386 | def f1(): 387 | print('foo') 388 | with open('/path/to/some/file/you/want/to/read') as file_1, \ 389 | open('/path/to/some/file/being/written', 'w') as file_2: 390 | file_2.write(file_1.read()) 391 | #: E127:5:11 392 | def f1(): 393 | print('foo') 394 | with open('/path/to/some/file/you/want/to/read') as file_1, \ 395 | open('/path/to/some/file/being/written', 'w') as file_2, \ 396 | open('later-misindent'): 397 | file_2.write(file_1.read()) 398 | -------------------------------------------------------------------------------- /testing/data/E12not.py: -------------------------------------------------------------------------------- 1 | if ( 2 | x == ( 3 | 3 4 | ) or y == 4): 5 | pass 6 | 7 | y = x == 2 \ 8 | or x == 3 9 | 10 | if x == 2 \ 11 | or y > 1 \ 12 | or x == 3: 13 | pass 14 | 15 | if x == 2 \ 16 | or y > 1 \ 17 | or x == 3: 18 | pass 19 | #: W503 20 | if (foo == bar 21 | and baz == frop): 22 | pass 23 | #: W503 24 | if ( 25 | foo == bar 26 | and baz == frop 27 | ): 28 | pass 29 | 30 | 31 | a = ( 32 | ) 33 | 34 | a = (123, 35 | ) 36 | 37 | 38 | # 39 | 40 | 41 | if start[1] > end_col and not ( 42 | over_indent == 4 and indent_next): 43 | return (0, "E121 continuation line over-" 44 | "indented for visual indent") 45 | 46 | 47 | print "OK", ("visual", 48 | "indent") 49 | 50 | print "Okay", ("visual", 51 | "indent_three" 52 | ) 53 | 54 | print "a-ok", ( 55 | "there", 56 | "dude", 57 | ) 58 | 59 | print "hello", ( 60 | "there", 61 | "dude") 62 | 63 | print "hello", ( 64 | 65 | "there", 66 | # "john", 67 | "dude") 68 | 69 | print "hello", ( 70 | "there", "dude") 71 | 72 | print "hello", ( 73 | "there", "dude", 74 | ) 75 | 76 | # Aligned with opening delimiter 77 | foo = long_function_name(var_one, var_two, 78 | var_three, var_four) 79 | 80 | # 81 | # Extra indentation is not necessary. 82 | foo = long_function_name( 83 | var_one, var_two, 84 | var_three, var_four) 85 | 86 | 87 | arm = 'AAA' \ 88 | 'BBB' \ 89 | 'CCC' 90 | 91 | bbb = 'AAA' \ 92 | 'BBB' \ 93 | 'CCC' 94 | 95 | cc = ('AAA' 96 | 'BBB' 97 | 'CCC') 98 | 99 | cc = {'text': 'AAA' 100 | 'BBB' 101 | 'CCC'} 102 | 103 | cc = dict(text='AAA' 104 | 'BBB') 105 | 106 | sat = 'AAA' \ 107 | 'BBB' \ 108 | 'iii' \ 109 | 'CCC' 110 | #: W504 W504 111 | abricot = (3 + 112 | 4 + 113 | 5 + 6) 114 | 115 | abricot = 3 + \ 116 | 4 + \ 117 | 5 + 6 118 | 119 | part = [-1, 2, 3, 120 | 4, 5, 6] 121 | 122 | part = [-1, (2, 3, 123 | 4, 5, 6), 7, 124 | 8, 9, 0] 125 | 126 | fnct(1, 2, 3, 127 | 4, 5, 6) 128 | 129 | fnct(1, 2, 3, 130 | 4, 5, 6, 131 | 7, 8, 9, 132 | 10, 11) 133 | 134 | 135 | def long_function_name( 136 | var_one, var_two, var_three, 137 | var_four): 138 | print(var_one) 139 | #: W504 140 | if ((row < 0 or self.moduleCount <= row or 141 | col < 0 or self.moduleCount <= col)): 142 | raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) 143 | 144 | 145 | result = { 146 | 'foo': [ 147 | 'bar', { 148 | 'baz': 'frop', 149 | } 150 | ] 151 | } 152 | 153 | 154 | foo = my.func({ 155 | "foo": "bar", 156 | }, "baz") 157 | 158 | 159 | # 160 | 161 | fooff(aaaa, 162 | cca( 163 | vvv, 164 | dadd 165 | ), fff, 166 | ggg) 167 | 168 | fooff(aaaa, 169 | abbb, 170 | cca( 171 | vvv, 172 | aaa, 173 | dadd), 174 | "visual indentation is not a multiple of four",) 175 | # 176 | 177 | if bar: 178 | return ( 179 | start, 'E121 lines starting with a ' 180 | 'closing bracket should be indented ' 181 | "to match that of the opening " 182 | "bracket's line" 183 | ) 184 | #: W504 185 | # you want vertical alignment, so use a parens 186 | if ((foo.bar("baz") and 187 | foo.bar("frop") 188 | )): 189 | print "yes" 190 | #: W504 191 | # also ok, but starting to look like LISP 192 | if ((foo.bar("baz") and 193 | foo.bar("frop"))): 194 | print "yes" 195 | #: W504 196 | if (a == 2 or 197 | b == "abc def ghi" 198 | "jkl mno"): 199 | return True 200 | #: W504 201 | if (a == 2 or 202 | b == """abc def ghi 203 | jkl mno"""): 204 | return True 205 | 206 | if length > options.max_line_length: 207 | return options.max_line_length, \ 208 | "E501 line too long (%d characters)" % length 209 | 210 | 211 | # 212 | 213 | 214 | print 'l.{line}\t{pos}\t{name}\t{text}'.format( 215 | line=token[2][0], 216 | pos=pos, 217 | name=tokenize.tok_name[token[0]], 218 | text=repr(token[1]), 219 | ) 220 | 221 | print('%-7d %s per second (%d total)' % ( 222 | options.counters[key] / elapsed, key, 223 | options.counters[key])) 224 | #: W504 225 | if os.path.exists(os.path.join(path, PEP8_BIN)): 226 | cmd = ([os.path.join(path, PEP8_BIN)] + 227 | self._pep8_options(targetfile)) 228 | #: W504 229 | fixed = (re.sub(r'\t+', ' ', target[c::-1], 1)[::-1] + 230 | target[c + 1:]) 231 | #: W504 232 | fixed = ( 233 | re.sub(r'\t+', ' ', target[c::-1], 1)[::-1] + 234 | target[c + 1:] 235 | ) 236 | #: W504 237 | if foo is None and bar is "frop" and \ 238 | blah == 'yeah': 239 | blah = 'yeahnah' 240 | 241 | 242 | """This is a multi-line 243 | docstring.""" 244 | 245 | 246 | if blah: 247 | # is this actually readable? :) 248 | multiline_literal = """ 249 | while True: 250 | if True: 251 | 1 252 | """.lstrip() 253 | multiline_literal = ( 254 | """ 255 | while True: 256 | if True: 257 | 1 258 | """.lstrip() 259 | ) 260 | multiline_literal = ( 261 | """ 262 | while True: 263 | if True: 264 | 1 265 | """ 266 | .lstrip() 267 | ) 268 | 269 | 270 | if blah: 271 | multiline_visual = (""" 272 | while True: 273 | if True: 274 | 1 275 | """ 276 | .lstrip()) 277 | 278 | 279 | rv = {'aaa': 42} 280 | rv.update(dict.fromkeys(( 281 | 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 282 | 'reasonComment_de', 'reasonComment_it'), '?')) 283 | 284 | rv.update(dict.fromkeys(('qualif_nr', 'reasonComment_en', 285 | 'reasonComment_fr', 'reasonComment_de', 286 | 'reasonComment_it'), '?')) 287 | 288 | rv.update(dict.fromkeys(('qualif_nr', 'reasonComment_en', 'reasonComment_fr', 289 | 'reasonComment_de', 'reasonComment_it'), '?')) 290 | 291 | 292 | rv.update(dict.fromkeys( 293 | ('qualif_nr', 'reasonComment_en', 'reasonComment_fr', 294 | 'reasonComment_de', 'reasonComment_it'), '?' 295 | ), "foo", context={ 296 | 'alpha': 4, 'beta': 53242234, 'gamma': 17, 297 | }) 298 | 299 | 300 | rv.update( 301 | dict.fromkeys(( 302 | 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 303 | 'reasonComment_de', 'reasonComment_it'), '?'), 304 | "foo", 305 | context={ 306 | 'alpha': 4, 'beta': 53242234, 'gamma': 17, 307 | }, 308 | ) 309 | 310 | 311 | # 312 | 313 | 314 | event_obj.write(cursor, user_id, { 315 | 'user': user, 316 | 'summary': text, 317 | 'data': data, 318 | }) 319 | 320 | event_obj.write(cursor, user_id, { 321 | 'user': user, 322 | 'summary': text, 323 | 'data': {'aaa': 1, 'bbb': 2}, 324 | }) 325 | 326 | event_obj.write(cursor, user_id, { 327 | 'user': user, 328 | 'summary': text, 329 | 'data': { 330 | 'aaa': 1, 331 | 'bbb': 2}, 332 | }) 333 | 334 | event_obj.write(cursor, user_id, { 335 | 'user': user, 336 | 'summary': text, 337 | 'data': {'timestamp': now, 'content': { 338 | 'aaa': 1, 339 | 'bbb': 2 340 | }}, 341 | }) 342 | 343 | 344 | def qualify_by_address( 345 | self, cr, uid, ids, context=None, 346 | params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): 347 | """ This gets called by the web server """ 348 | 349 | 350 | def qualify_by_address(self, cr, uid, ids, context=None, 351 | params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): 352 | """ This gets called by the web server """ 353 | 354 | 355 | _ipv4_re = re.compile(r'^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' 356 | r'(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' 357 | r'(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' 358 | r'(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$') 359 | 360 | 361 | fct(""" 362 | AAA """ + status_2_string) 363 | 364 | 365 | if context: 366 | msg = """\ 367 | action: GET-CONFIG 368 | payload: 369 | ip_address: "%(ip)s" 370 | username: "%(username)s" 371 | """ % context 372 | 373 | 374 | if context: 375 | msg = """\ 376 | action: \ 377 | GET-CONFIG 378 | """ % context 379 | 380 | 381 | if context: 382 | msg = """\ 383 | action: """\ 384 | """GET-CONFIG 385 | """ % context 386 | 387 | 388 | def unicode2html(s): 389 | """Convert the characters &<>'" in string s to HTML-safe sequences. 390 | Convert newline to
too.""" 391 | return unicode((s or '').replace('&', '&') 392 | .replace('>', '>') 393 | .replace('<', '<') 394 | .replace("'", ''') 395 | .replace('"', '"') 396 | .replace('\n', '
\n')) 397 | 398 | 399 | # 400 | parser.add_option('--count', action='store_true', 401 | help="print total number of errors and warnings " 402 | "to standard error and set exit code to 1 if " 403 | "total is not null") 404 | 405 | parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE, 406 | help="exclude files or directories which match these " 407 | "comma separated patterns (default: %s)" % 408 | DEFAULT_EXCLUDE) 409 | 410 | add_option('--count', 411 | help="print total number of errors " 412 | "to standard error total is not null") 413 | 414 | add_option('--count', 415 | help="print total number of errors " 416 | "to standard error " 417 | "total is not null") 418 | 419 | 420 | # 421 | 422 | 423 | help = ("print total number of errors " + 424 | "to standard error") 425 | 426 | help = "print total number of errors " \ 427 | "to standard error" 428 | 429 | help = u"print total number of errors " \ 430 | u"to standard error" 431 | 432 | help = b"print total number of errors " \ 433 | b"to standard error" 434 | 435 | help = br"print total number of errors " \ 436 | br"to standard error" 437 | 438 | help = f"print total number of errors " \ 439 | f"to standard error" 440 | 441 | d = dict('foo', help="exclude files or directories which match these " 442 | "comma separated patterns (default: %s)" % 443 | DEFAULT_EXCLUDE) 444 | 445 | d = dict('foo', help=u"exclude files or directories which match these " 446 | u"comma separated patterns (default: %s)" % 447 | DEFAULT_EXCLUDE) 448 | 449 | d = dict('foo', help=b"exclude files or directories which match these " 450 | b"comma separated patterns (default: %s)" % 451 | DEFAULT_EXCLUDE) 452 | 453 | d = dict('foo', help=br"exclude files or directories which match these " 454 | br"comma separated patterns (default: %s)" % 455 | DEFAULT_EXCLUDE) 456 | 457 | d = dict('foo', 458 | help="exclude files or directories which match these " 459 | "comma separated patterns (default: %s)" % 460 | DEFAULT_EXCLUDE) 461 | 462 | d = dict('foo', 463 | help="exclude files or directories which match these " 464 | "comma separated patterns (default: %s, %s)" % 465 | (DEFAULT_EXCLUDE, DEFAULT_IGNORE) 466 | ) 467 | 468 | d = dict('foo', 469 | help="exclude files or directories which match these " 470 | "comma separated patterns (default: %s, %s)" % 471 | # who knows what might happen here? 472 | (DEFAULT_EXCLUDE, DEFAULT_IGNORE) 473 | ) 474 | 475 | # parens used to allow the indenting. 476 | troublefree_hash = { 477 | "hash": "value", 478 | "long": ("the quick brown fox jumps over the lazy dog before doing a " 479 | "somersault"), 480 | "long key that tends to happen more when you're indented": ( 481 | "stringwithalongtoken you don't want to break" 482 | ), 483 | } 484 | 485 | # another accepted form 486 | troublefree_hash = { 487 | "hash": "value", 488 | "long": "the quick brown fox jumps over the lazy dog before doing " 489 | "a somersault", 490 | ("long key that tends to happen more " 491 | "when you're indented"): "stringwithalongtoken you don't want to break", 492 | } 493 | # confusing but accepted... don't do that 494 | troublesome_hash = { 495 | "hash": "value", 496 | "long": "the quick brown fox jumps over the lazy dog before doing a " 497 | "somersault", 498 | "long key that tends to happen more " 499 | "when you're indented": "stringwithalongtoken you don't want to break", 500 | } 501 | 502 | # 503 | d = dict('foo', 504 | help="exclude files or directories which match these " 505 | "comma separated patterns (default: %s)" % 506 | DEFAULT_EXCLUDE 507 | ) 508 | d = dict('foo', 509 | help="exclude files or directories which match these " 510 | "comma separated patterns (default: %s)" % DEFAULT_EXCLUDE, 511 | foobar="this clearly should work, because it is at " 512 | "the right indent level", 513 | ) 514 | 515 | rv.update(dict.fromkeys( 516 | ('qualif_nr', 'reasonComment_en', 'reasonComment_fr', 517 | 'reasonComment_de', 'reasonComment_it'), 518 | '?'), "foo", 519 | context={'alpha': 4, 'beta': 53242234, 'gamma': 17}) 520 | 521 | 522 | def f(): 523 | try: 524 | if not Debug: 525 | print(''' 526 | If you would like to see debugging output, 527 | try: %s -d5 528 | ''' % sys.argv[0]) 529 | 530 | 531 | d = { # comment 532 | 1: 2 533 | } 534 | 535 | # issue 138 536 | [ 537 | 12, # this is a multi-line inline 538 | # comment 539 | ] 540 | # issue 151 541 | if a > b and \ 542 | c > d: 543 | moo_like_a_cow() 544 | # 545 | my_list = [ 546 | 1, 2, 3, 547 | 4, 5, 6, 548 | ] 549 | 550 | my_list = [1, 2, 3, 551 | 4, 5, 6, 552 | ] 553 | 554 | result = some_function_that_takes_arguments( 555 | 'a', 'b', 'c', 556 | 'd', 'e', 'f', 557 | ) 558 | 559 | result = some_function_that_takes_arguments('a', 'b', 'c', 560 | 'd', 'e', 'f', 561 | ) 562 | 563 | # issue 203 564 | dica = { 565 | ('abc' 566 | 'def'): ( 567 | 'abc'), 568 | } 569 | 570 | (abcdef[0] 571 | [1]) = ( 572 | 'abc') 573 | 574 | ('abc' 575 | 'def') == ( 576 | 'abc') 577 | 578 | # issue 214 579 | bar( 580 | 1).zap( 581 | 2) 582 | 583 | bar( 584 | 1).zap( 585 | 2) 586 | # 587 | if True: 588 | 589 | def example_issue254(): 590 | return [node.copy( 591 | ( 592 | replacement 593 | # First, look at all the node's current children. 594 | for child in node.children 595 | # Replace them. 596 | for replacement in replace(child) 597 | ), 598 | dict(name=token.undefined) 599 | )] 600 | 601 | 602 | def valid_example(): 603 | return [node.copy(properties=dict( 604 | (key, val if val is not None else token.undefined) 605 | for key, val in node.items() 606 | ))] 607 | 608 | 609 | def other_example(): 610 | return [node.copy(properties=dict( 611 | (key, val if val is not None else token.undefined) 612 | for key, val in node.items() 613 | ))] 614 | 615 | 616 | foo([ 617 | 'bug' 618 | ]) 619 | 620 | # issue 144, finally! 621 | some_hash = { 622 | "long key that tends to happen more when you're indented": 623 | "stringwithalongtoken you don't want to break", 624 | } 625 | 626 | { 627 | 1: 628 | 999999 if True 629 | else 0, 630 | } 631 | 632 | 633 | print dedent( 634 | ''' 635 | mkdir -p ./{build}/ 636 | mv ./build/ ./{build}/%(revision)s/ 637 | '''.format( 638 | build='build', 639 | # more stuff 640 | ) 641 | ) 642 | 643 | 644 | def foo(): 645 | pass 646 | raise 123 + \ 647 | 123 648 | 649 | 650 | class Eggs: 651 | pass 652 | assert 123456 == \ 653 | 123456 654 | 655 | 656 | def f1(): 657 | print('foo') 658 | with open('/path/to/some/file/you/want/to/read') as file_1, \ 659 | open('/path/to/some/file/being/written', 'w') as file_2, \ 660 | open('just-making-sure-more-continuations-also-work'): 661 | file_2.write(file_1.read()) 662 | -------------------------------------------------------------------------------- /testing/data/E20.py: -------------------------------------------------------------------------------- 1 | #: E201:1:6 2 | spam( ham[1], {eggs: 2}) 3 | #: E201:1:10 4 | spam(ham[ 1], {eggs: 2}) 5 | #: E201:1:15 6 | spam(ham[1], { eggs: 2}) 7 | #: E201:1:6 8 | spam( ham[1], {eggs: 2}) 9 | #: E201:1:10 10 | spam(ham[ 1], {eggs: 2}) 11 | #: E201:1:15 12 | spam(ham[1], { eggs: 2}) 13 | #: Okay 14 | spam(ham[1], {eggs: 2}) 15 | #: 16 | 17 | 18 | #: E202:1:23 19 | spam(ham[1], {eggs: 2} ) 20 | #: E202:1:22 21 | spam(ham[1], {eggs: 2 }) 22 | #: E202:1:11 23 | spam(ham[1 ], {eggs: 2}) 24 | #: E202:1:23 25 | spam(ham[1], {eggs: 2} ) 26 | #: E202:1:22 27 | spam(ham[1], {eggs: 2 }) 28 | #: E202:1:11 29 | spam(ham[1 ], {eggs: 2}) 30 | #: Okay 31 | spam(ham[1], {eggs: 2}) 32 | 33 | result = func( 34 | arg1='some value', 35 | arg2='another value', 36 | ) 37 | 38 | result = func( 39 | arg1='some value', 40 | arg2='another value' 41 | ) 42 | 43 | result = [ 44 | item for item in items 45 | if item > 5 46 | ] 47 | #: 48 | 49 | 50 | #: E203:1:10 51 | if x == 4 : 52 | print x, y 53 | x, y = y, x 54 | #: E203:1:10 55 | if x == 4 : 56 | print x, y 57 | x, y = y, x 58 | #: E203:2:15 E702:2:16 59 | if x == 4: 60 | print x, y ; x, y = y, x 61 | #: E203:2:15 E702:2:16 62 | if x == 4: 63 | print x, y ; x, y = y, x 64 | #: E203:3:13 65 | if x == 4: 66 | print x, y 67 | x, y = y , x 68 | #: E203:3:13 69 | if x == 4: 70 | print x, y 71 | x, y = y , x 72 | #: Okay 73 | if x == 4: 74 | print x, y 75 | x, y = y, x 76 | a[b1, :] == a[b1, ...] 77 | b = a[:, b1] 78 | #: E204:1:2 79 | @ decorator 80 | def f(): 81 | pass 82 | #: E204:1:2 83 | @ decorator 84 | def f(): 85 | pass 86 | #: E204:1:2 87 | @ decorator 88 | def f(): 89 | pass 90 | #: E204:2:6 91 | if True: 92 | @ decorator 93 | def f(): 94 | pass 95 | #: 96 | -------------------------------------------------------------------------------- /testing/data/E21.py: -------------------------------------------------------------------------------- 1 | #: E211 2 | spam (1) 3 | #: E211 E211 4 | dict ['key'] = list [index] 5 | #: E211 6 | dict['key'] ['subkey'] = list[index] 7 | #: Okay 8 | spam(1) 9 | dict['key'] = list[index] 10 | 11 | 12 | # This is not prohibited by PEP8, but avoid it. 13 | class Foo (Bar, Baz): 14 | pass 15 | -------------------------------------------------------------------------------- /testing/data/E22.py: -------------------------------------------------------------------------------- 1 | #: E221 2 | a = 12 + 3 3 | b = 4 + 5 4 | #: E221 E221 5 | x = 1 6 | y = 2 7 | long_variable = 3 8 | #: E221 E221 9 | x[0] = 1 10 | x[1] = 2 11 | long_variable = 3 12 | #: E221 E221 13 | x = f(x) + 1 14 | y = long_variable + 2 15 | z = x[0] + 3 16 | #: E221:3:14 17 | text = """ 18 | bar 19 | foo %s""" % rofl 20 | #: Okay 21 | x = 1 22 | y = 2 23 | long_variable = 3 24 | #: 25 | 26 | 27 | #: E222 28 | a = a + 1 29 | b = b + 10 30 | #: E222 E222 31 | x = -1 32 | y = -2 33 | long_variable = 3 34 | #: E222 E222 35 | x[0] = 1 36 | x[1] = 2 37 | long_variable = 3 38 | #: 39 | 40 | 41 | #: E223 42 | foobart = 4 43 | a = 3 # aligned with tab 44 | #: 45 | 46 | 47 | #: E224 48 | a += 1 49 | b += 1000 50 | #: 51 | 52 | 53 | #: E225 54 | submitted +=1 55 | #: E225 56 | submitted+= 1 57 | #: E225 58 | c =-1 59 | #: E225 60 | x = x /2 - 1 61 | #: E225 62 | c = alpha -4 63 | #: E225 64 | c = alpha- 4 65 | #: E225 66 | z = x **y 67 | #: E225 68 | z = (x + 1) **y 69 | #: E225 70 | z = (x + 1)** y 71 | #: E225 72 | _1kB = _1MB >>10 73 | #: E225 74 | _1kB = _1MB>> 10 75 | #: E225 E225 76 | i=i+ 1 77 | #: E225 E225 78 | i=i +1 79 | #: E225 80 | i = 1and 1 81 | #: E225 82 | i = 1or 0 83 | #: E225 84 | 1is 1 85 | #: E225 86 | 1in [] 87 | #: E225 88 | i = 1 @2 89 | #: E225 90 | i = 1@ 2 91 | #: E225 E226 92 | i=i+1 93 | #: E225 E226 94 | i =i+1 95 | #: E225 E226 96 | i= i+1 97 | #: E225 E226 98 | c = (a +b)*(a - b) 99 | #: E225 E226 100 | c = (a+ b)*(a - b) 101 | #: E225 102 | x[lambda: None]=1 103 | #: 104 | 105 | #: E226 106 | z = 2//30 107 | #: E226 E226 108 | c = (a+b) * (a-b) 109 | #: E226 110 | norman = True+False 111 | #: E226 112 | x = x*2 - 1 113 | #: E226 114 | x = x/2 - 1 115 | #: E226 E226 116 | hypot2 = x*x + y*y 117 | #: E226 118 | c = (a + b)*(a - b) 119 | #: E226 120 | def halves(n): 121 | return (i//2 for i in range(n)) 122 | #: E227 123 | _1kB = _1MB>>10 124 | #: E227 125 | _1MB = _1kB<<10 126 | #: E227 127 | a = b|c 128 | #: E227 129 | b = c&a 130 | #: E227 131 | c = b^a 132 | #: E228 133 | a = b%c 134 | #: E228 135 | msg = fmt%(errno, errmsg) 136 | #: E228 137 | msg = "Error %d occurred"%errno 138 | #: 139 | 140 | #: Okay 141 | i = i + 1 142 | submitted += 1 143 | x = x * 2 - 1 144 | hypot2 = x * x + y * y 145 | c = (a + b) * (a - b) 146 | _1MiB = 2 ** 20 147 | _1TiB = 2**30 148 | foo(bar, key='word', *args, **kwargs) 149 | baz(**kwargs) 150 | negative = -1 151 | spam(-1) 152 | -negative 153 | func1(lambda *args, **kw: (args, kw)) 154 | func2(lambda a, b=h[:], c=0: (a, b, c)) 155 | if not -5 < x < +5: 156 | print >>sys.stderr, "x is out of range." 157 | print >> sys.stdout, "x is an integer." 158 | x = x / 2 - 1 159 | x = 1 @ 2 160 | 161 | if alpha[:-i]: 162 | *a, b = (1, 2, 3) 163 | 164 | 165 | def squares(n): 166 | return (i**2 for i in range(n)) 167 | 168 | 169 | ENG_PREFIXES = { 170 | -6: "\u03bc", # Greek letter mu 171 | -3: "m", 172 | } 173 | #: 174 | -------------------------------------------------------------------------------- /testing/data/E23.py: -------------------------------------------------------------------------------- 1 | #: E231 2 | a = (1,2) 3 | #: E231 4 | a[b1,:] 5 | #: E231 6 | a = [{'a':''}] 7 | #: Okay 8 | a = (4,) 9 | b = (5, ) 10 | c = {'text': text[5:]} 11 | 12 | result = { 13 | 'key1': 'value', 14 | 'key2': 'value', 15 | } 16 | -------------------------------------------------------------------------------- /testing/data/E24.py: -------------------------------------------------------------------------------- 1 | #: E241 2 | a = (1, 2) 3 | #: Okay 4 | b = (1, 20) 5 | #: E242 6 | a = (1, 2) # tab before 2 7 | #: Okay 8 | b = (1, 20) # space before 20 9 | #: E241 E241 E241 10 | # issue 135 11 | more_spaces = [a, b, 12 | ef, +h, 13 | c, -d] 14 | -------------------------------------------------------------------------------- /testing/data/E25.py: -------------------------------------------------------------------------------- 1 | #: E251 E251 2 | def foo(bar = False): 3 | '''Test function with an error in declaration''' 4 | pass 5 | #: E251 6 | foo(bar= True) 7 | #: E251 8 | foo(bar =True) 9 | #: E251 E251 10 | foo(bar = True) 11 | #: E251 12 | y = bar(root= "sdasd") 13 | #: E251:2:29 14 | parser.add_argument('--long-option', 15 | default= 16 | "/rather/long/filesystem/path/here/blah/blah/blah") 17 | #: E251:1:45 18 | parser.add_argument('--long-option', default 19 | ="/rather/long/filesystem/path/here/blah/blah/blah") 20 | #: E251:3:8 E251:3:10 21 | foo(True, 22 | baz=(1, 2), 23 | biz = 'foo' 24 | ) 25 | #: Okay 26 | foo(bar=(1 == 1)) 27 | foo(bar=(1 != 1)) 28 | foo(bar=(1 >= 1)) 29 | foo(bar=(1 <= 1)) 30 | (options, args) = parser.parse_args() 31 | d[type(None)] = _deepcopy_atomic 32 | 33 | # Annotated Function Definitions 34 | #: Okay 35 | def munge(input: AnyStr, sep: AnyStr = None, limit=1000, 36 | extra: Union[str, dict] = None) -> AnyStr: 37 | pass 38 | #: Okay 39 | async def add(a: int = 0, b: int = 0) -> int: 40 | return a + b 41 | # Previously E251 four times 42 | #: E271:1:6 43 | async def add(a: int = 0, b: int = 0) -> int: 44 | return a + b 45 | #: E252:1:15 E252:1:16 E252:1:27 E252:1:36 46 | def add(a: int=0, b: int =0, c: int= 0) -> int: 47 | return a + b + c 48 | #: Okay 49 | def add(a: int = _default(name='f')): 50 | return a 51 | -------------------------------------------------------------------------------- /testing/data/E26.py: -------------------------------------------------------------------------------- 1 | #: E261:1:5 2 | pass # an inline comment 3 | #: E262:1:12 4 | x = x + 1 #Increment x 5 | #: E262:1:12 6 | x = x + 1 # Increment x 7 | #: E262:1:12 8 | x = y + 1 #: Increment x 9 | #: E265:1:1 10 | #Block comment 11 | a = 1 12 | #: E265:2:1 13 | m = 42 14 | #! This is important 15 | mx = 42 - 42 16 | #: E266:3:5 E266:6:5 17 | def how_it_feel(r): 18 | 19 | ### This is a variable ### 20 | a = 42 21 | 22 | ### Of course it is unused 23 | return 24 | #: E265:1:1 E266:2:1 25 | ##if DEBUG: 26 | ## logging.error() 27 | #: W291:1:42 28 | ######################################### 29 | #: 30 | 31 | #: Okay 32 | #!/usr/bin/env python 33 | 34 | pass # an inline comment 35 | x = x + 1 # Increment x 36 | y = y + 1 #: Increment x 37 | 38 | # Block comment 39 | a = 1 40 | 41 | # Block comment1 42 | 43 | # Block comment2 44 | aaa = 1 45 | 46 | 47 | # example of docstring (not parsed) 48 | def oof(): 49 | """ 50 | #foo not parsed 51 | """ 52 | 53 | #################################################################### 54 | # A SEPARATOR # 55 | #################################################################### 56 | 57 | # ################################################################ # 58 | # ####################### another separator ###################### # 59 | # ################################################################ # 60 | #: E262:3:9 61 | # -*- coding: utf8 -*- 62 | #  (One space one NBSP) Ok for block comment 63 | a = 42 #  (One space one NBSP) 64 | #: E262:2:9 65 | # (Two spaces) Ok for block comment 66 | a = 42 # (Two spaces) 67 | -------------------------------------------------------------------------------- /testing/data/E27.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | True and False 3 | #: E271 4 | True and False 5 | #: E272 6 | True and False 7 | #: E271 8 | if 1: 9 | #: E273 10 | True and False 11 | #: E273 E274 12 | True and False 13 | #: E271 14 | a and b 15 | #: E271 16 | 1 and b 17 | #: E271 18 | a and 2 19 | #: E271 E272 20 | 1 and b 21 | #: E271 E272 22 | a and 2 23 | #: E272 24 | this and False 25 | #: E273 26 | a and b 27 | #: E274 28 | a and b 29 | #: E273 E274 30 | this and False 31 | #: Okay 32 | from u import (a, b) 33 | from v import c, d 34 | #: E271 35 | from w import (e, f) 36 | #: E275 37 | from w import(e, f) 38 | #: E275 39 | from importable.module import(e, f) 40 | #: E275 41 | try: 42 | from importable.module import(e, f) 43 | except ImportError: 44 | pass 45 | #: E275 46 | if(foo): 47 | pass 48 | else: 49 | pass 50 | #: Okay 51 | matched = {"true": True, "false": False} 52 | #: E275:2:11 53 | if True: 54 | assert(1) 55 | #: Okay 56 | def f(): 57 | print((yield)) 58 | x = (yield) 59 | -------------------------------------------------------------------------------- /testing/data/E30.py: -------------------------------------------------------------------------------- 1 | #: E301:5:5 2 | class X: 3 | 4 | def a(): 5 | pass 6 | def b(): 7 | pass 8 | #: E301:6:5 9 | class X: 10 | 11 | def a(): 12 | pass 13 | # comment 14 | def b(): 15 | pass 16 | #: 17 | 18 | 19 | #: E302:2:1 20 | """Main module.""" 21 | def _main(): 22 | pass 23 | #: E302:2:1 24 | import sys 25 | def get_sys_path(): 26 | return sys.path 27 | #: E302:4:1 28 | def a(): 29 | pass 30 | 31 | def b(): 32 | pass 33 | #: E302:6:1 34 | def a(): 35 | pass 36 | 37 | # comment 38 | 39 | def b(): 40 | pass 41 | #: 42 | #: E302:4:1 43 | def a(): 44 | pass 45 | 46 | async def b(): 47 | pass 48 | #: 49 | 50 | #: E303:5:1 51 | print 52 | 53 | 54 | 55 | print 56 | #: E303:5:1 57 | print 58 | 59 | 60 | 61 | # comment 62 | 63 | print 64 | #: E303:5:5 E303:8:5 65 | def a(): 66 | print 67 | 68 | 69 | # comment 70 | 71 | 72 | # another comment 73 | 74 | print 75 | #: 76 | 77 | 78 | #: E303:6:5 79 | class xyz: 80 | def a(self): 81 | pass 82 | 83 | 84 | def b(self): 85 | pass 86 | #: E303:5:5 87 | if True: 88 | a = 1 89 | 90 | 91 | a = 2 92 | #: E304:3:1 93 | @decorator 94 | 95 | def function(): 96 | pass 97 | #: E303:5:1 98 | #!python 99 | 100 | 101 | 102 | """This class docstring comes on line 5. 103 | It gives error E303: too many blank lines (3) 104 | """ 105 | #: 106 | 107 | #: E305:7:1 108 | def a(): 109 | print 110 | 111 | # comment 112 | 113 | # another comment 114 | a() 115 | #: E305:8:1 116 | def a(): 117 | print 118 | 119 | # comment 120 | 121 | # another comment 122 | 123 | try: 124 | a() 125 | except Exception: 126 | pass 127 | #: E305:5:1 128 | def a(): 129 | print 130 | 131 | # Two spaces before comments, too. 132 | if a(): 133 | a() 134 | #: 135 | 136 | #: E306:3:5 137 | def a(): 138 | x = 1 139 | def b(): 140 | pass 141 | #: E306:3:5 142 | async def a(): 143 | x = 1 144 | def b(): 145 | pass 146 | #: E306:3:5 E306:5:9 147 | def a(): 148 | x = 2 149 | def b(): 150 | x = 1 151 | def c(): 152 | pass 153 | #: E306:3:5 E306:6:5 154 | def a(): 155 | x = 1 156 | class C: 157 | pass 158 | x = 2 159 | def b(): 160 | pass 161 | #: 162 | 163 | #: E305:8:1 164 | # Example from https://github.com/PyCQA/pycodestyle/issues/400 165 | import stuff 166 | 167 | 168 | def main(): 169 | blah, blah 170 | 171 | if __name__ == '__main__': 172 | main() 173 | # Previously just E272:1:6 E272:4:6 174 | #: E302:4:1 E271:1:6 E271:4:6 175 | async def x(): 176 | pass 177 | 178 | async def x(y: int = 1): 179 | pass 180 | #: E704:3:1 E302:3:1 181 | def bar(): 182 | pass 183 | def baz(): pass 184 | #: E704:1:1 E302:2:1 185 | def bar(): pass 186 | def baz(): 187 | pass 188 | #: E704:4:5 E306:4:5 189 | def foo(): 190 | def bar(): 191 | pass 192 | def baz(): pass 193 | #: E704:2:5 E306:3:5 194 | def foo(): 195 | def bar(): pass 196 | def baz(): 197 | pass 198 | #: E302:5:1 199 | def f(): 200 | pass 201 | 202 | # wat 203 | @hi 204 | def g(): 205 | pass 206 | -------------------------------------------------------------------------------- /testing/data/E30not.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | class X: 3 | pass 4 | #: Okay 5 | 6 | def foo(): 7 | pass 8 | #: Okay 9 | # -*- coding: utf-8 -*- 10 | class X: 11 | pass 12 | #: Okay 13 | # -*- coding: utf-8 -*- 14 | def foo(): 15 | pass 16 | #: Okay 17 | class X: 18 | 19 | def a(): 20 | pass 21 | 22 | # comment 23 | def b(): 24 | pass 25 | 26 | # This is a 27 | # ... multi-line comment 28 | 29 | def c(): 30 | pass 31 | 32 | 33 | # This is a 34 | # ... multi-line comment 35 | 36 | @some_decorator 37 | class Y: 38 | 39 | def a(): 40 | pass 41 | 42 | # comment 43 | 44 | def b(): 45 | pass 46 | 47 | @property 48 | def c(): 49 | pass 50 | 51 | 52 | try: 53 | from nonexistent import Bar 54 | except ImportError: 55 | class Bar(object): 56 | """This is a Bar replacement""" 57 | 58 | 59 | def with_feature(f): 60 | """Some decorator""" 61 | wrapper = f 62 | if has_this_feature(f): 63 | def wrapper(*args): 64 | call_feature(args[0]) 65 | return f(*args) 66 | return wrapper 67 | 68 | 69 | try: 70 | next 71 | except NameError: 72 | def next(iterator, default): 73 | for item in iterator: 74 | return item 75 | return default 76 | 77 | 78 | def a(): 79 | pass 80 | 81 | 82 | class Foo(): 83 | """Class Foo""" 84 | 85 | def b(): 86 | 87 | pass 88 | 89 | 90 | # comment 91 | def c(): 92 | pass 93 | 94 | 95 | # comment 96 | 97 | 98 | def d(): 99 | pass 100 | 101 | # This is a 102 | # ... multi-line comment 103 | 104 | # And this one is 105 | # ... a second paragraph 106 | # ... which spans on 3 lines 107 | 108 | 109 | # Function `e` is below 110 | # NOTE: Hey this is a testcase 111 | 112 | def e(): 113 | pass 114 | 115 | 116 | def a(): 117 | print 118 | 119 | # comment 120 | 121 | print 122 | 123 | print 124 | 125 | # Comment 1 126 | 127 | # Comment 2 128 | 129 | 130 | # Comment 3 131 | 132 | def b(): 133 | 134 | pass 135 | #: Okay 136 | def foo(): 137 | pass 138 | 139 | 140 | def bar(): 141 | pass 142 | 143 | 144 | class Foo(object): 145 | pass 146 | 147 | 148 | class Bar(object): 149 | pass 150 | 151 | 152 | if __name__ == '__main__': 153 | foo() 154 | #: Okay 155 | classification_errors = None 156 | #: Okay 157 | defined_properly = True 158 | #: Okay 159 | defaults = {} 160 | defaults.update({}) 161 | #: Okay 162 | def foo(x): 163 | classification = x 164 | definitely = not classification 165 | #: E704:3:1 E704:4:1 166 | # This emits the (ignored-by-default) E704, but here we're testing 167 | # for no E30x being emitted. 168 | def bar(): pass 169 | def baz(): pass 170 | 171 | 172 | def main(): 173 | pass 174 | #: E704:4:5 E704:5:5 175 | def foo(): 176 | # This emits the (ignored-by-default) E704, but here we're testing 177 | # for no E30x being emitted. 178 | def bar(): pass 179 | def baz(): pass 180 | #: E704:8:1 E704:10:1 181 | from typing import overload 182 | from typing import Union 183 | 184 | 185 | # This emits the (ignored-by-default) E704, but here we're testing 186 | # for no E30x being emitted. 187 | @overload 188 | def f(x: int) -> int: ... 189 | @overload 190 | def f(x: str) -> str: ... 191 | 192 | 193 | def f(x: Union[int, str]) -> Union[int, str]: 194 | return x 195 | #: E704:8:5 E704:10:5 196 | from typing import Protocol 197 | 198 | 199 | class C(Protocol): 200 | # This emits the (ignored-by-default) E704, but here we're testing 201 | # for no E30x being emitted. 202 | @property 203 | def f(self) -> int: ... 204 | @property 205 | def g(self) -> str: ... 206 | #: Okay 207 | #!python 208 | # -*- coding: utf-8 -*- 209 | def a(): 210 | pass 211 | #: Okay 212 | def f( 213 | a, 214 | ): 215 | pass 216 | -------------------------------------------------------------------------------- /testing/data/E40.py: -------------------------------------------------------------------------------- 1 | #: E401 2 | import os, sys 3 | #: Okay 4 | import os 5 | import sys 6 | 7 | from subprocess import Popen, PIPE 8 | 9 | from myclass import MyClass 10 | from foo.bar.yourclass import YourClass 11 | 12 | import myclass 13 | import foo.bar.yourclass 14 | #: Okay 15 | __all__ = ['abc'] 16 | 17 | import foo 18 | #: Okay 19 | __version__ = "42" 20 | 21 | import foo 22 | #: Okay 23 | __author__ = "Simon Gomizelj" 24 | 25 | import foo 26 | #: Okay 27 | try: 28 | import foo 29 | except ImportError: 30 | pass 31 | else: 32 | print('imported foo') 33 | finally: 34 | print('made attempt to import foo') 35 | 36 | import bar 37 | #: Okay 38 | with warnings.catch_warnings(): 39 | warnings.filterwarnings("ignore", DeprecationWarning) 40 | import foo 41 | 42 | import bar 43 | #: Okay 44 | if False: 45 | import foo 46 | elif not True: 47 | import bar 48 | else: 49 | import mwahaha 50 | 51 | import bar 52 | #: E402 53 | VERSION = '1.2.3' 54 | 55 | import foo 56 | #: E402 57 | import foo 58 | 59 | a = 1 60 | 61 | import bar 62 | -------------------------------------------------------------------------------- /testing/data/E50.py: -------------------------------------------------------------------------------- 1 | #: E501 2 | a = '12345678901234567890123456789012345678901234567890123456789012345678901234567890' 3 | #: E501 4 | a = '1234567890123456789012345678901234567890123456789012345678901234567890' or \ 5 | 6 6 | #: E501 7 | a = 7 or \ 8 | '1234567890123456789012345678901234567890123456789012345678901234567890' or \ 9 | 6 10 | #: E501 E501 11 | a = 7 or \ 12 | '1234567890123456789012345678901234567890123456789012345678901234567890' or \ 13 | '1234567890123456789012345678901234567890123456789012345678901234567890' or \ 14 | 6 15 | #: E501 16 | a = '1234567890123456789012345678901234567890123456789012345678901234567890' # \ 17 | #: E502 18 | a = ('123456789012345678901234567890123456789012345678901234567890123456789' \ 19 | '01234567890') 20 | #: E502 21 | a = ('AAA \ 22 | BBB' \ 23 | 'CCC') 24 | #: E502 25 | if (foo is None and bar is "e000" and \ 26 | blah == 'yeah'): 27 | blah = 'yeahnah' 28 | #: E502 W503 W503 29 | y = ( 30 | 2 + 2 # \ 31 | + 3 # \ 32 | + 4 \ 33 | + 3 34 | ) 35 | # 36 | #: Okay 37 | a = ('AAA' 38 | 'BBB') 39 | 40 | a = ('AAA \ 41 | BBB' 42 | 'CCC') 43 | 44 | a = 'AAA' \ 45 | 'BBB' \ 46 | 'CCC' 47 | 48 | a = ('AAA\ 49 | BBBBBBBBB\ 50 | CCCCCCCCC\ 51 | DDDDDDDDD') 52 | # 53 | #: Okay 54 | if aaa: 55 | pass 56 | elif bbb or \ 57 | ccc: 58 | pass 59 | 60 | ddd = \ 61 | ccc 62 | 63 | ('\ 64 | ' + ' \ 65 | ') 66 | (''' 67 | ''' + ' \ 68 | ') 69 | #: E501 E225 E226 70 | very_long_identifiers=and_terrible_whitespace_habits(are_no_excuse+for_long_lines) 71 | # 72 | #: E501 W505 73 | '''multiline string 74 | with a long long long long long long long long long long long long long long long long line 75 | ''' 76 | #: E501 W505 77 | '''same thing, but this time without a terminal newline in the string 78 | long long long long long long long long long long long long long long long long line''' 79 | #: E501 80 | if True: 81 | x = f""" 82 | covdefaults>=1.2; python_version == '2.7' or python_version == '{py_ver}' 83 | """ 84 | # 85 | # issue 224 (unavoidable long lines in docstrings) 86 | #: Okay 87 | """ 88 | I'm some great documentation. Because I'm some great documentation, I'm 89 | going to give you a reference to some valuable information about some 90 | API that I'm calling: 91 | 92 | http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 93 | """ 94 | #: E501 W505 95 | """ 96 | longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces""" 97 | #: E501 W505 98 | # Regression test for #622 99 | def foo(): 100 | """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pulvinar vitae 101 | """ 102 | #: E501 103 | loooooong = 'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong' 104 | f"""\ 105 | """ 106 | #: Okay 107 | """ 108 | This 109 | almost_empty_line 110 | """ 111 | #: E501 W505 112 | """ 113 | This 114 | almost_empty_line 115 | """ 116 | #: E501 W505 117 | # A basic comment 118 | # with a long long long long long long long long long long long long long long long long line 119 | 120 | # 121 | #: Okay 122 | # I'm some great comment. Because I'm so great, I'm going to give you a 123 | # reference to some valuable information about some API that I'm 124 | # calling: 125 | # 126 | # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 127 | 128 | import this 129 | 130 | # longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces 131 | 132 | # 133 | #: Okay 134 | # This 135 | # almost_empty_line 136 | 137 | # 138 | #: E501 W505 139 | # This 140 | # almost_empty_line 141 | 142 | # 143 | #: Okay 144 | #!/reallylongpath/toexecutable --maybe --with --some ARGUMENTS TO DO WITH WHAT EXECUTABLE TO RUN 145 | -------------------------------------------------------------------------------- /testing/data/E70.py: -------------------------------------------------------------------------------- 1 | #: E701:1:5 2 | if a: a = False 3 | #: E701:1:40 4 | if not header or header[:6] != 'bytes=': return 5 | #: E702:1:10 6 | a = False; b = True 7 | #: E702:1:17 8 | import bdist_egg; bdist_egg.write_safety_flag(cmd.egg_info, safe) 9 | #: E703:1:13 10 | import shlex; 11 | #: E702:1:9 E703:1:23 12 | del a[:]; a.append(42); 13 | #: E704:1:1 14 | def f(x): return 2 15 | #: E704:1:1 16 | async def f(x): return 2 17 | #: E704:1:1 E271:1:6 18 | async def f(x): return 2 19 | #: E704:1:1 E226:1:19 20 | def f(x): return 2*x 21 | #: E704:2:5 E226:2:23 22 | while all is round: 23 | def f(x): return 2*x 24 | #: 25 | -------------------------------------------------------------------------------- /testing/data/E71.py: -------------------------------------------------------------------------------- 1 | #: E711 2 | if res == None: 3 | pass 4 | #: E711 5 | if res != None: 6 | pass 7 | #: E711 8 | if None == res: 9 | pass 10 | #: E711 11 | if None != res: 12 | pass 13 | #: E711 14 | if res[1] == None: 15 | pass 16 | #: E711 17 | if res[1] != None: 18 | pass 19 | #: E711 20 | if None != res[1]: 21 | pass 22 | #: E711 23 | if None == res[1]: 24 | pass 25 | 26 | # 27 | #: E712 28 | if res == True: 29 | pass 30 | #: E712 31 | if res != False: 32 | pass 33 | #: E712 34 | if True != res: 35 | pass 36 | #: E712 37 | if False == res: 38 | pass 39 | #: E712 40 | if res[1] == True: 41 | pass 42 | #: E712 43 | if res[1] != False: 44 | pass 45 | #: E712 E712 46 | var = 1 if cond == True else -1 if cond == False else cond 47 | 48 | # 49 | #: E713 50 | if not X in Y: 51 | pass 52 | #: E713 53 | if not X.B in Y: 54 | pass 55 | #: E713 56 | if not X in Y and Z == "zero": 57 | pass 58 | #: E713 59 | if X == "zero" or not Y in Z: 60 | pass 61 | 62 | # 63 | #: E714 64 | if not X is Y: 65 | pass 66 | #: E714 67 | if not X.B is Y: 68 | pass 69 | #: E714 70 | if not X is Y is not Z: 71 | pass 72 | #: E714 73 | if not X is not Y: 74 | pass 75 | 76 | # 77 | #: Okay 78 | if x not in y: 79 | pass 80 | 81 | if not (X in Y or X is Z): 82 | pass 83 | 84 | if not (X in Y): 85 | pass 86 | 87 | if x is not y: 88 | pass 89 | 90 | if X is not Y is not Z: 91 | pass 92 | 93 | if TrueElement.get_element(True) == TrueElement.get_element(False): 94 | pass 95 | 96 | if (True) == TrueElement or x == TrueElement: 97 | pass 98 | 99 | assert (not foo) in bar 100 | assert {'x': not foo} in bar 101 | assert [42, not foo] in bar 102 | #: 103 | -------------------------------------------------------------------------------- /testing/data/E72.py: -------------------------------------------------------------------------------- 1 | #: E721 2 | if type(res) == type(42): 3 | pass 4 | #: E721 5 | if type(res) != type(""): 6 | pass 7 | #: Okay 8 | res.type("") == "" 9 | #: Okay 10 | import types 11 | 12 | if res == types.IntType: 13 | pass 14 | #: Okay 15 | import types 16 | 17 | if type(res) is not types.ListType: 18 | pass 19 | #: E721 20 | assert type(res) == type(False) or type(res) == type(None) 21 | #: E721 22 | assert type(res) == type([]) 23 | #: E721 24 | assert type(res) == type(()) 25 | #: E721 26 | assert type(res) == type((0,)) 27 | #: E721 28 | assert type(res) == type((0)) 29 | #: E721 30 | assert type(res) != type((1, )) 31 | #: Okay 32 | assert type(res) is type((1, )) 33 | #: Okay 34 | assert type(res) is not type((1, )) 35 | #: E211 E721 36 | assert type(res) == type ([2, ]) 37 | #: E201 E201 E202 E721 38 | assert type(res) == type( ( ) ) 39 | #: E201 E202 E721 40 | assert type(res) == type( (0, ) ) 41 | #: 42 | 43 | #: Okay 44 | import types 45 | 46 | if isinstance(res, int): 47 | pass 48 | if isinstance(res, str): 49 | pass 50 | if isinstance(res, types.MethodType): 51 | pass 52 | #: Okay 53 | def func_histype(a, b, c): 54 | pass 55 | #: E722 56 | try: 57 | pass 58 | except: 59 | pass 60 | #: E722 61 | try: 62 | pass 63 | except Exception: 64 | pass 65 | except: 66 | pass 67 | #: E722 E203 E271 68 | try: 69 | pass 70 | except : 71 | pass 72 | #: Okay 73 | fake_code = """" 74 | try: 75 | do_something() 76 | except: 77 | pass 78 | """ 79 | try: 80 | pass 81 | except Exception: 82 | pass 83 | #: Okay 84 | from . import custom_types as types 85 | 86 | red = types.ColorTypeRED 87 | red is types.ColorType.RED 88 | #: Okay 89 | from . import compute_type 90 | 91 | if compute_type(foo) == 5: 92 | pass 93 | -------------------------------------------------------------------------------- /testing/data/E73.py: -------------------------------------------------------------------------------- 1 | #: E731:1:1 2 | f = lambda x: 2 * x 3 | #: E731:1:1 E226:1:16 4 | f = lambda x: 2*x 5 | #: E731:2:5 6 | while False: 7 | this = lambda y, z: 2 * x 8 | #: Okay 9 | f = object() 10 | f.method = lambda: 'Method' 11 | 12 | f = {} 13 | f['a'] = lambda x: x ** 2 14 | 15 | f = [] 16 | f.append(lambda x: x ** 2) 17 | 18 | lambda: 'no-op' 19 | -------------------------------------------------------------------------------- /testing/data/E74.py: -------------------------------------------------------------------------------- 1 | #: E741:1:8 2 | lambda l: dict(zip(l, range(len(l)))) 3 | #: E741:1:7 E704:1:1 4 | def f(l): print(l, l, l) 5 | #: E741:2:12 6 | x = ( 7 | lambda l: dict(zip(l, range(len(l)))), 8 | ) 9 | #: E741:2:12 E741:3:12 10 | x = ( 11 | lambda l: dict(zip(l, range(len(l)))), 12 | lambda l: dict(zip(l, range(len(l)))), 13 | ) 14 | -------------------------------------------------------------------------------- /testing/data/E90.py: -------------------------------------------------------------------------------- 1 | #: E901 2 | = [x 3 | #: E901 E101 W191 4 | while True: 5 | try: 6 | pass 7 | except: 8 | print 'Whoops' 9 | #: Okay 10 | 11 | # Issue #119 12 | # Do not crash with Python2 if the line endswith '\r\r\n' 13 | EMPTY_SET = set() 14 | SET_TYPE = type(EMPTY_SET) 15 | toto = 0 + 0 16 | #: 17 | -------------------------------------------------------------------------------- /testing/data/W19.py: -------------------------------------------------------------------------------- 1 | #: W191 2 | if False: 3 | print # indented with 1 tab 4 | #: 5 | 6 | 7 | #: W191 8 | y = x == 2 \ 9 | or x == 3 10 | #: E101 W191 W504 11 | if ( 12 | x == ( 13 | 3 14 | ) or 15 | y == 4): 16 | pass 17 | #: E101 W191 18 | if x == 2 \ 19 | or y > 1 \ 20 | or x == 3: 21 | pass 22 | #: E101 W191 23 | if x == 2 \ 24 | or y > 1 \ 25 | or x == 3: 26 | pass 27 | #: 28 | 29 | #: E101 W191 W504 30 | if (foo == bar and 31 | baz == frop): 32 | pass 33 | #: E101 W191 W504 34 | if ( 35 | foo == bar and 36 | baz == frop 37 | ): 38 | pass 39 | #: 40 | 41 | #: E101 E101 W191 W191 42 | if start[1] > end_col and not ( 43 | over_indent == 4 and indent_next): 44 | return (0, "E121 continuation line over-" 45 | "indented for visual indent") 46 | #: 47 | 48 | #: E101 W191 49 | 50 | 51 | def long_function_name( 52 | var_one, var_two, var_three, 53 | var_four): 54 | print(var_one) 55 | #: E101 W191 W504 56 | if ((row < 0 or self.moduleCount <= row or 57 | col < 0 or self.moduleCount <= col)): 58 | raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) 59 | #: E101 E101 E101 E101 W191 W191 W191 W191 W191 W191 60 | if bar: 61 | return ( 62 | start, 'E121 lines starting with a ' 63 | 'closing bracket should be indented ' 64 | "to match that of the opening " 65 | "bracket's line" 66 | ) 67 | # 68 | #: E101 W191 W504 69 | # you want vertical alignment, so use a parens 70 | if ((foo.bar("baz") and 71 | foo.bar("frop") 72 | )): 73 | print "yes" 74 | #: E101 W191 W504 75 | # also ok, but starting to look like LISP 76 | if ((foo.bar("baz") and 77 | foo.bar("frop"))): 78 | print "yes" 79 | #: E101 W191 W504 80 | if (a == 2 or 81 | b == "abc def ghi" 82 | "jkl mno"): 83 | return True 84 | #: E101 W191 W504 85 | if (a == 2 or 86 | b == """abc def ghi 87 | jkl mno"""): 88 | return True 89 | #: W191:2:1 W191:3:1 E101:3:2 90 | if length > options.max_line_length: 91 | return options.max_line_length, \ 92 | "E501 line too long (%d characters)" % length 93 | 94 | 95 | # 96 | #: E101 W191 W191 W504 97 | if os.path.exists(os.path.join(path, PEP8_BIN)): 98 | cmd = ([os.path.join(path, PEP8_BIN)] + 99 | self._pep8_options(targetfile)) 100 | #: W191 101 | ''' 102 | multiline string with tab in it''' 103 | #: E101 W191 104 | '''multiline string 105 | with tabs 106 | and spaces 107 | ''' 108 | #: Okay 109 | '''sometimes, you just need to go nuts in a multiline string 110 | and allow all sorts of crap 111 | like mixed tabs and spaces 112 | 113 | or trailing whitespace 114 | or long long long long long long long long long long long long long long long long long lines 115 | ''' # nopep8 116 | #: Okay 117 | '''this one 118 | will get no warning 119 | even though the noqa comment is not immediately after the string 120 | ''' + foo # noqa 121 | # 122 | #: E101 W191 123 | if foo is None and bar is "frop" and \ 124 | blah == 'yeah': 125 | blah = 'yeahnah' 126 | 127 | 128 | # 129 | #: W191 W191 W191 130 | if True: 131 | foo( 132 | 1, 133 | 2) 134 | #: W191 W191 W191 W191 W191 135 | def test_keys(self): 136 | """areas.json - All regions are accounted for.""" 137 | expected = set([ 138 | u'Norrbotten', 139 | u'V\xe4sterbotten', 140 | ]) 141 | #: W191 142 | x = [ 143 | 'abc' 144 | ] 145 | #: 146 | -------------------------------------------------------------------------------- /testing/data/W29.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | # 情 3 | #: W291:1:6 4 | print 5 | #: W293:2:1 6 | class Foo(object): 7 | 8 | bang = 12 9 | #: W291:2:35 10 | '''multiline 11 | string with trailing whitespace''' 12 | #: W291 W292 noeol 13 | x = 1 14 | #: W191 W292 noeol 15 | if False: 16 | pass # indented with tabs 17 | #: W292:1:5 E225:1:2 noeol 18 | 1+ 1 19 | #: W292:1:27 E261:1:12 noeol 20 | import this # no line feed 21 | #: W292:3:22 noeol 22 | class Test(object): 23 | def __repr__(self): 24 | return 'test' 25 | -------------------------------------------------------------------------------- /testing/data/W39.py: -------------------------------------------------------------------------------- 1 | #: W391:2:1 2 | # The next line is blank 3 | 4 | #: W391:3:1 5 | # Two additional empty lines 6 | 7 | 8 | #: W292:4:5 W293:3:1 W293:4:1 noeol 9 | # The last lines contain space 10 | 11 | 12 | 13 | #: Okay 14 | '''there is nothing wrong 15 | with a multiline string at EOF 16 | 17 | that happens to have a blank line in it 18 | ''' 19 | -------------------------------------------------------------------------------- /testing/data/W60.py: -------------------------------------------------------------------------------- 1 | #: W605:1:10 2 | regex = '\.png$' 3 | #: W605:2:1 4 | regex = ''' 5 | \.png$ 6 | ''' 7 | #: W605:2:6 8 | f( 9 | '\_' 10 | ) 11 | #: W605:4:6 12 | """ 13 | multi-line 14 | literal 15 | with \_ somewhere 16 | in the middle 17 | """ 18 | #: W605:1:3 19 | f"\d" 20 | #: Okay 21 | regex = r'\.png$' 22 | regex = '\\.png$' 23 | regex = r''' 24 | \.png$ 25 | ''' 26 | regex = r''' 27 | \\.png$ 28 | ''' 29 | s = '\\' 30 | regex = '\w' # noqa 31 | regex = ''' 32 | \w 33 | ''' # noqa 34 | -------------------------------------------------------------------------------- /testing/data/crlf.py: -------------------------------------------------------------------------------- 1 | '''\ 2 | test 3 | ''' 4 | -------------------------------------------------------------------------------- /testing/data/latin-1.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCQA/pycodestyle/a98638490e3c799efeebf0af638940d5a581b3c9/testing/data/latin-1.py -------------------------------------------------------------------------------- /testing/data/noqa.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | # silence E501 3 | url = 'https://api.github.com/repos/sigmavirus24/Todo.txt-python/branches/master?client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxx&?client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # noqa 4 | 5 | # silence E128 6 | from functools import (partial, reduce, wraps, # noqa 7 | cmp_to_key) 8 | 9 | from functools import (partial, reduce, wraps, 10 | cmp_to_key) # noqa 11 | 12 | a = 1 13 | if a == None: # noqa 14 | pass 15 | 16 | # should silence E501 17 | s = f''' 18 | loong {y} looooooooooooooong loooooooooooooong looooooooong loooooooong looooooooong 19 | {x} 20 | ''' # noqa 21 | #: 22 | -------------------------------------------------------------------------------- /testing/data/python3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from typing import ClassVar, List 3 | 4 | 5 | # Annotated function (Issue #29) 6 | def foo(x: int) -> int: 7 | return x + 1 8 | 9 | 10 | # Annotated variables #575 11 | CONST: int = 42 12 | match: int = 42 13 | case: int = 42 14 | 15 | 16 | class Class: 17 | # Camel-caes 18 | cls_var: ClassVar[str] 19 | for_var: ClassVar[str] 20 | while_var: ClassVar[str] 21 | def_var: ClassVar[str] 22 | if_var: ClassVar[str] 23 | elif_var: ClassVar[str] 24 | else_var: ClassVar[str] 25 | try_var: ClassVar[str] 26 | except_var: ClassVar[str] 27 | finally_var: ClassVar[str] 28 | with_var: ClassVar[str] 29 | forVar: ClassVar[str] 30 | whileVar: ClassVar[str] 31 | defVar: ClassVar[str] 32 | ifVar: ClassVar[str] 33 | elifVar: ClassVar[str] 34 | elseVar: ClassVar[str] 35 | tryVar: ClassVar[str] 36 | exceptVar: ClassVar[str] 37 | finallyVar: ClassVar[str] 38 | withVar: ClassVar[str] 39 | 40 | def m(self): 41 | xs: List[int] = [] 42 | 43 | 44 | # Used to trigger W504 45 | def f( 46 | x: str = ... 47 | ): 48 | ... 49 | -------------------------------------------------------------------------------- /testing/data/python310.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | var, var2 = 1, 2 3 | match (var, var2): 4 | case [2, 3]: 5 | pass 6 | case (1, 2): 7 | pass 8 | case _: 9 | print("Default") 10 | #: Okay 11 | var = 0, 1, 2 12 | match var: 13 | case *_, 1, 2: 14 | pass 15 | case 0, *_, 2: 16 | pass 17 | case 0, 1, *_: 18 | pass 19 | case (*_, 1, 2): 20 | pass 21 | case (0, *_, 2): 22 | pass 23 | case (0, 1, *_): 24 | pass 25 | -------------------------------------------------------------------------------- /testing/data/python311.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | try: 3 | ... 4 | except* OSError as e: 5 | pass 6 | #: Okay 7 | from typing import Generic 8 | from typing import TypeVarTuple 9 | 10 | 11 | Ts = TypeVarTuple('Ts') 12 | 13 | 14 | class Shape(Generic[*Ts]): 15 | pass 16 | 17 | 18 | def f(*args: *Ts) -> None: 19 | ... 20 | 21 | 22 | def g(x: Shape[*Ts]) -> Shape[*Ts]: 23 | ... 24 | -------------------------------------------------------------------------------- /testing/data/python312.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | # https://github.com/python/cpython/issues/90432: fixed in 3.12 3 | def foo(): 4 | pas 5 | 6 | \ 7 | 8 | def bar(): 9 | pass 10 | #: Okay 11 | # new type aliases 12 | type X = int | str 13 | type Y[T] = list[T] 14 | type Z[T: str] = list[T] 15 | #: Okay 16 | # new generics 17 | def f[T](x: T) -> T: 18 | pass 19 | 20 | 21 | def g[T: str, U: int](x: T, y: U) -> dict[T, U]: 22 | pass 23 | #: Okay 24 | # new nested f-strings 25 | f'{ 26 | thing 27 | } {f'{other} {thing}'}' 28 | #: E201:1:4 E202:1:17 29 | f'{ an_error_now }' 30 | #: Okay 31 | f'{x:02x}' 32 | -------------------------------------------------------------------------------- /testing/data/python313.py: -------------------------------------------------------------------------------- 1 | type Alias[T: (int, str) = str] = list[T] 2 | type Alias2[T = str] = list[T] 3 | 4 | 5 | class C[T: (int, str) = str]: 6 | pass 7 | 8 | 9 | class C2[T = str]: 10 | pass 11 | 12 | 13 | def f[T: (int, str) = str](t: T) -> T: 14 | pass 15 | 16 | 17 | def f2[T = str](t: T) -> T: 18 | pass 19 | -------------------------------------------------------------------------------- /testing/data/python314.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | try: 3 | raise AssertionError('hi') 4 | except AssertionError, ValueError: 5 | pass 6 | 7 | t'hello {world}' 8 | t'{hello}:{world}' 9 | t'in{x}' 10 | t'hello{world=}' 11 | #: Okay 12 | # new nested f-strings 13 | t'{ 14 | thing 15 | } {t'{other} {thing}'}' 16 | #: E201:1:4 E202:1:17 17 | t'{ an_error_now }' 18 | #: Okay 19 | t'{x:02x}' 20 | -------------------------------------------------------------------------------- /testing/data/python35.py: -------------------------------------------------------------------------------- 1 | #: E225 2 | def bar(a, b)->int: 3 | pass 4 | #: Okay 5 | def baz(a, b) -> int: 6 | pass 7 | -------------------------------------------------------------------------------- /testing/data/python36.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | f'{hello}:{world}' 3 | f'in{x}' 4 | -------------------------------------------------------------------------------- /testing/data/python38.py: -------------------------------------------------------------------------------- 1 | #: Okay 2 | def f1(a, /, b): 3 | pass 4 | 5 | 6 | def f2(a, b, /): 7 | pass 8 | 9 | 10 | def f3( 11 | a, 12 | /, 13 | b, 14 | ): 15 | pass 16 | 17 | 18 | lambda a, /: None 19 | #: Okay 20 | if x := 1: 21 | print(x) 22 | if m and (token := m.group(1)): 23 | pass 24 | stuff = [[y := f(x), x / y] for x in range(5)] 25 | #: E225:1:5 26 | if x:= 1: 27 | pass 28 | #: E225:1:18 29 | if False or (x :=1): 30 | pass 31 | #: Okay 32 | import typing as t 33 | 34 | __all__: t.List[str] = [] 35 | 36 | import logging 37 | 38 | logging.getLogger(__name__) 39 | #: E402 40 | import typing as t 41 | 42 | all_the_things: t.List[str] = [] 43 | 44 | import logging 45 | #: E221:1:5 E222:1:9 E221:3:6 46 | if x := 1: 47 | pass 48 | if (x := 2): 49 | pass 50 | #: E223:1:5 E224:1:8 51 | if x := 2: 52 | pass 53 | #: E221:1:6 E221:1:19 54 | if (x := 1) == (y := 2): 55 | pass 56 | #: E741 57 | while l := 1: 58 | pass 59 | #: E741 60 | if (l := 1): 61 | pass 62 | #: Okay 63 | f'{x=}' 64 | -------------------------------------------------------------------------------- /testing/data/python39.py: -------------------------------------------------------------------------------- 1 | #: W292:1:70 noeol 2 | # This line doesn't have a linefeed (in 3.8 this is reported thrice!) 3 | -------------------------------------------------------------------------------- /testing/data/utf-8-bom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | hello = 'こんにちわ' 5 | 6 | # EOF 7 | -------------------------------------------------------------------------------- /testing/data/utf-8.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Some random text with multi-byte characters (utf-8 encoded) 4 | # 5 | # Εδώ μάτσο κειμένων τη, τρόπο πιθανό διευθυντές ώρα μη. Νέων απλό π ροή 6 | # κι, το επί δεδομένη καθορίζουν. Πάντως ζητήσεις περιβάλλοντος ένα με, 7 | # ξέχασε αρπάζεις φαινόμενο όλη. Τρέξει εσφαλμένη χρησιμοποίησέ νέα τι. 8 | # πετάνε φακέλους, άρα με διακοπής λαμβάνουν εφαμοργής. Λες κι μειώσει 9 | # καθυστερεί. 10 | 11 | # 79 narrow chars 12 | # 01 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3[79] 13 | 14 | # 78 narrow chars (Na) + 1 wide char (W) 15 | # 01 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 情 16 | 17 | # 3 narrow chars (Na) + 40 wide chars (W) 18 | # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 19 | 20 | # 3 narrow chars (Na) + 69 wide chars (W) 21 | # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 22 | 23 | # 24 | #: E501 W505 25 | # 80 narrow chars (Na) 26 | # 01 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 [80] 27 | # 28 | #: E501 W505 29 | # 78 narrow chars (Na) + 2 wide char (W) 30 | # 01 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8情情 31 | # 32 | #: E501 W505 33 | # 3 narrow chars (Na) + 77 wide chars (W) 34 | # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 35 | # 36 | -------------------------------------------------------------------------------- /testing/support.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os.path 4 | 5 | from pycodestyle import BaseReport 6 | from pycodestyle import StyleGuide 7 | 8 | ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 9 | 10 | 11 | class InMemoryReport(BaseReport): 12 | """ 13 | Collect the results in memory, without printing anything. 14 | """ 15 | 16 | def __init__(self, options): 17 | super().__init__(options) 18 | self.in_memory_errors = [] 19 | 20 | def error(self, line_number, offset, text, check): 21 | """ 22 | Report an error, according to options. 23 | """ 24 | code = text[:4] 25 | self.in_memory_errors.append(f'{code}:{line_number}:{offset + 1}') 26 | return super().error(line_number, offset, text, check) 27 | 28 | 29 | def errors_from_src(src: str) -> list[str]: 30 | guide = StyleGuide(select=('E', 'W'), max_doc_length=72) 31 | reporter = guide.init_report(InMemoryReport) 32 | guide.input_file( 33 | filename='in-memory-test-file.py', 34 | lines=src.splitlines(True), 35 | ) 36 | return reporter.in_memory_errors 37 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCQA/pycodestyle/a98638490e3c799efeebf0af638940d5a581b3c9/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_E101.py: -------------------------------------------------------------------------------- 1 | """moved from data files due to 3.12 making this a TokenError""" 2 | import sys 3 | import unittest 4 | 5 | from testing.support import errors_from_src 6 | 7 | 8 | class E101Test(unittest.TestCase): 9 | def test_E101(self): 10 | errors = errors_from_src( 11 | 'if True:\n' 12 | '\tprint(1) # tabs\n' 13 | ' print(2) # spaces\n' 14 | ) 15 | if sys.version_info >= (3, 12): # pragma: >=3.12 cover 16 | self.assertEqual(errors, ['W191:2:1', 'E901:3:28']) 17 | else: # pragma: <3.12 cover 18 | self.assertEqual(errors, ['W191:2:1', 'E101:3:1']) 19 | -------------------------------------------------------------------------------- /tests/test_E901.py: -------------------------------------------------------------------------------- 1 | """moved from data files due to 3.12 changing syntax errors""" 2 | import sys 3 | import unittest 4 | 5 | from testing.support import errors_from_src 6 | 7 | 8 | class E901Test(unittest.TestCase): 9 | def test_closing_brace(self): 10 | errors = errors_from_src('}\n') 11 | if sys.version_info < (3, 12): # pragma: <3.12 cover 12 | self.assertEqual(errors, ['E901:2:1']) 13 | else: # pragma: >=3.12 cover 14 | self.assertEqual(errors, []) 15 | 16 | def test_unclosed_brace(self): 17 | src = '''\ 18 | if msg: 19 | errmsg = msg % progress.get(cr_dbname)) 20 | 21 | def lasting(self, duration=300): 22 | progress = self._progress.setdefault('foo', {} 23 | ''' 24 | errors = errors_from_src(src) 25 | if sys.version_info < (3, 12): # pragma: <3.12 cover 26 | expected = ['E122:4:1'] 27 | else: # pragma: >=3.12 cover 28 | expected = ['E122:4:1', 'E901:5:1'] # noqa: E501 29 | self.assertEqual(errors, expected) 30 | -------------------------------------------------------------------------------- /tests/test_all.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | import pycodestyle 4 | from testing.support import ROOT 5 | 6 | 7 | def test_own_dog_food(): 8 | style = pycodestyle.StyleGuide(select='E,W', quiet=True) 9 | files = [pycodestyle.__file__, __file__, os.path.join(ROOT, 'setup.py')] 10 | report = style.init_report(pycodestyle.StandardReport) 11 | report = style.check_files(files) 12 | assert list(report.messages) == ['W504'], f'Failures: {report.messages}' 13 | -------------------------------------------------------------------------------- /tests/test_api.py: -------------------------------------------------------------------------------- 1 | import io 2 | import os.path 3 | import shlex 4 | import sys 5 | import unittest 6 | 7 | import pycodestyle 8 | from testing.support import ROOT 9 | 10 | E11 = os.path.join(ROOT, 'testing', 'data', 'E11.py') 11 | 12 | 13 | class DummyChecker: 14 | def __init__(self, tree, filename): 15 | pass 16 | 17 | def run(self): 18 | if False: 19 | yield 20 | 21 | 22 | class APITestCase(unittest.TestCase): 23 | """Test the public methods.""" 24 | 25 | def setUp(self): 26 | self._saved_stdout = sys.stdout 27 | self._saved_stderr = sys.stderr 28 | self._saved_checks = pycodestyle._checks 29 | sys.stdout = io.StringIO() 30 | sys.stderr = io.StringIO() 31 | pycodestyle._checks = { 32 | k: {f: (vals[0][:], vals[1]) for (f, vals) in v.items()} 33 | for k, v in self._saved_checks.items() 34 | } 35 | 36 | def tearDown(self): 37 | sys.stdout = self._saved_stdout 38 | sys.stderr = self._saved_stderr 39 | pycodestyle._checks = self._saved_checks 40 | 41 | def reset(self): 42 | sys.stdout.seek(0) 43 | sys.stdout.truncate() 44 | sys.stderr.seek(0) 45 | sys.stderr.truncate() 46 | 47 | def test_register_physical_check(self): 48 | def check_dummy(physical_line, line_number): 49 | raise NotImplementedError 50 | pycodestyle.register_check(check_dummy, ['Z001']) 51 | 52 | self.assertTrue(check_dummy in pycodestyle._checks['physical_line']) 53 | codes, args = pycodestyle._checks['physical_line'][check_dummy] 54 | self.assertTrue('Z001' in codes) 55 | self.assertEqual(args, ['physical_line', 'line_number']) 56 | 57 | options = pycodestyle.StyleGuide().options 58 | functions = [func for _, func, _ in options.physical_checks] 59 | self.assertIn(check_dummy, functions) 60 | 61 | def test_register_logical_check(self): 62 | def check_dummy(logical_line, tokens): 63 | raise NotImplementedError 64 | pycodestyle.register_check(check_dummy, ['Z401']) 65 | 66 | self.assertTrue(check_dummy in pycodestyle._checks['logical_line']) 67 | codes, args = pycodestyle._checks['logical_line'][check_dummy] 68 | self.assertTrue('Z401' in codes) 69 | self.assertEqual(args, ['logical_line', 'tokens']) 70 | 71 | pycodestyle.register_check(check_dummy, []) 72 | pycodestyle.register_check(check_dummy, ['Z402', 'Z403']) 73 | codes, args = pycodestyle._checks['logical_line'][check_dummy] 74 | self.assertEqual(codes, ['Z401', 'Z402', 'Z403']) 75 | self.assertEqual(args, ['logical_line', 'tokens']) 76 | 77 | options = pycodestyle.StyleGuide().options 78 | functions = [func for _, func, _ in options.logical_checks] 79 | self.assertIn(check_dummy, functions) 80 | 81 | def test_register_ast_check(self): 82 | pycodestyle.register_check(DummyChecker, ['Z701']) 83 | 84 | self.assertTrue(DummyChecker in pycodestyle._checks['tree']) 85 | codes, args = pycodestyle._checks['tree'][DummyChecker] 86 | self.assertTrue('Z701' in codes) 87 | self.assertTrue(args is None) 88 | 89 | options = pycodestyle.StyleGuide().options 90 | classes = [cls for _, cls, _ in options.ast_checks] 91 | self.assertIn(DummyChecker, classes) 92 | 93 | def test_register_invalid_check(self): 94 | class InvalidChecker(DummyChecker): 95 | def __init__(self, filename): 96 | raise NotImplementedError 97 | 98 | def check_dummy(logical, tokens): 99 | raise NotImplementedError 100 | 101 | pycodestyle.register_check(InvalidChecker, ['Z741']) 102 | pycodestyle.register_check(check_dummy, ['Z441']) 103 | 104 | for checkers in pycodestyle._checks.values(): 105 | self.assertTrue(DummyChecker not in checkers) 106 | self.assertTrue(check_dummy not in checkers) 107 | 108 | self.assertRaises(TypeError, pycodestyle.register_check) 109 | 110 | def test_styleguide(self): 111 | report = pycodestyle.StyleGuide().check_files() 112 | self.assertEqual(report.total_errors, 0) 113 | self.assertFalse(sys.stdout.getvalue()) 114 | self.assertFalse(sys.stderr.getvalue()) 115 | self.reset() 116 | 117 | report = pycodestyle.StyleGuide().check_files(['missing-file']) 118 | stdout = sys.stdout.getvalue().splitlines() 119 | self.assertEqual(len(stdout), report.total_errors) 120 | self.assertEqual(report.total_errors, 1) 121 | # < 3.3 returns IOError; >= 3.3 returns FileNotFoundError 122 | assert stdout[0].startswith("missing-file:1:1: E902 ") 123 | self.assertFalse(sys.stderr.getvalue()) 124 | self.reset() 125 | 126 | report = pycodestyle.StyleGuide().check_files([E11]) 127 | stdout = sys.stdout.getvalue().splitlines() 128 | self.assertEqual(len(stdout), report.total_errors) 129 | self.assertEqual(report.total_errors, 24) 130 | self.assertFalse(sys.stderr.getvalue()) 131 | self.reset() 132 | 133 | # Passing the paths in the constructor gives same result 134 | report = pycodestyle.StyleGuide(paths=[E11]).check_files() 135 | stdout = sys.stdout.getvalue().splitlines() 136 | self.assertEqual(len(stdout), report.total_errors) 137 | self.assertEqual(report.total_errors, 24) 138 | self.assertFalse(sys.stderr.getvalue()) 139 | self.reset() 140 | 141 | def test_styleguide_options(self): 142 | # Instantiate a simple checker 143 | pep8style = pycodestyle.StyleGuide(paths=[E11]) 144 | 145 | # Check style's attributes 146 | self.assertEqual(pep8style.checker_class, pycodestyle.Checker) 147 | self.assertEqual(pep8style.paths, [E11]) 148 | self.assertEqual(pep8style.runner, pep8style.input_file) 149 | self.assertEqual(pep8style.options.ignore_code, pep8style.ignore_code) 150 | self.assertEqual(pep8style.options.paths, pep8style.paths) 151 | 152 | # Check unset options 153 | for o in ('benchmark', 'config', 'count', 'diff', 154 | 'quiet', 'show_pep8', 'show_source', 155 | 'statistics', 'verbose'): 156 | oval = getattr(pep8style.options, o) 157 | self.assertTrue(oval in (None, False), msg=f'{o} = {oval!r}') 158 | 159 | # Check default options 160 | self.assertTrue(pep8style.options.repeat) 161 | self.assertEqual(pep8style.options.benchmark_keys, 162 | ['directories', 'files', 163 | 'logical lines', 'physical lines']) 164 | self.assertEqual(pep8style.options.exclude, 165 | ['.svn', 'CVS', '.bzr', '.hg', 166 | '.git', '__pycache__', '.tox']) 167 | self.assertEqual(pep8style.options.filename, ['*.py']) 168 | self.assertEqual(pep8style.options.format, 'default') 169 | self.assertEqual(pep8style.options.select, ()) 170 | self.assertEqual(pep8style.options.ignore, ('E226', 'E24', 'W504')) 171 | self.assertEqual(pep8style.options.max_line_length, 79) 172 | 173 | def test_styleguide_ignore_code(self): 174 | def parse_argv(argstring): 175 | _saved_argv = sys.argv 176 | sys.argv = shlex.split('pycodestyle %s /dev/null' % argstring) 177 | try: 178 | return pycodestyle.StyleGuide(parse_argv=True) 179 | finally: 180 | sys.argv = _saved_argv 181 | 182 | options = parse_argv('').options 183 | self.assertEqual(options.select, ()) 184 | self.assertEqual( 185 | options.ignore, 186 | ('E121', 'E123', 'E126', 'E226', 'E24', 'E704', 'W503', 'W504') 187 | ) 188 | 189 | options = parse_argv('--ignore E,W').options 190 | self.assertEqual(options.select, ()) 191 | self.assertEqual(options.ignore, ('E', 'W')) 192 | 193 | options = parse_argv('--select E,W').options 194 | self.assertEqual(options.select, ('E', 'W')) 195 | self.assertEqual(options.ignore, ('',)) 196 | 197 | options = parse_argv('--select E --ignore E24').options 198 | self.assertEqual(options.select, ('E',)) 199 | self.assertEqual(options.ignore, ('',)) 200 | 201 | options = parse_argv('--ignore E --select E24').options 202 | self.assertEqual(options.select, ('E24',)) 203 | self.assertEqual(options.ignore, ('',)) 204 | 205 | options = parse_argv('--ignore W --select E24').options 206 | self.assertEqual(options.select, ('E24',)) 207 | self.assertEqual(options.ignore, ('',)) 208 | 209 | options = parse_argv('--max-doc-length=72').options 210 | self.assertEqual(options.max_doc_length, 72) 211 | 212 | options = parse_argv('').options 213 | self.assertEqual(options.max_doc_length, None) 214 | 215 | pep8style = pycodestyle.StyleGuide(paths=[E11]) 216 | self.assertFalse(pep8style.ignore_code('E112')) 217 | self.assertFalse(pep8style.ignore_code('W191')) 218 | self.assertTrue(pep8style.ignore_code('E241')) 219 | 220 | pep8style = pycodestyle.StyleGuide(select='E', paths=[E11]) 221 | self.assertFalse(pep8style.ignore_code('E112')) 222 | self.assertTrue(pep8style.ignore_code('W191')) 223 | self.assertFalse(pep8style.ignore_code('E241')) 224 | 225 | pep8style = pycodestyle.StyleGuide(select='W', paths=[E11]) 226 | self.assertTrue(pep8style.ignore_code('E112')) 227 | self.assertFalse(pep8style.ignore_code('W191')) 228 | self.assertTrue(pep8style.ignore_code('E241')) 229 | 230 | pep8style = pycodestyle.StyleGuide(select=('F401',), paths=[E11]) 231 | self.assertEqual(pep8style.options.select, ('F401',)) 232 | self.assertEqual(pep8style.options.ignore, ('',)) 233 | self.assertFalse(pep8style.ignore_code('F')) 234 | self.assertFalse(pep8style.ignore_code('F401')) 235 | self.assertTrue(pep8style.ignore_code('F402')) 236 | 237 | def test_styleguide_excluded(self): 238 | pep8style = pycodestyle.StyleGuide(paths=[E11]) 239 | 240 | self.assertFalse(pep8style.excluded('./foo/bar')) 241 | self.assertFalse(pep8style.excluded('./foo/bar/main.py')) 242 | 243 | self.assertTrue(pep8style.excluded('./CVS')) 244 | self.assertTrue(pep8style.excluded('./.tox')) 245 | self.assertTrue(pep8style.excluded('./subdir/CVS')) 246 | self.assertTrue(pep8style.excluded('__pycache__')) 247 | self.assertTrue(pep8style.excluded('./__pycache__')) 248 | self.assertTrue(pep8style.excluded('subdir/__pycache__')) 249 | 250 | self.assertFalse(pep8style.excluded('draftCVS')) 251 | self.assertFalse(pep8style.excluded('./CVSoup')) 252 | self.assertFalse(pep8style.excluded('./CVS/subdir')) 253 | 254 | def test_styleguide_checks(self): 255 | pep8style = pycodestyle.StyleGuide(paths=[E11]) 256 | 257 | # Default lists of checkers 258 | self.assertTrue(len(pep8style.options.physical_checks) > 4) 259 | self.assertTrue(len(pep8style.options.logical_checks) > 10) 260 | self.assertEqual(len(pep8style.options.ast_checks), 0) 261 | 262 | # Sanity check 263 | for name, check, args in pep8style.options.physical_checks: 264 | self.assertEqual(check.__name__, name) 265 | self.assertEqual(args[0], 'physical_line') 266 | for name, check, args in pep8style.options.logical_checks: 267 | self.assertEqual(check.__name__, name) 268 | self.assertEqual(args[0], 'logical_line') 269 | 270 | # Do run E11 checks 271 | options = pycodestyle.StyleGuide().options 272 | functions = [func for _, func, _ in options.logical_checks] 273 | self.assertIn(pycodestyle.indentation, functions) 274 | options = pycodestyle.StyleGuide(select=['E']).options 275 | functions = [func for _, func, _ in options.logical_checks] 276 | self.assertIn(pycodestyle.indentation, functions) 277 | options = pycodestyle.StyleGuide(ignore=['W']).options 278 | functions = [func for _, func, _ in options.logical_checks] 279 | self.assertIn(pycodestyle.indentation, functions) 280 | options = pycodestyle.StyleGuide(ignore=['E12']).options 281 | functions = [func for _, func, _ in options.logical_checks] 282 | self.assertIn(pycodestyle.indentation, functions) 283 | 284 | # Do not run E11 checks 285 | options = pycodestyle.StyleGuide(select=['W']).options 286 | functions = [func for _, func, _ in options.logical_checks] 287 | self.assertNotIn(pycodestyle.indentation, functions) 288 | options = pycodestyle.StyleGuide(ignore=['E']).options 289 | functions = [func for _, func, _ in options.logical_checks] 290 | self.assertNotIn(pycodestyle.indentation, functions) 291 | options = pycodestyle.StyleGuide(ignore=['E11']).options 292 | functions = [func for _, func, _ in options.logical_checks] 293 | self.assertNotIn(pycodestyle.indentation, functions) 294 | 295 | def test_styleguide_init_report(self): 296 | style = pycodestyle.StyleGuide(paths=[E11]) 297 | 298 | standard_report = pycodestyle.StandardReport 299 | 300 | self.assertEqual(style.options.reporter, standard_report) 301 | self.assertEqual(type(style.options.report), standard_report) 302 | 303 | class MinorityReport(pycodestyle.BaseReport): 304 | pass 305 | 306 | report = style.init_report(MinorityReport) 307 | self.assertEqual(style.options.report, report) 308 | self.assertEqual(type(report), MinorityReport) 309 | 310 | style = pycodestyle.StyleGuide(paths=[E11], reporter=MinorityReport) 311 | self.assertEqual(type(style.options.report), MinorityReport) 312 | self.assertEqual(style.options.reporter, MinorityReport) 313 | 314 | def test_styleguide_check_files(self): 315 | pep8style = pycodestyle.StyleGuide(paths=[E11]) 316 | 317 | report = pep8style.check_files() 318 | self.assertTrue(report.total_errors) 319 | 320 | self.assertRaises(TypeError, pep8style.check_files, 42) 321 | # < 3.3 raises TypeError; >= 3.3 raises AttributeError 322 | self.assertRaises(Exception, pep8style.check_files, [42]) 323 | 324 | def test_check_nullbytes(self): 325 | pycodestyle.register_check(DummyChecker, ['Z701']) 326 | 327 | pep8style = pycodestyle.StyleGuide() 328 | count_errors = pep8style.input_file('stdin', lines=['\x00\n']) 329 | 330 | stdout = sys.stdout.getvalue() 331 | if sys.version_info < (3, 11, 4): # pragma: <3.11 cover 332 | expected = ["stdin:1:1: E901 ValueError: source code string cannot contain null bytes"] # noqa: E501 333 | elif sys.version_info < (3, 12): # pragma: <3.12 cover # pragma: >=3.11 cover # noqa: E501 334 | expected = ["stdin:1:1: E901 SyntaxError: source code string cannot contain null bytes"] # noqa: E501 335 | else: # pragma: >=3.12 cover 336 | expected = [ 337 | "stdin:1:1: E901 SyntaxError: source code string cannot contain null bytes", # noqa: E501 338 | "stdin:1:1: E901 TokenError: source code cannot contain null bytes", # noqa: E501 339 | ] 340 | self.assertEqual(stdout.splitlines(), expected) 341 | self.assertFalse(sys.stderr.getvalue()) 342 | self.assertEqual(count_errors, len(expected)) 343 | 344 | def test_styleguide_unmatched_triple_quotes(self): 345 | pycodestyle.register_check(DummyChecker, ['Z701']) 346 | lines = [ 347 | 'def foo():\n', 348 | ' """test docstring""\'\n', 349 | ] 350 | 351 | pep8style = pycodestyle.StyleGuide() 352 | pep8style.input_file('stdin', lines=lines) 353 | stdout = sys.stdout.getvalue() 354 | 355 | if sys.version_info < (3, 10): # pragma: <3.10 cover 356 | expected = [ 357 | 'stdin:2:5: E901 TokenError: EOF in multi-line string', 358 | 'stdin:2:26: E901 SyntaxError: EOF while scanning triple-quoted string literal', # noqa: E501 359 | ] 360 | elif sys.version_info < (3, 12): # pragma: >=3.10 cover # pragma: <3.12 cover # noqa: E501 361 | expected = [ 362 | 'stdin:2:5: E901 TokenError: EOF in multi-line string', 363 | 'stdin:2:6: E901 SyntaxError: unterminated triple-quoted string literal (detected at line 2)', # noqa: E501 364 | ] 365 | else: # pragma: >=3.12 cover 366 | expected = [ 367 | 'stdin:2:6: E901 SyntaxError: unterminated triple-quoted string literal (detected at line 2)', # noqa: E501 368 | 'stdin:2:6: E901 TokenError: EOF in multi-line string', 369 | ] 370 | self.assertEqual(stdout.splitlines(), expected) 371 | 372 | def test_styleguides_other_indent_size(self): 373 | pycodestyle.register_check(DummyChecker, ['Z701']) 374 | lines = [ 375 | 'def foo():\n', 376 | ' pass\n', 377 | '\n', 378 | '\n', 379 | 'def foo_correct():\n', 380 | ' pass\n', 381 | '\n', 382 | '\n', 383 | 'def bar():\n', 384 | ' [1, 2, 3,\n', 385 | ' 4, 5, 6,\n', 386 | ' ]\n', 387 | '\n', 388 | '\n', 389 | 'if (1 in [1, 2, 3]\n', 390 | ' and bool(0) is False\n', 391 | ' and bool(1) is True):\n', 392 | ' pass\n' 393 | ] 394 | 395 | pep8style = pycodestyle.StyleGuide() 396 | pep8style.options.indent_size = 3 397 | count_errors = pep8style.input_file('stdin', lines=lines) 398 | stdout = sys.stdout.getvalue() 399 | self.assertEqual(count_errors, 4) 400 | expected = ( 401 | 'stdin:2:5: ' 402 | 'E111 indentation is not a multiple of 3' 403 | ) 404 | self.assertTrue(expected in stdout) 405 | expected = ( 406 | 'stdin:11:6: ' 407 | 'E127 continuation line over-indented for visual indent' 408 | ) 409 | self.assertTrue(expected in stdout) 410 | expected = ( 411 | 'stdin:12:6: ' 412 | 'E124 closing bracket does not match visual indentation' 413 | ) 414 | self.assertTrue(expected in stdout) 415 | expected = ( 416 | 'stdin:17:6: ' 417 | 'E127 continuation line over-indented for visual indent' 418 | ) 419 | self.assertTrue(expected in stdout) 420 | -------------------------------------------------------------------------------- /tests/test_blank_lines.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the blank_lines checker. 3 | 4 | It uses dedicated assertions which work with TestReport. 5 | """ 6 | import unittest 7 | 8 | import pycodestyle 9 | from testing.support import errors_from_src 10 | 11 | 12 | class BlankLinesTestCase(unittest.TestCase): 13 | """ 14 | Common code for running blank_lines tests. 15 | """ 16 | 17 | def assertNoErrors(self, actual): 18 | """ 19 | Check that the actual result from the checker has no errors. 20 | """ 21 | self.assertEqual([], actual) 22 | 23 | 24 | class TestBlankLinesDefault(BlankLinesTestCase): 25 | """ 26 | Tests for default blank with 2 blank lines for top level and 1 27 | blank line for methods. 28 | """ 29 | 30 | def test_initial_no_blank(self): 31 | """ 32 | It will accept no blank lines at the start of the file. 33 | """ 34 | result = errors_from_src("""def some_function(): 35 | pass 36 | """) 37 | 38 | self.assertNoErrors(result) 39 | 40 | def test_initial_lines_one_blank(self): 41 | """ 42 | It will accept 1 blank lines before the first line of actual 43 | code, even if in other places it asks for 2 44 | """ 45 | result = errors_from_src(""" 46 | def some_function(): 47 | pass 48 | """) 49 | 50 | self.assertNoErrors(result) 51 | 52 | def test_initial_lines_two_blanks(self): 53 | """ 54 | It will accept 2 blank lines before the first line of actual 55 | code, as normal. 56 | """ 57 | result = errors_from_src(""" 58 | 59 | def some_function(): 60 | pass 61 | """) 62 | 63 | self.assertNoErrors(result) 64 | 65 | def test_method_less_blank_lines(self): 66 | """ 67 | It will trigger an error when less than 1 blank lin is found 68 | before method definitions. 69 | """ 70 | result = errors_from_src("""# First comment line. 71 | class X: 72 | 73 | def a(): 74 | pass 75 | def b(): 76 | pass 77 | """) 78 | self.assertEqual([ 79 | 'E301:6:5', # b() call 80 | ], result) 81 | 82 | def test_method_less_blank_lines_comment(self): 83 | """ 84 | It will trigger an error when less than 1 blank lin is found 85 | before method definition, ignoring comments. 86 | """ 87 | result = errors_from_src("""# First comment line. 88 | class X: 89 | 90 | def a(): 91 | pass 92 | # A comment will not make it better. 93 | def b(): 94 | pass 95 | """) 96 | self.assertEqual([ 97 | 'E301:7:5', # b() call 98 | ], result) 99 | 100 | def test_top_level_fewer_blank_lines(self): 101 | """ 102 | It will trigger an error when less 2 blank lines are found 103 | before top level definitions. 104 | """ 105 | result = errors_from_src("""# First comment line. 106 | # Second line of comment. 107 | 108 | def some_function(): 109 | pass 110 | 111 | async def another_function(): 112 | pass 113 | 114 | 115 | def this_one_is_good(): 116 | pass 117 | 118 | class SomeCloseClass(object): 119 | pass 120 | 121 | 122 | async def this_async_is_good(): 123 | pass 124 | 125 | 126 | class AFarEnoughClass(object): 127 | pass 128 | """) 129 | self.assertEqual([ 130 | 'E302:7:1', # another_function 131 | 'E302:14:1', # SomeCloseClass 132 | ], result) 133 | 134 | def test_top_level_more_blank_lines(self): 135 | """ 136 | It will trigger an error when more 2 blank lines are found 137 | before top level definitions. 138 | """ 139 | result = errors_from_src("""# First comment line. 140 | # Second line of comment. 141 | 142 | 143 | 144 | def some_function(): 145 | pass 146 | 147 | 148 | def this_one_is_good(): 149 | pass 150 | 151 | 152 | 153 | class SomeFarClass(object): 154 | pass 155 | 156 | 157 | class AFarEnoughClass(object): 158 | pass 159 | """) 160 | self.assertEqual([ 161 | 'E303:6:1', # some_function 162 | 'E303:15:1', # SomeFarClass 163 | ], result) 164 | 165 | def test_method_more_blank_lines(self): 166 | """ 167 | It will trigger an error when more than 1 blank line is found 168 | before method definition 169 | """ 170 | result = errors_from_src("""# First comment line. 171 | 172 | 173 | class SomeCloseClass(object): 174 | 175 | 176 | def oneMethod(self): 177 | pass 178 | 179 | 180 | def anotherMethod(self): 181 | pass 182 | 183 | def methodOK(self): 184 | pass 185 | 186 | 187 | 188 | def veryFar(self): 189 | pass 190 | """) 191 | self.assertEqual([ 192 | 'E303:7:5', # oneMethod 193 | 'E303:11:5', # anotherMethod 194 | 'E303:19:5', # veryFar 195 | ], result) 196 | 197 | def test_initial_lines_more_blank(self): 198 | """ 199 | It will trigger an error for more than 2 blank lines before the 200 | first line of actual code. 201 | """ 202 | result = errors_from_src(""" 203 | 204 | 205 | def some_function(): 206 | pass 207 | """) 208 | self.assertEqual(['E303:4:1'], result) 209 | 210 | def test_blank_line_between_decorator(self): 211 | """ 212 | It will trigger an error when the decorator is followed by a 213 | blank line. 214 | """ 215 | result = errors_from_src("""# First line. 216 | 217 | 218 | @some_decorator 219 | 220 | def some_function(): 221 | pass 222 | 223 | 224 | class SomeClass(object): 225 | 226 | @method_decorator 227 | 228 | def some_method(self): 229 | pass 230 | """) 231 | self.assertEqual(['E304:6:1', 'E304:14:5'], result) 232 | 233 | def test_blank_line_decorator(self): 234 | """ 235 | It will accept the decorators which are adjacent to the function 236 | and method definition. 237 | """ 238 | result = errors_from_src("""# First line. 239 | 240 | 241 | @another_decorator 242 | @some_decorator 243 | def some_function(): 244 | pass 245 | 246 | 247 | class SomeClass(object): 248 | 249 | @method_decorator 250 | def some_method(self): 251 | pass 252 | """) 253 | self.assertNoErrors(result) 254 | 255 | def test_top_level_fewer_follow_lines(self): 256 | """ 257 | It will trigger an error when less than 2 blank lines are 258 | found between a top level definitions and other top level code. 259 | """ 260 | result = errors_from_src(""" 261 | def a(): 262 | print('Something') 263 | 264 | a() 265 | """) 266 | self.assertEqual([ 267 | 'E305:5:1', # a call 268 | ], result) 269 | 270 | def test_top_level_fewer_follow_lines_comments(self): 271 | """ 272 | It will trigger an error when less than 2 blank lines are 273 | found between a top level definitions and other top level code, 274 | even if we have comments before 275 | """ 276 | result = errors_from_src(""" 277 | def a(): 278 | print('Something') 279 | 280 | # comment 281 | 282 | # another comment 283 | 284 | # With comment still needs 2 spaces before, 285 | # as comments are ignored. 286 | a() 287 | """) 288 | self.assertEqual([ 289 | 'E305:11:1', # a call 290 | ], result) 291 | 292 | def test_top_level_good_follow_lines(self): 293 | """ 294 | It not trigger an error when 2 blank lines are 295 | found between a top level definitions and other top level code. 296 | """ 297 | result = errors_from_src(""" 298 | def a(): 299 | print('Something') 300 | 301 | # Some comments in other parts. 302 | 303 | # More comments. 304 | 305 | 306 | # With the right spaces, 307 | # It will work, even when we have comments. 308 | a() 309 | """) 310 | self.assertNoErrors(result) 311 | 312 | def test_method_fewer_follow_lines(self): 313 | """ 314 | It will trigger an error when less than 1 blank line is 315 | found between a method and previous definitions. 316 | """ 317 | result = errors_from_src(""" 318 | def a(): 319 | x = 1 320 | def b(): 321 | pass 322 | """) 323 | self.assertEqual([ 324 | 'E306:4:5', # b() call 325 | ], result) 326 | 327 | def test_method_nested_fewer_follow_lines(self): 328 | """ 329 | It will trigger an error when less than 1 blank line is 330 | found between a method and previous definitions, even when 331 | nested. 332 | """ 333 | result = errors_from_src(""" 334 | def a(): 335 | x = 2 336 | 337 | def b(): 338 | x = 1 339 | def c(): 340 | pass 341 | """) 342 | self.assertEqual([ 343 | 'E306:7:9', # c() call 344 | ], result) 345 | 346 | def test_method_nested_less_class(self): 347 | """ 348 | It will trigger an error when less than 1 blank line is found 349 | between a method and previous definitions, even when used to 350 | define a class. 351 | """ 352 | result = errors_from_src(""" 353 | def a(): 354 | x = 1 355 | class C: 356 | pass 357 | """) 358 | self.assertEqual([ 359 | 'E306:4:5', # class C definition. 360 | ], result) 361 | 362 | def test_method_nested_ok(self): 363 | """ 364 | Will not trigger an error when 1 blank line is found 365 | found between a method and previous definitions, even when 366 | nested. 367 | """ 368 | result = errors_from_src(""" 369 | def a(): 370 | x = 2 371 | 372 | def b(): 373 | x = 1 374 | 375 | def c(): 376 | pass 377 | 378 | class C: 379 | pass 380 | """) 381 | self.assertNoErrors(result) 382 | 383 | 384 | class TestBlankLinesTwisted(BlankLinesTestCase): 385 | """ 386 | Tests for blank_lines with 3 blank lines for top level and 2 blank 387 | line for methods as used by the Twisted coding style. 388 | """ 389 | 390 | def setUp(self): 391 | self._original_lines_config = pycodestyle.BLANK_LINES_CONFIG.copy() 392 | pycodestyle.BLANK_LINES_CONFIG['top_level'] = 3 393 | pycodestyle.BLANK_LINES_CONFIG['method'] = 2 394 | 395 | def tearDown(self): 396 | pycodestyle.BLANK_LINES_CONFIG = self._original_lines_config 397 | 398 | def test_initial_lines_one_blanks(self): 399 | """ 400 | It will accept less than 3 blank lines before the first line of 401 | actual code. 402 | """ 403 | result = errors_from_src(""" 404 | 405 | 406 | def some_function(): 407 | pass 408 | """) 409 | 410 | self.assertNoErrors(result) 411 | 412 | def test_initial_lines_tree_blanks(self): 413 | """ 414 | It will accept 3 blank lines before the first line of actual 415 | code, as normal. 416 | """ 417 | result = errors_from_src(""" 418 | 419 | 420 | def some_function(): 421 | pass 422 | """) 423 | 424 | self.assertNoErrors(result) 425 | 426 | def test_top_level_fewer_blank_lines(self): 427 | """ 428 | It will trigger an error when less 3 blank lines are found 429 | before top level definitions. 430 | """ 431 | result = errors_from_src("""# First comment line. 432 | # Second line of comment. 433 | 434 | 435 | def some_function(): 436 | pass 437 | 438 | 439 | async def another_function(): 440 | pass 441 | 442 | 443 | 444 | def this_one_is_good(): 445 | pass 446 | 447 | class SomeCloseClass(object): 448 | pass 449 | 450 | 451 | 452 | async def this_async_is_good(): 453 | pass 454 | 455 | 456 | 457 | class AFarEnoughClass(object): 458 | pass 459 | """) 460 | self.assertEqual([ 461 | 'E302:9:1', # another_function 462 | 'E302:17:1', # SomeCloseClass 463 | ], result) 464 | 465 | def test_top_level_more_blank_lines(self): 466 | """ 467 | It will trigger an error when more 2 blank lines are found 468 | before top level definitions. 469 | """ 470 | result = errors_from_src("""# First comment line. 471 | # Second line of comment. 472 | 473 | 474 | 475 | 476 | def some_function(): 477 | pass 478 | 479 | 480 | 481 | def this_one_is_good(): 482 | pass 483 | 484 | 485 | 486 | 487 | class SomeVeryFarClass(object): 488 | pass 489 | 490 | 491 | 492 | class AFarEnoughClass(object): 493 | pass 494 | """) 495 | self.assertEqual([ 496 | 'E303:7:1', # some_function 497 | 'E303:18:1', # SomeVeryFarClass 498 | ], result) 499 | 500 | def test_the_right_blanks(self): 501 | """ 502 | It will accept 3 blank for top level and 2 for nested. 503 | """ 504 | result = errors_from_src(""" 505 | 506 | 507 | def some_function(): 508 | pass 509 | 510 | 511 | 512 | # With comments. 513 | some_other = code_here 514 | 515 | 516 | 517 | class SomeClass: 518 | ''' 519 | Docstring here. 520 | ''' 521 | 522 | def some_method(): 523 | pass 524 | 525 | 526 | def another_method(): 527 | pass 528 | 529 | 530 | # More methods. 531 | def another_method_with_comment(): 532 | pass 533 | 534 | 535 | @decorator 536 | def another_method_with_comment(): 537 | pass 538 | """) 539 | 540 | self.assertNoErrors(result) 541 | -------------------------------------------------------------------------------- /tests/test_data.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import collections 4 | import os.path 5 | import re 6 | import sys 7 | 8 | import pytest 9 | 10 | import pycodestyle 11 | from testing.support import errors_from_src 12 | from testing.support import ROOT 13 | 14 | PY_RE = re.compile(r'^python(\d)(\d*)\.py$') 15 | CASE_RE = re.compile('^(#:.*\n)', re.MULTILINE) 16 | 17 | 18 | def _nsort(items: list[str]) -> list[str]: 19 | return sorted( 20 | items, 21 | key=lambda s: [ 22 | int(part) if part.isdigit() else part.lower() 23 | for part in re.split(r'(\d+)', s) 24 | ], 25 | ) 26 | 27 | 28 | def get_tests(): 29 | ret = [] 30 | for fname in _nsort(os.listdir(os.path.join(ROOT, 'testing', 'data'))): 31 | match = PY_RE.match(fname) 32 | if match is not None: 33 | major, minor = int(match[1]), int(match[2] or '0') 34 | mark = pytest.mark.skipif( 35 | sys.version_info < (major, minor), 36 | reason=f'requires Python {major}.{minor}', 37 | ) 38 | else: 39 | mark = () 40 | 41 | fname = os.path.join('testing', 'data', fname) 42 | fname_full = os.path.join(ROOT, fname) 43 | src = ''.join(pycodestyle.readlines(fname_full)) 44 | 45 | line = 1 46 | parts_it = iter(CASE_RE.split(src)) 47 | # the first case will not have a comment for it 48 | s = next(parts_it) 49 | if s.strip(): 50 | id_s = f'{fname}:{line}' 51 | ret.append(pytest.param('#: Okay', s, id=id_s, marks=mark)) 52 | line += s.count('\n') 53 | 54 | for comment, s in zip(parts_it, parts_it): 55 | if s.strip(): 56 | id_s = f'{fname}:{line}' 57 | ret.append(pytest.param(comment, s, id=id_s, marks=mark)) 58 | line += s.count('\n') + 1 59 | 60 | assert ret 61 | return ret 62 | 63 | 64 | @pytest.mark.parametrize(('case', 's'), get_tests()) 65 | def test(case, s): 66 | codes = collections.Counter() 67 | exact = collections.Counter() 68 | 69 | assert case.startswith('#:') 70 | for code in case[2:].strip().split(): 71 | if code == 'Okay': 72 | continue 73 | elif code == 'noeol': 74 | s = s.rstrip('\n') 75 | elif ':' in code: 76 | exact[code] += 1 77 | else: 78 | codes[code] += 1 79 | 80 | unexpected = collections.Counter() 81 | for code in errors_from_src(s): 82 | if exact[code]: 83 | exact[code] -= 1 84 | elif codes[code[:4]]: 85 | codes[code[:4]] -= 1 86 | else: # pragma: no cover 87 | unexpected[code] += 1 88 | 89 | messages = ( 90 | *(f'-{k}\n' for k, v in codes.items() for _ in range(v)), 91 | *(f'-{k}\n' for k, v in exact.items() for _ in range(v)), 92 | *(f'+{k}\n' for k, v in unexpected.items() for _ in range(v)), 93 | ) 94 | if messages: # pragma: no cover 95 | raise AssertionError(f'unexpected codes!\n{"".join(messages)}') 96 | -------------------------------------------------------------------------------- /tests/test_parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | import unittest 4 | 5 | import pycodestyle 6 | 7 | 8 | def _process_file(contents): 9 | with tempfile.NamedTemporaryFile(delete=False) as f: 10 | f.write(contents) 11 | 12 | options, args = pycodestyle.process_options(config_file=f.name) 13 | os.remove(f.name) 14 | 15 | return options, args 16 | 17 | 18 | class ParserTestCase(unittest.TestCase): 19 | 20 | def test_vanilla_ignore_parsing(self): 21 | contents = b""" 22 | [pycodestyle] 23 | ignore = E226,E24 24 | """ 25 | options, args = _process_file(contents) 26 | 27 | self.assertEqual(options.ignore, ["E226", "E24"]) 28 | 29 | def test_multiline_ignore_parsing(self): 30 | contents = b""" 31 | [pycodestyle] 32 | ignore = 33 | E226, 34 | E24 35 | """ 36 | 37 | options, args = _process_file(contents) 38 | 39 | self.assertEqual(options.ignore, ["E226", "E24"]) 40 | 41 | def test_trailing_comma_ignore_parsing(self): 42 | contents = b""" 43 | [pycodestyle] 44 | ignore = E226, 45 | """ 46 | 47 | options, args = _process_file(contents) 48 | 49 | self.assertEqual(options.ignore, ["E226"]) 50 | 51 | def test_multiline_trailing_comma_ignore_parsing(self): 52 | contents = b""" 53 | [pycodestyle] 54 | ignore = 55 | E226, 56 | E24, 57 | """ 58 | 59 | options, args = _process_file(contents) 60 | 61 | self.assertEqual(options.ignore, ["E226", "E24"]) 62 | -------------------------------------------------------------------------------- /tests/test_pycodestyle.py: -------------------------------------------------------------------------------- 1 | import io 2 | import sys 3 | import tokenize 4 | 5 | import pytest 6 | 7 | from pycodestyle import Checker 8 | from pycodestyle import expand_indent 9 | from pycodestyle import mute_string 10 | 11 | 12 | @pytest.mark.parametrize( 13 | ('s', 'expected'), 14 | ( 15 | (' ', 4), 16 | ('\t', 8), 17 | (' \t', 8), 18 | (' \t', 16), 19 | ), 20 | ) 21 | def test_expand_indent(s, expected): 22 | assert expand_indent(s) == expected 23 | 24 | 25 | @pytest.mark.parametrize( 26 | ('s', 'expected'), 27 | ( 28 | ('"abc"', '"xxx"'), 29 | ("'''abc'''", "'''xxx'''"), 30 | ("r'abc'", "r'xxx'"), 31 | ), 32 | ) 33 | def test_mute_string(s, expected): 34 | assert mute_string(s) == expected 35 | 36 | 37 | def test_fstring_logical_line(): 38 | src = '''\ 39 | f'hello {{ {thing} }} world' 40 | ''' 41 | checker = Checker(lines=src.splitlines()) 42 | checker.tokens = list(tokenize.generate_tokens(io.StringIO(src).readline)) 43 | checker.build_tokens_line() 44 | 45 | if sys.version_info >= (3, 12): # pragma: >3.12 cover 46 | assert checker.logical_line == "f'xxxxxxxxx{thing}xxxxxxxxx'" 47 | else: 48 | assert checker.logical_line == "f'xxxxxxxxxxxxxxxxxxxxxxxxx'" 49 | -------------------------------------------------------------------------------- /tests/test_self_doctests.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import pytest 4 | 5 | import pycodestyle 6 | from testing.support import errors_from_src 7 | 8 | SELFTEST_REGEX = re.compile(r'\b(Okay|[EW]\d{3}): (.*)') 9 | 10 | 11 | def get_tests(): 12 | ret = [ 13 | pytest.param( 14 | match[1], 15 | match[2], 16 | id=f'pycodestyle.py:{f.__code__.co_firstlineno}:{f.__name__}@{i}', 17 | ) 18 | for group in pycodestyle._checks.values() 19 | for f in group 20 | if f.__doc__ is not None 21 | for i, match in enumerate(SELFTEST_REGEX.finditer(f.__doc__)) 22 | ] 23 | assert ret 24 | return tuple(ret) 25 | 26 | 27 | @pytest.mark.parametrize(('expected', 's'), get_tests()) 28 | def test(expected, s): 29 | s = '\n'.join((*s.replace(r'\t', '\t').split(r'\n'), '')) 30 | errors = errors_from_src(s) 31 | if expected == 'Okay': 32 | assert errors == [] 33 | else: 34 | for error in errors: 35 | if error.startswith(f'{expected}:'): 36 | break 37 | else: 38 | raise AssertionError(f'expected {expected} from {s!r}') 39 | -------------------------------------------------------------------------------- /tests/test_shell.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | import io 3 | import os.path 4 | import sys 5 | import unittest 6 | 7 | import pycodestyle 8 | from testing.support import ROOT 9 | 10 | 11 | class ShellTestCase(unittest.TestCase): 12 | """Test the usual CLI options and output.""" 13 | 14 | def setUp(self): 15 | self._saved_argv = sys.argv 16 | self._saved_stdout = sys.stdout 17 | self._saved_stderr = sys.stderr 18 | self._saved_pconfig = pycodestyle.PROJECT_CONFIG 19 | self._saved_cpread = configparser.RawConfigParser._read 20 | self._saved_stdin_get_value = pycodestyle.stdin_get_value 21 | self._config_filenames = [] 22 | self.stdin = '' 23 | sys.argv = ['pycodestyle'] 24 | sys.stdout = io.StringIO() 25 | sys.stderr = io.StringIO() 26 | 27 | def fake_config_parser_read(cp, fp, filename): 28 | self._config_filenames.append(filename) 29 | configparser.RawConfigParser._read = fake_config_parser_read 30 | pycodestyle.stdin_get_value = self.stdin_get_value 31 | 32 | def tearDown(self): 33 | sys.argv = self._saved_argv 34 | sys.stdout = self._saved_stdout 35 | sys.stderr = self._saved_stderr 36 | pycodestyle.PROJECT_CONFIG = self._saved_pconfig 37 | configparser.RawConfigParser._read = self._saved_cpread 38 | pycodestyle.stdin_get_value = self._saved_stdin_get_value 39 | 40 | def stdin_get_value(self): 41 | return self.stdin 42 | 43 | def pycodestyle(self, *args): 44 | sys.stdout.seek(0) 45 | sys.stdout.truncate() 46 | sys.stderr.seek(0) 47 | sys.stderr.truncate() 48 | sys.argv[1:] = args 49 | try: 50 | pycodestyle._main() 51 | errorcode = None 52 | except SystemExit: 53 | errorcode = sys.exc_info()[1].code 54 | return sys.stdout.getvalue(), sys.stderr.getvalue(), errorcode 55 | 56 | def test_print_usage(self): 57 | stdout, stderr, errcode = self.pycodestyle('--help') 58 | self.assertFalse(errcode) 59 | self.assertFalse(stderr) 60 | self.assertTrue(stdout.startswith( 61 | "Usage: pycodestyle [options] input" 62 | )) 63 | 64 | stdout, stderr, errcode = self.pycodestyle('--version') 65 | self.assertFalse(errcode) 66 | self.assertFalse(stderr) 67 | self.assertEqual(stdout.count('\n'), 1) 68 | 69 | stdout, stderr, errcode = self.pycodestyle('--obfuscated') 70 | self.assertEqual(errcode, 2) 71 | self.assertEqual(stderr.splitlines(), 72 | ["Usage: pycodestyle [options] input ...", "", 73 | "pycodestyle: error: no such option: --obfuscated"]) 74 | self.assertFalse(stdout) 75 | 76 | self.assertFalse(self._config_filenames) 77 | 78 | def test_check_simple(self): 79 | E11 = os.path.join(ROOT, 'testing', 'data', 'E11.py') 80 | stdout, stderr, errcode = self.pycodestyle(E11) 81 | stdout = stdout.splitlines() 82 | self.assertEqual(errcode, 1) 83 | self.assertFalse(stderr) 84 | self.assertEqual(len(stdout), 24) 85 | for line, num, col in zip(stdout, (3, 6, 6, 9, 12), (3, 6, 6, 1, 5)): 86 | path, x, y, msg = line.rsplit(':', 3) 87 | self.assertTrue(path.endswith(E11)) 88 | self.assertEqual(x, str(num)) 89 | self.assertEqual(y, str(col)) 90 | self.assertTrue(msg.startswith(' E11')) 91 | # Config file read from the pycodestyle's setup.cfg 92 | config_filenames = [os.path.basename(p) 93 | for p in self._config_filenames] 94 | self.assertTrue('setup.cfg' in config_filenames) 95 | 96 | def test_check_stdin(self): 97 | pycodestyle.PROJECT_CONFIG = () 98 | stdout, stderr, errcode = self.pycodestyle('-') 99 | self.assertFalse(errcode) 100 | self.assertFalse(stderr) 101 | self.assertFalse(stdout) 102 | 103 | self.stdin = 'import os, sys\n' 104 | stdout, stderr, errcode = self.pycodestyle('-') 105 | stdout = stdout.splitlines() 106 | self.assertEqual(errcode, 1) 107 | self.assertFalse(stderr) 108 | self.assertEqual(stdout, 109 | ['stdin:1:10: E401 multiple imports on one line']) 110 | 111 | def test_check_non_existent(self): 112 | self.stdin = 'import os, sys\n' 113 | stdout, stderr, errcode = self.pycodestyle('fictitious.py') 114 | self.assertEqual(errcode, 1) 115 | self.assertFalse(stderr) 116 | self.assertTrue(stdout.startswith('fictitious.py:1:1: E902 ')) 117 | 118 | def test_check_noarg(self): 119 | # issue #170: do not read stdin by default 120 | pycodestyle.PROJECT_CONFIG = () 121 | stdout, stderr, errcode = self.pycodestyle() 122 | self.assertEqual(errcode, 2) 123 | self.assertEqual(stderr.splitlines(), 124 | ["Usage: pycodestyle [options] input ...", "", 125 | "pycodestyle: error: input not specified"]) 126 | self.assertFalse(self._config_filenames) 127 | 128 | def test_check_diff(self): 129 | pycodestyle.PROJECT_CONFIG = () 130 | diff_lines = [ 131 | "--- testing/data/E11.py 2006-06-01 08:49:50 +0500", 132 | "+++ testing/data/E11.py 2008-04-06 17:36:29 +0500", 133 | "@@ -2,4 +2,7 @@", 134 | " if x > 2:", 135 | " print x", 136 | "+#: E111", 137 | "+if True:", 138 | "+ print", 139 | " #: E112", 140 | " if False:", 141 | "", 142 | ] 143 | 144 | self.stdin = '\n'.join(diff_lines) 145 | stdout, stderr, errcode = self.pycodestyle('--diff') 146 | stdout = stdout.splitlines() 147 | self.assertEqual(errcode, 1) 148 | self.assertFalse(stderr) 149 | for line, num, col in zip(stdout, (3, 6), (3, 6)): 150 | path, x, y, msg = line.split(':') 151 | self.assertEqual(x, str(num)) 152 | self.assertEqual(y, str(col)) 153 | self.assertTrue(msg.startswith(' E11')) 154 | 155 | diff_lines[:2] = [ 156 | "--- a/testing/data/E11.py 2006-06-01 08:49 +0400", 157 | "+++ b/testing/data/E11.py 2008-04-06 17:36 +0400", 158 | ] 159 | self.stdin = '\n'.join(diff_lines) 160 | stdout, stderr, errcode = self.pycodestyle('--diff') 161 | stdout = stdout.splitlines() 162 | self.assertEqual(errcode, 1) 163 | self.assertFalse(stderr) 164 | for line, num, col in zip(stdout, (3, 6), (3, 6)): 165 | path, x, y, msg = line.split(':') 166 | self.assertEqual(x, str(num)) 167 | self.assertEqual(y, str(col)) 168 | self.assertTrue(msg.startswith(' E11')) 169 | 170 | # issue #127, #137: one-line chunks 171 | diff_lines[:-1] = [ 172 | "diff --git a/testing/data/E11.py b/testing/data/E11.py", 173 | "index 8735e25..2ecb529 100644", 174 | "--- a/testing/data/E11.py", 175 | "+++ b/testing/data/E11.py", 176 | "@@ -5,0 +6 @@ if True:", 177 | "+ print", 178 | ] 179 | self.stdin = '\n'.join(diff_lines) 180 | stdout, stderr, errcode = self.pycodestyle('--diff') 181 | stdout = stdout.splitlines() 182 | self.assertEqual(errcode, 1) 183 | self.assertFalse(stderr) 184 | self.assertTrue('testing/data/E11.py:6:6: E111 ' in stdout[0]) 185 | self.assertTrue('testing/data/E11.py:6:6: E117 ' in stdout[1]) 186 | 187 | # missing '--diff' 188 | self.stdin = '\n'.join(diff_lines) 189 | stdout, stderr, errcode = self.pycodestyle() 190 | self.assertEqual(errcode, 2) 191 | self.assertFalse(stdout) 192 | self.assertTrue(stderr.startswith( 193 | 'Usage: pycodestyle [options] input ...' 194 | )) 195 | 196 | # no matching file in the diff 197 | diff_lines[3] = "+++ b/testing/lost/E11.py" 198 | self.stdin = '\n'.join(diff_lines) 199 | stdout, stderr, errcode = self.pycodestyle('--diff') 200 | self.assertFalse(errcode) 201 | self.assertFalse(stdout) 202 | self.assertFalse(stderr) 203 | 204 | for index, diff_line in enumerate(diff_lines, 0): 205 | diff_line = diff_line.replace('a/', 'i/') 206 | diff_lines[index] = diff_line.replace('b/', 'w/') 207 | 208 | self.stdin = '\n'.join(diff_lines) 209 | stdout, stderr, errcode = self.pycodestyle('--diff') 210 | self.assertFalse(errcode) 211 | self.assertFalse(stdout) 212 | self.assertFalse(stderr) 213 | -------------------------------------------------------------------------------- /tests/test_util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | from pycodestyle import normalize_paths 5 | 6 | 7 | class UtilTestCase(unittest.TestCase): 8 | def test_normalize_paths(self): 9 | self.assertEqual(normalize_paths(''), []) 10 | self.assertEqual(normalize_paths([]), []) 11 | self.assertEqual(normalize_paths(None), []) 12 | self.assertEqual(normalize_paths(['foo']), ['foo']) 13 | self.assertEqual(normalize_paths('foo'), ['foo']) 14 | self.assertEqual(normalize_paths('foo,bar'), ['foo', 'bar']) 15 | self.assertEqual(normalize_paths('foo, bar '), ['foo', 'bar']) 16 | self.assertEqual( 17 | normalize_paths('/foo/bar,baz/../bat'), 18 | [os.path.realpath('/foo/bar'), os.path.abspath('bat')], 19 | ) 20 | self.assertEqual( 21 | normalize_paths(".pyc,\n build/*"), 22 | ['.pyc', os.path.abspath('build/*')], 23 | ) 24 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (https://tox.readthedocs.io/en/latest/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py, pypy3 8 | skip_missing_interpreters = True 9 | 10 | [testenv] 11 | deps = 12 | covdefaults 13 | coverage 14 | pytest 15 | commands = 16 | python -m pycodestyle --statistics pycodestyle.py 17 | coverage run -m pytest tests 18 | coverage report 19 | 20 | [testenv:flake8] 21 | skip_install = true 22 | deps = flake8 23 | commands = 24 | flake8 pycodestyle.py 25 | --------------------------------------------------------------------------------