pax_global_header00006660000000000000000000000064147414734660014532gustar00rootroot0000000000000052 comment=4046ad49e25b7fa1db275bf66b1b7d60600ac391 autopep8-2.3.2/000077500000000000000000000000001474147346600133035ustar00rootroot00000000000000autopep8-2.3.2/.codecov.yml000066400000000000000000000001061474147346600155230ustar00rootroot00000000000000coverage: status: project: default: threshold: 1% autopep8-2.3.2/.github/000077500000000000000000000000001474147346600146435ustar00rootroot00000000000000autopep8-2.3.2/.github/ISSUE_TEMPLATE.md000066400000000000000000000004301474147346600173450ustar00rootroot00000000000000 --- ## Python Code ```python YOUR CODE ``` ## Command Line and Configuration `.pep8`, `setup.cfg`, ... ```ini [pep8] ``` Command Line ```console $ autopep8 ``` ## Your Environment * Python version: * autopep8 version: * Platform: windows, linux, macOSX, and other OS... autopep8-2.3.2/.github/dependabot.yml000066400000000000000000000001661474147346600174760ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" autopep8-2.3.2/.github/workflows/000077500000000000000000000000001474147346600167005ustar00rootroot00000000000000autopep8-2.3.2/.github/workflows/codeql-analysis.yml000066400000000000000000000026531474147346600225210ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ main ] pull_request: # The branches below must be a subset of the branches above branches: [ main ] schedule: - cron: '33 15 * * 5' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'python' ] steps: - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 autopep8-2.3.2/.github/workflows/python-package.yml000066400000000000000000000037051474147346600223420ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Python package on: push: branches: [ main, v2 ] pull_request: branches: [ main, v2 ] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: [3.9, "3.10", "3.11", "3.12", "3.13", "pypy3.10"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install . pip install flake8 pytest pytest-cov pydiff if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | flake8 autopep8.py pycodestyle autopep8.py - name: doctest for readme if: matrix.python-version == 3.11 run: | python -m doctest -v README.rst - name: Test with pytest run: | pytest --cov-report xml --cov=autopep8 python test/acid.py -aaa --experimental test/example.py python test/acid.py -aaa --experimental test/example_with_reduce.py python test/acid.py --pycodestyle= -aaa --compare-bytecode --experimental test/example.py python test/acid.py --pycodestyle= --aggressive --line-range 550 610 test/inspect_example.py python test/acid.py --pycodestyle= --line-range 289 925 test/vectors_example.py python test/test_suite.py - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 if: (matrix.python-version == 3.11 || matrix.python-version == 3.12) && success() with: fail_ci_if_error: true flags: ${{ matrix.python-version }} token: ${{ secrets.CODECOV_TOKEN }} autopep8-2.3.2/.github/workflows/python-publish.yml000066400000000000000000000017031474147346600224110ustar00rootroot00000000000000# This workflows will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries name: Upload Python Package on: release: types: [created] jobs: deploy: runs-on: ubuntu-latest environment: name: pypi url: https://pypi.org/p/autopep8 permissions: id-token: write steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies run: | python -m pip install --upgrade pip build pip install setuptools wheel twine - name: Build run: | python -m build - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_API_TOKEN }} autopep8-2.3.2/.gitignore000066400000000000000000000003061474147346600152720ustar00rootroot00000000000000.eggs .idea/ *.class *.egg-info/ *.egg/ *.pyc *.swo *.swp .tox .travis-solo/ .build-*/ README.html __pycache__ .mypy_cache/ build .coverage coverage.xml dist htmlcov pep8.py test/suite/out/*.py.err autopep8-2.3.2/.pre-commit-config.yaml000066400000000000000000000001361474147346600175640ustar00rootroot00000000000000repos: - repo: https://github.com/pycqa/flake8 rev: 6.0.0 hooks: - id: flake8 autopep8-2.3.2/.pre-commit-hooks.yaml000066400000000000000000000003241474147346600174410ustar00rootroot00000000000000- id: autopep8 name: autopep8 description: A tool that automatically formats Python code to conform to the PEP 8 style guide. entry: autopep8 language: python types: [python] args: [-i] autopep8-2.3.2/AUTHORS.rst000066400000000000000000000037231474147346600151670ustar00rootroot00000000000000Main contributors ----------------- - Hideo Hattori (https://github.com/hhatto) - Steven Myint (https://github.com/myint) - Bill Wendling (https://github.com/gwelymernans) Patches ------- - Fraser Tweedale (https://github.com/frasertweedale) - clach04 (https://github.com/clach04) - Marc Abramowitz (https://github.com/msabramo) - dellis23 (https://github.com/dellis23) - Sam Vilain (https://github.com/samv) - Florent Xicluna (https://github.com/florentx) - Andras Tim (https://github.com/andras-tim) - tomscytale (https://github.com/tomscytale) - Filip Noetzel (https://github.com/peritus) - Erik Bray (https://github.com/iguananaut) - Christopher Medrela (https://github.com/chrismedrela) - 小明 (https://github.com/dongweiming) - Andy Hayden (https://github.com/hayd) - Fabio Zadrozny (https://github.com/fabioz) - Alex Chernetz (https://github.com/achernet) - Marc Schlaich (https://github.com/schlamar) - E. M. Bray (https://github.com/embray) - Thomas Hisch (https://github.com/thisch) - Florian Best (https://github.com/spaceone) - Ian Clark (https://github.com/evenicoulddoit) - Khairi Hafsham (https://github.com/khairihafsham) - Neil Halelamien (https://github.com/neilsh) - Hashem Nasarat (https://github.com/Hnasar) - Hugo van Kemenade (https://github.com/hugovk) - gmbnomis (https://github.com/gmbnomis) - Samuel Lelièvre (https://github.com/slel) - bigredengineer (https://github.com/bigredengineer) - Kai Chen (https://github.com/kx-chen) - Anthony Sottile (https://github.com/asottile) - 秋葉 (https://github.com/Hanaasagi) - Christian Clauss (https://github.com/cclauss) - tobixx (https://github.com/tobixx) - bigredengineer (https://github.com/bigredengineer) - Bastien Gérard (https://github.com/bagerard) - nicolasbonifas (https://github.com/nicolasbonifas) - Andrii Yurchuk (https://github.com/Ch00k) - José M. Guisado (https://github.com/pvxe) - Dai Truong (https://github.com/NovaDev94) - jnozsc (https://github.com/jnozsc) - Edwin Shepherd (https://github.com/shardros) autopep8-2.3.2/CONTRIBUTING.rst000066400000000000000000000020541474147346600157450ustar00rootroot00000000000000============ Contributing ============ Contributions are appreciated. Issues ====== When submitting a bug report, please provide the following: 1. Does the ``pycodestyle`` tool behave correctly? If not, then the bug report should be filed at the pycodestyle_ repository instead. 2. ``autopep8 --version`` 3. ``pycodestyle --version`` 4. ``python --version`` 5. ``uname -a`` if on Unix. 6. The example input that causes the bug. 7. The ``autopep8`` command-line options used to cause the bug. 8. The expected output. 9. Does the bug happen with the latest version of autopep8? To upgrade:: $ pip install --upgrade git+https://github.com/hhatto/autopep8 Pull requests ============= When submitting a pull request, please do the following. 1. Does the ``pycodestyle`` tool behave correctly? If not, then a pull request should be filed at the pycodestyle_ repository instead. 2. Add a test case to ``test/test_autopep8.py`` that demonstrates what your change does. 3. Make sure all tests pass. .. _pycodestyle: https://github.com/PyCQA/pycodestyle autopep8-2.3.2/LICENSE000066400000000000000000000022351474147346600143120ustar00rootroot00000000000000Copyright (C) 2010-2011 Hideo Hattori Copyright (C) 2011-2013 Hideo Hattori, Steven Myint Copyright (C) 2013-2016 Hideo Hattori, Steven Myint, Bill Wendling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. autopep8-2.3.2/MANIFEST.in000066400000000000000000000013151474147346600150410ustar00rootroot00000000000000include AUTHORS.rst include LICENSE include README.rst include test/__init__.py include test/acid.py include test/bad_encoding.py include test/bad_encoding2.py include test/e101_example.py include test/example include test/example/x.py include test/example.py include test/iso_8859_1.py include test/fake_configuration/.pep8 include test/fake_pycodestyle_configuration/tox.ini include tox.ini recursive-exclude test/suite *.py recursive-exclude test/suite/out *.py exclude CONTRIBUTING.rst exclude Makefile exclude hooks exclude hooks/pre-push exclude install_hooks.bash exclude test/.gitignore exclude test/acid_pypi.py exclude test/suite exclude test/suite/out exclude test/vim_autopep8.py exclude update_readme.py autopep8-2.3.2/Makefile000066400000000000000000000105511474147346600147450ustar00rootroot00000000000000all: @echo "make test(test_basic, test_diff, test_unit)" @echo "make fasttest" @echo "make benchmark" @echo "make pypireg" @echo "make coverage" @echo "make check" @echo "make clean" PYTHON?=python COVERAGE?=coverage TEST_DIR=test test: test_basic test_diff test_unit fasttest: test_fast test_basic: @echo '---> Running basic test' @${PYTHON} autopep8.py --aggressive test/example.py > .tmp.test.py pycodestyle --repeat .tmp.test.py @rm .tmp.test.py test_diff: @echo '---> Running --diff test' @cp test/example.py .tmp.example.py @${PYTHON} autopep8.py --aggressive --diff .tmp.example.py > .tmp.example.py.patch patch < .tmp.example.py.patch @rm .tmp.example.py.patch pycodestyle --repeat .tmp.example.py && ${PYTHON} -m py_compile .tmp.example.py @rm .tmp.example.py test_unit: @echo '---> Running unit tests' @${PYTHON} test/test_autopep8.py test_fast: @echo '[run]' > .pytest.coveragerc @echo 'branch = True' >> .pytest.coveragerc @echo 'omit = "*/site-packages/*"' >> .pytest.coveragerc @echo '[report]' >> .pytest.coveragerc @echo 'include = autopep8.py' >> .pytest.coveragerc @AUTOPEP8_COVERAGE=1 py.test -n4 --cov-config .pytest.coveragerc \ --cov-report term-missing --cov autopep8 test/test_autopep8.py @rm .pytest.coveragerc .coverage test_ci: pytest --cov-report xml --cov=autopep8 @${PYTHON} test/acid.py -aaa --experimental test/example.py @${PYTHON} test/acid.py --pycodestyle= -aaa --compare-bytecode --experimental test/example.py @${PYTHON} test/acid.py --pycodestyle= --aggressive --line-range 550 610 test/inspect_example.py @${PYTHON} test/acid.py --pycodestyle= --line-range 289 925 test/vectors_example.py @${PYTHON} test/test_suite.py coverage: @coverage erase @AUTOPEP8_COVERAGE=1 ${COVERAGE} run --branch --parallel-mode --omit='*/site-packages/*' test/test_autopep8.py @${COVERAGE} combine @${COVERAGE} report --show-missing @${COVERAGE} xml --include=autopep8.py open_coverage: coverage @${COVERAGE} html @python -m webbrowser -n "file://${PWD}/htmlcov/index.html" benchmark: @echo '---> Benchmark of autopep8.py test/example.py' @time ${PYTHON} autopep8.py --aggressive test/example.py > /dev/null @echo '---> Benchmark of test_unit' @time ${PYTHON} test/test_autopep8.py > /dev/null @echo '---> Benchmark of autopep8.py -d test/*.py' @time ${PYTHON} autopep8.py -d test/*.py > /dev/null readme: @${PYTHON} update_readme.py @rstcheck README.rst @${PYTHON} -m doctest -v README.rst open_readme: readme @python -m webbrowser -n "file://${PWD}/README.html" check: pycodestyle \ --ignore=E402,E226,E24,W50 \ autopep8.py setup.py test/acid.py test/acid_pypi.py update_readme.py pycodestyle \ --max-line-length=300 test/test_autopep8.py pylint \ --reports=no \ --msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' \ --disable=bad-builtin \ --disable=bad-continuation \ --disable=fixme \ --disable=import-error \ --disable=invalid-name \ --disable=locally-disabled \ --disable=missing-docstring \ --disable=no-member \ --disable=no-self-use \ --disable=not-callable \ --disable=protected-access \ --disable=redefined-builtin \ --disable=star-args \ --disable=super-on-old-class \ --disable=too-few-public-methods \ --disable=too-many-arguments \ --disable=too-many-boolean-expressions \ --disable=too-many-branches \ --disable=too-many-instance-attributes \ --disable=too-many-lines \ --disable=too-many-locals \ --disable=too-many-nested-blocks \ --disable=too-many-public-methods \ --disable=too-many-statements \ --disable=undefined-loop-variable \ --rcfile=/dev/null autopep8.py setup.py update_readme.py pylint \ --reports=no \ --msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' \ --errors-only \ --disable=no-member \ --rcfile=/dev/null \ test/acid.py test/acid_pypi.py test/test_autopep8.py ./autopep8.py --diff autopep8.py setup.py test/test_autopep8.py update_readme.py mutant: @mut.py --disable-operator RIL -t autopep8 -u test.test_autopep8 -mc pypireg: ${PYTHON} -m pip install twine build ${PYTHON} -m build ${PYTHON} -m twine upload dist/* clean: rm -rf .tmp.test.py temp *.pyc *egg-info dist build \ __pycache__ */__pycache__ */*/__pycache__ \ htmlcov coverage.xml .PHONY: \ all clean mutant pypireg test_basic test_unit \ benchmark coverage open_coverage readme test_diff \ check fasttest open_readme test test_fast test_ci autopep8-2.3.2/README.rst000066400000000000000000000365241474147346600150040ustar00rootroot00000000000000======== autopep8 ======== .. image:: https://img.shields.io/pypi/v/autopep8.svg :target: https://pypi.org/project/autopep8/ :alt: PyPI Version .. image:: https://github.com/hhatto/autopep8/workflows/Python%20package/badge.svg :target: https://github.com/hhatto/autopep8/actions :alt: Build status .. image:: https://codecov.io/gh/hhatto/autopep8/branch/main/graph/badge.svg :target: https://codecov.io/gh/hhatto/autopep8 :alt: Code Coverage autopep8 automatically formats Python code to conform to the `PEP 8`_ style guide. It uses the pycodestyle_ utility to determine what parts of the code needs to be formatted. autopep8 is capable of fixing most of the formatting issues_ that can be reported by pycodestyle. .. _PEP 8: https://www.python.org/dev/peps/pep-0008/ .. _issues: https://pycodestyle.readthedocs.org/en/latest/intro.html#error-codes .. contents:: Installation ============ From pip:: $ pip install --upgrade autopep8 Consider using the ``--user`` option_. .. _option: https://pip.pypa.io/en/latest/user_guide/#user-installs Requirements ============ autopep8 requires pycodestyle_. .. _pycodestyle: https://github.com/PyCQA/pycodestyle Usage ===== To modify a file in place (with aggressive level 2):: $ autopep8 --in-place --aggressive --aggressive Before running autopep8. .. code-block:: python import math, sys; def example1(): ####This is a long comment. This should be wrapped to fit within 72 characters. some_tuple=( 1,2, 3,'a' ); some_variable={'long':'Long code lines should be wrapped within 79 characters.', 'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'], 'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1, 20,300,40000,500000000,60000000000000000]}} return (some_tuple, some_variable) def example2(): return {'has_key() is deprecated':True}.has_key({'f':2}.has_key('')); class Example3( object ): def __init__ ( self, bar ): #Comments should have a space after the hash. if bar : bar+=1; bar=bar* bar ; return bar else: some_string = """ Indentation in multiline strings should not be touched. Only actual code should be reindented. """ return (sys.path, some_string) After running autopep8. .. code-block:: python import math import sys def example1(): # This is a long comment. This should be wrapped to fit within 72 # characters. some_tuple = (1, 2, 3, 'a') some_variable = { 'long': 'Long code lines should be wrapped within 79 characters.', 'other': [ math.pi, 100, 200, 300, 9876543210, 'This is a long string that goes on'], 'more': { 'inner': 'This whole logical line should be wrapped.', some_tuple: [ 1, 20, 300, 40000, 500000000, 60000000000000000]}} return (some_tuple, some_variable) def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True} class Example3(object): def __init__(self, bar): # Comments should have a space after the hash. if bar: bar += 1 bar = bar * bar return bar else: some_string = """ Indentation in multiline strings should not be touched. Only actual code should be reindented. """ return (sys.path, some_string) Options:: usage: autopep8 [-h] [--version] [-v] [-d] [-i] [--global-config filename] [--ignore-local-config] [-r] [-j n] [-p n] [-a] [--experimental] [--exclude globs] [--list-fixes] [--ignore errors] [--select errors] [--max-line-length n] [--line-range line line] [--hang-closing] [--exit-code] [files [files ...]] Automatically formats Python code to conform to the PEP 8 style guide. positional arguments: files files to format or '-' for standard in optional arguments: -h, --help show this help message and exit --version show program's version number and exit -v, --verbose print verbose messages; multiple -v result in more verbose messages -d, --diff print the diff for the fixed source -i, --in-place make changes to files in place --global-config filename path to a global pep8 config file; if this file does not exist then this is ignored (default: ~/.config/pep8) --ignore-local-config don't look for and apply local config files; if not passed, defaults are updated with any config files in the project's root directory -r, --recursive run recursively over directories; must be used with --in-place or --diff -j n, --jobs n number of parallel jobs; match CPU count if value is less than 1 -p n, --pep8-passes n maximum number of additional pep8 passes (default: infinite) -a, --aggressive enable non-whitespace changes; multiple -a result in more aggressive changes --experimental enable experimental fixes --exclude globs exclude file/directory names that match these comma- separated globs --list-fixes list codes for fixes; used by --ignore and --select --ignore errors do not fix these errors/warnings (default: E226,E24,W50,W690) --select errors fix only these errors/warnings (e.g. E4,W) --max-line-length n set maximum allowed line length (default: 79) --line-range line line, --range line line only fix errors found within this inclusive range of line numbers (e.g. 1 99); line numbers are indexed at 1 --hang-closing hang-closing option passed to pycodestyle --exit-code change to behavior of exit code. default behavior of return value, 0 is no differences, 1 is error exit. return 2 when add this option. 2 is exists differences. Features ======== autopep8 fixes the following issues_ reported by pycodestyle_:: E101 - Reindent all lines. E11 - Fix indentation. E121 - Fix indentation to be a multiple of four. E122 - Add absent indentation for hanging indentation. E123 - Align closing bracket to match opening bracket. E124 - Align closing bracket to match visual indentation. E125 - Indent to distinguish line from next logical line. E126 - Fix over-indented hanging indentation. E127 - Fix visual indentation. E128 - Fix visual indentation. E129 - Fix visual indentation. E131 - Fix hanging indent for unaligned continuation line. E133 - Fix missing indentation for closing bracket. E20 - Remove extraneous whitespace. E211 - Remove extraneous whitespace. E22 - Fix extraneous whitespace around keywords. E224 - Remove extraneous whitespace around operator. E225 - Fix missing whitespace around operator. E226 - Fix missing whitespace around arithmetic operator. E227 - Fix missing whitespace around bitwise/shift operator. E228 - Fix missing whitespace around modulo operator. E231 - Add missing whitespace. E241 - Fix extraneous whitespace around keywords. E242 - Remove extraneous whitespace around operator. E251 - Remove whitespace around parameter '=' sign. E252 - Missing whitespace around parameter equals. E26 - Fix spacing after comment hash for inline comments. E265 - Fix spacing after comment hash for block comments. E266 - Fix too many leading '#' for block comments. E27 - Fix extraneous whitespace around keywords. E301 - Add missing blank line. E302 - Add missing 2 blank lines. E303 - Remove extra blank lines. E304 - Remove blank line following function decorator. E305 - Expected 2 blank lines after end of function or class. E306 - Expected 1 blank line before a nested definition. E401 - Put imports on separate lines. E402 - Fix module level import not at top of file E501 - Try to make lines fit within --max-line-length characters. E502 - Remove extraneous escape of newline. E701 - Put colon-separated compound statement on separate lines. E70 - Put semicolon-separated compound statement on separate lines. E711 - Fix comparison with None. E712 - Fix comparison with boolean. E713 - Use 'not in' for test for membership. E714 - Use 'is not' test for object identity. E721 - Use "isinstance()" instead of comparing types directly. E722 - Fix bare except. E731 - Use a def when use do not assign a lambda expression. W291 - Remove trailing whitespace. W292 - Add a single newline at the end of the file. W293 - Remove trailing whitespace on blank line. W391 - Remove trailing blank lines. W503 - Fix line break before binary operator. W504 - Fix line break after binary operator. W605 - Fix invalid escape sequence 'x'. autopep8 also fixes some issues not found by pycodestyle_. - Normalize files with mixed line endings. - Put a blank line between a class docstring and its first method declaration. (Enabled with ``E301``.) - Remove blank lines between a function declaration and its docstring. (Enabled with ``E303``.) autopep8 avoids fixing some issues found by pycodestyle_. - ``E112``/``E113`` for non comments are reports of bad indentation that break syntax rules. These should not be modified at all. - ``E265``, which refers to spacing after comment hash, is ignored if the comment looks like code. autopep8 avoids modifying these since they are not real comments. If you really want to get rid of the pycodestyle_ warning, consider just removing the commented-out code. (This can be automated via eradicate_.) .. _eradicate: https://github.com/myint/eradicate More advanced usage =================== By default autopep8 only makes whitespace changes. Thus, by default, it does not fix ``E711`` and ``E712``. (Changing ``x == None`` to ``x is None`` may change the meaning of the program if ``x`` has its ``__eq__`` method overridden.) Nor does it correct deprecated code ``W6``. To enable these more aggressive fixes, use the ``--aggressive`` option:: $ autopep8 --aggressive Use multiple ``--aggressive`` to increase the aggressiveness level. For example, ``E712`` requires aggressiveness level 2 (since ``x == True`` could be changed to either ``x`` or ``x is True``, but autopep8 chooses the former). ``--aggressive`` will also shorten lines more aggressively. It will also remove trailing whitespace more aggressively. (Usually, we don't touch trailing whitespace in docstrings and other multiline strings. And to do even more aggressive changes to docstrings, use docformatter_.) .. _docformatter: https://github.com/myint/docformatter To enable only a subset of the fixes, use the ``--select`` option. For example, to fix various types of indentation issues:: $ autopep8 --select=E1,W1 If the file being fixed is large, you may want to enable verbose progress messages:: $ autopep8 -v Passing in ``--experimental`` enables the following functionality: - Shortens code lines by taking its length into account :: $ autopep8 --experimental Disabling line-by-line ---------------------- It is possible to disable autopep8 until it is turned back on again in the file, using ``autopep8: off`` and then reenabling with ``autopep8: on``. .. code-block:: python # autopep8: off [ [23, 23, 13, 43], [32, 34, 34, 34], [56, 34, 34, 11], [10, 10, 10, 10], ] # autopep8: on ``fmt: off`` and ``fmt: on`` are also valid. Use as a module =============== The simplest way of using autopep8 as a module is via the ``fix_code()`` function: >>> import autopep8 >>> autopep8.fix_code('x= 123\n') 'x = 123\n' Or with options: >>> import autopep8 >>> autopep8.fix_code('print( 123 )\n', ... options={'ignore': ['E']}) 'print( 123 )\n' Configuration ============= By default, if ``$HOME/.config/pycodestyle`` (``~\.pycodestyle`` in Windows environment) exists, it will be used as global configuration file. Alternatively, you can specify the global configuration file with the ``--global-config`` option. Also, if ``setup.cfg``, ``tox.ini``, ``.pep8`` and ``.flake8`` files exist in the directory where the target file exists, it will be used as the configuration file. ``pep8``, ``pycodestyle``, and ``flake8`` can be used as a section. configuration file example:: [pycodestyle] max_line_length = 120 ignore = E501 pyproject.toml -------------- autopep8 can also use ``pyproject.toml``. The section must be ``[tool.autopep8]``, and ``pyproject.toml`` takes precedence over any other configuration files. configuration file example:: [tool.autopep8] max_line_length = 120 ignore = "E501,W6" # or ["E501", "W6"] in-place = true recursive = true aggressive = 3 Usage with pre-commit ===================== autopep8 can be used as a hook for pre-commit_. To add autopep8 as a plugin, add this repo definition to your configuration: .. code-block:: yaml repos: - repo: https://github.com/hhatto/autopep8 rev: ... # select the tag or revision you want, or run `pre-commit autoupdate` hooks: - id: autopep8 .. _`pre-commit`: https://pre-commit.com Testing ======= Test cases are in ``test/test_autopep8.py``. They can be run directly via ``python test/test_autopep8.py`` or via tox_. The latter is useful for testing against multiple Python interpreters. (We currently test against CPython versions 3.9, 3.10, 3.11, 3.12 and 3.13. We also test against PyPy.) .. _`tox`: https://pypi.org/project/tox/ Broad spectrum testing is available via ``test/acid.py``. This script runs autopep8 against Python code and checks for correctness and completeness of the code fixes. It can check that the bytecode remains identical. ``test/acid_pypi.py`` makes use of ``acid.py`` to test against the latest released packages on PyPI. Troubleshooting =============== ``pkg_resources.DistributionNotFound`` -------------------------------------- If you are using an ancient version of ``setuptools``, you might encounter ``pkg_resources.DistributionNotFound`` when trying to run ``autopep8``. Try upgrading ``setuptools`` to workaround this ``setuptools`` problem:: $ pip install --upgrade setuptools Use ``sudo`` if you are installing to the system. Links ===== * PyPI_ * GitHub_ * Codecov_ .. _PyPI: https://pypi.org/project/autopep8/ .. _GitHub: https://github.com/hhatto/autopep8 .. _`Codecov`: https://app.codecov.io/gh/hhatto/autopep8 autopep8-2.3.2/autopep8.py000077500000000000000000004665421474147346600154460ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (C) 2010-2011 Hideo Hattori # Copyright (C) 2011-2013 Hideo Hattori, Steven Myint # Copyright (C) 2013-2016 Hideo Hattori, Steven Myint, Bill Wendling # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # Copyright (C) 2006-2009 Johann C. Rocholl # Copyright (C) 2009-2013 Florent Xicluna # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """Automatically formats Python code to conform to the PEP 8 style guide. Fixes that only need be done once can be added by adding a function of the form "fix_(source)" to this module. They should return the fixed source code. These fixes are picked up by apply_global_fixes(). Fixes that depend on pycodestyle should be added as methods to FixPEP8. See the class documentation for more information. """ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import argparse import codecs import collections import copy import difflib import fnmatch import importlib import inspect import io import itertools import keyword import locale import os import re import signal import sys import textwrap import token import tokenize import warnings import ast from configparser import ConfigParser as SafeConfigParser, Error import pycodestyle __version__ = '2.3.2' CR = '\r' LF = '\n' CRLF = '\r\n' PYTHON_SHEBANG_REGEX = re.compile(r'^#!.*\bpython[23]?\b\s*$') LAMBDA_REGEX = re.compile(r'([\w.]+)\s=\slambda\s*([)(=\w,\s.]*):') COMPARE_NEGATIVE_REGEX = re.compile(r'\b(not)\s+([^][)(}{]+?)\s+(in|is)\s') COMPARE_NEGATIVE_REGEX_THROUGH = re.compile(r'\b(not\s+in|is\s+not)\s') BARE_EXCEPT_REGEX = re.compile(r'except\s*:') STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\s.*\):') DOCSTRING_START_REGEX = re.compile(r'^u?r?(?P["\']{3})') ENABLE_REGEX = re.compile(r'# *(fmt|autopep8): *on') DISABLE_REGEX = re.compile(r'# *(fmt|autopep8): *off') ENCODING_MAGIC_COMMENT = re.compile( r'^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)' ) COMPARE_TYPE_REGEX = re.compile( r'([=!]=)\s+type(?:\s*\(\s*([^)]*[^ )])\s*\))' r'|\btype(?:\s*\(\s*([^)]*[^ )])\s*\))\s+([=!]=)' ) TYPE_REGEX = re.compile(r'(type\s*\(\s*[^)]*?[^\s)]\s*\))') EXIT_CODE_OK = 0 EXIT_CODE_ERROR = 1 EXIT_CODE_EXISTS_DIFF = 2 EXIT_CODE_ARGPARSE_ERROR = 99 # For generating line shortening candidates. SHORTEN_OPERATOR_GROUPS = frozenset([ frozenset([',']), frozenset(['%']), frozenset([',', '(', '[', '{']), frozenset(['%', '(', '[', '{']), frozenset([',', '(', '[', '{', '%', '+', '-', '*', '/', '//']), frozenset(['%', '+', '-', '*', '/', '//']), ]) DEFAULT_IGNORE = 'E226,E24,W50,W690' # TODO: use pycodestyle.DEFAULT_IGNORE DEFAULT_INDENT_SIZE = 4 # these fixes conflict with each other, if the `--ignore` setting causes both # to be enabled, disable both of them CONFLICTING_CODES = ('W503', 'W504') if sys.platform == 'win32': # pragma: no cover DEFAULT_CONFIG = os.path.expanduser(r'~\.pycodestyle') else: DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'pycodestyle') # fallback, use .pep8 if not os.path.exists(DEFAULT_CONFIG): # pragma: no cover if sys.platform == 'win32': DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8') else: DEFAULT_CONFIG = os.path.join(os.path.expanduser('~/.config'), 'pep8') PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8', '.flake8') MAX_PYTHON_FILE_DETECTION_BYTES = 1024 IS_SUPPORT_TOKEN_FSTRING = False if sys.version_info >= (3, 12): # pgrama: no cover IS_SUPPORT_TOKEN_FSTRING = True def _custom_formatwarning(message, category, _, __, line=None): return f"{category.__name__}: {message}\n" def open_with_encoding(filename, mode='r', encoding=None, limit_byte_check=-1): """Return opened file with a specific encoding.""" if not encoding: encoding = detect_encoding(filename, limit_byte_check=limit_byte_check) return io.open(filename, mode=mode, encoding=encoding, newline='') # Preserve line endings def _detect_encoding_from_file(filename: str): try: with open(filename) as input_file: for idx, line in enumerate(input_file): if idx == 0 and line[0] == '\ufeff': return "utf-8-sig" if idx >= 2: break match = ENCODING_MAGIC_COMMENT.search(line) if match: return match.groups()[0] except Exception: pass # Python3's default encoding return 'utf-8' def detect_encoding(filename, limit_byte_check=-1): """Return file encoding.""" encoding = _detect_encoding_from_file(filename) if encoding == "utf-8-sig": return encoding try: with open_with_encoding(filename, encoding=encoding) as test_file: test_file.read(limit_byte_check) return encoding except (LookupError, SyntaxError, UnicodeDecodeError): return 'latin-1' def readlines_from_file(filename): """Return contents of file.""" with open_with_encoding(filename) as input_file: return input_file.readlines() def extended_blank_lines(logical_line, blank_lines, blank_before, indent_level, previous_logical): """Check for missing blank lines after class declaration.""" if previous_logical.startswith(('def ', 'async def ')): if blank_lines and pycodestyle.DOCSTRING_REGEX.match(logical_line): yield (0, 'E303 too many blank lines ({})'.format(blank_lines)) elif pycodestyle.DOCSTRING_REGEX.match(previous_logical): # Missing blank line between class docstring and method declaration. if ( indent_level and not blank_lines and not blank_before and logical_line.startswith(('def ', 'async def ')) and '(self' in logical_line ): yield (0, 'E301 expected 1 blank line, found 0') def continued_indentation(logical_line, tokens, indent_level, hang_closing, indent_char, noqa): """Override pycodestyle's function to provide indentation information.""" first_row = tokens[0][2][0] nrows = 1 + tokens[-1][2][0] - first_row if noqa or nrows == 1: return # indent_next tells us whether the next block is indented. Assuming # that it is indented by 4 spaces, then we should not allow 4-space # indents on the final continuation line. In turn, some other # indents are allowed to have an extra 4 spaces. indent_next = logical_line.endswith(':') row = depth = 0 valid_hangs = ( (DEFAULT_INDENT_SIZE,) if indent_char != '\t' else (DEFAULT_INDENT_SIZE, 2 * DEFAULT_INDENT_SIZE) ) # Remember how many brackets were opened on each line. parens = [0] * nrows # Relative indents of physical lines. rel_indent = [0] * nrows # For each depth, collect a list of opening rows. open_rows = [[0]] # For each depth, memorize the hanging indentation. hangs = [None] # Visual indents. indent_chances = {} last_indent = tokens[0][2] indent = [last_indent[1]] last_token_multiline = None line = None last_line = '' last_line_begins_with_multiline = False for token_type, text, start, end, line in tokens: newline = row < start[0] - first_row if newline: row = start[0] - first_row newline = (not last_token_multiline and token_type not in (tokenize.NL, tokenize.NEWLINE)) last_line_begins_with_multiline = last_token_multiline if newline: # This is the beginning of a continuation line. last_indent = start # Record the initial indent. rel_indent[row] = pycodestyle.expand_indent(line) - indent_level # Identify closing bracket. close_bracket = (token_type == tokenize.OP and text in ']})') # Is the indent relative to an opening bracket line? for open_row in reversed(open_rows[depth]): hang = rel_indent[row] - rel_indent[open_row] hanging_indent = hang in valid_hangs if hanging_indent: break if hangs[depth]: hanging_indent = (hang == hangs[depth]) visual_indent = (not close_bracket and hang > 0 and indent_chances.get(start[1])) if close_bracket and indent[depth]: # Closing bracket for visual indent. if start[1] != indent[depth]: yield (start, 'E124 {}'.format(indent[depth])) elif close_bracket and not hang: # closing bracket matches indentation of opening bracket's line if hang_closing: yield (start, 'E133 {}'.format(indent[depth])) elif indent[depth] and start[1] < indent[depth]: if visual_indent is not True: # Visual indent is broken. yield (start, 'E128 {}'.format(indent[depth])) elif (hanging_indent or (indent_next and rel_indent[row] == 2 * DEFAULT_INDENT_SIZE)): # Hanging indent is verified. if close_bracket and not hang_closing: yield (start, 'E123 {}'.format(indent_level + rel_indent[open_row])) hangs[depth] = hang elif visual_indent is True: # Visual indent is verified. indent[depth] = start[1] elif visual_indent in (text, str): # Ignore token lined up with matching one from a previous line. pass else: one_indented = (indent_level + rel_indent[open_row] + DEFAULT_INDENT_SIZE) # Indent is broken. if hang <= 0: error = ('E122', one_indented) elif indent[depth]: error = ('E127', indent[depth]) elif not close_bracket and hangs[depth]: error = ('E131', one_indented) elif hang > DEFAULT_INDENT_SIZE: error = ('E126', one_indented) else: hangs[depth] = hang error = ('E121', one_indented) yield (start, '{} {}'.format(*error)) # Look for visual indenting. if ( parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT) and not indent[depth] ): indent[depth] = start[1] indent_chances[start[1]] = True # Deal with implicit string concatenation. elif (token_type in (tokenize.STRING, tokenize.COMMENT) or text in ('u', 'ur', 'b', 'br')): indent_chances[start[1]] = str # Special case for the "if" statement because len("if (") is equal to # 4. elif not indent_chances and not row and not depth and text == 'if': indent_chances[end[1] + 1] = True elif text == ':' and line[end[1]:].isspace(): open_rows[depth].append(row) # Keep track of bracket depth. if token_type == tokenize.OP: if text in '([{': depth += 1 indent.append(0) hangs.append(None) if len(open_rows) == depth: open_rows.append([]) open_rows[depth].append(row) parens[row] += 1 elif text in ')]}' and depth > 0: # Parent indents should not be more than this one. prev_indent = indent.pop() or last_indent[1] hangs.pop() for d in range(depth): if indent[d] > prev_indent: indent[d] = 0 for ind in list(indent_chances): if ind >= prev_indent: del indent_chances[ind] del open_rows[depth + 1:] depth -= 1 if depth: indent_chances[indent[depth]] = True for idx in range(row, -1, -1): if parens[idx]: parens[idx] -= 1 break assert len(indent) == depth + 1 if ( start[1] not in indent_chances and # This is for purposes of speeding up E121 (GitHub #90). not last_line.rstrip().endswith(',') ): # Allow to line up tokens. indent_chances[start[1]] = text last_token_multiline = (start[0] != end[0]) if last_token_multiline: rel_indent[end[0] - first_row] = rel_indent[row] last_line = line if ( indent_next and not last_line_begins_with_multiline and pycodestyle.expand_indent(line) == indent_level + DEFAULT_INDENT_SIZE ): pos = (start[0], indent[0] + 4) desired_indent = indent_level + 2 * DEFAULT_INDENT_SIZE if visual_indent: yield (pos, 'E129 {}'.format(desired_indent)) else: yield (pos, 'E125 {}'.format(desired_indent)) # NOTE: need reload with runpy and call twice # see: https://github.com/hhatto/autopep8/issues/625 importlib.reload(pycodestyle) del pycodestyle._checks['logical_line'][pycodestyle.continued_indentation] pycodestyle.register_check(extended_blank_lines) pycodestyle.register_check(continued_indentation) class FixPEP8(object): """Fix invalid code. Fixer methods are prefixed "fix_". The _fix_source() method looks for these automatically. The fixer method can take either one or two arguments (in addition to self). The first argument is "result", which is the error information from pycodestyle. The second argument, "logical", is required only for logical-line fixes. The fixer method can return the list of modified lines or None. An empty list would mean that no changes were made. None would mean that only the line reported in the pycodestyle error was modified. Note that the modified line numbers that are returned are indexed at 1. This typically would correspond with the line number reported in the pycodestyle error information. [fixed method list] - e111,e114,e115,e116 - e121,e122,e123,e124,e125,e126,e127,e128,e129 - e201,e202,e203 - e211 - e221,e222,e223,e224,e225 - e231 - e251,e252 - e261,e262 - e271,e272,e273,e274,e275 - e301,e302,e303,e304,e305,e306 - e401,e402 - e502 - e701,e702,e703,e704 - e711,e712,e713,e714 - e721,e722 - e731 - w291 - w503,504 """ def __init__(self, filename, options, contents=None, long_line_ignore_cache=None): self.filename = filename if contents is None: self.source = readlines_from_file(filename) else: sio = io.StringIO(contents) self.source = sio.readlines() self.options = options self.indent_word = _get_indentword(''.join(self.source)) self.original_source = copy.copy(self.source) # collect imports line self.imports = {} for i, line in enumerate(self.source): if (line.find("import ") == 0 or line.find("from ") == 0) and \ line not in self.imports: # collect only import statements that first appeared self.imports[line] = i self.long_line_ignore_cache = ( set() if long_line_ignore_cache is None else long_line_ignore_cache) # Many fixers are the same even though pycodestyle categorizes them # differently. self.fix_e115 = self.fix_e112 self.fix_e121 = self._fix_reindent self.fix_e122 = self._fix_reindent self.fix_e123 = self._fix_reindent self.fix_e124 = self._fix_reindent self.fix_e126 = self._fix_reindent self.fix_e127 = self._fix_reindent self.fix_e128 = self._fix_reindent self.fix_e129 = self._fix_reindent self.fix_e133 = self.fix_e131 self.fix_e202 = self.fix_e201 self.fix_e203 = self.fix_e201 self.fix_e204 = self.fix_e201 self.fix_e211 = self.fix_e201 self.fix_e221 = self.fix_e271 self.fix_e222 = self.fix_e271 self.fix_e223 = self.fix_e271 self.fix_e226 = self.fix_e225 self.fix_e227 = self.fix_e225 self.fix_e228 = self.fix_e225 self.fix_e241 = self.fix_e271 self.fix_e242 = self.fix_e224 self.fix_e252 = self.fix_e225 self.fix_e261 = self.fix_e262 self.fix_e272 = self.fix_e271 self.fix_e273 = self.fix_e271 self.fix_e274 = self.fix_e271 self.fix_e275 = self.fix_e271 self.fix_e306 = self.fix_e301 self.fix_e501 = ( self.fix_long_line_logically if options and (options.aggressive >= 2 or options.experimental) else self.fix_long_line_physically) self.fix_e703 = self.fix_e702 self.fix_w292 = self.fix_w291 self.fix_w293 = self.fix_w291 def _check_affected_anothers(self, result) -> bool: """Check if the fix affects the number of lines of another remark.""" line_index = result['line'] - 1 target = self.source[line_index] original_target = self.original_source[line_index] return target != original_target def _fix_source(self, results): try: (logical_start, logical_end) = _find_logical(self.source) logical_support = True except (SyntaxError, tokenize.TokenError): # pragma: no cover logical_support = False completed_lines = set() for result in sorted(results, key=_priority_key): if result['line'] in completed_lines: continue fixed_methodname = 'fix_' + result['id'].lower() if hasattr(self, fixed_methodname): fix = getattr(self, fixed_methodname) line_index = result['line'] - 1 original_line = self.source[line_index] is_logical_fix = len(_get_parameters(fix)) > 2 if is_logical_fix: logical = None if logical_support: logical = _get_logical(self.source, result, logical_start, logical_end) if logical and set(range( logical[0][0] + 1, logical[1][0] + 1)).intersection( completed_lines): continue if self._check_affected_anothers(result): continue modified_lines = fix(result, logical) else: if self._check_affected_anothers(result): continue modified_lines = fix(result) if modified_lines is None: # Force logical fixes to report what they modified. assert not is_logical_fix if self.source[line_index] == original_line: modified_lines = [] if modified_lines: completed_lines.update(modified_lines) elif modified_lines == []: # Empty list means no fix if self.options.verbose >= 2: print( '---> Not fixing {error} on line {line}'.format( error=result['id'], line=result['line']), file=sys.stderr) else: # We assume one-line fix when None. completed_lines.add(result['line']) else: if self.options.verbose >= 3: print( "---> '{}' is not defined.".format(fixed_methodname), file=sys.stderr) info = result['info'].strip() print('---> {}:{}:{}:{}'.format(self.filename, result['line'], result['column'], info), file=sys.stderr) def fix(self): """Return a version of the source code with PEP 8 violations fixed.""" pep8_options = { 'ignore': self.options.ignore, 'select': self.options.select, 'max_line_length': self.options.max_line_length, 'hang_closing': self.options.hang_closing, } results = _execute_pep8(pep8_options, self.source) if self.options.verbose: progress = {} for r in results: if r['id'] not in progress: progress[r['id']] = set() progress[r['id']].add(r['line']) print('---> {n} issue(s) to fix {progress}'.format( n=len(results), progress=progress), file=sys.stderr) if self.options.line_range: start, end = self.options.line_range results = [r for r in results if start <= r['line'] <= end] self._fix_source(filter_results(source=''.join(self.source), results=results, aggressive=self.options.aggressive)) if self.options.line_range: # If number of lines has changed then change line_range. count = sum(sline.count('\n') for sline in self.source[start - 1:end]) self.options.line_range[1] = start + count - 1 return ''.join(self.source) def _fix_reindent(self, result): """Fix a badly indented line. This is done by adding or removing from its initial indent only. """ num_indent_spaces = int(result['info'].split()[1]) line_index = result['line'] - 1 target = self.source[line_index] self.source[line_index] = ' ' * num_indent_spaces + target.lstrip() def fix_e112(self, result): """Fix under-indented comments.""" line_index = result['line'] - 1 target = self.source[line_index] if not target.lstrip().startswith('#'): # Don't screw with invalid syntax. return [] self.source[line_index] = self.indent_word + target def fix_e113(self, result): """Fix unexpected indentation.""" line_index = result['line'] - 1 target = self.source[line_index] indent = _get_indentation(target) stripped = target.lstrip() self.source[line_index] = indent[1:] + stripped def fix_e116(self, result): """Fix over-indented comments.""" line_index = result['line'] - 1 target = self.source[line_index] indent = _get_indentation(target) stripped = target.lstrip() if not stripped.startswith('#'): # Don't screw with invalid syntax. return [] self.source[line_index] = indent[1:] + stripped def fix_e117(self, result): """Fix over-indented.""" line_index = result['line'] - 1 target = self.source[line_index] indent = _get_indentation(target) if indent == '\t': return [] stripped = target.lstrip() self.source[line_index] = indent[1:] + stripped def fix_e125(self, result): """Fix indentation undistinguish from the next logical line.""" num_indent_spaces = int(result['info'].split()[1]) line_index = result['line'] - 1 target = self.source[line_index] spaces_to_add = num_indent_spaces - len(_get_indentation(target)) indent = len(_get_indentation(target)) modified_lines = [] while len(_get_indentation(self.source[line_index])) >= indent: self.source[line_index] = (' ' * spaces_to_add + self.source[line_index]) modified_lines.append(1 + line_index) # Line indexed at 1. line_index -= 1 return modified_lines def fix_e131(self, result): """Fix indentation undistinguish from the next logical line.""" num_indent_spaces = int(result['info'].split()[1]) line_index = result['line'] - 1 target = self.source[line_index] spaces_to_add = num_indent_spaces - len(_get_indentation(target)) indent_length = len(_get_indentation(target)) spaces_to_add = num_indent_spaces - indent_length if num_indent_spaces == 0 and indent_length == 0: spaces_to_add = 4 if spaces_to_add >= 0: self.source[line_index] = (' ' * spaces_to_add + self.source[line_index]) else: offset = abs(spaces_to_add) self.source[line_index] = self.source[line_index][offset:] def fix_e201(self, result): """Remove extraneous whitespace.""" line_index = result['line'] - 1 target = self.source[line_index] offset = result['column'] - 1 fixed = fix_whitespace(target, offset=offset, replacement='') self.source[line_index] = fixed def fix_e224(self, result): """Remove extraneous whitespace around operator.""" target = self.source[result['line'] - 1] offset = result['column'] - 1 fixed = target[:offset] + target[offset:].replace('\t', ' ') self.source[result['line'] - 1] = fixed def fix_e225(self, result): """Fix missing whitespace around operator.""" target = self.source[result['line'] - 1] offset = result['column'] - 1 fixed = target[:offset] + ' ' + target[offset:] # Only proceed if non-whitespace characters match. # And make sure we don't break the indentation. if ( fixed.replace(' ', '') == target.replace(' ', '') and _get_indentation(fixed) == _get_indentation(target) ): self.source[result['line'] - 1] = fixed error_code = result.get('id', 0) try: ts = generate_tokens(fixed) except (SyntaxError, tokenize.TokenError): return if not check_syntax(fixed.lstrip()): return try: _missing_whitespace = ( pycodestyle.missing_whitespace_around_operator ) except AttributeError: # pycodestyle >= 2.11.0 _missing_whitespace = pycodestyle.missing_whitespace errors = list(_missing_whitespace(fixed, ts)) for e in reversed(errors): if error_code != e[1].split()[0]: continue offset = e[0][1] fixed = fixed[:offset] + ' ' + fixed[offset:] self.source[result['line'] - 1] = fixed else: return [] def fix_e231(self, result): """Add missing whitespace.""" line_index = result['line'] - 1 target = self.source[line_index] offset = result['column'] fixed = target[:offset].rstrip() + ' ' + target[offset:].lstrip() self.source[line_index] = fixed def fix_e251(self, result): """Remove whitespace around parameter '=' sign.""" line_index = result['line'] - 1 target = self.source[line_index] # This is necessary since pycodestyle sometimes reports columns that # goes past the end of the physical line. This happens in cases like, # foo(bar\n=None) c = min(result['column'] - 1, len(target) - 1) if target[c].strip(): fixed = target else: fixed = target[:c].rstrip() + target[c:].lstrip() # There could be an escaped newline # # def foo(a=\ # 1) if fixed.endswith(('=\\\n', '=\\\r\n', '=\\\r')): self.source[line_index] = fixed.rstrip('\n\r \t\\') self.source[line_index + 1] = self.source[line_index + 1].lstrip() return [line_index + 1, line_index + 2] # Line indexed at 1 self.source[result['line'] - 1] = fixed def fix_e262(self, result): """Fix spacing after inline comment hash.""" target = self.source[result['line'] - 1] offset = result['column'] code = target[:offset].rstrip(' \t#') comment = target[offset:].lstrip(' \t#') fixed = code + (' # ' + comment if comment.strip() else '\n') self.source[result['line'] - 1] = fixed def fix_e265(self, result): """Fix spacing after block comment hash.""" target = self.source[result['line'] - 1] indent = _get_indentation(target) line = target.lstrip(' \t') pos = next((index for index, c in enumerate(line) if c != '#')) hashes = line[:pos] comment = line[pos:].lstrip(' \t') # Ignore special comments, even in the middle of the file. if comment.startswith('!'): return fixed = indent + hashes + (' ' + comment if comment.strip() else '\n') self.source[result['line'] - 1] = fixed def fix_e266(self, result): """Fix too many block comment hashes.""" target = self.source[result['line'] - 1] # Leave stylistic outlined blocks alone. if target.strip().endswith('#'): return indentation = _get_indentation(target) fixed = indentation + '# ' + target.lstrip('# \t') self.source[result['line'] - 1] = fixed def fix_e271(self, result): """Fix extraneous whitespace around keywords.""" line_index = result['line'] - 1 target = self.source[line_index] offset = result['column'] - 1 fixed = fix_whitespace(target, offset=offset, replacement=' ') if fixed == target: return [] else: self.source[line_index] = fixed def fix_e301(self, result): """Add missing blank line.""" cr = '\n' self.source[result['line'] - 1] = cr + self.source[result['line'] - 1] def fix_e302(self, result): """Add missing 2 blank lines.""" add_linenum = 2 - int(result['info'].split()[-1]) offset = 1 if self.source[result['line'] - 2].strip() == "\\": offset = 2 cr = '\n' * add_linenum self.source[result['line'] - offset] = ( cr + self.source[result['line'] - offset] ) def fix_e303(self, result): """Remove extra blank lines.""" delete_linenum = int(result['info'].split('(')[1].split(')')[0]) - 2 delete_linenum = max(1, delete_linenum) # We need to count because pycodestyle reports an offset line number if # there are comments. cnt = 0 line = result['line'] - 2 modified_lines = [] while cnt < delete_linenum and line >= 0: if not self.source[line].strip(): self.source[line] = '' modified_lines.append(1 + line) # Line indexed at 1 cnt += 1 line -= 1 return modified_lines def fix_e304(self, result): """Remove blank line following function decorator.""" line = result['line'] - 2 if not self.source[line].strip(): self.source[line] = '' def fix_e305(self, result): """Add missing 2 blank lines after end of function or class.""" add_delete_linenum = 2 - int(result['info'].split()[-1]) cnt = 0 offset = result['line'] - 2 modified_lines = [] if add_delete_linenum < 0: # delete cr add_delete_linenum = abs(add_delete_linenum) while cnt < add_delete_linenum and offset >= 0: if not self.source[offset].strip(): self.source[offset] = '' modified_lines.append(1 + offset) # Line indexed at 1 cnt += 1 offset -= 1 else: # add cr cr = '\n' # check comment line while True: if offset < 0: break line = self.source[offset].lstrip() if not line: break if line[0] != '#': break offset -= 1 offset += 1 self.source[offset] = cr + self.source[offset] modified_lines.append(1 + offset) # Line indexed at 1. return modified_lines def fix_e401(self, result): """Put imports on separate lines.""" line_index = result['line'] - 1 target = self.source[line_index] offset = result['column'] - 1 if not target.lstrip().startswith('import'): return [] indentation = re.split(pattern=r'\bimport\b', string=target, maxsplit=1)[0] fixed = (target[:offset].rstrip('\t ,') + '\n' + indentation + 'import ' + target[offset:].lstrip('\t ,')) self.source[line_index] = fixed def fix_e402(self, result): (line_index, offset, target) = get_index_offset_contents(result, self.source) for i in range(1, 100): line = "".join(self.source[line_index:line_index+i]) try: generate_tokens("".join(line)) except (SyntaxError, tokenize.TokenError): continue break if not (target in self.imports and self.imports[target] != line_index): mod_offset = get_module_imports_on_top_of_file(self.source, line_index) self.source[mod_offset] = line + self.source[mod_offset] for offset in range(i): self.source[line_index+offset] = '' def fix_long_line_logically(self, result, logical): """Try to make lines fit within --max-line-length characters.""" if ( not logical or len(logical[2]) == 1 or self.source[result['line'] - 1].lstrip().startswith('#') ): return self.fix_long_line_physically(result) start_line_index = logical[0][0] end_line_index = logical[1][0] logical_lines = logical[2] previous_line = get_item(self.source, start_line_index - 1, default='') next_line = get_item(self.source, end_line_index + 1, default='') single_line = join_logical_line(''.join(logical_lines)) try: fixed = self.fix_long_line( target=single_line, previous_line=previous_line, next_line=next_line, original=''.join(logical_lines)) except (SyntaxError, tokenize.TokenError): return self.fix_long_line_physically(result) if fixed: for line_index in range(start_line_index, end_line_index + 1): self.source[line_index] = '' self.source[start_line_index] = fixed return range(start_line_index + 1, end_line_index + 1) return [] def fix_long_line_physically(self, result): """Try to make lines fit within --max-line-length characters.""" line_index = result['line'] - 1 target = self.source[line_index] previous_line = get_item(self.source, line_index - 1, default='') next_line = get_item(self.source, line_index + 1, default='') try: fixed = self.fix_long_line( target=target, previous_line=previous_line, next_line=next_line, original=target) except (SyntaxError, tokenize.TokenError): return [] if fixed: self.source[line_index] = fixed return [line_index + 1] return [] def fix_long_line(self, target, previous_line, next_line, original): cache_entry = (target, previous_line, next_line) if cache_entry in self.long_line_ignore_cache: return [] if target.lstrip().startswith('#'): if self.options.aggressive: # Wrap commented lines. return shorten_comment( line=target, max_line_length=self.options.max_line_length, last_comment=not next_line.lstrip().startswith('#')) return [] fixed = get_fixed_long_line( target=target, previous_line=previous_line, original=original, indent_word=self.indent_word, max_line_length=self.options.max_line_length, aggressive=self.options.aggressive, experimental=self.options.experimental, verbose=self.options.verbose) if fixed and not code_almost_equal(original, fixed): return fixed self.long_line_ignore_cache.add(cache_entry) return None def fix_e502(self, result): """Remove extraneous escape of newline.""" (line_index, _, target) = get_index_offset_contents(result, self.source) self.source[line_index] = target.rstrip('\n\r \t\\') + '\n' def fix_e701(self, result): """Put colon-separated compound statement on separate lines.""" line_index = result['line'] - 1 target = self.source[line_index] c = result['column'] fixed_source = (target[:c] + '\n' + _get_indentation(target) + self.indent_word + target[c:].lstrip('\n\r \t\\')) self.source[result['line'] - 1] = fixed_source return [result['line'], result['line'] + 1] def fix_e702(self, result, logical): """Put semicolon-separated compound statement on separate lines.""" if not logical: return [] # pragma: no cover logical_lines = logical[2] # Avoid applying this when indented. # https://docs.python.org/reference/compound_stmts.html for line in logical_lines: if ( result['id'] == 'E702' and ':' in line and pycodestyle.STARTSWITH_INDENT_STATEMENT_REGEX.match(line) ): if self.options.verbose: print( '---> avoid fixing {error} with ' 'other compound statements'.format(error=result['id']), file=sys.stderr ) return [] line_index = result['line'] - 1 target = self.source[line_index] if target.rstrip().endswith('\\'): # Normalize '1; \\\n2' into '1; 2'. self.source[line_index] = target.rstrip('\n \r\t\\') self.source[line_index + 1] = self.source[line_index + 1].lstrip() return [line_index + 1, line_index + 2] if target.rstrip().endswith(';'): self.source[line_index] = target.rstrip('\n \r\t;') + '\n' return [line_index + 1] offset = result['column'] - 1 first = target[:offset].rstrip(';').rstrip() second = (_get_indentation(logical_lines[0]) + target[offset:].lstrip(';').lstrip()) # Find inline comment. inline_comment = None if target[offset:].lstrip(';').lstrip()[:2] == '# ': inline_comment = target[offset:].lstrip(';') if inline_comment: self.source[line_index] = first + inline_comment else: self.source[line_index] = first + '\n' + second return [line_index + 1] def fix_e704(self, result): """Fix multiple statements on one line def""" (line_index, _, target) = get_index_offset_contents(result, self.source) match = STARTSWITH_DEF_REGEX.match(target) if match: self.source[line_index] = '{}\n{}{}'.format( match.group(0), _get_indentation(target) + self.indent_word, target[match.end(0):].lstrip()) def fix_e711(self, result): """Fix comparison with None.""" (line_index, offset, target) = get_index_offset_contents(result, self.source) right_offset = offset + 2 if right_offset >= len(target): return [] left = target[:offset].rstrip() center = target[offset:right_offset] right = target[right_offset:].lstrip() if center.strip() == '==': new_center = 'is' elif center.strip() == '!=': new_center = 'is not' else: return [] self.source[line_index] = ' '.join([left, new_center, right]) def fix_e712(self, result): """Fix (trivial case of) comparison with boolean.""" (line_index, offset, target) = get_index_offset_contents(result, self.source) # Handle very easy "not" special cases. if re.match(r'^\s*if [\w."\'\[\]]+ == False:$', target): self.source[line_index] = re.sub(r'if ([\w."\'\[\]]+) == False:', r'if not \1:', target, count=1) elif re.match(r'^\s*if [\w."\'\[\]]+ != True:$', target): self.source[line_index] = re.sub(r'if ([\w."\'\[\]]+) != True:', r'if not \1:', target, count=1) else: right_offset = offset + 2 if right_offset >= len(target): return [] left = target[:offset].rstrip() center = target[offset:right_offset] right = target[right_offset:].lstrip() # Handle simple cases only. new_right = None if center.strip() == '==': if re.match(r'\bTrue\b', right): new_right = re.sub(r'\bTrue\b *', '', right, count=1) elif center.strip() == '!=': if re.match(r'\bFalse\b', right): new_right = re.sub(r'\bFalse\b *', '', right, count=1) if new_right is None: return [] if new_right[0].isalnum(): new_right = ' ' + new_right self.source[line_index] = left + new_right def fix_e713(self, result): """Fix (trivial case of) non-membership check.""" (line_index, offset, target) = get_index_offset_contents(result, self.source) # to convert once 'not in' -> 'in' before_target = target[:offset] target = target[offset:] match_notin = COMPARE_NEGATIVE_REGEX_THROUGH.search(target) notin_pos_start, notin_pos_end = 0, 0 if match_notin: notin_pos_start = match_notin.start(1) notin_pos_end = match_notin.end() target = '{}{} {}'.format( target[:notin_pos_start], 'in', target[notin_pos_end:]) # fix 'not in' match = COMPARE_NEGATIVE_REGEX.search(target) if match: if match.group(3) == 'in': pos_start = match.start(1) new_target = '{5}{0}{1} {2} {3} {4}'.format( target[:pos_start], match.group(2), match.group(1), match.group(3), target[match.end():], before_target) if match_notin: # revert 'in' -> 'not in' pos_start = notin_pos_start + offset pos_end = notin_pos_end + offset - 4 # len('not ') new_target = '{}{} {}'.format( new_target[:pos_start], 'not in', new_target[pos_end:]) self.source[line_index] = new_target def fix_e714(self, result): """Fix object identity should be 'is not' case.""" (line_index, offset, target) = get_index_offset_contents(result, self.source) # to convert once 'is not' -> 'is' before_target = target[:offset] target = target[offset:] match_isnot = COMPARE_NEGATIVE_REGEX_THROUGH.search(target) isnot_pos_start, isnot_pos_end = 0, 0 if match_isnot: isnot_pos_start = match_isnot.start(1) isnot_pos_end = match_isnot.end() target = '{}{} {}'.format( target[:isnot_pos_start], 'in', target[isnot_pos_end:]) match = COMPARE_NEGATIVE_REGEX.search(target) if match: if match.group(3).startswith('is'): pos_start = match.start(1) new_target = '{5}{0}{1} {2} {3} {4}'.format( target[:pos_start], match.group(2), match.group(3), match.group(1), target[match.end():], before_target) if match_isnot: # revert 'is' -> 'is not' pos_start = isnot_pos_start + offset pos_end = isnot_pos_end + offset - 4 # len('not ') new_target = '{}{} {}'.format( new_target[:pos_start], 'is not', new_target[pos_end:]) self.source[line_index] = new_target def fix_e721(self, result): """fix comparison type""" (line_index, _, target) = get_index_offset_contents(result, self.source) match = COMPARE_TYPE_REGEX.search(target) if match: # NOTE: match objects # * type(a) == type(b) -> (None, None, 'a', '==') # * str == type(b) -> ('==', 'b', None, None) # * type(b) == str -> (None, None, 'b', '==') # * type("") != type(b) -> (None, None, '""', '!=') start = match.start() end = match.end() _prefix = "" _suffix = "" first_match_type_obj = match.groups()[1] if first_match_type_obj is None: _target_obj = match.groups()[2] else: _target_obj = match.groups()[1] _suffix = target[end:] isinstance_stmt = " isinstance" is_not_condition = ( match.groups()[0] == "!=" or match.groups()[3] == "!=" ) if is_not_condition: isinstance_stmt = " not isinstance" _type_comp = f"{_target_obj}, {target[:start]}" indent_match = re.match(r'^\s+', target) indent = "" if indent_match: indent = indent_match.group() _prefix_tmp = target[:start].split() if len(_prefix_tmp) >= 1: _type_comp = f"{_target_obj}, {target[:start]}" if first_match_type_obj is not None: _prefix = " ".join(_prefix_tmp[:-1]) _type_comp = f"{_target_obj}, {_prefix_tmp[-1]}" else: _prefix = " ".join(_prefix_tmp) _suffix_tmp = target[end:] _suffix_type_match = TYPE_REGEX.search(_suffix_tmp) if _suffix_type_match: if len(_suffix_tmp.split()) >= 1: type_match_end = _suffix_type_match.end() _suffix = _suffix_tmp[type_match_end:] cmp_b = _suffix_type_match.groups()[0] _type_comp = f"{_target_obj}, {cmp_b}" else: _else_suffix_match = re.match( r"^\s*([^\s:]+)(.*)$", _suffix_tmp, ) if _else_suffix_match: _else_suffix = _else_suffix_match.group(1) _else_suffix_other = _else_suffix_match.group(2) _type_comp = f"{_target_obj}, {_else_suffix}" _else_suffix_end = _suffix_tmp[_else_suffix_match.end():] _suffix = f"{_else_suffix_other}{_else_suffix_end}" # `else` route is not care fix_line = ( f"{indent}{_prefix}{isinstance_stmt}({_type_comp}){_suffix}" ) self.source[line_index] = fix_line def fix_e722(self, result): """fix bare except""" (line_index, _, target) = get_index_offset_contents(result, self.source) match = BARE_EXCEPT_REGEX.search(target) if match: self.source[line_index] = '{}{}{}'.format( target[:result['column'] - 1], "except BaseException:", target[match.end():]) def fix_e731(self, result): """Fix do not assign a lambda expression check.""" (line_index, _, target) = get_index_offset_contents(result, self.source) match = LAMBDA_REGEX.search(target) if match: end = match.end() self.source[line_index] = '{}def {}({}): return {}'.format( target[:match.start(0)], match.group(1), match.group(2), target[end:].lstrip()) def fix_w291(self, result): """Remove trailing whitespace.""" fixed_line = self.source[result['line'] - 1].rstrip() self.source[result['line'] - 1] = fixed_line + '\n' def fix_w391(self, _): """Remove trailing blank lines.""" blank_count = 0 for line in reversed(self.source): line = line.rstrip() if line: break else: blank_count += 1 original_length = len(self.source) self.source = self.source[:original_length - blank_count] return range(1, 1 + original_length) def fix_w503(self, result): (line_index, _, target) = get_index_offset_contents(result, self.source) one_string_token = target.split()[0] try: ts = generate_tokens(one_string_token) except (SyntaxError, tokenize.TokenError): return if not _is_binary_operator(ts[0][0], one_string_token): return # find comment comment_index = 0 found_not_comment_only_line = False comment_only_linenum = 0 for i in range(5): # NOTE: try to parse code in 5 times if (line_index - i) < 0: break from_index = line_index - i - 1 if from_index < 0 or len(self.source) <= from_index: break to_index = line_index + 1 strip_line = self.source[from_index].lstrip() if ( not found_not_comment_only_line and strip_line and strip_line[0] == '#' ): comment_only_linenum += 1 continue found_not_comment_only_line = True try: ts = generate_tokens("".join(self.source[from_index:to_index])) except (SyntaxError, tokenize.TokenError): continue newline_count = 0 newline_index = [] for index, t in enumerate(ts): if t[0] in (tokenize.NEWLINE, tokenize.NL): newline_index.append(index) newline_count += 1 if newline_count > 2: tts = ts[newline_index[-3]:] else: tts = ts old = [] for t in tts: if t[0] in (tokenize.NEWLINE, tokenize.NL): newline_count -= 1 if newline_count <= 1: break if tokenize.COMMENT == t[0] and old and old[0] != tokenize.NL: comment_index = old[3][1] break old = t break i = target.index(one_string_token) fix_target_line = line_index - 1 - comment_only_linenum self.source[line_index] = '{}{}'.format( target[:i], target[i + len(one_string_token):].lstrip()) nl = find_newline(self.source[fix_target_line:line_index]) before_line = self.source[fix_target_line] bl = before_line.index(nl) if comment_index: self.source[fix_target_line] = '{} {} {}'.format( before_line[:comment_index], one_string_token, before_line[comment_index + 1:]) else: if before_line[:bl].endswith("#"): # special case # see: https://github.com/hhatto/autopep8/issues/503 self.source[fix_target_line] = '{}{} {}'.format( before_line[:bl-2], one_string_token, before_line[bl-2:]) else: self.source[fix_target_line] = '{} {}{}'.format( before_line[:bl], one_string_token, before_line[bl:]) def fix_w504(self, result): (line_index, _, target) = get_index_offset_contents(result, self.source) # NOTE: is not collect pointed out in pycodestyle==2.4.0 comment_index = 0 operator_position = None # (start_position, end_position) for i in range(1, 6): to_index = line_index + i try: ts = generate_tokens("".join(self.source[line_index:to_index])) except (SyntaxError, tokenize.TokenError): continue newline_count = 0 newline_index = [] for index, t in enumerate(ts): if _is_binary_operator(t[0], t[1]): if t[2][0] == 1 and t[3][0] == 1: operator_position = (t[2][1], t[3][1]) elif t[0] == tokenize.NAME and t[1] in ("and", "or"): if t[2][0] == 1 and t[3][0] == 1: operator_position = (t[2][1], t[3][1]) elif t[0] in (tokenize.NEWLINE, tokenize.NL): newline_index.append(index) newline_count += 1 if newline_count > 2: tts = ts[:newline_index[-3]] else: tts = ts old = [] for t in tts: if tokenize.COMMENT == t[0] and old: comment_row, comment_index = old[3] break old = t break if not operator_position: return target_operator = target[operator_position[0]:operator_position[1]] if comment_index and comment_row == 1: self.source[line_index] = '{}{}'.format( target[:operator_position[0]].rstrip(), target[comment_index:]) else: self.source[line_index] = '{}{}{}'.format( target[:operator_position[0]].rstrip(), target[operator_position[1]:].lstrip(), target[operator_position[1]:]) next_line = self.source[line_index + 1] next_line_indent = 0 m = re.match(r'\s*', next_line) if m: next_line_indent = m.span()[1] self.source[line_index + 1] = '{}{} {}'.format( next_line[:next_line_indent], target_operator, next_line[next_line_indent:]) def fix_w605(self, result): (line_index, offset, target) = get_index_offset_contents(result, self.source) self.source[line_index] = '{}\\{}'.format( target[:offset + 1], target[offset + 1:]) def get_module_imports_on_top_of_file(source, import_line_index): """return import or from keyword position example: > 0: import sys 1: import os 2: 3: def function(): """ def is_string_literal(line): if line[0] in 'uUbB': line = line[1:] if line and line[0] in 'rR': line = line[1:] return line and (line[0] == '"' or line[0] == "'") def is_future_import(line): nodes = ast.parse(line) for n in nodes.body: if isinstance(n, ast.ImportFrom) and n.module == '__future__': return True return False def has_future_import(source): offset = 0 line = '' for _, next_line in source: for line_part in next_line.strip().splitlines(True): line = line + line_part try: return is_future_import(line), offset except SyntaxError: continue offset += 1 return False, offset allowed_try_keywords = ('try', 'except', 'else', 'finally') in_docstring = False docstring_kind = '"""' source_stream = iter(enumerate(source)) for cnt, line in source_stream: if not in_docstring: m = DOCSTRING_START_REGEX.match(line.lstrip()) if m is not None: in_docstring = True docstring_kind = m.group('kind') remain = line[m.end(): m.endpos].rstrip() if remain[-3:] == docstring_kind: # one line doc in_docstring = False continue if in_docstring: if line.rstrip()[-3:] == docstring_kind: in_docstring = False continue if not line.rstrip(): continue elif line.startswith('#'): continue if line.startswith('import '): if cnt == import_line_index: continue return cnt elif line.startswith('from '): if cnt == import_line_index: continue hit, offset = has_future_import( itertools.chain([(cnt, line)], source_stream) ) if hit: # move to the back return cnt + offset + 1 return cnt elif pycodestyle.DUNDER_REGEX.match(line): return cnt elif any(line.startswith(kw) for kw in allowed_try_keywords): continue elif is_string_literal(line): return cnt else: return cnt return 0 def get_index_offset_contents(result, source): """Return (line_index, column_offset, line_contents).""" line_index = result['line'] - 1 return (line_index, result['column'] - 1, source[line_index]) def get_fixed_long_line(target, previous_line, original, indent_word=' ', max_line_length=79, aggressive=0, experimental=False, verbose=False): """Break up long line and return result. Do this by generating multiple reformatted candidates and then ranking the candidates to heuristically select the best option. """ indent = _get_indentation(target) source = target[len(indent):] assert source.lstrip() == source assert not target.lstrip().startswith('#') # Check for partial multiline. tokens = list(generate_tokens(source)) candidates = shorten_line( tokens, source, indent, indent_word, max_line_length, aggressive=aggressive, experimental=experimental, previous_line=previous_line) # Also sort alphabetically as a tie breaker (for determinism). candidates = sorted( sorted(set(candidates).union([target, original])), key=lambda x: line_shortening_rank( x, indent_word, max_line_length, experimental=experimental)) if verbose >= 4: print(('-' * 79 + '\n').join([''] + candidates + ['']), file=wrap_output(sys.stderr, 'utf-8')) if candidates: best_candidate = candidates[0] # Don't allow things to get longer. if longest_line_length(best_candidate) > longest_line_length(original): return None return best_candidate def longest_line_length(code): """Return length of longest line.""" if len(code) == 0: return 0 return max(len(line) for line in code.splitlines()) def join_logical_line(logical_line): """Return single line based on logical line input.""" indentation = _get_indentation(logical_line) return indentation + untokenize_without_newlines( generate_tokens(logical_line.lstrip())) + '\n' def untokenize_without_newlines(tokens): """Return source code based on tokens.""" text = '' last_row = 0 last_column = -1 for t in tokens: token_string = t[1] (start_row, start_column) = t[2] (end_row, end_column) = t[3] if start_row > last_row: last_column = 0 if ( (start_column > last_column or token_string == '\n') and not text.endswith(' ') ): text += ' ' if token_string != '\n': text += token_string last_row = end_row last_column = end_column return text.rstrip() def _find_logical(source_lines): # Make a variable which is the index of all the starts of lines. logical_start = [] logical_end = [] last_newline = True parens = 0 for t in generate_tokens(''.join(source_lines)): if t[0] in [tokenize.COMMENT, tokenize.DEDENT, tokenize.INDENT, tokenize.NL, tokenize.ENDMARKER]: continue if not parens and t[0] in [tokenize.NEWLINE, tokenize.SEMI]: last_newline = True logical_end.append((t[3][0] - 1, t[2][1])) continue if last_newline and not parens: logical_start.append((t[2][0] - 1, t[2][1])) last_newline = False if t[0] == tokenize.OP: if t[1] in '([{': parens += 1 elif t[1] in '}])': parens -= 1 return (logical_start, logical_end) def _get_logical(source_lines, result, logical_start, logical_end): """Return the logical line corresponding to the result. Assumes input is already E702-clean. """ row = result['line'] - 1 col = result['column'] - 1 ls = None le = None for i in range(0, len(logical_start), 1): assert logical_end x = logical_end[i] if x[0] > row or (x[0] == row and x[1] > col): le = x ls = logical_start[i] break if ls is None: return None original = source_lines[ls[0]:le[0] + 1] return ls, le, original def get_item(items, index, default=None): if 0 <= index < len(items): return items[index] return default def reindent(source, indent_size, leave_tabs=False): """Reindent all lines.""" reindenter = Reindenter(source, leave_tabs) return reindenter.run(indent_size) def code_almost_equal(a, b): """Return True if code is similar. Ignore whitespace when comparing specific line. """ split_a = split_and_strip_non_empty_lines(a) split_b = split_and_strip_non_empty_lines(b) if len(split_a) != len(split_b): return False for (index, _) in enumerate(split_a): if ''.join(split_a[index].split()) != ''.join(split_b[index].split()): return False return True def split_and_strip_non_empty_lines(text): """Return lines split by newline. Ignore empty lines. """ return [line.strip() for line in text.splitlines() if line.strip()] def find_newline(source): """Return type of newline used in source. Input is a list of lines. """ assert not isinstance(source, str) counter = collections.defaultdict(int) for line in source: if line.endswith(CRLF): counter[CRLF] += 1 elif line.endswith(CR): counter[CR] += 1 elif line.endswith(LF): counter[LF] += 1 return (sorted(counter, key=counter.get, reverse=True) or [LF])[0] def _get_indentword(source): """Return indentation type.""" indent_word = ' ' # Default in case source has no indentation try: for t in generate_tokens(source): if t[0] == token.INDENT: indent_word = t[1] break except (SyntaxError, tokenize.TokenError): pass return indent_word def _get_indentation(line): """Return leading whitespace.""" if line.strip(): non_whitespace_index = len(line) - len(line.lstrip()) return line[:non_whitespace_index] return '' def get_diff_text(old, new, filename): """Return text of unified diff between old and new.""" newline = '\n' diff = difflib.unified_diff( old, new, 'original/' + filename, 'fixed/' + filename, lineterm=newline) text = '' for line in diff: text += line # Work around missing newline (http://bugs.python.org/issue2142). if text and not line.endswith(newline): text += newline + r'\ No newline at end of file' + newline return text def _priority_key(pep8_result): """Key for sorting PEP8 results. Global fixes should be done first. This is important for things like indentation. """ priority = [ # Fix multiline colon-based before semicolon based. 'e701', # Break multiline statements early. 'e702', # Things that make lines longer. 'e225', 'e231', # Remove extraneous whitespace before breaking lines. 'e201', # Shorten whitespace in comment before resorting to wrapping. 'e262' ] middle_index = 10000 lowest_priority = [ # We need to shorten lines last since the logical fixer can get in a # loop, which causes us to exit early. 'e501', ] key = pep8_result['id'].lower() try: return priority.index(key) except ValueError: try: return middle_index + lowest_priority.index(key) + 1 except ValueError: return middle_index def shorten_line(tokens, source, indentation, indent_word, max_line_length, aggressive=0, experimental=False, previous_line=''): """Separate line at OPERATOR. Multiple candidates will be yielded. """ for candidate in _shorten_line(tokens=tokens, source=source, indentation=indentation, indent_word=indent_word, aggressive=aggressive, previous_line=previous_line): yield candidate if aggressive: for key_token_strings in SHORTEN_OPERATOR_GROUPS: shortened = _shorten_line_at_tokens( tokens=tokens, source=source, indentation=indentation, indent_word=indent_word, key_token_strings=key_token_strings, aggressive=aggressive) if shortened is not None and shortened != source: yield shortened if experimental: for shortened in _shorten_line_at_tokens_new( tokens=tokens, source=source, indentation=indentation, max_line_length=max_line_length): yield shortened def _shorten_line(tokens, source, indentation, indent_word, aggressive=0, previous_line=''): """Separate line at OPERATOR. The input is expected to be free of newlines except for inside multiline strings and at the end. Multiple candidates will be yielded. """ in_string = False for (token_type, token_string, start_offset, end_offset) in token_offsets(tokens): if IS_SUPPORT_TOKEN_FSTRING: if token_type == tokenize.FSTRING_START: in_string = True elif token_type == tokenize.FSTRING_END: in_string = False if in_string: continue if ( token_type == tokenize.COMMENT and not is_probably_part_of_multiline(previous_line) and not is_probably_part_of_multiline(source) and not source[start_offset + 1:].strip().lower().startswith( ('noqa', 'pragma:', 'pylint:')) ): # Move inline comments to previous line. first = source[:start_offset] second = source[start_offset:] yield (indentation + second.strip() + '\n' + indentation + first.strip() + '\n') elif token_type == token.OP and token_string != '=': # Don't break on '=' after keyword as this violates PEP 8. assert token_type != token.INDENT first = source[:end_offset] second_indent = indentation if (first.rstrip().endswith('(') and source[end_offset:].lstrip().startswith(')')): pass elif first.rstrip().endswith('('): second_indent += indent_word elif '(' in first: second_indent += ' ' * (1 + first.find('(')) else: second_indent += indent_word second = (second_indent + source[end_offset:].lstrip()) if ( not second.strip() or second.lstrip().startswith('#') ): continue # Do not begin a line with a comma if second.lstrip().startswith(','): continue # Do end a line with a dot if first.rstrip().endswith('.'): continue if token_string in '+-*/': fixed = first + ' \\' + '\n' + second else: fixed = first + '\n' + second # Only fix if syntax is okay. if check_syntax(normalize_multiline(fixed) if aggressive else fixed): yield indentation + fixed def _is_binary_operator(token_type, text): return ((token_type == tokenize.OP or text in ['and', 'or']) and text not in '()[]{},:.;@=%~') # A convenient way to handle tokens. Token = collections.namedtuple('Token', ['token_type', 'token_string', 'spos', 'epos', 'line']) class ReformattedLines(object): """The reflowed lines of atoms. Each part of the line is represented as an "atom." They can be moved around when need be to get the optimal formatting. """ ########################################################################### # Private Classes class _Indent(object): """Represent an indentation in the atom stream.""" def __init__(self, indent_amt): self._indent_amt = indent_amt def emit(self): return ' ' * self._indent_amt @property def size(self): return self._indent_amt class _Space(object): """Represent a space in the atom stream.""" def emit(self): return ' ' @property def size(self): return 1 class _LineBreak(object): """Represent a line break in the atom stream.""" def emit(self): return '\n' @property def size(self): return 0 def __init__(self, max_line_length): self._max_line_length = max_line_length self._lines = [] self._bracket_depth = 0 self._prev_item = None self._prev_prev_item = None self._in_fstring = False def __repr__(self): return self.emit() ########################################################################### # Public Methods def add(self, obj, indent_amt, break_after_open_bracket): if isinstance(obj, Atom): self._add_item(obj, indent_amt) return self._add_container(obj, indent_amt, break_after_open_bracket) def add_comment(self, item): num_spaces = 2 if len(self._lines) > 1: if isinstance(self._lines[-1], self._Space): num_spaces -= 1 if len(self._lines) > 2: if isinstance(self._lines[-2], self._Space): num_spaces -= 1 while num_spaces > 0: self._lines.append(self._Space()) num_spaces -= 1 self._lines.append(item) def add_indent(self, indent_amt): self._lines.append(self._Indent(indent_amt)) def add_line_break(self, indent): self._lines.append(self._LineBreak()) self.add_indent(len(indent)) def add_line_break_at(self, index, indent_amt): self._lines.insert(index, self._LineBreak()) self._lines.insert(index + 1, self._Indent(indent_amt)) def add_space_if_needed(self, curr_text, equal=False): if ( not self._lines or isinstance( self._lines[-1], (self._LineBreak, self._Indent, self._Space)) ): return prev_text = str(self._prev_item) prev_prev_text = ( str(self._prev_prev_item) if self._prev_prev_item else '') if ( # The previous item was a keyword or identifier and the current # item isn't an operator that doesn't require a space. ((self._prev_item.is_keyword or self._prev_item.is_string or self._prev_item.is_name or self._prev_item.is_number) and (curr_text[0] not in '([{.,:}])' or (curr_text[0] == '=' and equal))) or # Don't place spaces around a '.', unless it's in an 'import' # statement. ((prev_prev_text != 'from' and prev_text[-1] != '.' and curr_text != 'import') and # Don't place a space before a colon. curr_text[0] != ':' and # Don't split up ending brackets by spaces. ((prev_text[-1] in '}])' and curr_text[0] not in '.,}])') or # Put a space after a colon or comma. prev_text[-1] in ':,' or # Put space around '=' if asked to. (equal and prev_text == '=') or # Put spaces around non-unary arithmetic operators. ((self._prev_prev_item and (prev_text not in '+-' and (self._prev_prev_item.is_name or self._prev_prev_item.is_number or self._prev_prev_item.is_string)) and prev_text in ('+', '-', '%', '*', '/', '//', '**', 'in'))))) ): self._lines.append(self._Space()) def previous_item(self): """Return the previous non-whitespace item.""" return self._prev_item def fits_on_current_line(self, item_extent): return self.current_size() + item_extent <= self._max_line_length def current_size(self): """The size of the current line minus the indentation.""" size = 0 for item in reversed(self._lines): size += item.size if isinstance(item, self._LineBreak): break return size def line_empty(self): return (self._lines and isinstance(self._lines[-1], (self._LineBreak, self._Indent))) def emit(self): string = '' for item in self._lines: if isinstance(item, self._LineBreak): string = string.rstrip() string += item.emit() return string.rstrip() + '\n' ########################################################################### # Private Methods def _add_item(self, item, indent_amt): """Add an item to the line. Reflow the line to get the best formatting after the item is inserted. The bracket depth indicates if the item is being inserted inside of a container or not. """ if item.is_fstring_start: self._in_fstring = True elif self._prev_item and self._prev_item.is_fstring_end: self._in_fstring = False if self._prev_item and self._prev_item.is_string and item.is_string: # Place consecutive string literals on separate lines. self._lines.append(self._LineBreak()) self._lines.append(self._Indent(indent_amt)) item_text = str(item) if self._lines and self._bracket_depth: # Adding the item into a container. self._prevent_default_initializer_splitting(item, indent_amt) if item_text in '.,)]}': self._split_after_delimiter(item, indent_amt) elif self._lines and not self.line_empty(): # Adding the item outside of a container. if self.fits_on_current_line(len(item_text)): self._enforce_space(item) else: # Line break for the new item. self._lines.append(self._LineBreak()) self._lines.append(self._Indent(indent_amt)) self._lines.append(item) self._prev_item, self._prev_prev_item = item, self._prev_item if item_text in '([{' and not self._in_fstring: self._bracket_depth += 1 elif item_text in '}])' and not self._in_fstring: self._bracket_depth -= 1 assert self._bracket_depth >= 0 def _add_container(self, container, indent_amt, break_after_open_bracket): actual_indent = indent_amt + 1 if ( str(self._prev_item) != '=' and not self.line_empty() and not self.fits_on_current_line( container.size + self._bracket_depth + 2) ): if str(container)[0] == '(' and self._prev_item.is_name: # Don't split before the opening bracket of a call. break_after_open_bracket = True actual_indent = indent_amt + 4 elif ( break_after_open_bracket or str(self._prev_item) not in '([{' ): # If the container doesn't fit on the current line and the # current line isn't empty, place the container on the next # line. self._lines.append(self._LineBreak()) self._lines.append(self._Indent(indent_amt)) break_after_open_bracket = False else: actual_indent = self.current_size() + 1 break_after_open_bracket = False if isinstance(container, (ListComprehension, IfExpression)): actual_indent = indent_amt # Increase the continued indentation only if recursing on a # container. container.reflow(self, ' ' * actual_indent, break_after_open_bracket=break_after_open_bracket) def _prevent_default_initializer_splitting(self, item, indent_amt): """Prevent splitting between a default initializer. When there is a default initializer, it's best to keep it all on the same line. It's nicer and more readable, even if it goes over the maximum allowable line length. This goes back along the current line to determine if we have a default initializer, and, if so, to remove extraneous whitespaces and add a line break/indent before it if needed. """ if str(item) == '=': # This is the assignment in the initializer. Just remove spaces for # now. self._delete_whitespace() return if (not self._prev_item or not self._prev_prev_item or str(self._prev_item) != '='): return self._delete_whitespace() prev_prev_index = self._lines.index(self._prev_prev_item) if ( isinstance(self._lines[prev_prev_index - 1], self._Indent) or self.fits_on_current_line(item.size + 1) ): # The default initializer is already the only item on this line. # Don't insert a newline here. return # Replace the space with a newline/indent combo. if isinstance(self._lines[prev_prev_index - 1], self._Space): del self._lines[prev_prev_index - 1] self.add_line_break_at(self._lines.index(self._prev_prev_item), indent_amt) def _split_after_delimiter(self, item, indent_amt): """Split the line only after a delimiter.""" self._delete_whitespace() if self.fits_on_current_line(item.size): return last_space = None for current_item in reversed(self._lines): if ( last_space and (not isinstance(current_item, Atom) or not current_item.is_colon) ): break else: last_space = None if isinstance(current_item, self._Space): last_space = current_item if isinstance(current_item, (self._LineBreak, self._Indent)): return if not last_space: return self.add_line_break_at(self._lines.index(last_space), indent_amt) def _enforce_space(self, item): """Enforce a space in certain situations. There are cases where we will want a space where normally we wouldn't put one. This just enforces the addition of a space. """ if isinstance(self._lines[-1], (self._Space, self._LineBreak, self._Indent)): return if not self._prev_item: return item_text = str(item) prev_text = str(self._prev_item) # Prefer a space around a '.' in an import statement, and between the # 'import' and '('. if ( (item_text == '.' and prev_text == 'from') or (item_text == 'import' and prev_text == '.') or (item_text == '(' and prev_text == 'import') ): self._lines.append(self._Space()) def _delete_whitespace(self): """Delete all whitespace from the end of the line.""" while isinstance(self._lines[-1], (self._Space, self._LineBreak, self._Indent)): del self._lines[-1] class Atom(object): """The smallest unbreakable unit that can be reflowed.""" def __init__(self, atom): self._atom = atom def __repr__(self): return self._atom.token_string def __len__(self): return self.size def reflow( self, reflowed_lines, continued_indent, extent, break_after_open_bracket=False, is_list_comp_or_if_expr=False, next_is_dot=False ): if self._atom.token_type == tokenize.COMMENT: reflowed_lines.add_comment(self) return total_size = extent if extent else self.size if self._atom.token_string not in ',:([{}])': # Some atoms will need an extra 1-sized space token after them. total_size += 1 prev_item = reflowed_lines.previous_item() if ( not is_list_comp_or_if_expr and not reflowed_lines.fits_on_current_line(total_size) and not (next_is_dot and reflowed_lines.fits_on_current_line(self.size + 1)) and not reflowed_lines.line_empty() and not self.is_colon and not (prev_item and prev_item.is_name and str(self) == '(') ): # Start a new line if there is already something on the line and # adding this atom would make it go over the max line length. reflowed_lines.add_line_break(continued_indent) else: reflowed_lines.add_space_if_needed(str(self)) reflowed_lines.add(self, len(continued_indent), break_after_open_bracket) def emit(self): return self.__repr__() @property def is_keyword(self): return keyword.iskeyword(self._atom.token_string) @property def is_string(self): return self._atom.token_type == tokenize.STRING @property def is_fstring_start(self): if not IS_SUPPORT_TOKEN_FSTRING: return False return self._atom.token_type == tokenize.FSTRING_START @property def is_fstring_end(self): if not IS_SUPPORT_TOKEN_FSTRING: return False return self._atom.token_type == tokenize.FSTRING_END @property def is_name(self): return self._atom.token_type == tokenize.NAME @property def is_number(self): return self._atom.token_type == tokenize.NUMBER @property def is_comma(self): return self._atom.token_string == ',' @property def is_colon(self): return self._atom.token_string == ':' @property def size(self): return len(self._atom.token_string) class Container(object): """Base class for all container types.""" def __init__(self, items): self._items = items def __repr__(self): string = '' last_was_keyword = False for item in self._items: if item.is_comma: string += ', ' elif item.is_colon: string += ': ' else: item_string = str(item) if ( string and (last_was_keyword or (not string.endswith(tuple('([{,.:}]) ')) and not item_string.startswith(tuple('([{,.:}])')))) ): string += ' ' string += item_string last_was_keyword = item.is_keyword return string def __iter__(self): for element in self._items: yield element def __getitem__(self, idx): return self._items[idx] def reflow(self, reflowed_lines, continued_indent, break_after_open_bracket=False): last_was_container = False for (index, item) in enumerate(self._items): next_item = get_item(self._items, index + 1) if isinstance(item, Atom): is_list_comp_or_if_expr = ( isinstance(self, (ListComprehension, IfExpression))) item.reflow(reflowed_lines, continued_indent, self._get_extent(index), is_list_comp_or_if_expr=is_list_comp_or_if_expr, next_is_dot=(next_item and str(next_item) == '.')) if last_was_container and item.is_comma: reflowed_lines.add_line_break(continued_indent) last_was_container = False else: # isinstance(item, Container) reflowed_lines.add(item, len(continued_indent), break_after_open_bracket) last_was_container = not isinstance(item, (ListComprehension, IfExpression)) if ( break_after_open_bracket and index == 0 and # Prefer to keep empty containers together instead of # separating them. str(item) == self.open_bracket and (not next_item or str(next_item) != self.close_bracket) and (len(self._items) != 3 or not isinstance(next_item, Atom)) ): reflowed_lines.add_line_break(continued_indent) break_after_open_bracket = False else: next_next_item = get_item(self._items, index + 2) if ( str(item) not in ['.', '%', 'in'] and next_item and not isinstance(next_item, Container) and str(next_item) != ':' and next_next_item and (not isinstance(next_next_item, Atom) or str(next_item) == 'not') and not reflowed_lines.line_empty() and not reflowed_lines.fits_on_current_line( self._get_extent(index + 1) + 2) ): reflowed_lines.add_line_break(continued_indent) def _get_extent(self, index): """The extent of the full element. E.g., the length of a function call or keyword. """ extent = 0 prev_item = get_item(self._items, index - 1) seen_dot = prev_item and str(prev_item) == '.' while index < len(self._items): item = get_item(self._items, index) index += 1 if isinstance(item, (ListComprehension, IfExpression)): break if isinstance(item, Container): if prev_item and prev_item.is_name: if seen_dot: extent += 1 else: extent += item.size prev_item = item continue elif (str(item) not in ['.', '=', ':', 'not'] and not item.is_name and not item.is_string): break if str(item) == '.': seen_dot = True extent += item.size prev_item = item return extent @property def is_string(self): return False @property def size(self): return len(self.__repr__()) @property def is_keyword(self): return False @property def is_name(self): return False @property def is_comma(self): return False @property def is_colon(self): return False @property def open_bracket(self): return None @property def close_bracket(self): return None class Tuple(Container): """A high-level representation of a tuple.""" @property def open_bracket(self): return '(' @property def close_bracket(self): return ')' class List(Container): """A high-level representation of a list.""" @property def open_bracket(self): return '[' @property def close_bracket(self): return ']' class DictOrSet(Container): """A high-level representation of a dictionary or set.""" @property def open_bracket(self): return '{' @property def close_bracket(self): return '}' class ListComprehension(Container): """A high-level representation of a list comprehension.""" @property def size(self): length = 0 for item in self._items: if isinstance(item, IfExpression): break length += item.size return length class IfExpression(Container): """A high-level representation of an if-expression.""" def _parse_container(tokens, index, for_or_if=None): """Parse a high-level container, such as a list, tuple, etc.""" # Store the opening bracket. items = [Atom(Token(*tokens[index]))] index += 1 num_tokens = len(tokens) while index < num_tokens: tok = Token(*tokens[index]) if tok.token_string in ',)]}': # First check if we're at the end of a list comprehension or # if-expression. Don't add the ending token as part of the list # comprehension or if-expression, because they aren't part of those # constructs. if for_or_if == 'for': return (ListComprehension(items), index - 1) elif for_or_if == 'if': return (IfExpression(items), index - 1) # We've reached the end of a container. items.append(Atom(tok)) # If not, then we are at the end of a container. if tok.token_string == ')': # The end of a tuple. return (Tuple(items), index) elif tok.token_string == ']': # The end of a list. return (List(items), index) elif tok.token_string == '}': # The end of a dictionary or set. return (DictOrSet(items), index) elif tok.token_string in '([{': # A sub-container is being defined. (container, index) = _parse_container(tokens, index) items.append(container) elif tok.token_string == 'for': (container, index) = _parse_container(tokens, index, 'for') items.append(container) elif tok.token_string == 'if': (container, index) = _parse_container(tokens, index, 'if') items.append(container) else: items.append(Atom(tok)) index += 1 return (None, None) def _parse_tokens(tokens): """Parse the tokens. This converts the tokens into a form where we can manipulate them more easily. """ index = 0 parsed_tokens = [] num_tokens = len(tokens) while index < num_tokens: tok = Token(*tokens[index]) assert tok.token_type != token.INDENT if tok.token_type == tokenize.NEWLINE: # There's only one newline and it's at the end. break if tok.token_string in '([{': (container, index) = _parse_container(tokens, index) if not container: return None parsed_tokens.append(container) else: parsed_tokens.append(Atom(tok)) index += 1 return parsed_tokens def _reflow_lines(parsed_tokens, indentation, max_line_length, start_on_prefix_line): """Reflow the lines so that it looks nice.""" if str(parsed_tokens[0]) == 'def': # A function definition gets indented a bit more. continued_indent = indentation + ' ' * 2 * DEFAULT_INDENT_SIZE else: continued_indent = indentation + ' ' * DEFAULT_INDENT_SIZE break_after_open_bracket = not start_on_prefix_line lines = ReformattedLines(max_line_length) lines.add_indent(len(indentation.lstrip('\r\n'))) if not start_on_prefix_line: # If splitting after the opening bracket will cause the first element # to be aligned weirdly, don't try it. first_token = get_item(parsed_tokens, 0) second_token = get_item(parsed_tokens, 1) if ( first_token and second_token and str(second_token)[0] == '(' and len(indentation) + len(first_token) + 1 == len(continued_indent) ): return None for item in parsed_tokens: lines.add_space_if_needed(str(item), equal=True) save_continued_indent = continued_indent if start_on_prefix_line and isinstance(item, Container): start_on_prefix_line = False continued_indent = ' ' * (lines.current_size() + 1) item.reflow(lines, continued_indent, break_after_open_bracket) continued_indent = save_continued_indent return lines.emit() def _shorten_line_at_tokens_new(tokens, source, indentation, max_line_length): """Shorten the line taking its length into account. The input is expected to be free of newlines except for inside multiline strings and at the end. """ # Yield the original source so to see if it's a better choice than the # shortened candidate lines we generate here. yield indentation + source parsed_tokens = _parse_tokens(tokens) if parsed_tokens: # Perform two reflows. The first one starts on the same line as the # prefix. The second starts on the line after the prefix. fixed = _reflow_lines(parsed_tokens, indentation, max_line_length, start_on_prefix_line=True) if fixed and check_syntax(normalize_multiline(fixed.lstrip())): yield fixed fixed = _reflow_lines(parsed_tokens, indentation, max_line_length, start_on_prefix_line=False) if fixed and check_syntax(normalize_multiline(fixed.lstrip())): yield fixed def _shorten_line_at_tokens(tokens, source, indentation, indent_word, key_token_strings, aggressive): """Separate line by breaking at tokens in key_token_strings. The input is expected to be free of newlines except for inside multiline strings and at the end. """ offsets = [] for (index, _t) in enumerate(token_offsets(tokens)): (token_type, token_string, start_offset, end_offset) = _t assert token_type != token.INDENT if token_string in key_token_strings: # Do not break in containers with zero or one items. unwanted_next_token = { '(': ')', '[': ']', '{': '}'}.get(token_string) if unwanted_next_token: if ( get_item(tokens, index + 1, default=[None, None])[1] == unwanted_next_token or get_item(tokens, index + 2, default=[None, None])[1] == unwanted_next_token ): continue if ( index > 2 and token_string == '(' and tokens[index - 1][1] in ',(%[' ): # Don't split after a tuple start, or before a tuple start if # the tuple is in a list. continue if end_offset < len(source) - 1: # Don't split right before newline. offsets.append(end_offset) else: # Break at adjacent strings. These were probably meant to be on # separate lines in the first place. previous_token = get_item(tokens, index - 1) if ( token_type == tokenize.STRING and previous_token and previous_token[0] == tokenize.STRING ): offsets.append(start_offset) current_indent = None fixed = None for line in split_at_offsets(source, offsets): if fixed: fixed += '\n' + current_indent + line for symbol in '([{': if line.endswith(symbol): current_indent += indent_word else: # First line. fixed = line assert not current_indent current_indent = indent_word assert fixed is not None if check_syntax(normalize_multiline(fixed) if aggressive > 1 else fixed): return indentation + fixed return None def token_offsets(tokens): """Yield tokens and offsets.""" end_offset = 0 previous_end_row = 0 previous_end_column = 0 for t in tokens: token_type = t[0] token_string = t[1] (start_row, start_column) = t[2] (end_row, end_column) = t[3] # Account for the whitespace between tokens. end_offset += start_column if previous_end_row == start_row: end_offset -= previous_end_column # Record the start offset of the token. start_offset = end_offset # Account for the length of the token itself. end_offset += len(token_string) yield (token_type, token_string, start_offset, end_offset) previous_end_row = end_row previous_end_column = end_column def normalize_multiline(line): """Normalize multiline-related code that will cause syntax error. This is for purposes of checking syntax. """ if line.startswith(('def ', 'async def ')) and line.rstrip().endswith(':'): return line + ' pass' elif line.startswith('return '): return 'def _(): ' + line elif line.startswith('@'): return line + 'def _(): pass' elif line.startswith('class '): return line + ' pass' elif line.startswith(('if ', 'elif ', 'for ', 'while ')): return line + ' pass' return line def fix_whitespace(line, offset, replacement): """Replace whitespace at offset and return fixed line.""" # Replace escaped newlines too left = line[:offset].rstrip('\n\r \t\\') right = line[offset:].lstrip('\n\r \t\\') if right.startswith('#'): return line return left + replacement + right def _execute_pep8(pep8_options, source): """Execute pycodestyle via python method calls.""" class QuietReport(pycodestyle.BaseReport): """Version of checker that does not print.""" def __init__(self, options): super(QuietReport, self).__init__(options) self.__full_error_results = [] def error(self, line_number, offset, text, check): """Collect errors.""" code = super(QuietReport, self).error(line_number, offset, text, check) if code: self.__full_error_results.append( {'id': code, 'line': line_number, 'column': offset + 1, 'info': text}) def full_error_results(self): """Return error results in detail. Results are in the form of a list of dictionaries. Each dictionary contains 'id', 'line', 'column', and 'info'. """ return self.__full_error_results checker = pycodestyle.Checker('', lines=source, reporter=QuietReport, **pep8_options) checker.check_all() return checker.report.full_error_results() def _remove_leading_and_normalize(line, with_rstrip=True): # ignore FF in first lstrip() if with_rstrip: return line.lstrip(' \t\v').rstrip(CR + LF) + '\n' return line.lstrip(' \t\v') class Reindenter(object): """Reindents badly-indented code to uniformly use four-space indentation. Released to the public domain, by Tim Peters, 03 October 2000. """ def __init__(self, input_text, leave_tabs=False): sio = io.StringIO(input_text) source_lines = sio.readlines() self.string_content_line_numbers = multiline_string_lines(input_text) # File lines, rstripped & tab-expanded. Dummy at start is so # that we can use tokenize's 1-based line numbering easily. # Note that a line is all-blank iff it is a newline. self.lines = [] for line_number, line in enumerate(source_lines, start=1): # Do not modify if inside a multiline string. if line_number in self.string_content_line_numbers: self.lines.append(line) else: # Only expand leading tabs. with_rstrip = line_number != len(source_lines) if leave_tabs: self.lines.append( _get_indentation(line) + _remove_leading_and_normalize(line, with_rstrip) ) else: self.lines.append( _get_indentation(line).expandtabs() + _remove_leading_and_normalize(line, with_rstrip) ) self.lines.insert(0, None) self.index = 1 # index into self.lines of next line self.input_text = input_text def run(self, indent_size=DEFAULT_INDENT_SIZE): """Fix indentation and return modified line numbers. Line numbers are indexed at 1. """ if indent_size < 1: return self.input_text try: stats = _reindent_stats(tokenize.generate_tokens(self.getline)) except (SyntaxError, tokenize.TokenError): return self.input_text # Remove trailing empty lines. lines = self.lines # Sentinel. stats.append((len(lines), 0)) # Map count of leading spaces to # we want. have2want = {} # Program after transformation. after = [] # Copy over initial empty lines -- there's nothing to do until # we see a line with *something* on it. i = stats[0][0] after.extend(lines[1:i]) for i in range(len(stats) - 1): thisstmt, thislevel = stats[i] nextstmt = stats[i + 1][0] have = _leading_space_count(lines[thisstmt]) want = thislevel * indent_size if want < 0: # A comment line. if have: # An indented comment line. If we saw the same # indentation before, reuse what it most recently # mapped to. want = have2want.get(have, -1) if want < 0: # Then it probably belongs to the next real stmt. for j in range(i + 1, len(stats) - 1): jline, jlevel = stats[j] if jlevel >= 0: if have == _leading_space_count(lines[jline]): want = jlevel * indent_size break # Maybe it's a hanging comment like this one, if want < 0: # in which case we should shift it like its base # line got shifted. for j in range(i - 1, -1, -1): jline, jlevel = stats[j] if jlevel >= 0: want = (have + _leading_space_count( after[jline - 1]) - _leading_space_count(lines[jline])) break if want < 0: # Still no luck -- leave it alone. want = have else: want = 0 assert want >= 0 have2want[have] = want diff = want - have if diff == 0 or have == 0: after.extend(lines[thisstmt:nextstmt]) else: for line_number, line in enumerate(lines[thisstmt:nextstmt], start=thisstmt): if line_number in self.string_content_line_numbers: after.append(line) elif diff > 0: if line == '\n': after.append(line) else: after.append(' ' * diff + line) else: remove = min(_leading_space_count(line), -diff) after.append(line[remove:]) return ''.join(after) def getline(self): """Line-getter for tokenize.""" if self.index >= len(self.lines): line = '' else: line = self.lines[self.index] self.index += 1 return line def _reindent_stats(tokens): """Return list of (lineno, indentlevel) pairs. One for each stmt and comment line. indentlevel is -1 for comment lines, as a signal that tokenize doesn't know what to do about them; indeed, they're our headache! """ find_stmt = 1 # Next token begins a fresh stmt? level = 0 # Current indent level. stats = [] for t in tokens: token_type = t[0] sline = t[2][0] line = t[4] if token_type == tokenize.NEWLINE: # A program statement, or ENDMARKER, will eventually follow, # after some (possibly empty) run of tokens of the form # (NL | COMMENT)* (INDENT | DEDENT+)? find_stmt = 1 elif token_type == tokenize.INDENT: find_stmt = 1 level += 1 elif token_type == tokenize.DEDENT: find_stmt = 1 level -= 1 elif token_type == tokenize.COMMENT: if find_stmt: stats.append((sline, -1)) # But we're still looking for a new stmt, so leave # find_stmt alone. elif token_type == tokenize.NL: pass elif find_stmt: # This is the first "real token" following a NEWLINE, so it # must be the first token of the next program statement, or an # ENDMARKER. find_stmt = 0 if line: # Not endmarker. stats.append((sline, level)) return stats def _leading_space_count(line): """Return number of leading spaces in line.""" i = 0 while i < len(line) and line[i] == ' ': i += 1 return i def check_syntax(code): """Return True if syntax is okay.""" try: return compile(code, '', 'exec', dont_inherit=True) except (SyntaxError, TypeError, ValueError): return False def find_with_line_numbers(pattern, contents): """A wrapper around 're.finditer' to find line numbers. Returns a list of line numbers where pattern was found in contents. """ matches = list(re.finditer(pattern, contents)) if not matches: return [] end = matches[-1].start() # -1 so a failed `rfind` maps to the first line. newline_offsets = { -1: 0 } for line_num, m in enumerate(re.finditer(r'\n', contents), 1): offset = m.start() if offset > end: break newline_offsets[offset] = line_num def get_line_num(match, contents): """Get the line number of string in a files contents. Failing to find the newline is OK, -1 maps to 0 """ newline_offset = contents.rfind('\n', 0, match.start()) return newline_offsets[newline_offset] return [get_line_num(match, contents) + 1 for match in matches] def get_disabled_ranges(source): """Returns a list of tuples representing the disabled ranges. If disabled and no re-enable will disable for rest of file. """ enable_line_nums = find_with_line_numbers(ENABLE_REGEX, source) disable_line_nums = find_with_line_numbers(DISABLE_REGEX, source) total_lines = len(re.findall("\n", source)) + 1 enable_commands = {} for num in enable_line_nums: enable_commands[num] = True for num in disable_line_nums: enable_commands[num] = False disabled_ranges = [] currently_enabled = True disabled_start = None for line, commanded_enabled in sorted(enable_commands.items()): if commanded_enabled is False and currently_enabled is True: disabled_start = line currently_enabled = False elif commanded_enabled is True and currently_enabled is False: disabled_ranges.append((disabled_start, line)) currently_enabled = True if currently_enabled is False: disabled_ranges.append((disabled_start, total_lines)) return disabled_ranges def filter_disabled_results(result, disabled_ranges): """Filter out reports based on tuple of disabled ranges. """ line = result['line'] for disabled_range in disabled_ranges: if disabled_range[0] <= line <= disabled_range[1]: return False return True def filter_results(source, results, aggressive): """Filter out spurious reports from pycodestyle. If aggressive is True, we allow possibly unsafe fixes (E711, E712). """ non_docstring_string_line_numbers = multiline_string_lines( source, include_docstrings=False) all_string_line_numbers = multiline_string_lines( source, include_docstrings=True) commented_out_code_line_numbers = commented_out_code_lines(source) # Filter out the disabled ranges disabled_ranges = get_disabled_ranges(source) if disabled_ranges: results = [ result for result in results if filter_disabled_results( result, disabled_ranges, ) ] has_e901 = any(result['id'].lower() == 'e901' for result in results) for r in results: issue_id = r['id'].lower() if r['line'] in non_docstring_string_line_numbers: if issue_id.startswith(('e1', 'e501', 'w191')): continue if r['line'] in all_string_line_numbers: if issue_id in ['e501']: continue # We must offset by 1 for lines that contain the trailing contents of # multiline strings. if not aggressive and (r['line'] + 1) in all_string_line_numbers: # Do not modify multiline strings in non-aggressive mode. Remove # trailing whitespace could break doctests. if issue_id.startswith(('w29', 'w39')): continue if aggressive <= 0: if issue_id.startswith(('e711', 'e72', 'w6')): continue if aggressive <= 1: if issue_id.startswith(('e712', 'e713', 'e714')): continue if aggressive <= 2: if issue_id.startswith(('e704')): continue if r['line'] in commented_out_code_line_numbers: if issue_id.startswith(('e261', 'e262', 'e501')): continue # Do not touch indentation if there is a token error caused by # incomplete multi-line statement. Otherwise, we risk screwing up the # indentation. if has_e901: if issue_id.startswith(('e1', 'e7')): continue yield r def multiline_string_lines(source, include_docstrings=False): """Return line numbers that are within multiline strings. The line numbers are indexed at 1. Docstrings are ignored. """ line_numbers = set() previous_token_type = '' _check_target_tokens = [tokenize.STRING] if IS_SUPPORT_TOKEN_FSTRING: _check_target_tokens.extend([ tokenize.FSTRING_START, tokenize.FSTRING_MIDDLE, tokenize.FSTRING_END, ]) try: for t in generate_tokens(source): token_type = t[0] start_row = t[2][0] end_row = t[3][0] if token_type in _check_target_tokens and start_row != end_row: if ( include_docstrings or previous_token_type != tokenize.INDENT ): # We increment by one since we want the contents of the # string. line_numbers |= set(range(1 + start_row, 1 + end_row)) previous_token_type = token_type except (SyntaxError, tokenize.TokenError): pass return line_numbers def commented_out_code_lines(source): """Return line numbers of comments that are likely code. Commented-out code is bad practice, but modifying it just adds even more clutter. """ line_numbers = [] try: for t in generate_tokens(source): token_type = t[0] token_string = t[1] start_row = t[2][0] line = t[4] # Ignore inline comments. if not line.lstrip().startswith('#'): continue if token_type == tokenize.COMMENT: stripped_line = token_string.lstrip('#').strip() with warnings.catch_warnings(): # ignore SyntaxWarning in Python3.8+ # refs: # https://bugs.python.org/issue15248 # https://docs.python.org/3.8/whatsnew/3.8.html#other-language-changes warnings.filterwarnings("ignore", category=SyntaxWarning) if ( ' ' in stripped_line and '#' not in stripped_line and check_syntax(stripped_line) ): line_numbers.append(start_row) except (SyntaxError, tokenize.TokenError): pass return line_numbers def shorten_comment(line, max_line_length, last_comment=False): """Return trimmed or split long comment line. If there are no comments immediately following it, do a text wrap. Doing this wrapping on all comments in general would lead to jagged comment text. """ assert len(line) > max_line_length line = line.rstrip() # PEP 8 recommends 72 characters for comment text. indentation = _get_indentation(line) + '# ' max_line_length = min(max_line_length, len(indentation) + 72) MIN_CHARACTER_REPEAT = 5 if ( len(line) - len(line.rstrip(line[-1])) >= MIN_CHARACTER_REPEAT and not line[-1].isalnum() ): # Trim comments that end with things like --------- return line[:max_line_length] + '\n' elif last_comment and re.match(r'\s*#+\s*\w+', line): split_lines = textwrap.wrap(line.lstrip(' \t#'), initial_indent=indentation, subsequent_indent=indentation, width=max_line_length, break_long_words=False, break_on_hyphens=False) return '\n'.join(split_lines) + '\n' return line + '\n' def normalize_line_endings(lines, newline): """Return fixed line endings. All lines will be modified to use the most common line ending. """ line = [line.rstrip('\n\r') + newline for line in lines] if line and lines[-1] == lines[-1].rstrip('\n\r'): line[-1] = line[-1].rstrip('\n\r') return line def mutual_startswith(a, b): return b.startswith(a) or a.startswith(b) def code_match(code, select, ignore): if ignore: assert not isinstance(ignore, str) for ignored_code in [c.strip() for c in ignore]: if mutual_startswith(code.lower(), ignored_code.lower()): return False if select: assert not isinstance(select, str) for selected_code in [c.strip() for c in select]: if mutual_startswith(code.lower(), selected_code.lower()): return True return False return True def fix_code(source, options=None, encoding=None, apply_config=False): """Return fixed source code. "encoding" will be used to decode "source" if it is a byte string. """ options = _get_options(options, apply_config) # normalize options.ignore = [opt.upper() for opt in options.ignore] options.select = [opt.upper() for opt in options.select] # check ignore args # NOTE: If W50x is not included, add W50x because the code # correction result is indefinite. ignore_opt = options.ignore if not {"W50", "W503", "W504"} & set(ignore_opt): options.ignore.append("W50") if not isinstance(source, str): source = source.decode(encoding or get_encoding()) sio = io.StringIO(source) return fix_lines(sio.readlines(), options=options) def _get_options(raw_options, apply_config): """Return parsed options.""" if not raw_options: return parse_args([''], apply_config=apply_config) if isinstance(raw_options, dict): options = parse_args([''], apply_config=apply_config) for name, value in raw_options.items(): if not hasattr(options, name): raise ValueError("No such option '{}'".format(name)) # Check for very basic type errors. expected_type = type(getattr(options, name)) if not isinstance(expected_type, (str, )): if isinstance(value, (str, )): raise ValueError( "Option '{}' should not be a string".format(name)) setattr(options, name, value) else: options = raw_options return options def fix_lines(source_lines, options, filename=''): """Return fixed source code.""" # Transform everything to line feed. Then change them back to original # before returning fixed source code. original_newline = find_newline(source_lines) tmp_source = ''.join(normalize_line_endings(source_lines, '\n')) # Keep a history to break out of cycles. previous_hashes = set() if options.line_range: # Disable "apply_local_fixes()" for now due to issue #175. fixed_source = tmp_source else: # Apply global fixes only once (for efficiency). fixed_source = apply_global_fixes(tmp_source, options, filename=filename) passes = 0 long_line_ignore_cache = set() while hash(fixed_source) not in previous_hashes: if options.pep8_passes >= 0 and passes > options.pep8_passes: break passes += 1 previous_hashes.add(hash(fixed_source)) tmp_source = copy.copy(fixed_source) fix = FixPEP8( filename, options, contents=tmp_source, long_line_ignore_cache=long_line_ignore_cache) fixed_source = fix.fix() sio = io.StringIO(fixed_source) return ''.join(normalize_line_endings(sio.readlines(), original_newline)) def fix_file(filename, options=None, output=None, apply_config=False): if not options: options = parse_args([filename], apply_config=apply_config) original_source = readlines_from_file(filename) fixed_source = original_source if options.in_place or options.diff or output: encoding = detect_encoding(filename) if output: output = LineEndingWrapper(wrap_output(output, encoding=encoding)) fixed_source = fix_lines(fixed_source, options, filename=filename) if options.diff: new = io.StringIO(fixed_source) new = new.readlines() diff = get_diff_text(original_source, new, filename) if output: output.write(diff) output.flush() elif options.jobs > 1: diff = diff.encode(encoding) return diff elif options.in_place: original = "".join(original_source).splitlines() fixed = fixed_source.splitlines() original_source_last_line = ( original_source[-1].split("\n")[-1] if original_source else "" ) fixed_source_last_line = fixed_source.split("\n")[-1] if original != fixed or ( original_source_last_line != fixed_source_last_line ): with open_with_encoding(filename, 'w', encoding=encoding) as fp: fp.write(fixed_source) return fixed_source return None else: if output: output.write(fixed_source) output.flush() return fixed_source def global_fixes(): """Yield multiple (code, function) tuples.""" for function in list(globals().values()): if inspect.isfunction(function): arguments = _get_parameters(function) if arguments[:1] != ['source']: continue code = extract_code_from_function(function) if code: yield (code, function) def _get_parameters(function): # pylint: disable=deprecated-method if sys.version_info.major >= 3: # We need to match "getargspec()", which includes "self" as the first # value for methods. # https://bugs.python.org/issue17481#msg209469 if inspect.ismethod(function): function = function.__func__ return list(inspect.signature(function).parameters) else: return inspect.getargspec(function)[0] def apply_global_fixes(source, options, where='global', filename='', codes=None): """Run global fixes on source code. These are fixes that only need be done once (unlike those in FixPEP8, which are dependent on pycodestyle). """ if codes is None: codes = [] if any(code_match(code, select=options.select, ignore=options.ignore) for code in ['E101', 'E111']): source = reindent( source, indent_size=options.indent_size, leave_tabs=not ( code_match( 'W191', select=options.select, ignore=options.ignore ) ) ) for (code, function) in global_fixes(): if code_match(code, select=options.select, ignore=options.ignore): if options.verbose: print('---> Applying {} fix for {}'.format(where, code.upper()), file=sys.stderr) source = function(source, aggressive=options.aggressive) return source def extract_code_from_function(function): """Return code handled by function.""" if not function.__name__.startswith('fix_'): return None code = re.sub('^fix_', '', function.__name__) if not code: return None try: int(code[1:]) except ValueError: return None return code def _get_package_version(): packages = ["pycodestyle: {}".format(pycodestyle.__version__)] return ", ".join(packages) def create_parser(): """Return command-line parser.""" parser = argparse.ArgumentParser(description=docstring_summary(__doc__), prog='autopep8') parser.add_argument('--version', action='version', version='%(prog)s {} ({})'.format( __version__, _get_package_version())) parser.add_argument('-v', '--verbose', action='count', default=0, help='print verbose messages; ' 'multiple -v result in more verbose messages') parser.add_argument('-d', '--diff', action='store_true', help='print the diff for the fixed source') parser.add_argument('-i', '--in-place', action='store_true', help='make changes to files in place') parser.add_argument('--global-config', metavar='filename', default=DEFAULT_CONFIG, help='path to a global pep8 config file; if this file ' 'does not exist then this is ignored ' '(default: {})'.format(DEFAULT_CONFIG)) parser.add_argument('--ignore-local-config', action='store_true', help="don't look for and apply local config files; " 'if not passed, defaults are updated with any ' "config files in the project's root directory") parser.add_argument('-r', '--recursive', action='store_true', help='run recursively over directories; ' 'must be used with --in-place or --diff') parser.add_argument('-j', '--jobs', type=int, metavar='n', default=1, help='number of parallel jobs; ' 'match CPU count if value is less than 1') parser.add_argument('-p', '--pep8-passes', metavar='n', default=-1, type=int, help='maximum number of additional pep8 passes ' '(default: infinite)') parser.add_argument('-a', '--aggressive', action='count', default=0, help='enable non-whitespace changes; ' 'multiple -a result in more aggressive changes') parser.add_argument('--experimental', action='store_true', help='enable experimental fixes') parser.add_argument('--exclude', metavar='globs', help='exclude file/directory names that match these ' 'comma-separated globs') parser.add_argument('--list-fixes', action='store_true', help='list codes for fixes; ' 'used by --ignore and --select') parser.add_argument('--ignore', metavar='errors', default='', help='do not fix these errors/warnings ' '(default: {})'.format(DEFAULT_IGNORE)) parser.add_argument('--select', metavar='errors', default='', help='fix only these errors/warnings (e.g. E4,W)') parser.add_argument('--max-line-length', metavar='n', default=79, type=int, help='set maximum allowed line length ' '(default: %(default)s)') parser.add_argument('--line-range', '--range', metavar='line', default=None, type=int, nargs=2, help='only fix errors found within this inclusive ' 'range of line numbers (e.g. 1 99); ' 'line numbers are indexed at 1') parser.add_argument('--indent-size', default=DEFAULT_INDENT_SIZE, type=int, help=argparse.SUPPRESS) parser.add_argument('--hang-closing', action='store_true', help='hang-closing option passed to pycodestyle') parser.add_argument('--exit-code', action='store_true', help='change to behavior of exit code.' ' default behavior of return value, 0 is no ' 'differences, 1 is error exit. return 2 when' ' add this option. 2 is exists differences.') parser.add_argument('files', nargs='*', help="files to format or '-' for standard in") return parser def _expand_codes(codes, ignore_codes): """expand to individual E/W codes""" ret = set() is_conflict = False if all( any( conflicting_code.startswith(code) for code in codes ) for conflicting_code in CONFLICTING_CODES ): is_conflict = True is_ignore_w503 = "W503" in ignore_codes is_ignore_w504 = "W504" in ignore_codes for code in codes: if code == "W": if is_ignore_w503 and is_ignore_w504: ret.update({"W1", "W2", "W3", "W505", "W6"}) elif is_ignore_w503: ret.update({"W1", "W2", "W3", "W504", "W505", "W6"}) else: ret.update({"W1", "W2", "W3", "W503", "W505", "W6"}) elif code in ("W5", "W50"): if is_ignore_w503 and is_ignore_w504: ret.update({"W505"}) elif is_ignore_w503: ret.update({"W504", "W505"}) else: ret.update({"W503", "W505"}) elif not (code in ("W503", "W504") and is_conflict): ret.add(code) return ret def _parser_error_with_code( parser: argparse.ArgumentParser, code: int, msg: str, ) -> None: """wrap parser.error with exit code""" parser.print_usage(sys.stderr) parser.exit(code, f"{msg}\n") def parse_args(arguments, apply_config=False): """Parse command-line options.""" parser = create_parser() args = parser.parse_args(arguments) if not args.files and not args.list_fixes: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, 'incorrect number of arguments', ) args.files = [decode_filename(name) for name in args.files] if apply_config: parser = read_config(args, parser) # prioritize settings when exist pyproject.toml's tool.autopep8 section try: parser_with_pyproject_toml = read_pyproject_toml(args, parser) except Exception: parser_with_pyproject_toml = None if parser_with_pyproject_toml: parser = parser_with_pyproject_toml args = parser.parse_args(arguments) args.files = [decode_filename(name) for name in args.files] if '-' in args.files: if len(args.files) > 1: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, 'cannot mix stdin and regular files', ) if args.diff: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--diff cannot be used with standard input', ) if args.in_place: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--in-place cannot be used with standard input', ) if args.recursive: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--recursive cannot be used with standard input', ) if len(args.files) > 1 and not (args.in_place or args.diff): _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, 'autopep8 only takes one filename as argument ' 'unless the "--in-place" or "--diff" args are used', ) if args.recursive and not (args.in_place or args.diff): _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--recursive must be used with --in-place or --diff', ) if args.in_place and args.diff: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--in-place and --diff are mutually exclusive', ) if args.max_line_length <= 0: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--max-line-length must be greater than 0', ) if args.indent_size <= 0: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--indent-size must be greater than 0', ) if args.select: args.select = _expand_codes( _split_comma_separated(args.select), (_split_comma_separated(args.ignore) if args.ignore else []) ) if args.ignore: args.ignore = _split_comma_separated(args.ignore) if all( not any( conflicting_code.startswith(ignore_code) for ignore_code in args.ignore ) for conflicting_code in CONFLICTING_CODES ): args.ignore.update(CONFLICTING_CODES) elif not args.select: if args.aggressive: # Enable everything by default if aggressive. args.select = {'E', 'W1', 'W2', 'W3', 'W6'} else: args.ignore = _split_comma_separated(DEFAULT_IGNORE) if args.exclude: args.exclude = _split_comma_separated(args.exclude) else: args.exclude = {} if args.jobs < 1: # Do not import multiprocessing globally in case it is not supported # on the platform. import multiprocessing args.jobs = multiprocessing.cpu_count() if args.jobs > 1 and not (args.in_place or args.diff): _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, 'parallel jobs requires --in-place', ) if args.line_range: if args.line_range[0] <= 0: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, '--range must be positive numbers', ) if args.line_range[0] > args.line_range[1]: _parser_error_with_code( parser, EXIT_CODE_ARGPARSE_ERROR, 'First value of --range should be less than or equal ' 'to the second', ) original_formatwarning = warnings.formatwarning warnings.formatwarning = _custom_formatwarning if args.experimental: warnings.warn( "`experimental` option is deprecated and will be " "removed in a future version.", DeprecationWarning, ) warnings.formatwarning = original_formatwarning return args def _get_normalize_options(args, config, section, option_list): for (k, v) in config.items(section): norm_opt = k.lstrip('-').replace('-', '_') if not option_list.get(norm_opt): continue opt_type = option_list[norm_opt] if opt_type is int: if v.strip() == "auto": # skip to special case if args.verbose: print(f"ignore config: {k}={v}") continue value = config.getint(section, k) elif opt_type is bool: value = config.getboolean(section, k) else: value = config.get(section, k) yield norm_opt, k, value def read_config(args, parser): """Read both user configuration and local configuration.""" config = SafeConfigParser() try: if args.verbose and os.path.exists(args.global_config): print("read config path: {}".format(args.global_config)) config.read(args.global_config) if not args.ignore_local_config: parent = tail = args.files and os.path.abspath( os.path.commonprefix(args.files)) while tail: if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]): if args.verbose: for fn in PROJECT_CONFIG: config_file = os.path.join(parent, fn) if not os.path.exists(config_file): continue print( "read config path: {}".format( os.path.join(parent, fn) ) ) break (parent, tail) = os.path.split(parent) defaults = {} option_list = {o.dest: o.type or type(o.default) for o in parser._actions} for section in ['pep8', 'pycodestyle', 'flake8']: if not config.has_section(section): continue for norm_opt, k, value in _get_normalize_options( args, config, section, option_list ): if args.verbose: print("enable config: section={}, key={}, value={}".format( section, k, value)) defaults[norm_opt] = value parser.set_defaults(**defaults) except Error: # Ignore for now. pass return parser def read_pyproject_toml(args, parser): """Read pyproject.toml and load configuration.""" if sys.version_info >= (3, 11): import tomllib else: import tomli as tomllib config = None if os.path.exists(args.global_config): with open(args.global_config, "rb") as fp: config = tomllib.load(fp) if not args.ignore_local_config: parent = tail = args.files and os.path.abspath( os.path.commonprefix(args.files)) while tail: pyproject_toml = os.path.join(parent, "pyproject.toml") if os.path.exists(pyproject_toml): with open(pyproject_toml, "rb") as fp: config = tomllib.load(fp) break (parent, tail) = os.path.split(parent) if not config: return None if config.get("tool", {}).get("autopep8") is None: return None config = config.get("tool", {}).get("autopep8") defaults = {} option_list = {o.dest: o.type or type(o.default) for o in parser._actions} TUPLED_OPTIONS = ("ignore", "select") for (k, v) in config.items(): norm_opt = k.lstrip('-').replace('-', '_') if not option_list.get(norm_opt): continue if type(v) in (list, tuple) and norm_opt in TUPLED_OPTIONS: value = ",".join(v) else: value = v if args.verbose: print("enable pyproject.toml config: " "key={}, value={}".format(k, value)) defaults[norm_opt] = value if defaults: # set value when exists key-value in defaults dict parser.set_defaults(**defaults) return parser def _split_comma_separated(string): """Return a set of strings.""" return {text.strip() for text in string.split(',') if text.strip()} def decode_filename(filename): """Return Unicode filename.""" if isinstance(filename, str): return filename return filename.decode(sys.getfilesystemencoding()) def supported_fixes(): """Yield pep8 error codes that autopep8 fixes. Each item we yield is a tuple of the code followed by its description. """ yield ('E101', docstring_summary(reindent.__doc__)) instance = FixPEP8(filename=None, options=None, contents='') for attribute in dir(instance): code = re.match('fix_([ew][0-9][0-9][0-9])', attribute) if code: yield ( code.group(1).upper(), re.sub(r'\s+', ' ', docstring_summary(getattr(instance, attribute).__doc__)) ) for (code, function) in sorted(global_fixes()): yield (code.upper() + (4 - len(code)) * ' ', re.sub(r'\s+', ' ', docstring_summary(function.__doc__))) def docstring_summary(docstring): """Return summary of docstring.""" return docstring.split('\n')[0] if docstring else '' def line_shortening_rank(candidate, indent_word, max_line_length, experimental=False): """Return rank of candidate. This is for sorting candidates. """ if not candidate.strip(): return 0 rank = 0 lines = candidate.rstrip().split('\n') offset = 0 if ( not lines[0].lstrip().startswith('#') and lines[0].rstrip()[-1] not in '([{' ): for (opening, closing) in ('()', '[]', '{}'): # Don't penalize empty containers that aren't split up. Things like # this "foo(\n )" aren't particularly good. opening_loc = lines[0].find(opening) closing_loc = lines[0].find(closing) if opening_loc >= 0: if closing_loc < 0 or closing_loc != opening_loc + 1: offset = max(offset, 1 + opening_loc) current_longest = max(offset + len(x.strip()) for x in lines) rank += 4 * max(0, current_longest - max_line_length) rank += len(lines) # Too much variation in line length is ugly. rank += 2 * standard_deviation(len(line) for line in lines) bad_staring_symbol = { '(': ')', '[': ']', '{': '}'}.get(lines[0][-1]) if len(lines) > 1: if ( bad_staring_symbol and lines[1].lstrip().startswith(bad_staring_symbol) ): rank += 20 for lineno, current_line in enumerate(lines): current_line = current_line.strip() if current_line.startswith('#'): continue for bad_start in ['.', '%', '+', '-', '/']: if current_line.startswith(bad_start): rank += 100 # Do not tolerate operators on their own line. if current_line == bad_start: rank += 1000 if ( current_line.endswith(('.', '%', '+', '-', '/')) and "': " in current_line ): rank += 1000 if current_line.endswith(('(', '[', '{', '.')): # Avoid lonely opening. They result in longer lines. if len(current_line) <= len(indent_word): rank += 100 # Avoid the ugliness of ", (\n". if ( current_line.endswith('(') and current_line[:-1].rstrip().endswith(',') ): rank += 100 # Avoid the ugliness of "something[\n" and something[index][\n. if ( current_line.endswith('[') and len(current_line) > 1 and (current_line[-2].isalnum() or current_line[-2] in ']') ): rank += 300 # Also avoid the ugliness of "foo.\nbar" if current_line.endswith('.'): rank += 100 if has_arithmetic_operator(current_line): rank += 100 # Avoid breaking at unary operators. if re.match(r'.*[(\[{]\s*[\-\+~]$', current_line.rstrip('\\ ')): rank += 1000 if re.match(r'.*lambda\s*\*$', current_line.rstrip('\\ ')): rank += 1000 if current_line.endswith(('%', '(', '[', '{')): rank -= 20 # Try to break list comprehensions at the "for". if current_line.startswith('for '): rank -= 50 if current_line.endswith('\\'): # If a line ends in \-newline, it may be part of a # multiline string. In that case, we would like to know # how long that line is without the \-newline. If it's # longer than the maximum, or has comments, then we assume # that the \-newline is an okay candidate and only # penalize it a bit. total_len = len(current_line) lineno += 1 while lineno < len(lines): total_len += len(lines[lineno]) if lines[lineno].lstrip().startswith('#'): total_len = max_line_length break if not lines[lineno].endswith('\\'): break lineno += 1 if total_len < max_line_length: rank += 10 else: rank += 100 if experimental else 1 # Prefer breaking at commas rather than colon. if ',' in current_line and current_line.endswith(':'): rank += 10 # Avoid splitting dictionaries between key and value. if current_line.endswith(':'): rank += 100 rank += 10 * count_unbalanced_brackets(current_line) return max(0, rank) def standard_deviation(numbers): """Return standard deviation.""" numbers = list(numbers) if not numbers: return 0 mean = sum(numbers) / len(numbers) return (sum((n - mean) ** 2 for n in numbers) / len(numbers)) ** .5 def has_arithmetic_operator(line): """Return True if line contains any arithmetic operators.""" for operator in pycodestyle.ARITHMETIC_OP: if operator in line: return True return False def count_unbalanced_brackets(line): """Return number of unmatched open/close brackets.""" count = 0 for opening, closing in ['()', '[]', '{}']: count += abs(line.count(opening) - line.count(closing)) return count def split_at_offsets(line, offsets): """Split line at offsets. Return list of strings. """ result = [] previous_offset = 0 current_offset = 0 for current_offset in sorted(offsets): if current_offset < len(line) and previous_offset != current_offset: result.append(line[previous_offset:current_offset].strip()) previous_offset = current_offset result.append(line[current_offset:]) return result class LineEndingWrapper(object): r"""Replace line endings to work with sys.stdout. It seems that sys.stdout expects only '\n' as the line ending, no matter the platform. Otherwise, we get repeated line endings. """ def __init__(self, output): self.__output = output def write(self, s): self.__output.write(s.replace('\r\n', '\n').replace('\r', '\n')) def flush(self): self.__output.flush() def match_file(filename, exclude): """Return True if file is okay for modifying/recursing.""" base_name = os.path.basename(filename) if base_name.startswith('.'): return False for pattern in exclude: if fnmatch.fnmatch(base_name, pattern): return False if fnmatch.fnmatch(filename, pattern): return False if not os.path.isdir(filename) and not is_python_file(filename): return False return True def find_files(filenames, recursive, exclude): """Yield filenames.""" while filenames: name = filenames.pop(0) if recursive and os.path.isdir(name): for root, directories, children in os.walk(name): filenames += [os.path.join(root, f) for f in children if match_file(os.path.join(root, f), exclude)] directories[:] = [d for d in directories if match_file(os.path.join(root, d), exclude)] else: is_exclude_match = False for pattern in exclude: if fnmatch.fnmatch(name, pattern): is_exclude_match = True break if not is_exclude_match: yield name def _fix_file(parameters): """Helper function for optionally running fix_file() in parallel.""" if parameters[1].verbose: print('[file:{}]'.format(parameters[0]), file=sys.stderr) try: return fix_file(*parameters) except IOError as error: print(str(error), file=sys.stderr) raise error def fix_multiple_files(filenames, options, output=None): """Fix list of files. Optionally fix files recursively. """ results = [] filenames = find_files(filenames, options.recursive, options.exclude) if options.jobs > 1: import multiprocessing pool = multiprocessing.Pool(options.jobs) rets = [] for name in filenames: ret = pool.apply_async(_fix_file, ((name, options),)) rets.append(ret) pool.close() pool.join() if options.diff: for r in rets: sys.stdout.write(r.get().decode()) sys.stdout.flush() results.extend([x.get() for x in rets if x is not None]) else: for name in filenames: ret = _fix_file((name, options, output)) if ret is None: continue if options.diff: if ret != '': results.append(ret) elif options.in_place: results.append(ret) else: original_source = readlines_from_file(name) if "".join(original_source).splitlines() != ret.splitlines(): results.append(ret) return results def is_python_file(filename): """Return True if filename is Python file.""" if filename.endswith('.py'): return True try: with open_with_encoding( filename, limit_byte_check=MAX_PYTHON_FILE_DETECTION_BYTES) as f: text = f.read(MAX_PYTHON_FILE_DETECTION_BYTES) if not text: return False first_line = text.splitlines()[0] except (IOError, IndexError): return False if not PYTHON_SHEBANG_REGEX.match(first_line): return False return True def is_probably_part_of_multiline(line): """Return True if line is likely part of a multiline string. When multiline strings are involved, pep8 reports the error as being at the start of the multiline string, which doesn't work for us. """ return ( '"""' in line or "'''" in line or line.rstrip().endswith('\\') ) def wrap_output(output, encoding): """Return output with specified encoding.""" return codecs.getwriter(encoding)(output.buffer if hasattr(output, 'buffer') else output) def get_encoding(): """Return preferred encoding.""" return locale.getpreferredencoding() or sys.getdefaultencoding() def main(argv=None, apply_config=True): """Command-line entry.""" if argv is None: argv = sys.argv try: # Exit on broken pipe. signal.signal(signal.SIGPIPE, signal.SIG_DFL) except AttributeError: # pragma: no cover # SIGPIPE is not available on Windows. pass try: args = parse_args(argv[1:], apply_config=apply_config) if args.list_fixes: for code, description in sorted(supported_fixes()): print('{code} - {description}'.format( code=code, description=description)) return EXIT_CODE_OK if args.files == ['-']: assert not args.in_place encoding = sys.stdin.encoding or get_encoding() read_stdin = sys.stdin.read() fixed_stdin = fix_code(read_stdin, args, encoding=encoding) # LineEndingWrapper is unnecessary here due to the symmetry between # standard in and standard out. wrap_output(sys.stdout, encoding=encoding).write(fixed_stdin) if hash(read_stdin) != hash(fixed_stdin): if args.exit_code: return EXIT_CODE_EXISTS_DIFF else: if args.in_place or args.diff: args.files = list(set(args.files)) else: assert len(args.files) == 1 assert not args.recursive results = fix_multiple_files(args.files, args, sys.stdout) if args.diff: ret = any([len(ret) != 0 for ret in results]) else: # with in-place option ret = any([ret is not None for ret in results]) if args.exit_code and ret: return EXIT_CODE_EXISTS_DIFF except IOError: return EXIT_CODE_ERROR except KeyboardInterrupt: return EXIT_CODE_ERROR # pragma: no cover class CachedTokenizer(object): """A one-element cache around tokenize.generate_tokens(). Original code written by Ned Batchelder, in coverage.py. """ def __init__(self): self.last_text = None self.last_tokens = None def generate_tokens(self, text): """A stand-in for tokenize.generate_tokens().""" if text != self.last_text: string_io = io.StringIO(text) self.last_tokens = list( tokenize.generate_tokens(string_io.readline) ) self.last_text = text return self.last_tokens _cached_tokenizer = CachedTokenizer() generate_tokens = _cached_tokenizer.generate_tokens if __name__ == '__main__': sys.exit(main()) autopep8-2.3.2/hooks/000077500000000000000000000000001474147346600144265ustar00rootroot00000000000000autopep8-2.3.2/hooks/pre-push000077500000000000000000000002541474147346600161200ustar00rootroot00000000000000#!/bin/bash -e z40=0000000000000000000000000000000000000000 IFS=' ' while read _ local_sha _ _ do if [ "$local_sha" != $z40 ] then make check fi done autopep8-2.3.2/install_hooks.bash000077500000000000000000000001341474147346600170140ustar00rootroot00000000000000#!/bin/bash -ex readonly root=$(dirname "$0") cd "$root"/.git/hooks ln -fs ../../hooks/* . autopep8-2.3.2/pyproject.toml000066400000000000000000000026361474147346600162260ustar00rootroot00000000000000[project] name = "autopep8" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" license = {file = "LICENSE.rst"} authors = [ {name = "Hideo Hattori", email = "hhatto.jp@gmail.com"}, ] readme = "README.rst" keywords = [ "automation", "pep8", "format", "pycodestyle", ] classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Quality Assurance", ] requires-python = ">=3.9" dependencies = [ "pycodestyle >= 2.12.0", "tomli; python_version < '3.11'", ] dynamic = ["version"] [project.urls] Repository = "https://github.com/hhatto/autopep8" [project.scripts] autopep8 = "autopep8:main" [tool.setuptools] py-modules = ["autopep8"] [tool.setuptools.dynamic] version = {attr = "autopep8.__version__"} [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" autopep8-2.3.2/setup.cfg000066400000000000000000000000341474147346600151210ustar00rootroot00000000000000[bdist_wheel] universal = 1 autopep8-2.3.2/test/000077500000000000000000000000001474147346600142625ustar00rootroot00000000000000autopep8-2.3.2/test/.gitignore000066400000000000000000000000261474147346600162500ustar00rootroot00000000000000pypi_tmp/ github_tmp/ autopep8-2.3.2/test/__init__.py000066400000000000000000000000001474147346600163610ustar00rootroot00000000000000autopep8-2.3.2/test/acid.py000077500000000000000000000212141474147346600155370ustar00rootroot00000000000000#!/usr/bin/env python """Test that autopep8 runs without crashing on various Python files.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function import argparse import os import random import shlex import sys import subprocess import tempfile try: basestring except NameError: basestring = str ROOT_PATH = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] # Override system-installed version of autopep8. sys.path = [ROOT_PATH] + sys.path import autopep8 if sys.stdout.isatty(): YELLOW = '\x1b[33m' END = '\x1b[0m' else: YELLOW = '' END = '' RANDOM_MAX = 1000 def colored(text, color): """Return color coded text.""" return color + text + END def run(filename, command, max_line_length=79, ignore='', check_ignore='', verbose=False, comparison_function=None, aggressive=0, experimental=False, line_range=None, random_range=False, pycodestyle=True): """Run autopep8 on file at filename. Return True on success. """ if random_range: if not line_range: line_range = [1, RANDOM_MAX] first = random.randint(*line_range) line_range = [first, random.randint(first, line_range[1])] command = (shlex.split(command) + (['--verbose'] if verbose else []) + ['--max-line-length={}'.format(max_line_length), '--ignore=' + ignore, filename] + aggressive * ['--aggressive'] + (['--experimental'] if experimental else []) + (['--line-range', str(line_range[0]), str(line_range[1])] if line_range else [])) print(' '.join(command), file=sys.stderr) with tempfile.NamedTemporaryFile(suffix='.py') as tmp_file: if subprocess.call(command, stdout=tmp_file) != 0: sys.stderr.write('autopep8 crashed on ' + filename + '\n') return False if pycodestyle and subprocess.call( [pycodestyle, '--ignore=' + ','.join([x for x in ignore.split(',') + check_ignore.split(',') if x]), '--show-source', tmp_file.name], stdout=sys.stdout) != 0: sys.stderr.write('autopep8 did not completely fix ' + filename + '\n') try: if check_syntax(filename): try: check_syntax(tmp_file.name, raise_error=True) except (SyntaxError, TypeError, UnicodeDecodeError) as exception: sys.stderr.write('autopep8 broke ' + filename + '\n' + str(exception) + '\n') return False if comparison_function: if not comparison_function(filename, tmp_file.name): return False except IOError as exception: sys.stderr.write(str(exception) + '\n') return True def check_syntax(filename, raise_error=False): """Return True if syntax is okay.""" with autopep8.open_with_encoding(filename) as input_file: try: compile(input_file.read(), '', 'exec', dont_inherit=True) return True except (SyntaxError, TypeError, UnicodeDecodeError): if raise_error: raise else: return False def process_args(): """Return processed arguments (options and positional arguments).""" compare_bytecode_ignore = 'E71,E721,W' parser = argparse.ArgumentParser() parser.add_argument( '--command', default='{} {}'.format(sys.executable, os.path.join(ROOT_PATH, 'autopep8.py')), help='autopep8 command (default: %(default)s)') parser.add_argument('--ignore', help='comma-separated errors to ignore', default='') parser.add_argument('--check-ignore', help='comma-separated errors to ignore when checking ' 'for completeness (default: %(default)s)', default='') parser.add_argument('--max-line-length', metavar='n', default=79, type=int, help='set maximum allowed line length ' '(default: %(default)s)') parser.add_argument('--compare-bytecode', action='store_true', help='compare bytecode before and after fixes; ' 'sets default --ignore=' + compare_bytecode_ignore) parser.add_argument('-a', '--aggressive', action='count', default=0, help='run autopep8 in aggressive mode') parser.add_argument('--experimental', action='store_true', help='run experimental fixes') parser.add_argument('--line-range', metavar='line', default=None, type=int, nargs=2, help='pass --line-range to autope8') parser.add_argument('--random-range', action='store_true', help='pass random --line-range to autope8') parser.add_argument('--pycodestyle', default='pycodestyle', help='location of pycodestyle; ' 'set to empty string to disable this check') parser.add_argument('-v', '--verbose', action='store_true', help='print verbose messages') parser.add_argument('paths', nargs='*', help='paths to use for testing') args = parser.parse_args() if args.compare_bytecode and not args.ignore: args.ignore = compare_bytecode_ignore return args def compare_bytecode(filename_a, filename_b): try: import pydiff except ImportError: raise SystemExit('pydiff required for bytecode comparison; ' 'run "pip install pydiff"') diff = pydiff.diff_bytecode_of_files(filename_a, filename_b) if diff: sys.stderr.write('New bytecode does not match original:\n' + diff + '\n') return not diff def check(paths, args): """Run recursively run autopep8 on directory of files. Return False if the fix results in broken syntax. """ if paths: dir_paths = paths else: dir_paths = [path for path in sys.path if os.path.isdir(path)] filenames = dir_paths completed_filenames = set() if args.compare_bytecode: comparison_function = compare_bytecode else: comparison_function = None while filenames: try: name = os.path.realpath(filenames.pop(0)) if not os.path.exists(name): # Invalid symlink. continue if name in completed_filenames: sys.stderr.write( colored( '---> Skipping previously tested ' + name + '\n', YELLOW)) continue else: completed_filenames.update(name) if os.path.isdir(name): for root, directories, children in os.walk(name): filenames += [os.path.join(root, f) for f in children if f.endswith('.py') and not f.startswith('.')] directories[:] = [d for d in directories if not d.startswith('.')] else: verbose_message = '---> Testing with ' + name sys.stderr.write(colored(verbose_message + '\n', YELLOW)) if not run(os.path.join(name), command=args.command, max_line_length=args.max_line_length, ignore=args.ignore, check_ignore=args.check_ignore, verbose=args.verbose, comparison_function=comparison_function, aggressive=args.aggressive, experimental=args.experimental, line_range=args.line_range, random_range=args.random_range, pycodestyle=args.pycodestyle): return False except (UnicodeDecodeError, UnicodeEncodeError) as exception: # Ignore annoying codec problems on Python 2. print(exception) continue return True def main(): """Run main.""" args = process_args() return 0 if check(args.paths, args) else 1 if __name__ == '__main__': try: sys.exit(main()) except KeyboardInterrupt: sys.exit(1) autopep8-2.3.2/test/acid_pypi.py000077500000000000000000000074601474147346600166070ustar00rootroot00000000000000#!/usr/bin/env python """Run acid test against latest packages on PyPI.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function import os import subprocess import sys import tarfile import zipfile import acid TMP_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'pypi_tmp') def latest_packages(last_hours): """Return names of latest released packages on PyPI.""" process = subprocess.Popen( ['yolk', '--latest-releases={hours}'.format(hours=last_hours)], stdout=subprocess.PIPE) for line in process.communicate()[0].decode('utf-8').split('\n'): if line: yield line.split()[0] def download_package(name, output_directory): """Download package to output_directory. Raise CalledProcessError on failure. """ subprocess.check_call(['yolk', '--fetch-package={name}'.format(name=name)], cwd=output_directory) def extract_package(path, output_directory): """Extract package at path.""" if path.lower().endswith('.tar.gz'): try: tar = tarfile.open(path) tar.extractall(path=output_directory) tar.close() return True except (tarfile.ReadError, IOError): return False elif path.lower().endswith('.zip'): try: archive = zipfile.ZipFile(path) archive.extractall(path=output_directory) archive.close() except (zipfile.BadZipfile, IOError): return False return True return False def main(): """Run main.""" try: os.mkdir(TMP_DIR) except OSError: pass args = acid.process_args() if args.paths: # Copy names = list(args.paths) else: names = None checked_packages = [] skipped_packages = [] last_hours = 1 while True: if args.paths: if not names: break else: while not names: # Continually populate if user did not specify a package # explicitly. names = [p for p in latest_packages(last_hours) if p not in checked_packages and p not in skipped_packages] if not names: last_hours *= 2 package_name = names.pop(0) print(package_name, file=sys.stderr) package_tmp_dir = os.path.join(TMP_DIR, package_name) try: os.mkdir(package_tmp_dir) except OSError: print('Skipping already checked package', file=sys.stderr) skipped_packages.append(package_name) continue try: download_package( package_name, output_directory=package_tmp_dir) except subprocess.CalledProcessError: print('yolk fetch failed', file=sys.stderr) continue for download_name in os.listdir(package_tmp_dir): try: if not extract_package( os.path.join(package_tmp_dir, download_name), output_directory=package_tmp_dir): print('Could not extract package', file=sys.stderr) continue except UnicodeDecodeError: print('Could not extract package', file=sys.stderr) continue if acid.check([package_tmp_dir], args): checked_packages.append(package_name) else: return 1 if checked_packages: print('\nTested packages:\n ' + '\n '.join(checked_packages), file=sys.stderr) if __name__ == '__main__': try: sys.exit(main()) except KeyboardInterrupt: sys.exit(1) autopep8-2.3.2/test/bad_encoding.py000066400000000000000000000000331474147346600172240ustar00rootroot00000000000000# -*- coding: zlatin-1 -*- autopep8-2.3.2/test/bad_encoding2.py000066400000000000000000000000361474147346600173110ustar00rootroot00000000000000#coding: utf8 print('我') autopep8-2.3.2/test/e101_example.py000066400000000000000000001273211474147346600170230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # From https://github.com/coto/gae-boilerplate/blob/233a88c59e46bb10de7a901ef4e6a5b60d0006a5/web/handlers.py """ This example will take a long time if we don't filter innocuous E101 errors from pep8. """ import models.models as models from webapp2_extras.auth import InvalidAuthIdError from webapp2_extras.auth import InvalidPasswordError from webapp2_extras import security from lib import utils from lib import captcha from lib.basehandler import BaseHandler from lib.basehandler import user_required from google.appengine.api import taskqueue import logging import config import webapp2 import web.forms as forms from webapp2_extras.i18n import gettext as _ from webapp2_extras.appengine.auth.models import Unique from lib import twitter class LoginBaseHandler(BaseHandler): """ Base class for handlers with login form. """ @webapp2.cached_property def form(self): return forms.LoginForm(self) class RegisterBaseHandler(BaseHandler): """ Base class for handlers with registration and login forms. """ @webapp2.cached_property def form(self): if self.is_mobile: return forms.RegisterMobileForm(self) else: return forms.RegisterForm(self) @webapp2.cached_property def form_login(self): return forms.LoginForm(self) @webapp2.cached_property def forms(self): return {'form_login' : self.form_login, 'form' : self.form} class SendEmailHandler(BaseHandler): """ Handler for sending Emails Use with TaskQueue """ def post(self): to = self.request.get("to") subject = self.request.get("subject") body = self.request.get("body") sender = self.request.get("sender") utils.send_email(to, subject, body, sender) class LoginHandler(LoginBaseHandler): """ Handler for authentication """ def get(self): """ Returns a simple HTML form for login """ if self.user: self.redirect_to('home', id=self.user_id) params = {} return self.render_template('boilerplate_login.html', **params) def post(self): """ username: Get the username from POST dict password: Get the password from POST dict """ if not self.form.validate(): return self.get() username = self.form.username.data.lower() try: if utils.is_email_valid(username): user = models.User.get_by_email(username) if user: auth_id = user.auth_ids[0] else: raise InvalidAuthIdError else: auth_id = "own:%s" % username user = models.User.get_by_auth_id(auth_id) password = self.form.password.data.strip() remember_me = True if str(self.request.POST.get('remember_me')) == 'on' else False # Password to SHA512 password = utils.encrypt(password, config.salt) # Try to login user with password # Raises InvalidAuthIdError if user is not found # Raises InvalidPasswordError if provided password # doesn't match with specified user self.auth.get_user_by_password( auth_id, password, remember=remember_me) # if user account is not activated, logout and redirect to home if (user.activated == False): # logout self.auth.unset_session() # redirect to home with error message resend_email_uri = self.uri_for('resend-account-activation', encoded_email=utils.encode(user.email)) message = _('Sorry, your account') + ' {0:>s}'.format(username) + " " +\ _('has not been activated. Please check your email to activate your account') + ". " +\ _('Or click') + " " + _('this') + " " + _('to resend the email') self.add_message(message, 'error') return self.redirect_to('home') # check twitter association in session twitter_helper = twitter.TwitterAuth(self) twitter_association_data = twitter_helper.get_association_data() if twitter_association_data is not None: if models.SocialUser.check_unique(user.key, 'twitter', str(twitter_association_data['id'])): social_user = models.SocialUser( user = user.key, provider = 'twitter', uid = str(twitter_association_data['id']), extra_data = twitter_association_data ) social_user.put() logVisit = models.LogVisit( user=user.key, uastring=self.request.user_agent, ip=self.request.remote_addr, timestamp=utils.get_date_time() ) logVisit.put() self.redirect_to('home') except (InvalidAuthIdError, InvalidPasswordError), e: # Returns error message to self.response.write in # the BaseHandler.dispatcher message = _("Login invalid, Try again.") + "
" + _("Don't have an account?") + \ ' ' + _("Sign Up") + '' self.add_message(message, 'error') return self.redirect_to('login') class SocialLoginHandler(BaseHandler): """ Handler for Social authentication """ def get(self, provider_name): provider_display_name = models.SocialUser.PROVIDERS_INFO[provider_name]['label'] if not config.enable_federated_login: message = _('Federated login is disabled.') self.add_message(message,'warning') return self.redirect_to('login') callback_url = "%s/social_login/%s/complete" % (self.request.host_url, provider_name) if provider_name == "twitter": twitter_helper = twitter.TwitterAuth(self, redirect_uri=callback_url) self.redirect(twitter_helper.auth_url()) else: message = _('%s authentication is not implemented yet.') % provider_display_name self.add_message(message,'warning') self.redirect_to('edit-profile') class CallbackSocialLoginHandler(BaseHandler): """ Callback (Save Information) for Social Authentication """ def get(self, provider_name): if not config.enable_federated_login: message = _('Federated login is disabled.') self.add_message(message,'warning') return self.redirect_to('login') if provider_name == "twitter": oauth_token = self.request.get('oauth_token') oauth_verifier = self.request.get('oauth_verifier') twitter_helper = twitter.TwitterAuth(self) user_data = twitter_helper.auth_complete(oauth_token, oauth_verifier) if self.user: # new association with twitter user_info = models.User.get_by_id(long(self.user_id)) if models.SocialUser.check_unique(user_info.key, 'twitter', str(user_data['id'])): social_user = models.SocialUser( user = user_info.key, provider = 'twitter', uid = str(user_data['id']), extra_data = user_data ) social_user.put() message = _('Twitter association added!') self.add_message(message,'success') else: message = _('This Twitter account is already in use!') self.add_message(message,'error') self.redirect_to('edit-profile') else: # login with twitter social_user = models.SocialUser.get_by_provider_and_uid('twitter', str(user_data['id'])) if social_user: # Social user exists. Need authenticate related site account user = social_user.user.get() self.auth.set_session(self.auth.store.user_to_dict(user), remember=True) logVisit = models.LogVisit( user = user.key, uastring = self.request.user_agent, ip = self.request.remote_addr, timestamp = utils.get_date_time() ) logVisit.put() self.redirect_to('home') else: # Social user does not exists. Need show login and registration forms twitter_helper.save_association_data(user_data) message = _('Account with association to your Twitter does not exist. You can associate it right now, if you login with existing site account or create new on Sign up page.') self.add_message(message,'info') self.redirect_to('login') # Debug Callback information provided # for k,v in user_data.items(): # print(k +":"+ v ) # google, myopenid, yahoo OpenID Providers elif provider_name in models.SocialUser.open_id_providers(): provider_display_name = models.SocialUser.PROVIDERS_INFO[provider_name]['label'] # get info passed from OpenId Provider from google.appengine.api import users current_user = users.get_current_user() if current_user: if current_user.federated_identity(): uid = current_user.federated_identity() else: uid = current_user.user_id() email = current_user.email() else: message = _('No user authentication information received from %s. Please ensure you are logging in from an authorized OpenID Provider (OP).' % provider_display_name) self.add_message(message,'error') return self.redirect_to('login') if self.user: # add social account to user user_info = models.User.get_by_id(long(self.user_id)) if models.SocialUser.check_unique(user_info.key, provider_name, uid): social_user = models.SocialUser( user = user_info.key, provider = provider_name, uid = uid ) social_user.put() message = provider_display_name + _(' association added!') self.add_message(message,'success') else: message = _('This %s account is already in use!' % provider_display_name) self.add_message(message,'error') self.redirect_to('edit-profile') else: # login with OpenId Provider social_user = models.SocialUser.get_by_provider_and_uid(provider_name, uid) if social_user: # Social user found. Authenticate the user user = social_user.user.get() self.auth.set_session(self.auth.store.user_to_dict(user), remember=True) logVisit = models.LogVisit( user = user.key, uastring = self.request.user_agent, ip = self.request.remote_addr, timestamp = utils.get_date_time() ) logVisit.put() self.redirect_to('home') else: # Social user does not exist yet so create it with the federated identity provided (uid) # and create prerequisite user and log the user account in if models.SocialUser.check_unique_uid(provider_name, uid): # create user # Returns a tuple, where first value is BOOL. # If True ok, If False no new user is created # Assume provider has already verified email address # if email is provided so set activated to True auth_id = "%s:%s" % (provider_name, uid) if email: unique_properties = ['email'] user_info = self.auth.store.user_model.create_user( auth_id, unique_properties, email=email, activated=True ) else: user_info = self.auth.store.user_model.create_user( auth_id, activated=True ) if not user_info[0]: #user is a tuple message = _('This %s account is already in use!' % provider_display_name) self.add_message(message, 'error') return self.redirect_to('register') user = user_info[1] # create social user and associate with user social_user = models.SocialUser( user = user.key, provider = provider_name, uid = uid ) social_user.put() # authenticate user self.auth.set_session(self.auth.store.user_to_dict(user), remember=True) logVisit = models.LogVisit( user = user.key, uastring = self.request.user_agent, ip = self.request.remote_addr, timestamp = utils.get_date_time() ) logVisit.put() self.redirect_to('home') message = provider_display_name + _(' association added!') self.add_message(message,'success') self.redirect_to('home') else: message = _('This %s account is already in use!' % provider_display_name) self.add_message(message,'error') self.redirect_to('login') else: message = _('%s authentication is not implemented yet.') % provider_display_name self.add_message(message,'warning') self.redirect_to('login') class DeleteSocialProviderHandler(BaseHandler): """ Delete Social association with an account """ @user_required def get(self, provider_name): if self.user: user_info = models.User.get_by_id(long(self.user_id)) social_user = models.SocialUser.get_by_user_and_provider(user_info.key, provider_name) if social_user: social_user.key.delete() message = provider_name + _(' disassociated!') self.add_message(message,'success') else: message = _('Social account on ') + provider_name + _(' not found for this user!') self.add_message(message,'error') self.redirect_to('edit-profile') class LogoutHandler(BaseHandler): """ Destroy user session and redirect to login """ def get(self): if self.user: message = _("You've signed out successfully. Warning: Please clear all cookies and logout \ of OpenId providers too if you logged in on a public computer.") # Info message self.add_message(message, 'info') self.auth.unset_session() # User is logged out, let's try redirecting to login page try: self.redirect(self.auth_config['login_url']) except (AttributeError, KeyError), e: return _("User is logged out, but there was an error "\ "on the redirection.") class RegisterHandler(RegisterBaseHandler): """ Handler for Sign Up Users """ def get(self): """ Returns a simple HTML form for create a new user """ if self.user: self.redirect_to('home', id=self.user_id) params = {} return self.render_template('boilerplate_register.html', **params) def post(self): """ Get fields from POST dict """ if not self.form.validate(): return self.get() username = self.form.username.data.lower() name = self.form.name.data.strip() last_name = self.form.last_name.data.strip() email = self.form.email.data.lower() password = self.form.password.data.strip() country = self.form.country.data # Password to SHA512 password = utils.encrypt(password, config.salt) # Passing password_raw=password so password will be hashed # Returns a tuple, where first value is BOOL. # If True ok, If False no new user is created unique_properties = ['username', 'email'] auth_id = "own:%s" % username user = self.auth.store.user_model.create_user( auth_id, unique_properties, password_raw=password, username=username, name=name, last_name=last_name, email=email, country=country, activated=False ) if not user[0]: #user is a tuple message = _('Sorry, This user') + ' {0:>s}'.format(username) + " " +\ _('is already registered.') self.add_message(message, 'error') return self.redirect_to('register') else: # User registered successfully # But if the user registered using the form, the user has to check their email to activate the account ??? try: user_info = models.User.get_by_email(email) if (user_info.activated == False): # send email subject = config.app_name + " Account Verification Email" encoded_email = utils.encode(email) confirmation_url = self.uri_for("account-activation", encoded_email = encoded_email, _full = True) # load email's template template_val = { "app_name": config.app_name, "username": username, "confirmation_url": confirmation_url, "support_url": self.uri_for("contact", _full=True) } body_path = "emails/account_activation.txt" body = self.jinja2.render_template(body_path, **template_val) email_url = self.uri_for('taskqueue-send-email') taskqueue.add(url = email_url, params={ 'to': str(email), 'subject' : subject, 'body' : body, }) message = _('Congratulations') + ", " + str(username) + "! " + _('You are now registered') +\ ". " + _('Please check your email to activate your account') self.add_message(message, 'success') return self.redirect_to('home') # If the user didn't register using registration form ??? db_user = self.auth.get_user_by_password(user[1].auth_ids[0], password) # Check twitter association in session twitter_helper = twitter.TwitterAuth(self) twitter_association_data = twitter_helper.get_association_data() if twitter_association_data is not None: if models.SocialUser.check_unique(user[1].key, 'twitter', str(twitter_association_data['id'])): social_user = models.SocialUser( user = user[1].key, provider = 'twitter', uid = str(twitter_association_data['id']), extra_data = twitter_association_data ) social_user.put() message = _('Welcome') + " " + str(username) + ", " + _('you are now logged in.') self.add_message(message, 'success') return self.redirect_to('home') except (AttributeError, KeyError), e: message = _('Unexpected error creating '\ 'user') + " " + '{0:>s}.'.format(username) self.add_message(message, 'error') self.abort(403) class AccountActivationHandler(BaseHandler): """ Handler for account activation """ def get(self, encoded_email): try: email = utils.decode(encoded_email) user = models.User.get_by_email(email) # activate the user's account user.activated = True user.put() message = _('Congratulations') + "! " + _('Your account') + " (@" + user.username + ") " +\ _('has just been activated') + ". " + _('Please login to your account') self.add_message(message, "success") self.redirect_to('login') except (AttributeError, KeyError, InvalidAuthIdError), e: message = _('Unexpected error activating '\ 'account') + " " + '{0:>s}.'.format(user.username) self.add_message(message, 'error') self.abort(403) class ResendActivationEmailHandler(BaseHandler): """ Handler to resend activation email """ def get(self, encoded_email): try: email = utils.decode(encoded_email) user = models.User.get_by_email(email) if (user.activated == False): # send email subject = config.app_name + " Account Verification Email" encoded_email = utils.encode(email) confirmation_url = self.uri_for("account-activation", encoded_email = encoded_email, _full = True) # load email's template template_val = { "app_name": config.app_name, "username": user.username, "confirmation_url": confirmation_url, "support_url": self.uri_for("contact", _full=True) } body_path = "emails/account_activation.txt" body = self.jinja2.render_template(body_path, **template_val) email_url = self.uri_for('taskqueue-send-email') taskqueue.add(url = email_url, params={ 'to': str(email), 'subject' : subject, 'body' : body, }) message = _('The verification email has been resent to') + " " + str(email) + ". " +\ _('Please check your email to activate your account') self.add_message(message, "success") return self.redirect_to('home') else: message = _('Your account has been activated') + ". " +\ _('Please login to your account') self.add_message(message, "warning") return self.redirect_to('home') except (KeyError, AttributeError), e: message = _('Sorry') + ". " + _('Some error occurred') + "." self.add_message(message, "error") return self.redirect_to('home') class ContactHandler(BaseHandler): """ Handler for Contact Form """ def get(self): """ Returns a simple HTML for contact form """ if self.user: user_info = models.User.get_by_id(long(self.user_id)) if user_info.name or user_info.last_name: self.form.name.data = user_info.name + " " + user_info.last_name if user_info.email: self.form.email.data = user_info.email params = { "exception" : self.request.get('exception') } return self.render_template('boilerplate_contact.html', **params) def post(self): """ validate contact form """ if not self.form.validate(): return self.get() remoteip = self.request.remote_addr user_agent = self.request.user_agent exception = self.request.POST.get('exception') name = self.form.name.data.strip() email = self.form.email.data.lower() message = self.form.message.data.strip() try: subject = _("Contact") body = "" # exceptions for error pages that redirect to contact if exception != "": body = "* Exception error: %s" % exception body = body + """ * IP Address: %s * Web Browser: %s * Sender name: %s * Sender email: %s * Message: %s """ % (remoteip, user_agent, name, email, message) email_url = self.uri_for('taskqueue-send-email') taskqueue.add(url = email_url, params={ 'to': config.contact_recipient, 'subject' : subject, 'body' : body, 'sender' : config.contact_sender, }) message = _('Message sent successfully.') self.add_message(message, 'success') return self.redirect_to('contact') except (AttributeError, KeyError), e: message = _('Error sending the message. Please try again later.') self.add_message(message, 'error') return self.redirect_to('contact') @webapp2.cached_property def form(self): return forms.ContactForm(self) class EditProfileHandler(BaseHandler): """ Handler for Edit User Profile """ @user_required def get(self): """ Returns a simple HTML form for edit profile """ params = {} if self.user: user_info = models.User.get_by_id(long(self.user_id)) self.form.username.data = user_info.username self.form.name.data = user_info.name self.form.last_name.data = user_info.last_name self.form.country.data = user_info.country providers_info = user_info.get_social_providers_info() params['used_providers'] = providers_info['used'] params['unused_providers'] = providers_info['unused'] params['country'] = user_info.country return self.render_template('boilerplate_edit_profile.html', **params) def post(self): """ Get fields from POST dict """ if not self.form.validate(): return self.get() username = self.form.username.data.lower() name = self.form.name.data.strip() last_name = self.form.last_name.data.strip() country = self.form.country.data try: user_info = models.User.get_by_id(long(self.user_id)) try: message='' # update username if it has changed and it isn't already taken if username != user_info.username: user_info.unique_properties = ['username','email'] uniques = [ 'User.username:%s' % username, 'User.auth_id:own:%s' % username, ] # Create the unique username and auth_id. success, existing = Unique.create_multi(uniques) if success: # free old uniques Unique.delete_multi(['User.username:%s' % user_info.username, 'User.auth_id:own:%s' % user_info.username]) # The unique values were created, so we can save the user. user_info.username=username user_info.auth_ids[0]='own:%s' % username message+= _('Your new username is ') + '' + username + '.' else: message+= _('Username') + " " + username + " " + _('is already taken. It is not changed.') # At least one of the values is not unique. self.add_message(message,'error') return self.get() user_info.name=name user_info.last_name=last_name user_info.country=country user_info.put() message+= " " + _('Your profile has been updated!') self.add_message(message,'success') return self.get() except (AttributeError, KeyError, ValueError), e: message = _('Unable to update profile!') logging.error('Unable to update profile: ' + e) self.add_message(message,'error') return self.get() except (AttributeError, TypeError), e: login_error_message = _('Sorry you are not logged in!') self.add_message(login_error_message,'error') self.redirect_to('login') @webapp2.cached_property def form(self): return forms.EditProfileForm(self) class EditPasswordHandler(BaseHandler): """ Handler for Edit User Password """ @user_required def get(self): """ Returns a simple HTML form for editing password """ params = {} return self.render_template('boilerplate_edit_password.html', **params) def post(self): """ Get fields from POST dict """ if not self.form.validate(): return self.get() current_password = self.form.current_password.data.strip() password = self.form.password.data.strip() try: user_info = models.User.get_by_id(long(self.user_id)) auth_id = "own:%s" % user_info.username # Password to SHA512 current_password = utils.encrypt(current_password, config.salt) try: user = models.User.get_by_auth_password(auth_id, current_password) # Password to SHA512 password = utils.encrypt(password, config.salt) user.password = security.generate_password_hash(password, length=12) user.put() # send email subject = config.app_name + " Account Password Changed" # load email's template template_val = { "app_name": config.app_name, "first_name": user.name, "username": user.username, "email": user.email, "reset_password_url": self.uri_for("password-reset", _full=True) } email_body_path = "emails/password_changed.txt" email_body = self.jinja2.render_template(email_body_path, **template_val) email_url = self.uri_for('taskqueue-send-email') taskqueue.add(url = email_url, params={ 'to': user.email, 'subject' : subject, 'body' : email_body, 'sender' : config.contact_sender, }) # Login User self.auth.get_user_by_password(user.auth_ids[0], password) self.add_message(_('Password changed successfully'), 'success') return self.redirect_to('edit-profile') except (InvalidAuthIdError, InvalidPasswordError), e: # Returns error message to self.response.write in # the BaseHandler.dispatcher message = _("Your Current Password is wrong, please try again") self.add_message(message, 'error') return self.redirect_to('edit-password') except (AttributeError,TypeError), e: login_error_message = _('Sorry you are not logged in!') self.add_message(login_error_message,'error') self.redirect_to('login') @webapp2.cached_property def form(self): if self.is_mobile: return forms.EditPasswordMobileForm(self) else: return forms.EditPasswordForm(self) class EditEmailHandler(BaseHandler): """ Handler for Edit User's Email """ @user_required def get(self): """ Returns a simple HTML form for edit email """ params = {} if self.user: user_info = models.User.get_by_id(long(self.user_id)) self.form.new_email.data = user_info.email return self.render_template('boilerplate_edit_email.html', **params) def post(self): """ Get fields from POST dict """ if not self.form.validate(): return self.get() new_email = self.form.new_email.data.strip() password = self.form.password.data.strip() try: user_info = models.User.get_by_id(long(self.user_id)) auth_id = "own:%s" % user_info.username # Password to SHA512 password = utils.encrypt(password, config.salt) try: # authenticate user by its password user = models.User.get_by_auth_password(auth_id, password) # if the user change his/her email address if new_email != user.email: # check whether the new email has been used by another user aUser = models.User.get_by_email(new_email) if aUser is not None: message = _("The email %s is already registered." % new_email) self.add_message(message, "error") return self.redirect_to("edit-email") # send email subject = config.app_name + " Email Changed Notification" user_token = models.User.create_auth_token(self.user_id) confirmation_url = self.uri_for("email-changed-check", user_id = user_info.get_id(), encoded_email = utils.encode(new_email), token = user_token, _full = True) # load email's template template_val = { "app_name": config.app_name, "first_name": user.name, "username": user.username, "new_email": new_email, "confirmation_url": confirmation_url, "support_url": self.uri_for("contact", _full=True) } old_body_path = "emails/email_changed_notification_old.txt" old_body = self.jinja2.render_template(old_body_path, **template_val) new_body_path = "emails/email_changed_notification_new.txt" new_body = self.jinja2.render_template(new_body_path, **template_val) email_url = self.uri_for('taskqueue-send-email') taskqueue.add(url = email_url, params={ 'to': user.email, 'subject' : subject, 'body' : old_body, }) email_url = self.uri_for('taskqueue-send-email') taskqueue.add(url = email_url, params={ 'to': new_email, 'subject' : subject, 'body' : new_body, }) logging.error(user) # display successful message msg = _("Please check your new email for confirmation. Your email will be updated after confirmation.") self.add_message(msg, 'success') return self.redirect_to('edit-profile') else: self.add_message(_("You didn't change your email"), "warning") return self.redirect_to("edit-email") except (InvalidAuthIdError, InvalidPasswordError), e: # Returns error message to self.response.write in # the BaseHandler.dispatcher message = _("Your password is wrong, please try again") self.add_message(message, 'error') return self.redirect_to('edit-email') except (AttributeError,TypeError), e: login_error_message = _('Sorry you are not logged in!') self.add_message(login_error_message,'error') self.redirect_to('login') @webapp2.cached_property def form(self): return forms.EditEmailForm(self) class PasswordResetHandler(LoginBaseHandler): """ Password Reset Handler with Captcha """ reCaptcha_public_key = config.captcha_public_key reCaptcha_private_key = config.captcha_private_key def get(self): chtml = captcha.displayhtml( public_key = self.reCaptcha_public_key, use_ssl = False, error = None) params = { 'captchahtml': chtml, } return self.render_template('boilerplate_password_reset.html', **params) def post(self): # check captcha challenge = self.request.POST.get('recaptcha_challenge_field') response = self.request.POST.get('recaptcha_response_field') remoteip = self.request.remote_addr cResponse = captcha.submit( challenge, response, self.reCaptcha_private_key, remoteip) if cResponse.is_valid: # captcha was valid... carry on..nothing to see here pass else: logging.warning(cResponse.error_code) _message = _('Wrong image verification code. Please try again.') self.add_message(_message, 'error') return self.redirect_to('password-reset') # check if we got an email or username email_or_username = str(self.request.POST.get('email_or_username')).lower().strip() if utils.is_email_valid(email_or_username): user = models.User.get_by_email(email_or_username) _message = _("If the e-mail address you entered") + " (%s) " % email_or_username else: auth_id = "own:%s" % email_or_username user = models.User.get_by_auth_id(auth_id) _message = _("If the username you entered") + " (%s) " % email_or_username if user is not None: user_id = user.get_id() token = models.User.create_auth_token(user_id) email_url = self.uri_for('taskqueue-send-email') reset_url = self.uri_for('password-reset-check', user_id=user_id, token=token, _full=True) subject = _("Password reminder") body = _('Please click below to create a new password:') +\ """ %s """ % reset_url taskqueue.add(url = email_url, params={ 'to': user.email, 'subject' : subject, 'body' : body, 'sender' : config.contact_sender, }) _message = _message + _("is associated with an account in our records, you will receive "\ "an e-mail from us with instructions for resetting your password. "\ "
If you don't receive this e-mail, please check your junk mail folder or ") +\ '' + _('contact us') + ' ' + _("for further assistance.") self.add_message(_message, 'success') return self.redirect_to('login') _message = _('Your email / username was not found. Please try another or ') + '' + _('create an account') + '' self.add_message(_message, 'error') return self.redirect_to('password-reset') class PasswordResetCompleteHandler(LoginBaseHandler): """ Handler to process the link of reset password that received the user """ def get(self, user_id, token): verify = models.User.get_by_auth_token(int(user_id), token) params = {} if verify[0] is None: message = _('There was an error or the link is outdated. Please copy and paste the link from your email or enter your details again below to get a new one.') self.add_message(message, 'warning') return self.redirect_to('password-reset') else: return self.render_template('boilerplate_password_reset_complete.html', **params) def post(self, user_id, token): verify = models.User.get_by_auth_token(int(user_id), token) user = verify[0] password = self.form.password.data.strip() if user and self.form.validate(): # Password to SHA512 password = utils.encrypt(password, config.salt) user.password = security.generate_password_hash(password, length=12) user.put() # Delete token models.User.delete_auth_token(int(user_id), token) # Login User self.auth.get_user_by_password(user.auth_ids[0], password) self.add_message(_('Password changed successfully'), 'success') return self.redirect_to('home') else: self.add_message(_('Please correct the form errors.'), 'error') return self.redirect_to('password-reset-check', user_id=user_id, token=token) @webapp2.cached_property def form(self): if self.is_mobile: return forms.PasswordResetCompleteMobileForm(self) else: return forms.PasswordResetCompleteForm(self) class EmailChangedCompleteHandler(BaseHandler): """ Handler for completed email change Will be called when the user click confirmation link from email """ def get(self, user_id, encoded_email, token): verify = models.User.get_by_auth_token(int(user_id), token) email = utils.decode(encoded_email) if verify[0] is None: self.add_message('There was an error or the link is outdated. Please copy and paste the link from your email.', 'warning') self.redirect_to('home') else: # save new email user = verify[0] user.email = email user.put() # delete token models.User.delete_auth_token(int(user_id), token) # add successful message and redirect self.add_message("Your email has been successfully updated!", "success") self.redirect_to('edit-profile') class SecureRequestHandler(BaseHandler): """ Only accessible to users that are logged in """ @user_required def get(self, **kwargs): user_session = self.user user_session_object = self.auth.store.get_session(self.request) user_info = models.User.get_by_id(long( self.user_id )) user_info_object = self.auth.store.user_model.get_by_auth_token( user_session['user_id'], user_session['token']) try: params = { "user_session" : user_session, "user_session_object" : user_session_object, "user_info" : user_info, "user_info_object" : user_info_object, "userinfo_logout-url" : self.auth_config['logout_url'], } return self.render_template('boilerplate_secure_zone.html', **params) except (AttributeError, KeyError), e: return _("Secure zone error:") + " %s." % e class HomeRequestHandler(RegisterBaseHandler): """ Handler to show the home page """ def get(self): """ Returns a simple HTML form for home """ params = {} return self.render_template('boilerplate_home.html', **params) autopep8-2.3.2/test/example.py000066400000000000000000000042161474147346600162720ustar00rootroot00000000000000import sys, os def foo(): import subprocess, argparse import copy; import math, email print(1) print(2) # e261 d = {1: 2,# e261 3: 4} print(2) ## e262 print(2) #### e262 print(2) #e262 print(2) # e262 1 /1 1 *2 1 +1 1 -1 1 **2 def dummy1 ( a ): print(a) print(a) def dummy2(a) : if 1 in a: print("a") print(1+1) # e225 print(1 +1) # e225 print(1+ 1) # e225 print(1 +1) # e221+e225 print(1 + 1) # e221 print(1 * 1) # e221 print(1 + 1) # e222 print(1 * 1) # e222 print(a) def func1(): print("A") return 0 def func11(): a = (1,2, 3,"a") b = [1, 2, 3,"b"] c = 0,11/2 return 1 # comment after too empty lines def func2(): pass def func22(): pass; def func_oneline(): print(1) def func_last(): if True: print(1) pass def func_e251(a, b=1, c = 3): pass def func_e251_t(a, b=1, c = 3, d = 4): pass # e201 ( 1) [ 1] { 1: 2} # e202 (1 ) [1 ] {1: 2 } # e203 {4 : 2} [4 , 2] # e211 d = [1] d [0] dummy1 (0) def func_e702(): 4; 1; 4; 1; 4; 1; 4; 1; print(2); print(4); 6;8 if True: 1; 2; 3 0; 1 2;3 4; 5; def func_w602(): raise ValueError, "w602 test" raise ValueError, "w602 test" # my comment raise ValueError raise ValueError # comment raise ValueError, 'arg' ; print(1) raise ValueError, 'arg' ; print(2) # my comment raise ValueError, \ 'arg no comment' raise ValueError, \ 'arg' # my comment raise ValueError, \ """arg""" # my comment raise ValueError, \ """arg """ # my comment raise ValueError, \ '''multiline ''' # my comment a = 'a' raise ValueError, "%s" % (a,) raise 'string' def func_w603(): if 1 <> 2: if 2 <> 2: print(True) else: print(False) def func_w604(): a = 1.1 b = ```a``` def func_e101(): print('abc') if True: print('hello') if __name__ == '__main__': func_last() autopep8-2.3.2/test/fake_configuration/000077500000000000000000000000001474147346600201175ustar00rootroot00000000000000autopep8-2.3.2/test/fake_configuration/.pep8000066400000000000000000000000251474147346600207710ustar00rootroot00000000000000[pep8] indent-size=2 autopep8-2.3.2/test/fake_pycodestyle_configuration/000077500000000000000000000000001474147346600225435ustar00rootroot00000000000000autopep8-2.3.2/test/fake_pycodestyle_configuration/tox.ini000066400000000000000000000000431474147346600240530ustar00rootroot00000000000000[pycodestyle] max-line-length = 40 autopep8-2.3.2/test/inspect_example.py000066400000000000000000003123511474147346600200210ustar00rootroot00000000000000"""Get useful information from live Python objects. This module encapsulates the interface provided by the internal special attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion. It also provides some help for examining source code and class layout. Here are some of the useful functions provided by this module: ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(), isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(), isroutine() - check object types getmembers() - get members of an object that satisfy a given condition getfile(), getsourcefile(), getsource() - find an object's source code getdoc(), getcomments() - get documentation on an object getmodule() - determine the module that an object came from getclasstree() - arrange classes so as to represent their hierarchy getargspec(), getargvalues(), getcallargs() - get info about function arguments getfullargspec() - same, with support for Python-3000 features formatargspec(), formatargvalues() - format an argument spec getouterframes(), getinnerframes() - get info about frames currentframe() - get the current stack frame stack(), trace() - get info about frames on the stack or in a traceback signature() - get a Signature object for the callable """ # This module is in the public domain. No warranties. __author__ = ('Ka-Ping Yee ', 'Yury Selivanov ') import ast import importlib.machinery import itertools import linecache import os import re import sys import tokenize import token import types import warnings import functools import builtins from operator import attrgetter from collections import namedtuple, OrderedDict # Create constants for the compiler flags in Include/code.h # We try to get them from dis to avoid duplication, but fall # back to hard-coding so the dependency is optional try: from dis import COMPILER_FLAG_NAMES as _flag_names except ImportError: CO_OPTIMIZED, CO_NEWLOCALS = 0x1, 0x2 CO_VARARGS, CO_VARKEYWORDS = 0x4, 0x8 CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40 else: mod_dict = globals() for k, v in _flag_names.items(): mod_dict["CO_" + v] = k # See Include/object.h TPFLAGS_IS_ABSTRACT = 1 << 20 # ----------------------------------------------------------- type-checking def ismodule(object): """Return true if the object is a module. Module objects provide these attributes: __cached__ pathname to byte compiled file __doc__ documentation string __file__ filename (missing for built-in modules)""" return isinstance(object, types.ModuleType) def isclass(object): """Return true if the object is a class. Class objects provide these attributes: __doc__ documentation string __module__ name of module in which this class was defined""" return isinstance(object, type) def ismethod(object): """Return true if the object is an instance method. Instance method objects provide these attributes: __doc__ documentation string __name__ name with which this method was defined __func__ function object containing implementation of method __self__ instance to which this method is bound""" return isinstance(object, types.MethodType) def ismethoddescriptor(object): """Return true if the object is a method descriptor. But not if ismethod() or isclass() or isfunction() are true. This is new in Python 2.2, and, for example, is true of int.__add__. An object passing this test has a __get__ attribute but not a __set__ attribute, but beyond that the set of attributes varies. __name__ is usually sensible, and __doc__ often is. Methods implemented via descriptors that also pass one of the other tests return false from the ismethoddescriptor() test, simply because the other tests promise more -- you can, e.g., count on having the __func__ attribute (etc) when an object passes ismethod().""" if isclass(object) or ismethod(object) or isfunction(object): # mutual exclusion return False tp = type(object) return hasattr(tp, "__get__") and not hasattr(tp, "__set__") def isdatadescriptor(object): """Return true if the object is a data descriptor. Data descriptors have both a __get__ and a __set__ attribute. Examples are properties (defined in Python) and getsets and members (defined in C). Typically, data descriptors will also have __name__ and __doc__ attributes (properties, getsets, and members have both of these attributes), but this is not guaranteed.""" if isclass(object) or ismethod(object) or isfunction(object): # mutual exclusion return False tp = type(object) return hasattr(tp, "__set__") and hasattr(tp, "__get__") if hasattr(types, 'MemberDescriptorType'): # CPython and equivalent def ismemberdescriptor(object): """Return true if the object is a member descriptor. Member descriptors are specialized descriptors defined in extension modules.""" return isinstance(object, types.MemberDescriptorType) else: # Other implementations def ismemberdescriptor(object): """Return true if the object is a member descriptor. Member descriptors are specialized descriptors defined in extension modules.""" return False if hasattr(types, 'GetSetDescriptorType'): # CPython and equivalent def isgetsetdescriptor(object): """Return true if the object is a getset descriptor. getset descriptors are specialized descriptors defined in extension modules.""" return isinstance(object, types.GetSetDescriptorType) else: # Other implementations def isgetsetdescriptor(object): """Return true if the object is a getset descriptor. getset descriptors are specialized descriptors defined in extension modules.""" return False def isfunction(object): """Return true if the object is a user-defined function. Function objects provide these attributes: __doc__ documentation string __name__ name with which this function was defined __code__ code object containing compiled function bytecode __defaults__ tuple of any default values for arguments __globals__ global namespace in which this function was defined __annotations__ dict of parameter annotations __kwdefaults__ dict of keyword only parameters with defaults""" return isinstance(object, types.FunctionType) def isgeneratorfunction(object): """Return true if the object is a user-defined generator function. Generator function objects provides same attributes as functions. See help(isfunction) for attributes listing.""" return bool((isfunction(object) or ismethod(object)) and object.__code__.co_flags & CO_GENERATOR) def isgenerator(object): """Return true if the object is a generator. Generator objects provide these attributes: __iter__ defined to support iteration over container close raises a new GeneratorExit exception inside the generator to terminate the iteration gi_code code object gi_frame frame object or possibly None once the generator has been exhausted gi_running set to 1 when generator is executing, 0 otherwise next return the next item from the container send resumes the generator and "sends" a value that becomes the result of the current yield-expression throw used to raise an exception inside the generator""" return isinstance(object, types.GeneratorType) def istraceback(object): """Return true if the object is a traceback. Traceback objects provide these attributes: tb_frame frame object at this level tb_lasti index of last attempted instruction in bytecode tb_lineno current line number in Python source code tb_next next inner traceback object (called by this level)""" return isinstance(object, types.TracebackType) def isframe(object): """Return true if the object is a frame object. Frame objects provide these attributes: f_back next outer frame object (this frame's caller) f_builtins built-in namespace seen by this frame f_code code object being executed in this frame f_globals global namespace seen by this frame f_lasti index of last attempted instruction in bytecode f_lineno current line number in Python source code f_locals local namespace seen by this frame f_trace tracing function for this frame, or None""" return isinstance(object, types.FrameType) def iscode(object): """Return true if the object is a code object. Code objects provide these attributes: co_argcount number of arguments (not including * or ** args) co_code string of raw compiled bytecode co_consts tuple of constants used in the bytecode co_filename name of file in which this code object was created co_firstlineno number of first line in Python source code co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg co_lnotab encoded mapping of line numbers to bytecode indices co_name name with which this code object was defined co_names tuple of names of local variables co_nlocals number of local variables co_stacksize virtual machine stack space required co_varnames tuple of names of arguments and local variables""" return isinstance(object, types.CodeType) def isbuiltin(object): """Return true if the object is a built-in function or method. Built-in functions and methods provide these attributes: __doc__ documentation string __name__ original name of this function or method __self__ instance to which a method is bound, or None""" return isinstance(object, types.BuiltinFunctionType) def isroutine(object): """Return true if the object is any kind of function or method.""" return (isbuiltin(object) or isfunction(object) or ismethod(object) or ismethoddescriptor(object)) def isabstract(object): """Return true if the object is an abstract base class (ABC).""" return bool(isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT) def getmembers(object, predicate=None): """Return all members of an object as (name, value) pairs sorted by name. Optionally, only return members that satisfy a given predicate.""" if isclass(object): mro = (object,) + getmro(object) else: mro = () results = [] processed = set() names = dir(object) # :dd any DynamicClassAttributes to the list of names if object is a class; # this may result in duplicate entries if, for example, a virtual # attribute with the same name as a DynamicClassAttribute exists try: for base in object.__bases__: for k, v in base.__dict__.items(): if isinstance(v, types.DynamicClassAttribute): names.append(k) except AttributeError: pass for key in names: # First try to get the value via getattr. Some descriptors don't # like calling their __get__ (see bug #1785), so fall back to # looking in the __dict__. try: value = getattr(object, key) # handle the duplicate key if key in processed: raise AttributeError except AttributeError: for base in mro: if key in base.__dict__: value = base.__dict__[key] break else: # could be a (currently) missing slot member, or a buggy # __dir__; discard and move on continue if not predicate or predicate(value): results.append((key, value)) processed.add(key) results.sort(key=lambda pair: pair[0]) return results Attribute = namedtuple('Attribute', 'name kind defining_class object') def classify_class_attrs(cls): """Return list of attribute-descriptor tuples. For each name in dir(cls), the return list contains a 4-tuple with these elements: 0. The name (a string). 1. The kind of attribute this is, one of these strings: 'class method' created via classmethod() 'static method' created via staticmethod() 'property' created via property() 'method' any other flavor of method or descriptor 'data' not a method 2. The class which defined this attribute (a class). 3. The object as obtained by calling getattr; if this fails, or if the resulting object does not live anywhere in the class' mro (including metaclasses) then the object is looked up in the defining class's dict (found by walking the mro). If one of the items in dir(cls) is stored in the metaclass it will now be discovered and not have None be listed as the class in which it was defined. Any items whose home class cannot be discovered are skipped. """ mro = getmro(cls) metamro = getmro(type(cls)) # for attributes stored in the metaclass metamro = tuple([cls for cls in metamro if cls not in (type, object)]) class_bases = (cls,) + mro all_bases = class_bases + metamro names = dir(cls) # :dd any DynamicClassAttributes to the list of names; # this may result in duplicate entries if, for example, a virtual # attribute with the same name as a DynamicClassAttribute exists. for base in mro: for k, v in base.__dict__.items(): if isinstance(v, types.DynamicClassAttribute): names.append(k) result = [] processed = set() for name in names: # Get the object associated with the name, and where it was defined. # Normal objects will be looked up with both getattr and directly in # its class' dict (in case getattr fails [bug #1785], and also to look # for a docstring). # For DynamicClassAttributes on the second pass we only look in the # class's dict. # # Getting an obj from the __dict__ sometimes reveals more than # using getattr. Static and class methods are dramatic examples. homecls = None get_obj = None dict_obj = None if name not in processed: try: if name == '__dict__': raise Exception("__dict__ is special, don't want the proxy") get_obj = getattr(cls, name) except Exception as exc: pass else: homecls = getattr(get_obj, "__objclass__", homecls) if homecls not in class_bases: # if the resulting object does not live somewhere in the # mro, drop it and search the mro manually homecls = None last_cls = None # first look in the classes for srch_cls in class_bases: srch_obj = getattr(srch_cls, name, None) if srch_obj == get_obj: last_cls = srch_cls # then check the metaclasses for srch_cls in metamro: try: srch_obj = srch_cls.__getattr__(cls, name) except AttributeError: continue if srch_obj == get_obj: last_cls = srch_cls if last_cls is not None: homecls = last_cls for base in all_bases: if name in base.__dict__: dict_obj = base.__dict__[name] if homecls not in metamro: homecls = base break if homecls is None: # unable to locate the attribute anywhere, most likely due to # buggy custom __dir__; discard and move on continue obj = get_obj or dict_obj # Classify the object or its descriptor. if isinstance(dict_obj, staticmethod): kind = "static method" obj = dict_obj elif isinstance(dict_obj, classmethod): kind = "class method" obj = dict_obj elif isinstance(dict_obj, property): kind = "property" obj = dict_obj elif isroutine(obj): kind = "method" else: kind = "data" result.append(Attribute(name, kind, homecls, obj)) processed.add(name) return result # ----------------------------------------------------------- class helpers def getmro(cls): "Return tuple of base classes (including cls) in method resolution order." return cls.__mro__ # -------------------------------------------------------- function helpers def unwrap(func, *, stop=None): """Get the object wrapped by *func*. Follows the chain of :attr:`__wrapped__` attributes returning the last object in the chain. *stop* is an optional callback accepting an object in the wrapper chain as its sole argument that allows the unwrapping to be terminated early if the callback returns a true value. If the callback never returns a true value, the last object in the chain is returned as usual. For example, :func:`signature` uses this to stop unwrapping if any object in the chain has a ``__signature__`` attribute defined. :exc:`ValueError` is raised if a cycle is encountered. """ if stop is None: def _is_wrapper(f): return hasattr(f, '__wrapped__') else: def _is_wrapper(f): return hasattr(f, '__wrapped__') and not stop(f) f = func # remember the original func for error reporting memo = {id(f)} # Memoise by id to tolerate non-hashable objects while _is_wrapper(func): func = func.__wrapped__ id_func = id(func) if id_func in memo: raise ValueError('wrapper loop when unwrapping {!r}'.format(f)) memo.add(id_func) return func # -------------------------------------------------- source code extraction def indentsize(line): """Return the indent size, in spaces, at the start of a line of text.""" expline = line.expandtabs() return len(expline) - len(expline.lstrip()) def getdoc(object): """Get the documentation string for an object. All tabs are expanded to spaces. To clean up docstrings that are indented to line up with blocks of code, any whitespace than can be uniformly removed from the second line onwards is removed.""" try: doc = object.__doc__ except AttributeError: return None if not isinstance(doc, str): return None return cleandoc(doc) def cleandoc(doc): """Clean up indentation from docstrings. Any whitespace that can be uniformly removed from the second line onwards is removed.""" try: lines = doc.expandtabs().split('\n') except UnicodeError: return None else: # Find minimum indentation of any non-blank lines after first line. margin = sys.maxsize for line in lines[1:]: content = len(line.lstrip()) if content: indent = len(line) - content margin = min(margin, indent) # Remove indentation. if lines: lines[0] = lines[0].lstrip() if margin < sys.maxsize: for i in range(1, len(lines)): lines[i] = lines[i][margin:] # Remove any trailing or leading blank lines. while lines and not lines[-1]: lines.pop() while lines and not lines[0]: lines.pop(0) return '\n'.join(lines) def getfile(object): """Work out which source or compiled file an object was defined in.""" if ismodule(object): if hasattr(object, '__file__'): return object.__file__ raise TypeError('{!r} is a built-in module'.format(object)) if isclass(object): if hasattr(object, '__module__'): object = sys.modules.get(object.__module__) if hasattr(object, '__file__'): return object.__file__ raise TypeError('{!r} is a built-in class'.format(object)) if ismethod(object): object = object.__func__ if isfunction(object): object = object.__code__ if istraceback(object): object = object.tb_frame if isframe(object): object = object.f_code if iscode(object): return object.co_filename raise TypeError('{!r} is not a module, class, method, ' 'function, traceback, frame, or code object'.format(object)) ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type') def getmodulename(path): """Return the module name for a given file, or None.""" fname = os.path.basename(path) # Check for paths that look like an actual module file suffixes = [(-len(suffix), suffix) for suffix in importlib.machinery.all_suffixes()] suffixes.sort() # try longest suffixes first, in case they overlap for neglen, suffix in suffixes: if fname.endswith(suffix): return fname[:neglen] return None def getsourcefile(object): """Return the filename that can be used to locate an object's source. Return None if no way can be identified to get the source. """ filename = getfile(object) all_bytecode_suffixes = importlib.machinery.DEBUG_BYTECODE_SUFFIXES[:] all_bytecode_suffixes += importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES[:] if any(filename.endswith(s) for s in all_bytecode_suffixes): filename = (os.path.splitext(filename)[0] + importlib.machinery.SOURCE_SUFFIXES[0]) elif any(filename.endswith(s) for s in importlib.machinery.EXTENSION_SUFFIXES): return None if os.path.exists(filename): return filename # only return a non-existent filename if the module has a PEP 302 loader if getattr(getmodule(object, filename), '__loader__', None) is not None: return filename # or it is in the linecache if filename in linecache.cache: return filename def getabsfile(object, _filename=None): """Return an absolute path to the source or compiled file for an object. The idea is for each object to have a unique origin, so this routine normalizes the result as much as possible.""" if _filename is None: _filename = getsourcefile(object) or getfile(object) return os.path.normcase(os.path.abspath(_filename)) modulesbyfile = {} _filesbymodname = {} def getmodule(object, _filename=None): """Return the module an object was defined in, or None if not found.""" if ismodule(object): return object if hasattr(object, '__module__'): return sys.modules.get(object.__module__) # Try the filename to modulename cache if _filename is not None and _filename in modulesbyfile: return sys.modules.get(modulesbyfile[_filename]) # Try the cache again with the absolute file name try: file = getabsfile(object, _filename) except TypeError: return None if file in modulesbyfile: return sys.modules.get(modulesbyfile[file]) # Update the filename to module name cache and check yet again # Copy sys.modules in order to cope with changes while iterating for modname, module in list(sys.modules.items()): if ismodule(module) and hasattr(module, '__file__'): f = module.__file__ if f == _filesbymodname.get(modname, None): # Have already mapped this module, so skip it continue _filesbymodname[modname] = f f = getabsfile(module) # Always map to the name the module knows itself by modulesbyfile[f] = modulesbyfile[ os.path.realpath(f)] = module.__name__ if file in modulesbyfile: return sys.modules.get(modulesbyfile[file]) # Check the main module main = sys.modules['__main__'] if not hasattr(object, '__name__'): return None if hasattr(main, object.__name__): mainobject = getattr(main, object.__name__) if mainobject is object: return main # Check builtins builtin = sys.modules['builtins'] if hasattr(builtin, object.__name__): builtinobject = getattr(builtin, object.__name__) if builtinobject is object: return builtin def findsource(object): """Return the entire source file and starting line number for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a list of all the lines in the file and the line number indexes a line in that list. An OSError is raised if the source code cannot be retrieved.""" file = getsourcefile(object) if file: # Invalidate cache if needed. linecache.checkcache(file) else: file = getfile(object) # Allow filenames in form of "" to pass through. # `doctest` monkeypatches `linecache` module to enable # inspection, so let `linecache.getlines` to be called. if not (file.startswith('<') and file.endswith('>')): raise OSError('source code not available') module = getmodule(object, file) if module: lines = linecache.getlines(file, module.__dict__) else: lines = linecache.getlines(file) if not lines: raise OSError('could not get source code') if ismodule(object): return lines, 0 if isclass(object): name = object.__name__ pat = re.compile(r'^(\s*)class\s*' + name + r'\b') # make some effort to find the best matching class definition: # use the one with the least indentation, which is the one # that's most probably not inside a function definition. candidates = [] for i in range(len(lines)): match = pat.match(lines[i]) if match: # if it's at toplevel, it's already the best one if lines[i][0] == 'c': return lines, i # else add whitespace to candidate list candidates.append((match.group(1), i)) if candidates: # this will sort by whitespace, and by line number, # less whitespace first candidates.sort() return lines, candidates[0][1] else: raise OSError('could not find class definition') if ismethod(object): object = object.__func__ if isfunction(object): object = object.__code__ if istraceback(object): object = object.tb_frame if isframe(object): object = object.f_code if iscode(object): if not hasattr(object, 'co_firstlineno'): raise OSError('could not find function definition') lnum = object.co_firstlineno - 1 pat = re.compile(r'^(\s*def\s)|(.*(? 0: if pat.match(lines[lnum]): break lnum = lnum - 1 return lines, lnum raise OSError('could not find code object') def getcomments(object): """Get lines of comments immediately preceding an object's source code. Returns None when source can't be found. """ try: lines, lnum = findsource(object) except (OSError, TypeError): return None if ismodule(object): # Look for a comment block at the top of the file. start = 0 if lines and lines[0][:2] == '#!': start = 1 while start < len(lines) and lines[start].strip() in ('', '#'): start = start + 1 if start < len(lines) and lines[start][:1] == '#': comments = [] end = start while end < len(lines) and lines[end][:1] == '#': comments.append(lines[end].expandtabs()) end = end + 1 return ''.join(comments) # Look for a preceding block of comments at the same indentation. elif lnum > 0: indent = indentsize(lines[lnum]) end = lnum - 1 if end >= 0 and lines[end].lstrip()[:1] == '#' and \ indentsize(lines[end]) == indent: comments = [lines[end].expandtabs().lstrip()] if end > 0: end = end - 1 comment = lines[end].expandtabs().lstrip() while comment[:1] == '#' and indentsize(lines[end]) == indent: comments[:0] = [comment] end = end - 1 if end < 0: break comment = lines[end].expandtabs().lstrip() while comments and comments[0].strip() == '#': comments[:1] = [] while comments and comments[-1].strip() == '#': comments[-1:] = [] return ''.join(comments) class EndOfBlock(Exception): pass class BlockFinder: """Provide a tokeneater() method to detect the end of a code block.""" def __init__(self): self.indent = 0 self.islambda = False self.started = False self.passline = False self.last = 1 def tokeneater(self, type, token, srowcol, erowcol, line): if not self.started: # look for the first "def", "class" or "lambda" if token in ("def", "class", "lambda"): if token == "lambda": self.islambda = True self.started = True self.passline = True # skip to the end of the line elif type == tokenize.NEWLINE: self.passline = False # stop skipping when a NEWLINE is seen self.last = srowcol[0] if self.islambda: # lambdas always end at the first NEWLINE raise EndOfBlock elif self.passline: pass elif type == tokenize.INDENT: self.indent = self.indent + 1 self.passline = True elif type == tokenize.DEDENT: self.indent = self.indent - 1 # the end of matching indent/dedent pairs end a block # (note that this only works for "def"/"class" blocks, # not e.g. for "if: else:" or "try: finally:" blocks) if self.indent <= 0: raise EndOfBlock elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL): # any other token on the same indentation level end the previous # block as well, except the pseudo-tokens COMMENT and NL. raise EndOfBlock def getblock(lines): """Extract the block of code at the top of the given list of lines.""" blockfinder = BlockFinder() try: tokens = tokenize.generate_tokens(iter(lines).__next__) for _token in tokens: blockfinder.tokeneater(*_token) except (EndOfBlock, IndentationError): pass return lines[:blockfinder.last] def getsourcelines(object): """Return a list of source lines and starting line number for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a list of the lines corresponding to the object and the line number indicates where in the original source file the first line of code was found. An OSError is raised if the source code cannot be retrieved.""" lines, lnum = findsource(object) if ismodule(object): return lines, 0 else: return getblock(lines[lnum:]), lnum + 1 def getsource(object): """Return the text of the source code for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a single string. An OSError is raised if the source code cannot be retrieved.""" lines, lnum = getsourcelines(object) return ''.join(lines) # --------------------------------------------------- class tree extraction def walktree(classes, children, parent): """Recursive helper function for getclasstree().""" results = [] classes.sort(key=attrgetter('__module__', '__name__')) for c in classes: results.append((c, c.__bases__)) if c in children: results.append(walktree(children[c], children, c)) return results def getclasstree(classes, unique=False): """Arrange the given list of classes into a hierarchy of nested lists. Where a nested list appears, it contains classes derived from the class whose entry immediately precedes the list. Each entry is a 2-tuple containing a class and a tuple of its base classes. If the 'unique' argument is true, exactly one entry appears in the returned structure for each class in the given list. Otherwise, classes using multiple inheritance and their descendants will appear multiple times.""" children = {} roots = [] for c in classes: if c.__bases__: for parent in c.__bases__: if not parent in children: children[parent] = [] if c not in children[parent]: children[parent].append(c) if unique and parent in classes: break elif c not in roots: roots.append(c) for parent in children: if parent not in classes: roots.append(parent) return walktree(roots, children, None) # ------------------------------------------------ argument list extraction Arguments = namedtuple('Arguments', 'args, varargs, varkw') def getargs(co): """Get information about the arguments accepted by a code object. Three things are returned: (args, varargs, varkw), where 'args' is the list of argument names. Keyword-only arguments are appended. 'varargs' and 'varkw' are the names of the * and ** arguments or None.""" args, varargs, kwonlyargs, varkw = _getfullargs(co) return Arguments(args + kwonlyargs, varargs, varkw) def _getfullargs(co): """Get information about the arguments accepted by a code object. Four things are returned: (args, varargs, kwonlyargs, varkw), where 'args' and 'kwonlyargs' are lists of argument names, and 'varargs' and 'varkw' are the names of the * and ** arguments or None.""" if not iscode(co): raise TypeError('{!r} is not a code object'.format(co)) nargs = co.co_argcount names = co.co_varnames nkwargs = co.co_kwonlyargcount args = list(names[:nargs]) kwonlyargs = list(names[nargs:nargs+nkwargs]) step = 0 nargs += nkwargs varargs = None if co.co_flags & CO_VARARGS: varargs = co.co_varnames[nargs] nargs = nargs + 1 varkw = None if co.co_flags & CO_VARKEYWORDS: varkw = co.co_varnames[nargs] return args, varargs, kwonlyargs, varkw ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults') def getargspec(func): """Get the names and default values of a function's arguments. A tuple of four things is returned: (args, varargs, varkw, defaults). 'args' is a list of the argument names. 'args' will include keyword-only argument names. 'varargs' and 'varkw' are the names of the * and ** arguments or None. 'defaults' is an n-tuple of the default values of the last n arguments. Use the getfullargspec() API for Python-3000 code, as annotations and keyword arguments are supported. getargspec() will raise ValueError if the func has either annotations or keyword arguments. """ args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \ getfullargspec(func) if kwonlyargs or ann: raise ValueError("Function has keyword-only arguments or annotations" ", use getfullargspec() API which can support them") return ArgSpec(args, varargs, varkw, defaults) FullArgSpec = namedtuple('FullArgSpec', 'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations') def getfullargspec(func): """Get the names and default values of a callable object's arguments. A tuple of seven things is returned: (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults annotations). 'args' is a list of the argument names. 'varargs' and 'varkw' are the names of the * and ** arguments or None. 'defaults' is an n-tuple of the default values of the last n arguments. 'kwonlyargs' is a list of keyword-only argument names. 'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults. 'annotations' is a dictionary mapping argument names to annotations. The first four items in the tuple correspond to getargspec(). """ try: # Re: `skip_bound_arg=False` # # There is a notable difference in behaviour between getfullargspec # and Signature: the former always returns 'self' parameter for bound # methods, whereas the Signature always shows the actual calling # signature of the passed object. # # To simulate this behaviour, we "unbind" bound methods, to trick # inspect.signature to always return their first parameter ("self", # usually) # Re: `follow_wrapper_chains=False` # # getfullargspec() historically ignored __wrapped__ attributes, # so we ensure that remains the case in 3.3+ sig = _signature_internal(func, follow_wrapper_chains=False, skip_bound_arg=False) except Exception as ex: # Most of the times 'signature' will raise ValueError. # But, it can also raise AttributeError, and, maybe something # else. So to be fully backwards compatible, we catch all # possible exceptions here, and reraise a TypeError. raise TypeError('unsupported callable') from ex args = [] varargs = None varkw = None kwonlyargs = [] defaults = () annotations = {} defaults = () kwdefaults = {} if sig.return_annotation is not sig.empty: annotations['return'] = sig.return_annotation for param in sig.parameters.values(): kind = param.kind name = param.name if kind is _POSITIONAL_ONLY: args.append(name) elif kind is _POSITIONAL_OR_KEYWORD: args.append(name) if param.default is not param.empty: defaults += (param.default,) elif kind is _VAR_POSITIONAL: varargs = name elif kind is _KEYWORD_ONLY: kwonlyargs.append(name) if param.default is not param.empty: kwdefaults[name] = param.default elif kind is _VAR_KEYWORD: varkw = name if param.annotation is not param.empty: annotations[name] = param.annotation if not kwdefaults: # compatibility with 'func.__kwdefaults__' kwdefaults = None if not defaults: # compatibility with 'func.__defaults__' defaults = None return FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwdefaults, annotations) ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') def getargvalues(frame): """Get information about arguments passed into a particular frame. A tuple of four things is returned: (args, varargs, varkw, locals). 'args' is a list of the argument names. 'varargs' and 'varkw' are the names of the * and ** arguments or None. 'locals' is the locals dictionary of the given frame.""" args, varargs, varkw = getargs(frame.f_code) return ArgInfo(args, varargs, varkw, frame.f_locals) def formatannotation(annotation, base_module=None): if isinstance(annotation, type): if annotation.__module__ in ('builtins', base_module): return annotation.__name__ return annotation.__module__+'.'+annotation.__name__ return repr(annotation) def formatannotationrelativeto(object): module = getattr(object, '__module__', None) def _formatannotation(annotation): return formatannotation(annotation, module) return _formatannotation def formatargspec(args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults={}, annotations={}, formatarg=str, formatvarargs=lambda name: '*' + name, formatvarkw=lambda name: '**' + name, formatvalue=lambda value: '=' + repr(value), formatreturns=lambda text: ' -> ' + text, formatannotation=formatannotation): """Format an argument spec from the values returned by getargspec or getfullargspec. The first seven arguments are (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations). The other five arguments are the corresponding optional formatting functions that are called to turn names and values into strings. The last argument is an optional function to format the sequence of arguments.""" def formatargandannotation(arg): result = formatarg(arg) if arg in annotations: result += ': ' + formatannotation(annotations[arg]) return result specs = [] if defaults: firstdefault = len(args) - len(defaults) for i, arg in enumerate(args): spec = formatargandannotation(arg) if defaults and i >= firstdefault: spec = spec + formatvalue(defaults[i - firstdefault]) specs.append(spec) if varargs is not None: specs.append(formatvarargs(formatargandannotation(varargs))) else: if kwonlyargs: specs.append('*') if kwonlyargs: for kwonlyarg in kwonlyargs: spec = formatargandannotation(kwonlyarg) if kwonlydefaults and kwonlyarg in kwonlydefaults: spec += formatvalue(kwonlydefaults[kwonlyarg]) specs.append(spec) if varkw is not None: specs.append(formatvarkw(formatargandannotation(varkw))) result = '(' + ', '.join(specs) + ')' if 'return' in annotations: result += formatreturns(formatannotation(annotations['return'])) return result def formatargvalues(args, varargs, varkw, locals, formatarg=str, formatvarargs=lambda name: '*' + name, formatvarkw=lambda name: '**' + name, formatvalue=lambda value: '=' + repr(value)): """Format an argument spec from the 4 values returned by getargvalues. The first four arguments are (args, varargs, varkw, locals). The next four arguments are the corresponding optional formatting functions that are called to turn names and values into strings. The ninth argument is an optional function to format the sequence of arguments.""" def convert(name, locals=locals, formatarg=formatarg, formatvalue=formatvalue): return formatarg(name) + formatvalue(locals[name]) specs = [] for i in range(len(args)): specs.append(convert(args[i])) if varargs: specs.append(formatvarargs(varargs) + formatvalue(locals[varargs])) if varkw: specs.append(formatvarkw(varkw) + formatvalue(locals[varkw])) return '(' + ', '.join(specs) + ')' def _missing_arguments(f_name, argnames, pos, values): names = [repr(name) for name in argnames if name not in values] missing = len(names) if missing == 1: s = names[0] elif missing == 2: s = "{} and {}".format(*names) else: tail = ", {} and {}".format(*names[-2:]) del names[-2:] s = ", ".join(names) + tail raise TypeError("%s() missing %i required %s argument%s: %s" % (f_name, missing, "positional" if pos else "keyword-only", "" if missing == 1 else "s", s)) def _too_many(f_name, args, kwonly, varargs, defcount, given, values): atleast = len(args) - defcount kwonly_given = len([arg for arg in kwonly if arg in values]) if varargs: plural = atleast != 1 sig = "at least %d" % (atleast,) elif defcount: plural = True sig = "from %d to %d" % (atleast, len(args)) else: plural = len(args) != 1 sig = str(len(args)) kwonly_sig = "" if kwonly_given: msg = " positional argument%s (and %d keyword-only argument%s)" kwonly_sig = (msg % ("s" if given != 1 else "", kwonly_given, "s" if kwonly_given != 1 else "")) raise TypeError("%s() takes %s positional argument%s but %d%s %s given" % (f_name, sig, "s" if plural else "", given, kwonly_sig, "was" if given == 1 and not kwonly_given else "were")) def getcallargs(*func_and_positional, **named): """Get the mapping of arguments to values. A dict is returned, with keys the function argument names (including the names of the * and ** arguments, if any), and values the respective bound values from 'positional' and 'named'.""" func = func_and_positional[0] positional = func_and_positional[1:] spec = getfullargspec(func) args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec f_name = func.__name__ arg2value = {} if ismethod(func) and func.__self__ is not None: # implicit 'self' (or 'cls' for classmethods) argument positional = (func.__self__,) + positional num_pos = len(positional) num_args = len(args) num_defaults = len(defaults) if defaults else 0 n = min(num_pos, num_args) for i in range(n): arg2value[args[i]] = positional[i] if varargs: arg2value[varargs] = tuple(positional[n:]) possible_kwargs = set(args + kwonlyargs) if varkw: arg2value[varkw] = {} for kw, value in named.items(): if kw not in possible_kwargs: if not varkw: raise TypeError("%s() got an unexpected keyword argument %r" % (f_name, kw)) arg2value[varkw][kw] = value continue if kw in arg2value: raise TypeError("%s() got multiple values for argument %r" % (f_name, kw)) arg2value[kw] = value if num_pos > num_args and not varargs: _too_many(f_name, args, kwonlyargs, varargs, num_defaults, num_pos, arg2value) if num_pos < num_args: req = args[:num_args - num_defaults] for arg in req: if arg not in arg2value: _missing_arguments(f_name, req, True, arg2value) for i, arg in enumerate(args[num_args - num_defaults:]): if arg not in arg2value: arg2value[arg] = defaults[i] missing = 0 for kwarg in kwonlyargs: if kwarg not in arg2value: if kwonlydefaults and kwarg in kwonlydefaults: arg2value[kwarg] = kwonlydefaults[kwarg] else: missing += 1 if missing: _missing_arguments(f_name, kwonlyargs, False, arg2value) return arg2value ClosureVars = namedtuple('ClosureVars', 'nonlocals globals builtins unbound') def getclosurevars(func): """ Get the mapping of free variables to their current values. Returns a named tuple of dicts mapping the current nonlocal, global and builtin references as seen by the body of the function. A final set of unbound names that could not be resolved is also provided. """ if ismethod(func): func = func.__func__ if not isfunction(func): raise TypeError("'{!r}' is not a Python function".format(func)) code = func.__code__ # Nonlocal references are named in co_freevars and resolved # by looking them up in __closure__ by positional index if func.__closure__ is None: nonlocal_vars = {} else: nonlocal_vars = { var : cell.cell_contents for var, cell in zip(code.co_freevars, func.__closure__) } # Global and builtin references are named in co_names and resolved # by looking them up in __globals__ or __builtins__ global_ns = func.__globals__ builtin_ns = global_ns.get("__builtins__", builtins.__dict__) if ismodule(builtin_ns): builtin_ns = builtin_ns.__dict__ global_vars = {} builtin_vars = {} unbound_names = set() for name in code.co_names: if name in ("None", "True", "False"): # Because these used to be builtins instead of keywords, they # may still show up as name references. We ignore them. continue try: global_vars[name] = global_ns[name] except KeyError: try: builtin_vars[name] = builtin_ns[name] except KeyError: unbound_names.add(name) return ClosureVars(nonlocal_vars, global_vars, builtin_vars, unbound_names) # -------------------------------------------------- stack frame extraction Traceback = namedtuple('Traceback', 'filename lineno function code_context index') def getframeinfo(frame, context=1): """Get information about a frame or traceback object. A tuple of five things is returned: the filename, the line number of the current line, the function name, a list of lines of context from the source code, and the index of the current line within that list. The optional second argument specifies the number of lines of context to return, which are centered around the current line.""" if istraceback(frame): lineno = frame.tb_lineno frame = frame.tb_frame else: lineno = frame.f_lineno if not isframe(frame): raise TypeError('{!r} is not a frame or traceback object'.format(frame)) filename = getsourcefile(frame) or getfile(frame) if context > 0: start = lineno - 1 - context//2 try: lines, lnum = findsource(frame) except OSError: lines = index = None else: start = max(start, 1) start = max(0, min(start, len(lines) - context)) lines = lines[start:start+context] index = lineno - 1 - start else: lines = index = None return Traceback(filename, lineno, frame.f_code.co_name, lines, index) def getlineno(frame): """Get the line number from a frame object, allowing for optimization.""" # FrameType.f_lineno is now a descriptor that grovels co_lnotab return frame.f_lineno def getouterframes(frame, context=1): """Get a list of records for a frame and all higher (calling) frames. Each record contains a frame object, filename, line number, function name, a list of lines of context, and index within the context.""" framelist = [] while frame: framelist.append((frame,) + getframeinfo(frame, context)) frame = frame.f_back return framelist def getinnerframes(tb, context=1): """Get a list of records for a traceback's frame and all lower frames. Each record contains a frame object, filename, line number, function name, a list of lines of context, and index within the context.""" framelist = [] while tb: framelist.append((tb.tb_frame,) + getframeinfo(tb, context)) tb = tb.tb_next return framelist def currentframe(): """Return the frame of the caller or None if this is not possible.""" return sys._getframe(1) if hasattr(sys, "_getframe") else None def stack(context=1): """Return a list of records for the stack above the caller's frame.""" return getouterframes(sys._getframe(1), context) def trace(context=1): """Return a list of records for the stack below the current exception.""" return getinnerframes(sys.exc_info()[2], context) # ------------------------------------------------ static version of getattr _sentinel = object() def _static_getmro(klass): return type.__dict__['__mro__'].__get__(klass) def _check_instance(obj, attr): instance_dict = {} try: instance_dict = object.__getattribute__(obj, "__dict__") except AttributeError: pass return dict.get(instance_dict, attr, _sentinel) def _check_class(klass, attr): for entry in _static_getmro(klass): if _shadowed_dict(type(entry)) is _sentinel: try: return entry.__dict__[attr] except KeyError: pass return _sentinel def _is_type(obj): try: _static_getmro(obj) except TypeError: return False return True def _shadowed_dict(klass): dict_attr = type.__dict__["__dict__"] for entry in _static_getmro(klass): try: class_dict = dict_attr.__get__(entry)["__dict__"] except KeyError: pass else: if not (type(class_dict) is types.GetSetDescriptorType and class_dict.__name__ == "__dict__" and class_dict.__objclass__ is entry): return class_dict return _sentinel def getattr_static(obj, attr, default=_sentinel): """Retrieve attributes without triggering dynamic lookup via the descriptor protocol, __getattr__ or __getattribute__. Note: this function may not be able to retrieve all attributes that getattr can fetch (like dynamically created attributes) and may find attributes that getattr can't (like descriptors that raise AttributeError). It can also return descriptor objects instead of instance members in some cases. See the documentation for details. """ instance_result = _sentinel if not _is_type(obj): klass = type(obj) dict_attr = _shadowed_dict(klass) if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType): instance_result = _check_instance(obj, attr) else: klass = obj klass_result = _check_class(klass, attr) if instance_result is not _sentinel and klass_result is not _sentinel: if (_check_class(type(klass_result), '__get__') is not _sentinel and _check_class(type(klass_result), '__set__') is not _sentinel): return klass_result if instance_result is not _sentinel: return instance_result if klass_result is not _sentinel: return klass_result if obj is klass: # for types we check the metaclass too for entry in _static_getmro(type(klass)): if _shadowed_dict(type(entry)) is _sentinel: try: return entry.__dict__[attr] except KeyError: pass if default is not _sentinel: return default raise AttributeError(attr) # ------------------------------------------------ generator introspection GEN_CREATED = 'GEN_CREATED' GEN_RUNNING = 'GEN_RUNNING' GEN_SUSPENDED = 'GEN_SUSPENDED' GEN_CLOSED = 'GEN_CLOSED' def getgeneratorstate(generator): """Get current state of a generator-iterator. Possible states are: GEN_CREATED: Waiting to start execution. GEN_RUNNING: Currently being executed by the interpreter. GEN_SUSPENDED: Currently suspended at a yield expression. GEN_CLOSED: Execution has completed. """ if generator.gi_running: return GEN_RUNNING if generator.gi_frame is None: return GEN_CLOSED if generator.gi_frame.f_lasti == -1: return GEN_CREATED return GEN_SUSPENDED def getgeneratorlocals(generator): """ Get the mapping of generator local variables to their current values. A dict is returned, with the keys the local variable names and values the bound values.""" if not isgenerator(generator): raise TypeError("'{!r}' is not a Python generator".format(generator)) frame = getattr(generator, "gi_frame", None) if frame is not None: return generator.gi_frame.f_locals else: return {} ############################################################################### ### Function Signature Object (PEP 362) ############################################################################### _WrapperDescriptor = type(type.__call__) _MethodWrapper = type(all.__call__) _ClassMethodWrapper = type(int.__dict__['from_bytes']) _NonUserDefinedCallables = (_WrapperDescriptor, _MethodWrapper, _ClassMethodWrapper, types.BuiltinFunctionType) def _signature_get_user_defined_method(cls, method_name): try: meth = getattr(cls, method_name) except AttributeError: return else: if not isinstance(meth, _NonUserDefinedCallables): # Once '__signature__' will be added to 'C'-level # callables, this check won't be necessary return meth def _signature_get_partial(wrapped_sig, partial, extra_args=()): # Internal helper to calculate how 'wrapped_sig' signature will # look like after applying a 'functools.partial' object (or alike) # on it. old_params = wrapped_sig.parameters new_params = OrderedDict(old_params.items()) partial_args = partial.args or () partial_keywords = partial.keywords or {} if extra_args: partial_args = extra_args + partial_args try: ba = wrapped_sig.bind_partial(*partial_args, **partial_keywords) except TypeError as ex: msg = 'partial object {!r} has incorrect arguments'.format(partial) raise ValueError(msg) from ex transform_to_kwonly = False for param_name, param in old_params.items(): try: arg_value = ba.arguments[param_name] except KeyError: pass else: if param.kind is _POSITIONAL_ONLY: # If positional-only parameter is bound by partial, # it effectively disappears from the signature new_params.pop(param_name) continue if param.kind is _POSITIONAL_OR_KEYWORD: if param_name in partial_keywords: # This means that this parameter, and all parameters # after it should be keyword-only (and var-positional # should be removed). Here's why. Consider the following # function: # foo(a, b, *args, c): # pass # # "partial(foo, a='spam')" will have the following # signature: "(*, a='spam', b, c)". Because attempting # to call that partial with "(10, 20)" arguments will # raise a TypeError, saying that "a" argument received # multiple values. transform_to_kwonly = True # Set the new default value new_params[param_name] = param.replace(default=arg_value) else: # was passed as a positional argument new_params.pop(param.name) continue if param.kind is _KEYWORD_ONLY: # Set the new default value new_params[param_name] = param.replace(default=arg_value) if transform_to_kwonly: assert param.kind is not _POSITIONAL_ONLY if param.kind is _POSITIONAL_OR_KEYWORD: new_param = new_params[param_name].replace(kind=_KEYWORD_ONLY) new_params[param_name] = new_param new_params.move_to_end(param_name) elif param.kind in (_KEYWORD_ONLY, _VAR_KEYWORD): new_params.move_to_end(param_name) elif param.kind is _VAR_POSITIONAL: new_params.pop(param.name) return wrapped_sig.replace(parameters=new_params.values()) def _signature_bound_method(sig): # Internal helper to transform signatures for unbound # functions to bound methods params = tuple(sig.parameters.values()) if not params or params[0].kind in (_VAR_KEYWORD, _KEYWORD_ONLY): raise ValueError('invalid method signature') kind = params[0].kind if kind in (_POSITIONAL_OR_KEYWORD, _POSITIONAL_ONLY): # Drop first parameter: # '(p1, p2[, ...])' -> '(p2[, ...])' params = params[1:] else: if kind is not _VAR_POSITIONAL: # Unless we add a new parameter type we never # get here raise ValueError('invalid argument type') # It's a var-positional parameter. # Do nothing. '(*args[, ...])' -> '(*args[, ...])' return sig.replace(parameters=params) def _signature_is_builtin(obj): # Internal helper to test if `obj` is a callable that might # support Argument Clinic's __text_signature__ protocol. return (isbuiltin(obj) or ismethoddescriptor(obj) or isinstance(obj, _NonUserDefinedCallables) or # Can't test 'isinstance(type)' here, as it would # also be True for regular python classes obj in (type, object)) def _signature_is_functionlike(obj): # Internal helper to test if `obj` is a duck type of FunctionType. # A good example of such objects are functions compiled with # Cython, which have all attributes that a pure Python function # would have, but have their code statically compiled. if not callable(obj) or isclass(obj): # All function-like objects are obviously callables, # and not classes. return False name = getattr(obj, '__name__', None) code = getattr(obj, '__code__', None) defaults = getattr(obj, '__defaults__', _void) # Important to use _void ... kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here annotations = getattr(obj, '__annotations__', None) return (isinstance(code, types.CodeType) and isinstance(name, str) and (defaults is None or isinstance(defaults, tuple)) and (kwdefaults is None or isinstance(kwdefaults, dict)) and isinstance(annotations, dict)) def _signature_get_bound_param(spec): # Internal helper to get first parameter name from a # __text_signature__ of a builtin method, which should # be in the following format: '($param1, ...)'. # Assumptions are that the first argument won't have # a default value or an annotation. assert spec.startswith('($') pos = spec.find(',') if pos == -1: pos = spec.find(')') cpos = spec.find(':') assert cpos == -1 or cpos > pos cpos = spec.find('=') assert cpos == -1 or cpos > pos return spec[2:pos] def _signature_strip_non_python_syntax(signature): """ Takes a signature in Argument Clinic's extended signature format. Returns a tuple of three things: * that signature re-rendered in standard Python syntax, * the index of the "self" parameter (generally 0), or None if the function does not have a "self" parameter, and * the index of the last "positional only" parameter, or None if the signature has no positional-only parameters. """ if not signature: return signature, None, None self_parameter = None last_positional_only = None lines = [l.encode('ascii') for l in signature.split('\n')] generator = iter(lines).__next__ token_stream = tokenize.tokenize(generator) delayed_comma = False skip_next_comma = False text = [] add = text.append current_parameter = 0 OP = token.OP ERRORTOKEN = token.ERRORTOKEN # token stream always starts with ENCODING token, skip it t = next(token_stream) assert t.type == tokenize.ENCODING for t in token_stream: type, string = t.type, t.string if type == OP: if string == ',': if skip_next_comma: skip_next_comma = False else: assert not delayed_comma delayed_comma = True current_parameter += 1 continue if string == '/': assert not skip_next_comma assert last_positional_only is None skip_next_comma = True last_positional_only = current_parameter - 1 continue if (type == ERRORTOKEN) and (string == '$'): assert self_parameter is None self_parameter = current_parameter continue if delayed_comma: delayed_comma = False if not ((type == OP) and (string == ')')): add(', ') add(string) if (string == ','): add(' ') clean_signature = ''.join(text) return clean_signature, self_parameter, last_positional_only def _signature_fromstr(cls, obj, s, skip_bound_arg=True): # Internal helper to parse content of '__text_signature__' # and return a Signature based on it Parameter = cls._parameter_cls clean_signature, self_parameter, last_positional_only = \ _signature_strip_non_python_syntax(s) program = "def foo" + clean_signature + ": pass" try: module = ast.parse(program) except SyntaxError: module = None if not isinstance(module, ast.Module): raise ValueError("{!r} builtin has invalid signature".format(obj)) f = module.body[0] parameters = [] empty = Parameter.empty invalid = object() module = None module_dict = {} module_name = getattr(obj, '__module__', None) if module_name: module = sys.modules.get(module_name, None) if module: module_dict = module.__dict__ sys_module_dict = sys.modules def parse_name(node): assert isinstance(node, ast.arg) if node.annotation != None: raise ValueError("Annotations are not currently supported") return node.arg def wrap_value(s): try: value = eval(s, module_dict) except NameError: try: value = eval(s, sys_module_dict) except NameError: raise RuntimeError() if isinstance(value, str): return ast.Str(value) if isinstance(value, (int, float)): return ast.Num(value) if isinstance(value, bytes): return ast.Bytes(value) if value in (True, False, None): return ast.NameConstant(value) raise RuntimeError() class RewriteSymbolics(ast.NodeTransformer): def visit_Attribute(self, node): a = [] n = node while isinstance(n, ast.Attribute): a.append(n.attr) n = n.value if not isinstance(n, ast.Name): raise RuntimeError() a.append(n.id) value = ".".join(reversed(a)) return wrap_value(value) def visit_Name(self, node): if not isinstance(node.ctx, ast.Load): raise ValueError() return wrap_value(node.id) def p(name_node, default_node, default=empty): name = parse_name(name_node) if name is invalid: return None if default_node and default_node is not _empty: try: default_node = RewriteSymbolics().visit(default_node) o = ast.literal_eval(default_node) except ValueError: o = invalid if o is invalid: return None default = o if o is not invalid else default parameters.append(Parameter(name, kind, default=default, annotation=empty)) # non-keyword-only parameters args = reversed(f.args.args) defaults = reversed(f.args.defaults) iter = itertools.zip_longest(args, defaults, fillvalue=None) if last_positional_only is not None: kind = Parameter.POSITIONAL_ONLY else: kind = Parameter.POSITIONAL_OR_KEYWORD for i, (name, default) in enumerate(reversed(list(iter))): p(name, default) if i == last_positional_only: kind = Parameter.POSITIONAL_OR_KEYWORD # *args if f.args.vararg: kind = Parameter.VAR_POSITIONAL p(f.args.vararg, empty) # keyword-only arguments kind = Parameter.KEYWORD_ONLY for name, default in zip(f.args.kwonlyargs, f.args.kw_defaults): p(name, default) # **kwargs if f.args.kwarg: kind = Parameter.VAR_KEYWORD p(f.args.kwarg, empty) if self_parameter is not None: # Possibly strip the bound argument: # - We *always* strip first bound argument if # it is a module. # - We don't strip first bound argument if # skip_bound_arg is False. assert parameters _self = getattr(obj, '__self__', None) self_isbound = _self is not None self_ismodule = ismodule(_self) if self_isbound and (self_ismodule or skip_bound_arg): parameters.pop(0) else: # for builtins, self parameter is always positional-only! p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY) parameters[0] = p return cls(parameters, return_annotation=cls.empty) def _signature_from_builtin(cls, func, skip_bound_arg=True): # Internal helper function to get signature for # builtin callables if not _signature_is_builtin(func): raise TypeError("{!r} is not a Python builtin " "function".format(func)) s = getattr(func, "__text_signature__", None) if not s: raise ValueError("no signature found for builtin {!r}".format(func)) return _signature_fromstr(cls, func, s, skip_bound_arg) def _signature_internal(obj, follow_wrapper_chains=True, skip_bound_arg=True): if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) if isinstance(obj, types.MethodType): # In this case we skip the first parameter of the underlying # function (usually `self` or `cls`). sig = _signature_internal(obj.__func__, follow_wrapper_chains, skip_bound_arg) if skip_bound_arg: return _signature_bound_method(sig) else: return sig # Was this function wrapped by a decorator? if follow_wrapper_chains: obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__"))) try: sig = obj.__signature__ except AttributeError: pass else: if sig is not None: if not isinstance(sig, Signature): raise TypeError( 'unexpected object {!r} in __signature__ ' 'attribute'.format(sig)) return sig try: partialmethod = obj._partialmethod except AttributeError: pass else: if isinstance(partialmethod, functools.partialmethod): # Unbound partialmethod (see functools.partialmethod) # This means, that we need to calculate the signature # as if it's a regular partial object, but taking into # account that the first positional argument # (usually `self`, or `cls`) will not be passed # automatically (as for boundmethods) wrapped_sig = _signature_internal(partialmethod.func, follow_wrapper_chains, skip_bound_arg) sig = _signature_get_partial(wrapped_sig, partialmethod, (None,)) first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] new_params = (first_wrapped_param,) + tuple(sig.parameters.values()) return sig.replace(parameters=new_params) if isfunction(obj) or _signature_is_functionlike(obj): # If it's a pure Python function, or an object that is duck type # of a Python function (Cython functions, for instance), then: return Signature.from_function(obj) if _signature_is_builtin(obj): return _signature_from_builtin(Signature, obj, skip_bound_arg=skip_bound_arg) if isinstance(obj, functools.partial): wrapped_sig = _signature_internal(obj.func, follow_wrapper_chains, skip_bound_arg) return _signature_get_partial(wrapped_sig, obj) sig = None if isinstance(obj, type): # obj is a class or a metaclass # First, let's see if it has an overloaded __call__ defined # in its metaclass call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: sig = _signature_internal(call, follow_wrapper_chains, skip_bound_arg) else: # Now we check if the 'obj' class has a '__new__' method new = _signature_get_user_defined_method(obj, '__new__') if new is not None: sig = _signature_internal(new, follow_wrapper_chains, skip_bound_arg) else: # Finally, we should have at least __init__ implemented init = _signature_get_user_defined_method(obj, '__init__') if init is not None: sig = _signature_internal(init, follow_wrapper_chains, skip_bound_arg) if sig is None: # At this point we know, that `obj` is a class, with no user- # defined '__init__', '__new__', or class-level '__call__' for base in obj.__mro__[:-1]: # Since '__text_signature__' is implemented as a # descriptor that extracts text signature from the # class docstring, if 'obj' is derived from a builtin # class, its own '__text_signature__' may be 'None'. # Therefore, we go through the MRO (except the last # class in there, which is 'object') to find the first # class with non-empty text signature. try: text_sig = base.__text_signature__ except AttributeError: pass else: if text_sig: # If 'obj' class has a __text_signature__ attribute: # return a signature based on it return _signature_fromstr(Signature, obj, text_sig) # No '__text_signature__' was found for the 'obj' class. # Last option is to check if its '__init__' is # object.__init__ or type.__init__. if type not in obj.__mro__: # We have a class (not metaclass), but no user-defined # __init__ or __new__ for it if obj.__init__ is object.__init__: # Return a signature of 'object' builtin. return signature(object) elif not isinstance(obj, _NonUserDefinedCallables): # An object with __call__ # We also check that the 'obj' is not an instance of # _WrapperDescriptor or _MethodWrapper to avoid # infinite recursion (and even potential segfault) call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: try: sig = _signature_internal(call, follow_wrapper_chains, skip_bound_arg) except ValueError as ex: msg = 'no signature found for {!r}'.format(obj) raise ValueError(msg) from ex if sig is not None: # For classes and objects we skip the first parameter of their # __call__, __new__, or __init__ methods if skip_bound_arg: return _signature_bound_method(sig) else: return sig if isinstance(obj, types.BuiltinFunctionType): # Raise a nicer error message for builtins msg = 'no signature found for builtin function {!r}'.format(obj) raise ValueError(msg) raise ValueError('callable {!r} is not supported by signature'.format(obj)) def signature(obj): '''Get a signature object for the passed callable.''' return _signature_internal(obj) class _void: '''A private marker - used in Parameter & Signature''' class _empty: pass class _ParameterKind(int): def __new__(self, *args, name): obj = int.__new__(self, *args) obj._name = name return obj def __str__(self): return self._name def __repr__(self): return '<_ParameterKind: {!r}>'.format(self._name) _POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') _POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') _VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') _KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') _VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') class Parameter: '''Represents a parameter in a function signature. Has the following public attributes: * name : str The name of the parameter as a string. * default : object The default value for the parameter if specified. If the parameter has no default value, this attribute is set to `Parameter.empty`. * annotation The annotation for the parameter if specified. If the parameter has no annotation, this attribute is set to `Parameter.empty`. * kind : str Describes how argument values are bound to the parameter. Possible values: `Parameter.POSITIONAL_ONLY`, `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. ''' __slots__ = ('_name', '_kind', '_default', '_annotation') POSITIONAL_ONLY = _POSITIONAL_ONLY POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD VAR_POSITIONAL = _VAR_POSITIONAL KEYWORD_ONLY = _KEYWORD_ONLY VAR_KEYWORD = _VAR_KEYWORD empty = _empty def __init__(self, name, kind, *, default=_empty, annotation=_empty): if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): raise ValueError("invalid value for 'Parameter.kind' attribute") self._kind = kind if default is not _empty: if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): msg = '{} parameters cannot have default values'.format(kind) raise ValueError(msg) self._default = default self._annotation = annotation if name is _empty: raise ValueError('name is a required attribute for Parameter') if not isinstance(name, str): raise TypeError("name must be a str, not a {!r}".format(name)) if not name.isidentifier(): raise ValueError('{!r} is not a valid parameter name'.format(name)) self._name = name @property def name(self): return self._name @property def default(self): return self._default @property def annotation(self): return self._annotation @property def kind(self): return self._kind def replace(self, *, name=_void, kind=_void, annotation=_void, default=_void): '''Creates a customized copy of the Parameter.''' if name is _void: name = self._name if kind is _void: kind = self._kind if annotation is _void: annotation = self._annotation if default is _void: default = self._default return type(self)(name, kind, default=default, annotation=annotation) def __str__(self): kind = self.kind formatted = self._name # Add annotation and default value if self._annotation is not _empty: formatted = '{}:{}'.format(formatted, formatannotation(self._annotation)) if self._default is not _empty: formatted = '{}={}'.format(formatted, repr(self._default)) if kind == _VAR_POSITIONAL: formatted = '*' + formatted elif kind == _VAR_KEYWORD: formatted = '**' + formatted return formatted def __repr__(self): return '<{} at {:#x} {!r}>'.format(self.__class__.__name__, id(self), self.name) def __eq__(self, other): return (issubclass(other.__class__, Parameter) and self._name == other._name and self._kind == other._kind and self._default == other._default and self._annotation == other._annotation) def __ne__(self, other): return not self.__eq__(other) class BoundArguments: '''Result of `Signature.bind` call. Holds the mapping of arguments to the function's parameters. Has the following public attributes: * arguments : OrderedDict An ordered mutable mapping of parameters' names to arguments' values. Does not contain arguments' default values. * signature : Signature The Signature object that created this instance. * args : tuple Tuple of positional arguments values. * kwargs : dict Dict of keyword arguments values. ''' def __init__(self, signature, arguments): self.arguments = arguments self._signature = signature @property def signature(self): return self._signature @property def args(self): args = [] for param_name, param in self._signature.parameters.items(): if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): break try: arg = self.arguments[param_name] except KeyError: # We're done here. Other arguments # will be mapped in 'BoundArguments.kwargs' break else: if param.kind == _VAR_POSITIONAL: # *args args.extend(arg) else: # plain argument args.append(arg) return tuple(args) @property def kwargs(self): kwargs = {} kwargs_started = False for param_name, param in self._signature.parameters.items(): if not kwargs_started: if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): kwargs_started = True else: if param_name not in self.arguments: kwargs_started = True continue if not kwargs_started: continue try: arg = self.arguments[param_name] except KeyError: pass else: if param.kind == _VAR_KEYWORD: # **kwargs kwargs.update(arg) else: # plain keyword argument kwargs[param_name] = arg return kwargs def __eq__(self, other): return (issubclass(other.__class__, BoundArguments) and self.signature == other.signature and self.arguments == other.arguments) def __ne__(self, other): return not self.__eq__(other) class Signature: '''A Signature object represents the overall signature of a function. It stores a Parameter object for each parameter accepted by the function, as well as information specific to the function itself. A Signature object has the following public attributes and methods: * parameters : OrderedDict An ordered mapping of parameters' names to the corresponding Parameter objects (keyword-only arguments are in the same order as listed in `code.co_varnames`). * return_annotation : object The annotation for the return type of the function if specified. If the function has no annotation for its return type, this attribute is set to `Signature.empty`. * bind(*args, **kwargs) -> BoundArguments Creates a mapping from positional and keyword arguments to parameters. * bind_partial(*args, **kwargs) -> BoundArguments Creates a partial mapping from positional and keyword arguments to parameters (simulating 'functools.partial' behavior.) ''' __slots__ = ('_return_annotation', '_parameters') _parameter_cls = Parameter _bound_arguments_cls = BoundArguments empty = _empty def __init__(self, parameters=None, *, return_annotation=_empty, __validate_parameters__=True): '''Constructs Signature from the given list of Parameter objects and 'return_annotation'. All arguments are optional. ''' if parameters is None: params = OrderedDict() else: if __validate_parameters__: params = OrderedDict() top_kind = _POSITIONAL_ONLY kind_defaults = False for idx, param in enumerate(parameters): kind = param.kind name = param.name if kind < top_kind: msg = 'wrong parameter order: {!r} before {!r}' msg = msg.format(top_kind, kind) raise ValueError(msg) elif kind > top_kind: kind_defaults = False top_kind = kind if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD): if param.default is _empty: if kind_defaults: # No default for this parameter, but the # previous parameter of the same kind had # a default msg = 'non-default argument follows default ' \ 'argument' raise ValueError(msg) else: # There is a default for this parameter. kind_defaults = True if name in params: msg = 'duplicate parameter name: {!r}'.format(name) raise ValueError(msg) params[name] = param else: params = OrderedDict(((param.name, param) for param in parameters)) self._parameters = types.MappingProxyType(params) self._return_annotation = return_annotation @classmethod def from_function(cls, func): '''Constructs Signature for the given python function''' is_duck_function = False if not isfunction(func): if _signature_is_functionlike(func): is_duck_function = True else: # If it's not a pure Python function, and not a duck type # of pure function: raise TypeError('{!r} is not a Python function'.format(func)) Parameter = cls._parameter_cls # Parameter information. func_code = func.__code__ pos_count = func_code.co_argcount arg_names = func_code.co_varnames positional = tuple(arg_names[:pos_count]) keyword_only_count = func_code.co_kwonlyargcount keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] annotations = func.__annotations__ defaults = func.__defaults__ kwdefaults = func.__kwdefaults__ if defaults: pos_default_count = len(defaults) else: pos_default_count = 0 parameters = [] # Non-keyword-only parameters w/o defaults. non_default_count = pos_count - pos_default_count for name in positional[:non_default_count]: annotation = annotations.get(name, _empty) parameters.append(Parameter(name, annotation=annotation, kind=_POSITIONAL_OR_KEYWORD)) # ... w/ defaults. for offset, name in enumerate(positional[non_default_count:]): annotation = annotations.get(name, _empty) parameters.append(Parameter(name, annotation=annotation, kind=_POSITIONAL_OR_KEYWORD, default=defaults[offset])) # *args if func_code.co_flags & CO_VARARGS: name = arg_names[pos_count + keyword_only_count] annotation = annotations.get(name, _empty) parameters.append(Parameter(name, annotation=annotation, kind=_VAR_POSITIONAL)) # Keyword-only parameters. for name in keyword_only: default = _empty if kwdefaults is not None: default = kwdefaults.get(name, _empty) annotation = annotations.get(name, _empty) parameters.append(Parameter(name, annotation=annotation, kind=_KEYWORD_ONLY, default=default)) # **kwargs if func_code.co_flags & CO_VARKEYWORDS: index = pos_count + keyword_only_count if func_code.co_flags & CO_VARARGS: index += 1 name = arg_names[index] annotation = annotations.get(name, _empty) parameters.append(Parameter(name, annotation=annotation, kind=_VAR_KEYWORD)) # Is 'func' is a pure Python function - don't validate the # parameters list (for correct order and defaults), it should be OK. return cls(parameters, return_annotation=annotations.get('return', _empty), __validate_parameters__=is_duck_function) @classmethod def from_builtin(cls, func): return _signature_from_builtin(cls, func) @property def parameters(self): return self._parameters @property def return_annotation(self): return self._return_annotation def replace(self, *, parameters=_void, return_annotation=_void): '''Creates a customized copy of the Signature. Pass 'parameters' and/or 'return_annotation' arguments to override them in the new copy. ''' if parameters is _void: parameters = self.parameters.values() if return_annotation is _void: return_annotation = self._return_annotation return type(self)(parameters, return_annotation=return_annotation) def __eq__(self, other): if (not issubclass(type(other), Signature) or self.return_annotation != other.return_annotation or len(self.parameters) != len(other.parameters)): return False other_positions = {param: idx for idx, param in enumerate(other.parameters.keys())} for idx, (param_name, param) in enumerate(self.parameters.items()): if param.kind == _KEYWORD_ONLY: try: other_param = other.parameters[param_name] except KeyError: return False else: if param != other_param: return False else: try: other_idx = other_positions[param_name] except KeyError: return False else: if (idx != other_idx or param != other.parameters[param_name]): return False return True def __ne__(self, other): return not self.__eq__(other) def _bind(self, args, kwargs, *, partial=False): '''Private method. Don't use directly.''' arguments = OrderedDict() parameters = iter(self.parameters.values()) parameters_ex = () arg_vals = iter(args) while True: # Let's iterate through the positional arguments and corresponding # parameters try: arg_val = next(arg_vals) except StopIteration: # No more positional arguments try: param = next(parameters) except StopIteration: # No more parameters. That's it. Just need to check that # we have no `kwargs` after this while loop break else: if param.kind == _VAR_POSITIONAL: # That's OK, just empty *args. Let's start parsing # kwargs break elif param.name in kwargs: if param.kind == _POSITIONAL_ONLY: msg = '{arg!r} parameter is positional only, ' \ 'but was passed as a keyword' msg = msg.format(arg=param.name) raise TypeError(msg) from None parameters_ex = (param,) break elif (param.kind == _VAR_KEYWORD or param.default is not _empty): # That's fine too - we have a default value for this # parameter. So, lets start parsing `kwargs`, starting # with the current parameter parameters_ex = (param,) break else: # No default, not VAR_KEYWORD, not VAR_POSITIONAL, # not in `kwargs` if partial: parameters_ex = (param,) break else: msg = '{arg!r} parameter lacking default value' msg = msg.format(arg=param.name) raise TypeError(msg) from None else: # We have a positional argument to process try: param = next(parameters) except StopIteration: raise TypeError('too many positional arguments') from None else: if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): # Looks like we have no parameter for this positional # argument raise TypeError('too many positional arguments') if param.kind == _VAR_POSITIONAL: # We have an '*args'-like argument, let's fill it with # all positional arguments we have left and move on to # the next phase values = [arg_val] values.extend(arg_vals) arguments[param.name] = tuple(values) break if param.name in kwargs: raise TypeError('multiple values for argument ' '{arg!r}'.format(arg=param.name)) arguments[param.name] = arg_val # Now, we iterate through the remaining parameters to process # keyword arguments kwargs_param = None for param in itertools.chain(parameters_ex, parameters): if param.kind == _VAR_KEYWORD: # Memorize that we have a '**kwargs'-like parameter kwargs_param = param continue if param.kind == _VAR_POSITIONAL: # Named arguments don't refer to '*args'-like parameters. # We only arrive here if the positional arguments ended # before reaching the last parameter before *args. continue param_name = param.name try: arg_val = kwargs.pop(param_name) except KeyError: # We have no value for this parameter. It's fine though, # if it has a default value, or it is an '*args'-like # parameter, left alone by the processing of positional # arguments. if (not partial and param.kind != _VAR_POSITIONAL and param.default is _empty): raise TypeError('{arg!r} parameter lacking default value'. \ format(arg=param_name)) from None else: if param.kind == _POSITIONAL_ONLY: # This should never happen in case of a properly built # Signature object (but let's have this check here # to ensure correct behaviour just in case) raise TypeError('{arg!r} parameter is positional only, ' 'but was passed as a keyword'. \ format(arg=param.name)) arguments[param_name] = arg_val if kwargs: if kwargs_param is not None: # Process our '**kwargs'-like parameter arguments[kwargs_param.name] = kwargs else: raise TypeError('too many keyword arguments') return self._bound_arguments_cls(self, arguments) def bind(*args, **kwargs): '''Get a BoundArguments object, that maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. ''' return args[0]._bind(args[1:], kwargs) def bind_partial(*args, **kwargs): '''Get a BoundArguments object, that partially maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. ''' return args[0]._bind(args[1:], kwargs, partial=True) def __str__(self): result = [] render_pos_only_separator = False render_kw_only_separator = True for param in self.parameters.values(): formatted = str(param) kind = param.kind if kind == _POSITIONAL_ONLY: render_pos_only_separator = True elif render_pos_only_separator: # It's not a positional-only parameter, and the flag # is set to 'True' (there were pos-only params before.) result.append('/') render_pos_only_separator = False if kind == _VAR_POSITIONAL: # OK, we have an '*args'-like parameter, so we won't need # a '*' to separate keyword-only arguments render_kw_only_separator = False elif kind == _KEYWORD_ONLY and render_kw_only_separator: # We have a keyword-only parameter to render and we haven't # rendered an '*args'-like parameter before, so add a '*' # separator to the parameters list ("foo(arg1, *, arg2)" case) result.append('*') # This condition should be only triggered once, so # reset the flag render_kw_only_separator = False result.append(formatted) if render_pos_only_separator: # There were only positional-only parameters, hence the # flag was not reset to 'False' result.append('/') rendered = '({})'.format(', '.join(result)) if self.return_annotation is not _empty: anno = formatannotation(self.return_annotation) rendered += ' -> {}'.format(anno) return rendered def _main(): """ Logic for inspecting an object given at command line """ import argparse import importlib parser = argparse.ArgumentParser() parser.add_argument( 'object', help="The object to be analysed. " "It supports the 'module:qualname' syntax") parser.add_argument( '-d', '--details', action='store_true', help='Display info about the module rather than its source code') args = parser.parse_args() target = args.object mod_name, has_attrs, attrs = target.partition(":") try: obj = module = importlib.import_module(mod_name) except Exception as exc: msg = "Failed to import {} ({}: {})".format(mod_name, type(exc).__name__, exc) print(msg, file=sys.stderr) exit(2) if has_attrs: parts = attrs.split(".") obj = module for part in parts: obj = getattr(obj, part) if module.__name__ in sys.builtin_module_names: print("Can't get info for builtin modules.", file=sys.stderr) exit(1) if args.details: print('Target: {}'.format(target)) print('Origin: {}'.format(getsourcefile(module))) print('Cached: {}'.format(module.__cached__)) if obj is module: print('Loader: {}'.format(repr(module.__loader__))) if hasattr(module, '__path__'): print('Submodule search path: {}'.format(module.__path__)) else: try: __, lineno = findsource(obj) except Exception: pass else: print('Line: {}'.format(lineno)) print('\n') else: print(getsource(obj)) if __name__ == "__main__": _main() autopep8-2.3.2/test/iso_8859_1.py000066400000000000000000000000351474147346600163410ustar00rootroot00000000000000# -*- coding: iso-8859-1 -*- autopep8-2.3.2/test/suite/000077500000000000000000000000001474147346600154135ustar00rootroot00000000000000autopep8-2.3.2/test/suite/E10.py000066400000000000000000000011511474147346600163100ustar00rootroot00000000000000#: E101 E122 W191 W191 if True: pass change_2_log = \ """Change 2 by slamb@testclient on 2006/04/13 21:46:23 creation """ p4change = { 2: change_2_log, } class TestP4Poller(unittest.TestCase): def setUp(self): self.setUpGetProcessOutput() return self.setUpChangeSource() def tearDown(self): pass # #: E101 W191 W191 if True: foo(1, 2) #: E101 E101 W191 W191 def test_keys(self): """areas.json - All regions are accounted for.""" expected = set([ u'Norrbotten', u'V\xe4sterbotten', ]) #: E101 W191 if True: print(""" tab at start of this line """) autopep8-2.3.2/test/suite/E11.py000066400000000000000000000003141474147346600163110ustar00rootroot00000000000000#: E111 if x > 2: print x #: E111 if True: print #: E112 if False: print #: E113 print print #: E111 E113 mimetype = 'application/x-directory' # 'httpd/unix-directory' create_date = False autopep8-2.3.2/test/suite/E12.py000066400000000000000000000151561474147346600163240ustar00rootroot00000000000000#: E121 print "E121", ( "dent") #: E122 print "E122", ( "dent") #: E123 my_list = [ 1, 2, 3, 4, 5, 6, ] #: E124 print "E124", ("visual", "indent_two" ) #: E124 print "E124", ("visual", "indent_five" ) #: E124 a = (123, ) #: E129 if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col): raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) #: E126 print "E126", ( "dent") #: E126 print "E126", ( "dent") #: E127 print "E127", ("over-", "over-indent") #: E128 print "E128", ("visual", "hanging") #: E128 print "E128", ("under-", "under-indent") #: #: E126 my_list = [ 1, 2, 3, 4, 5, 6, ] #: E121 result = { 'key1': 'value', 'key2': 'value', } #: E126 E126 rv.update(dict.fromkeys(( 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 'reasonComment_de', 'reasonComment_it'), '?'), "foo") #: E126 abricot = 3 + \ 4 + \ 5 + 6 #: E131 print "hello", ( "there", # "john", "dude") #: E126 part = set_mimetype(( a.get('mime_type', 'text')), 'default') #: #: E122 if True: result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', ) #: E122 if some_very_very_very_long_variable_name or var \ or another_very_long_variable_name: raise Exception() #: E122 if some_very_very_very_long_variable_name or var[0] \ or another_very_long_variable_name: raise Exception() #: E122 if True: if some_very_very_very_long_variable_name or var \ or another_very_long_variable_name: raise Exception() #: E122 if True: if some_very_very_very_long_variable_name or var[0] \ or another_very_long_variable_name: raise Exception() #: E122 dictionary = [ "is": { "nested": yes(), }, ] #: E122 setup('', scripts=[''], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', ]) #: #: E123 W291 print "E123", ( "bad", "hanging", "close" ) # #: E123 E123 E123 result = { 'foo': [ 'bar', { 'baz': 'frop', } ] } #: E123 result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', ) #: E124 my_list = [1, 2, 3, 4, 5, 6, ] #: E124 my_list = [1, 2, 3, 4, 5, 6, ] #: E124 result = some_function_that_takes_arguments('a', 'b', 'c', 'd', 'e', 'f', ) #: E124 fooff(aaaa, cca( vvv, dadd ), fff, ) #: E124 fooff(aaaa, ccaaa( vvv, dadd ), fff, ) #: E124 d = dict('foo', help="exclude files or directories which match these " "comma separated patterns (default: %s)" % DEFAULT_EXCLUDE ) #: E124 E128 E128 if line_removed: self.event(cr, uid, name="Removing the option for contract", description="contract line has been removed", ) #: #: E125 if foo is None and bar is "frop" and \ blah == 'yeah': blah = 'yeahnah' #: E125 # Further indentation required as indentation is not distinguishable def long_function_name( var_one, var_two, var_three, var_four): print(var_one) # #: E125 def qualify_by_address( self, cr, uid, ids, context=None, params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): """ This gets called by the web server """ #: E129 if (a == 2 or b == "abc def ghi" "jkl mno"): return True #: #: E126 my_list = [ 1, 2, 3, 4, 5, 6, ] #: E126 abris = 3 + \ 4 + \ 5 + 6 #: E126 fixed = re.sub(r'\t+', ' ', target[c::-1], 1)[::-1] + \ target[c + 1:] #: E126 E126 rv.update(dict.fromkeys(( 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 'reasonComment_de', 'reasonComment_it'), '?'), "foo") #: E126 eat_a_dict_a_day({ "foo": "bar", }) #: E126 if ( x == ( 3 ) or y == 4): pass #: E126 if ( x == ( 3 ) or x == ( 3 ) or y == 4): pass #: E131 troublesome_hash = { "hash": "value", "long": "the quick brown fox jumps over the lazy dog before doing a " "somersault", } #: #: E128 # Arguments on first line forbidden when not using vertical alignment foo = long_function_name(var_one, var_two, var_three, var_four) # #: E128 print('l.%s\t%s\t%s\t%r' % (token[2][0], pos, tokenize.tok_name[token[0]], token[1])) #: E128 def qualify_by_address(self, cr, uid, ids, context=None, params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): """ This gets called by the web server """ #: #: E128 foo(1, 2, 3, 4, 5, 6) #: E128 foo(1, 2, 3, 4, 5, 6) #: E128 foo(1, 2, 3, 4, 5, 6) #: E128 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E128 E128 if line_removed: self.event(cr, uid, name="Removing the option for contract", description="contract line has been removed", ) #: E124 E127 E127 if line_removed: self.event(cr, uid, name="Removing the option for contract", description="contract line has been removed", ) #: E127 rv.update(d=('a', 'b', 'c'), e=42) # #: E127 rv.update(d=('a' + 'b', 'c'), e=42, f=42 + 42) #: E127 input1 = {'a': {'calc': 1 + 2}, 'b': 1 + 42} #: E128 rv.update(d=('a' + 'b', 'c'), e=42, f=(42 + 42)) #: E123 if True: def example_issue254(): return [node.copy( ( replacement # First, look at all the node's current children. for child in node.children # Replace them. for replacement in replace(child) ), dict(name=token.undefined) )] #: E125:2:5 E125:8:5 if (""" """): pass for foo in """ abc 123 """.strip().split(): print(foo) #: E122:6:5 E122:7:5 E122:8:1 print dedent( ''' mkdir -p ./{build}/ mv ./build/ ./{build}/%(revision)s/ '''.format( build='build', # more stuff ) ) #: E701:1:8 E122:2:1 E203:4:8 E128:5:1 if True:\ print(True) print(a , end=' ') #: autopep8-2.3.2/test/suite/E20.py000066400000000000000000000013631474147346600163160ustar00rootroot00000000000000#: E201:1:6 spam( ham[1], {eggs: 2}) #: E201:1:10 spam(ham[ 1], {eggs: 2}) #: E201:1:15 spam(ham[1], { eggs: 2}) #: Okay spam(ham[1], {eggs: 2}) #: #: E202:1:23 spam(ham[1], {eggs: 2} ) #: E202:1:22 spam(ham[1], {eggs: 2 }) #: E202:1:11 spam(ham[1 ], {eggs: 2}) #: Okay spam(ham[1], {eggs: 2}) result = func( arg1='some value', arg2='another value', ) result = func( arg1='some value', arg2='another value' ) result = [ item for item in items if item > 5 ] #: #: E203:1:10 if x == 4 : print x, y x, y = y, x #: E203:2:15 E702:2:16 if x == 4: print x, y ; x, y = y, x #: E203:3:13 if x == 4: print x, y x, y = y , x #: Okay if x == 4: print x, y x, y = y, x a[b1, :] == a[b1, ...] b = a[:, b1] #: autopep8-2.3.2/test/suite/E21.py000066400000000000000000000003421474147346600163130ustar00rootroot00000000000000#: E211 spam (1) #: E211 E211 dict ['key'] = list [index] #: E211 dict['key'] ['subkey'] = list[index] #: Okay spam(1) dict['key'] = list[index] # This is not prohibited by PEP8, but avoid it. class Foo (Bar, Baz): pass autopep8-2.3.2/test/suite/E22.py000066400000000000000000000035601474147346600163210ustar00rootroot00000000000000#: E221 a = 12 + 3 b = 4 + 5 #: E221 E221 x = 1 y = 2 long_variable = 3 #: E221 E221 x[0] = 1 x[1] = 2 long_variable = 3 #: E221 E221 x = f(x) + 1 y = long_variable + 2 z = x[0] + 3 #: E221:3:14 text = """ bar foo %s""" % rofl #: Okay x = 1 y = 2 long_variable = 3 #: #: E222 a = a + 1 b = b + 10 #: E222 E222 x = -1 y = -2 long_variable = 3 #: E222 E222 x[0] = 1 x[1] = 2 long_variable = 3 #: #: E223 foobart = 4 a = 3 # aligned with tab #: #: E224 a += 1 b += 1000 #: #: E225 submitted +=1 #: E225 submitted+= 1 #: E225 c =-1 #: E225 x = x /2 - 1 #: E225 c = alpha -4 #: E225 c = alpha- 4 #: E225 z = x **y #: E225 z = (x + 1) **y #: E225 z = (x + 1)** y #: E225 _1kB = _1MB >>10 #: E225 _1kB = _1MB>> 10 #: E225 E225 i=i+ 1 #: E225 E225 i=i +1 #: E225 E226 i=i+1 #: E225 E226 i =i+1 #: E225 E226 i= i+1 #: E225 E226 c = (a +b)*(a - b) #: E225 E226 c = (a+ b)*(a - b) #: #: E226 z = 2**30 #: E226 E226 c = (a+b) * (a-b) #: E226 norman = True+False #: E226 x = x*2 - 1 #: E226 x = x/2 - 1 #: E226 E226 hypot2 = x*x + y*y #: E226 c = (a + b)*(a - b) #: E226 def squares(n): return (i**2 for i in range(n)) #: E227 _1kB = _1MB>>10 #: E227 _1MB = _1kB<<10 #: E227 a = b|c #: E227 b = c&a #: E227 c = b^a #: E228 a = b%c #: E228 msg = fmt%(errno, errmsg) #: E228 msg = "Error %d occured"%errno #: #: Okay i = i + 1 submitted += 1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b) _1MB = 2 ** 20 foo(bar, key='word', *args, **kwargs) baz(**kwargs) negative = -1 spam(-1) -negative lambda *args, **kw: (args, kw) lambda a, b=h[:], c=0: (a, b, c) if not -5 < x < +5: print >>sys.stderr, "x is out of range." print >> sys.stdout, "x is an integer." z = 2 ** 30 x = x / 2 - 1 if alpha[:-i]: *a, b = (1, 2, 3) def squares(n): return (i ** 2 for i in range(n)) #: autopep8-2.3.2/test/suite/E23.py000066400000000000000000000002431474147346600163150ustar00rootroot00000000000000#: E231 a = (1,2) #: E231 a[b1,:] #: E231 a = [{'a':''}] #: Okay a = (4,) b = (5, ) c = {'text': text[5:]} result = { 'key1': 'value', 'key2': 'value', } autopep8-2.3.2/test/suite/E24.py000066400000000000000000000003301474147346600163130ustar00rootroot00000000000000#: E241 a = (1, 2) #: Okay b = (1, 20) #: E242 a = (1, 2) # tab before 2 #: Okay b = (1, 20) # space before 20 #: E241 E241 E241 # issue 135 more_spaces = [a, b, ef, +h, c, -d] autopep8-2.3.2/test/suite/E25.py000066400000000000000000000011741474147346600163230ustar00rootroot00000000000000#: E251 E251 def foo(bar = False): '''Test function with an error in declaration''' pass #: E251 foo(bar= True) #: E251 foo(bar =True) #: E251 E251 foo(bar = True) #: E251 y = bar(root= "sdasd") #: E251:2:29 parser.add_argument('--long-option', default= "/rather/long/filesystem/path/here/blah/blah/blah") #: E251:1:45 parser.add_argument('--long-option', default ="/rather/long/filesystem/path/here/blah/blah/blah") #: Okay foo(bar=(1 == 1)) foo(bar=(1 != 1)) foo(bar=(1 >= 1)) foo(bar=(1 <= 1)) (options, args) = parser.parse_args() d[type(None)] = _deepcopy_atomic autopep8-2.3.2/test/suite/E26.py000066400000000000000000000007321474147346600163230ustar00rootroot00000000000000#: E261 pass # an inline comment #: E262 x = x + 1 #Increment x #: E262 x = x + 1 # Increment x #: E262 x = y + 1 #: Increment x #: E265 #Block comment a = 1 #: E265 m = 42 #! This is important mx = 42 - 42 #: Okay #!/usr/bin/env python pass # an inline comment x = x + 1 # Increment x y = y + 1 #: Increment x # Block comment a = 1 # Block comment1 # Block comment2 aaa = 1 # example of docstring (not parsed) def oof(): """ #foo not parsed """ autopep8-2.3.2/test/suite/E27.py000066400000000000000000000012171474147346600163230ustar00rootroot00000000000000#: E275 from w import(e, f) #: E275 from importable.module import(e, f) #: E275 try: from importable.module import(e, f) except ImportError: pass #: Okay True and False #: E271 True and False #: E272 True and False #: E271 if 1: #: E273 True and False #: E273 E274 True and False #: E271 a and b #: E271 1 and b #: E271 a and 2 #: E271 E272 1 and b #: E271 E272 a and 2 #: E272 this and False #: E273 a and b #: E274 a and b #: E273 E274 this and False #: E275 if(foo): pass else: pass #: Okay matched = {"true": True, "false": False} #: E275:2:11 if True: assert(1) #: Okay def f(): print((yield)) x = (yield) autopep8-2.3.2/test/suite/E30.py000066400000000000000000000021461474147346600163170ustar00rootroot00000000000000#: E301:5:5 class X: def a(): pass def b(): pass #: E301:6:5 class X: def a(): pass # comment def b(): pass #: #: E302:3:1 #!python # -*- coding: utf-8 -*- def a(): pass #: E302:2:1 """Main module.""" def _main(): pass #: E302:2:1 import sys def get_sys_path(): return sys.path #: E302:4:1 def a(): pass def b(): pass #: E302:6:1 def a(): pass # comment def b(): pass #: #: E303:5:1 print print #: E303:5:1 print # comment print #: E303:5:5 E303:8:5 def a(): print # comment # another comment print #: #: E306 def test_descriptors(arg): class descriptor(object): def __init__(self, fn): self.fn = fn def __get__(self, obj, owner): if obj is not None: return self.fn(obj, obj) else: return self def method(self): return 'method' #: E304:3:1 @decorator def function(): pass #: E303:5:1 #!python """This class docstring comes on line 5. It gives error E303: too many blank lines (3) """ #: autopep8-2.3.2/test/suite/E30not.py000066400000000000000000000025771474147346600170500ustar00rootroot00000000000000#: Okay class X: pass #: Okay def foo(): pass #: Okay # -*- coding: utf-8 -*- class X: pass #: Okay # -*- coding: utf-8 -*- def foo(): pass #: Okay class X: def a(): pass # comment def b(): pass # This is a # ... multi-line comment def c(): pass # This is a # ... multi-line comment @some_decorator class Y: def a(): pass # comment def b(): pass @property def c(): pass try: from nonexistent import Bar except ImportError: class Bar(object): """This is a Bar replacement""" def with_feature(f): """Some decorator""" wrapper = f if has_this_feature(f): def wrapper(*args): call_feature(args[0]) return f(*args) return wrapper try: next except NameError: def next(iterator, default): for item in iterator: return item return default def a(): pass class Foo(): """Class Foo""" def b(): pass # comment def c(): pass # comment def d(): pass # This is a # ... multi-line comment # And this one is # ... a second paragraph # ... which spans on 3 lines # Function `e` is below # NOTE: Hey this is a testcase def e(): pass def a(): print # comment print print # Comment 1 # Comment 2 # Comment 3 def b(): pass autopep8-2.3.2/test/suite/E40.py000066400000000000000000000003061474147346600163140ustar00rootroot00000000000000#: E401 import os, sys #: Okay import os import sys from subprocess import Popen, PIPE from myclass import MyClass from foo.bar.yourclass import YourClass import myclass import foo.bar.yourclass autopep8-2.3.2/test/suite/E50.py000066400000000000000000000044671474147346600163310ustar00rootroot00000000000000#: E501 a = '12345678901234567890123456789012345678901234567890123456789012345678901234567890' #: E502 a = ('123456789012345678901234567890123456789012345678901234567890123456789' \ '01234567890') #: E502 a = ('AAA \ BBB' \ 'CCC') #: E502 if (foo is None and bar is "e000" and \ blah == 'yeah'): blah = 'yeahnah' # #: Okay a = ('AAA' 'BBB') a = ('AAA \ BBB' 'CCC') a = 'AAA' \ 'BBB' \ 'CCC' a = ('AAA\ BBBBBBBBB\ CCCCCCCCC\ DDDDDDDDD') # #: Okay if aaa: pass elif bbb or \ ccc: pass ddd = \ ccc ('\ ' + ' \ ') (''' ''' + ' \ ') #: E501 E225 E226 very_long_identifiers=and_terrible_whitespace_habits(are_no_excuse+for_long_lines) # #: E501 '''multiline string with a long long long long long long long long long long long long long long long long line ''' #: E501 '''same thing, but this time without a terminal newline in the string long long long long long long long long long long long long long long long long line''' # # issue 224 (unavoidable long lines in docstrings) #: Okay """ I'm some great documentation. Because I'm some great documentation, I'm going to give you a reference to some valuable information about some API that I'm calling: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx """ #: E501 """ longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces""" #: Okay """ This almost_empty_line """ #: E501 """ This almost_empty_line """ #: E501 # A basic comment # with a long long long long long long long long long long long long long long long long line # #: Okay # I'm some great comment. Because I'm so great, I'm going to give you a # reference to some valuable information about some API that I'm calling: # # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx import this # longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces # #: Okay # This # almost_empty_line # #: E501 # This # almost_empty_line autopep8-2.3.2/test/suite/E70.py000066400000000000000000000003501474147346600163160ustar00rootroot00000000000000#: E701 if a: a = False #: E701 if not header or header[:6] != 'bytes=': return #: E702 a = False; b = True #: E702 print(1); bdist_egg.write_safety_flag(cmd.egg_info, safe) #: E703 print(1); #: E702 E703 del a[:]; a.append(42); #: autopep8-2.3.2/test/suite/E71.py000066400000000000000000000007061474147346600163240ustar00rootroot00000000000000#: E711 if res == None: pass #: E712 if res == True: pass #: E712 if res != False: pass # #: E713 if not X in Y: pass #: E713 if not X.B in Y: pass #: E713 if not X in Y and Z == "zero": pass #: E713 if X == "zero" or not Y in Z: pass # #: E714 if not X is Y: pass #: E714 if not X.B is Y: pass #: Okay if x not in y: pass if not (X in Y or X is Z): pass if not (X in Y): pass if x is not y: pass #: autopep8-2.3.2/test/suite/E72.py000066400000000000000000000016051474147346600163240ustar00rootroot00000000000000#: E721 if type(res) == type(42): pass #: E721 if type(res) != type(""): pass #: E721 import types if res == types.IntType: pass #: E721 import types if type(res) is not types.ListType: pass #: E721 assert type(res) == type(False) or type(res) == type(None) #: E721 assert type(res) == type([]) #: E721 assert type(res) == type(()) #: E721 assert type(res) == type((0,)) #: E721 assert type(res) == type((0)) #: E721 assert type(res) != type((1, )) #: Okay assert type(res) is type((1, )) #: Okay assert type(res) is not type((1, )) #: E211 E721 assert type(res) == type ([2, ]) #: E201 E201 E202 E721 assert type(res) == type( ( ) ) #: E201 E202 E721 assert type(res) == type( (0, ) ) #: #: Okay import types if isinstance(res, int): pass if isinstance(res, str): pass if isinstance(res, types.MethodType): pass if type(a) != type(b) or type(a) == type(ccc): pass autopep8-2.3.2/test/suite/E90.py000066400000000000000000000003471474147346600163260ustar00rootroot00000000000000#: E901 = [x #: E901 E101 W191 while True: try: pass except: print 'Whoops' #: Okay # Issue #119 # Do not crash with Python2 if the line endswith '\r\r\n' EMPTY_SET = set() SET_TYPE = type(EMPTY_SET) toto = 0 + 0 #: autopep8-2.3.2/test/suite/W19.py000066400000000000000000000051041474147346600163450ustar00rootroot00000000000000#: W191 if False: print # indented with 1 tab #: #: W191 y = x == 2 \ or x == 3 #: E101 W191 if ( x == ( 3 ) or y == 4): pass #: E101 W191 if x == 2 \ or y > 1 \ or x == 3: pass #: E101 W191 if x == 2 \ or y > 1 \ or x == 3: pass #: #: E101 W191 if (foo == bar and baz == frop): pass #: E101 W191 if ( foo == bar and baz == frop ): pass #: #: E101 E101 W191 W191 if start[1] > end_col and not ( over_indent == 4 and indent_next): return(0, "E121 continuation line over-" "indented for visual indent") #: #: E101 W191 def long_function_name( var_one, var_two, var_three, var_four): print(var_one) #: E101 W191 if ((row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col)): raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) #: E101 E101 E101 E101 W191 W191 W191 W191 W191 W191 if bar: return( start, 'E121 lines starting with a ' 'closing bracket should be indented ' "to match that of the opening " "bracket's line" ) # #: E101 W191 # you want vertical alignment, so use a parens if ((foo.bar("baz") and foo.bar("frop") )): print "yes" #: E101 W191 # also ok, but starting to look like LISP if ((foo.bar("baz") and foo.bar("frop"))): print "yes" #: E101 W191 if (a == 2 or b == "abc def ghi" "jkl mno"): return True #: E101 W191 if (a == 2 or b == """abc def ghi jkl mno"""): return True #: E101 W191 if length > options.max_line_length: return options.max_line_length, \ "E501 line too long (%d characters)" % length # #: E101 W191 W191 if os.path.exists(os.path.join(path, PEP8_BIN)): cmd = ([os.path.join(path, PEP8_BIN)] + self._pep8_options(targetfile)) #: W191 ''' multiline string with tab in it''' #: E101 W191 '''multiline string with tabs and spaces ''' #: Okay '''sometimes, you just need to go nuts in a multiline string and allow all sorts of crap like mixed tabs and spaces or trailing whitespace or long long long long long long long long long long long long long long long long long lines ''' # nopep8 #: Okay '''this one will get no warning even though the noqa comment is not immediately after the string ''' + foo # noqa # #: E101 W191 if foo is None and bar is "frop" and \ blah == 'yeah': blah = 'yeahnah' # #: W191 W191 W191 if True: foo( 1, 2) #: W191 W191 W191 W191 W191 def test_keys(self): """areas.json - All regions are accounted for.""" expected = set([ u'Norrbotten', u'V\xe4sterbotten', ]) #: W191 x = [ 'abc' ] #: autopep8-2.3.2/test/suite/W29.py000066400000000000000000000002611474147346600163450ustar00rootroot00000000000000#: Okay # 情 #: W291 print #: W293 class Foo(object): bang = 12 #: W291 '''multiline string with trailing whitespace''' #: W292 # This line doesn't have a linefeedautopep8-2.3.2/test/suite/W39.py000066400000000000000000000002201474147346600163410ustar00rootroot00000000000000#: W391 # The next line is blank #: Okay '''there is nothing wrong with a multiline string at EOF that happens to have a blank line in it ''' autopep8-2.3.2/test/suite/W60.py000066400000000000000000000001001474147346600163300ustar00rootroot00000000000000#: Okay raise type_, val, tb raise Exception, Exception("f"), t autopep8-2.3.2/test/suite/latin-1.py000066400000000000000000000002301474147346600172250ustar00rootroot00000000000000# -*- coding: latin-1 -*- # Test non-UTF8 encoding latin1 = ('' '') c = ("w") autopep8-2.3.2/test/suite/long_lines.py000066400000000000000000000004061474147346600201160ustar00rootroot00000000000000if True: if True: if True: self.__heap.sort() # pylint: builtin sort probably faster than O(n)-time heapify if True: foo = '( '+array[0] +' ' autopep8-2.3.2/test/suite/noqa.py000066400000000000000000000006301474147346600167220ustar00rootroot00000000000000#: Okay # silence E501 url = 'https://api.github.com/repos/sigmavirus24/Todo.txt-python/branches/master?client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxx&?client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # noqa # silence E128 from functools import (partial, reduce, wraps, # noqa cmp_to_key) from functools import (partial, reduce, wraps, cmp_to_key) # noqa a = 1 if a == None: # noqa pass #: autopep8-2.3.2/test/suite/out/000077500000000000000000000000001474147346600162225ustar00rootroot00000000000000autopep8-2.3.2/test/suite/out/E10.py000066400000000000000000000012111474147346600171140ustar00rootroot00000000000000#: E101 E122 W191 W191 if True: pass change_2_log = \ """Change 2 by slamb@testclient on 2006/04/13 21:46:23 creation """ p4change = { 2: change_2_log, } class TestP4Poller(unittest.TestCase): def setUp(self): self.setUpGetProcessOutput() return self.setUpChangeSource() def tearDown(self): pass # #: E101 W191 W191 if True: foo(1, 2) #: E101 E101 W191 W191 def test_keys(self): """areas.json - All regions are accounted for.""" expected = set([ u'Norrbotten', u'V\xe4sterbotten', ]) #: E101 W191 if True: print(""" tab at start of this line """) autopep8-2.3.2/test/suite/out/E11.py000066400000000000000000000003041474147346600171170ustar00rootroot00000000000000#: E111 if x > 2: print x #: E111 if True: print #: E112 if False: print #: E113 print print #: E111 E113 mimetype = 'application/x-directory' # 'httpd/unix-directory' create_date = False autopep8-2.3.2/test/suite/out/E12.py000066400000000000000000000152151474147346600171270ustar00rootroot00000000000000#: E121 print "E121", ( "dent") #: E122 print "E122", ( "dent") #: E123 my_list = [ 1, 2, 3, 4, 5, 6, ] #: E124 print "E124", ("visual", "indent_two" ) #: E124 print "E124", ("visual", "indent_five" ) #: E124 a = (123, ) #: E129 if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col): raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) #: E126 print "E126", ( "dent") #: E126 print "E126", ( "dent") #: E127 print "E127", ("over-", "over-indent") #: E128 print "E128", ("visual", "hanging") #: E128 print "E128", ("under-", "under-indent") #: #: E126 my_list = [ 1, 2, 3, 4, 5, 6, ] #: E121 result = { 'key1': 'value', 'key2': 'value', } #: E126 E126 rv.update(dict.fromkeys(( 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 'reasonComment_de', 'reasonComment_it'), '?'), "foo") #: E126 abricot = 3 + \ 4 + \ 5 + 6 #: E131 print "hello", ( "there", # "john", "dude") #: E126 part = set_mimetype(( a.get('mime_type', 'text')), 'default') #: #: E122 if True: result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', ) #: E122 if some_very_very_very_long_variable_name or var \ or another_very_long_variable_name: raise Exception() #: E122 if some_very_very_very_long_variable_name or var[0] \ or another_very_long_variable_name: raise Exception() #: E122 if True: if some_very_very_very_long_variable_name or var \ or another_very_long_variable_name: raise Exception() #: E122 if True: if some_very_very_very_long_variable_name or var[0] \ or another_very_long_variable_name: raise Exception() #: E122 dictionary = [ "is": { "nested": yes(), }, ] #: E122 setup('', scripts=[''], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', ]) #: #: E123 W291 print "E123", ( "bad", "hanging", "close" ) # #: E123 E123 E123 result = { 'foo': [ 'bar', { 'baz': 'frop', } ] } #: E123 result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', ) #: E124 my_list = [1, 2, 3, 4, 5, 6, ] #: E124 my_list = [1, 2, 3, 4, 5, 6, ] #: E124 result = some_function_that_takes_arguments('a', 'b', 'c', 'd', 'e', 'f', ) #: E124 fooff(aaaa, cca( vvv, dadd ), fff, ) #: E124 fooff(aaaa, ccaaa( vvv, dadd ), fff, ) #: E124 d = dict('foo', help="exclude files or directories which match these " "comma separated patterns (default: %s)" % DEFAULT_EXCLUDE ) #: E124 E128 E128 if line_removed: self.event(cr, uid, name="Removing the option for contract", description="contract line has been removed", ) #: #: E125 if foo is None and bar is "frop" and \ blah == 'yeah': blah = 'yeahnah' #: E125 # Further indentation required as indentation is not distinguishable def long_function_name( var_one, var_two, var_three, var_four): print(var_one) # #: E125 def qualify_by_address( self, cr, uid, ids, context=None, params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): """ This gets called by the web server """ #: E129 if (a == 2 or b == "abc def ghi" "jkl mno"): return True #: #: E126 my_list = [ 1, 2, 3, 4, 5, 6, ] #: E126 abris = 3 + \ 4 + \ 5 + 6 #: E126 fixed = re.sub(r'\t+', ' ', target[c::-1], 1)[::-1] + \ target[c + 1:] #: E126 E126 rv.update(dict.fromkeys(( 'qualif_nr', 'reasonComment_en', 'reasonComment_fr', 'reasonComment_de', 'reasonComment_it'), '?'), "foo") #: E126 eat_a_dict_a_day({ "foo": "bar", }) #: E126 if ( x == ( 3 ) or y == 4): pass #: E126 if ( x == ( 3 ) or x == ( 3 ) or y == 4): pass #: E131 troublesome_hash = { "hash": "value", "long": "the quick brown fox jumps over the lazy dog before doing a " "somersault", } #: #: E128 # Arguments on first line forbidden when not using vertical alignment foo = long_function_name(var_one, var_two, var_three, var_four) # #: E128 print('l.%s\t%s\t%s\t%r' % (token[2][0], pos, tokenize.tok_name[token[0]], token[1])) #: E128 def qualify_by_address(self, cr, uid, ids, context=None, params_to_check=frozenset(QUALIF_BY_ADDRESS_PARAM)): """ This gets called by the web server """ #: #: E128 foo(1, 2, 3, 4, 5, 6) #: E128 foo(1, 2, 3, 4, 5, 6) #: E128 foo(1, 2, 3, 4, 5, 6) #: E128 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E127 foo(1, 2, 3, 4, 5, 6) #: E128 E128 if line_removed: self.event(cr, uid, name="Removing the option for contract", description="contract line has been removed", ) #: E124 E127 E127 if line_removed: self.event(cr, uid, name="Removing the option for contract", description="contract line has been removed", ) #: E127 rv.update(d=('a', 'b', 'c'), e=42) # #: E127 rv.update(d=('a' + 'b', 'c'), e=42, f=42 + 42) #: E127 input1 = {'a': {'calc': 1 + 2}, 'b': 1 + 42} #: E128 rv.update(d=('a' + 'b', 'c'), e=42, f=(42 + 42)) #: E123 if True: def example_issue254(): return [node.copy( ( replacement # First, look at all the node's current children. for child in node.children # Replace them. for replacement in replace(child) ), dict(name=token.undefined) )] #: E125:2:5 E125:8:5 if (""" """): pass for foo in """ abc 123 """.strip().split(): print(foo) #: E122:6:5 E122:7:5 E122:8:1 print dedent( ''' mkdir -p ./{build}/ mv ./build/ ./{build}/%(revision)s/ '''.format( build='build', # more stuff ) ) #: E701:1:8 E122:2:1 E203:4:8 E128:5:1 if True: print(True) print(a, end=' ') #: autopep8-2.3.2/test/suite/out/E20.py000066400000000000000000000013551474147346600171260ustar00rootroot00000000000000#: E201:1:6 spam(ham[1], {eggs: 2}) #: E201:1:10 spam(ham[1], {eggs: 2}) #: E201:1:15 spam(ham[1], {eggs: 2}) #: Okay spam(ham[1], {eggs: 2}) #: #: E202:1:23 spam(ham[1], {eggs: 2}) #: E202:1:22 spam(ham[1], {eggs: 2}) #: E202:1:11 spam(ham[1], {eggs: 2}) #: Okay spam(ham[1], {eggs: 2}) result = func( arg1='some value', arg2='another value', ) result = func( arg1='some value', arg2='another value' ) result = [ item for item in items if item > 5 ] #: #: E203:1:10 if x == 4: print x, y x, y = y, x #: E203:2:15 E702:2:16 if x == 4: print x, y x, y = y, x #: E203:3:13 if x == 4: print x, y x, y = y, x #: Okay if x == 4: print x, y x, y = y, x a[b1, :] == a[b1, ...] b = a[:, b1] #: autopep8-2.3.2/test/suite/out/E21.py000066400000000000000000000003361474147346600171250ustar00rootroot00000000000000#: E211 spam(1) #: E211 E211 dict['key'] = list[index] #: E211 dict['key']['subkey'] = list[index] #: Okay spam(1) dict['key'] = list[index] # This is not prohibited by PEP8, but avoid it. class Foo (Bar, Baz): pass autopep8-2.3.2/test/suite/out/E22.py000066400000000000000000000035161474147346600171310ustar00rootroot00000000000000#: E221 a = 12 + 3 b = 4 + 5 #: E221 E221 x = 1 y = 2 long_variable = 3 #: E221 E221 x[0] = 1 x[1] = 2 long_variable = 3 #: E221 E221 x = f(x) + 1 y = long_variable + 2 z = x[0] + 3 #: E221:3:14 text = """ bar foo %s""" % rofl #: Okay x = 1 y = 2 long_variable = 3 #: #: E222 a = a + 1 b = b + 10 #: E222 E222 x = -1 y = -2 long_variable = 3 #: E222 E222 x[0] = 1 x[1] = 2 long_variable = 3 #: #: E223 foobart = 4 a = 3 # aligned with tab #: #: E224 a += 1 b += 1000 #: #: E225 submitted += 1 #: E225 submitted += 1 #: E225 c = -1 #: E225 x = x / 2 - 1 #: E225 c = alpha - 4 #: E225 c = alpha - 4 #: E225 z = x ** y #: E225 z = (x + 1) ** y #: E225 z = (x + 1) ** y #: E225 _1kB = _1MB >> 10 #: E225 _1kB = _1MB >> 10 #: E225 E225 i = i + 1 #: E225 E225 i = i + 1 #: E225 E226 i = i + 1 #: E225 E226 i = i + 1 #: E225 E226 i = i + 1 #: E225 E226 c = (a + b) * (a - b) #: E225 E226 c = (a + b) * (a - b) #: #: E226 z = 2**30 #: E226 E226 c = (a + b) * (a - b) #: E226 norman = True + False #: E226 x = x * 2 - 1 #: E226 x = x / 2 - 1 #: E226 E226 hypot2 = x * x + y * y #: E226 c = (a + b) * (a - b) #: E226 def squares(n): return (i**2 for i in range(n)) #: E227 _1kB = _1MB >> 10 #: E227 _1MB = _1kB << 10 #: E227 a = b | c #: E227 b = c & a #: E227 c = b ^ a #: E228 a = b % c #: E228 msg = fmt % (errno, errmsg) #: E228 msg = "Error %d occured" % errno #: #: Okay i = i + 1 submitted += 1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b) _1MB = 2 ** 20 foo(bar, key='word', *args, **kwargs) baz(**kwargs) negative = -1 spam(-1) -negative lambda *args, **kw: (args, kw) lambda a, b=h[:], c=0: (a, b, c) if not -5 < x < +5: print >>sys.stderr, "x is out of range." print >> sys.stdout, "x is an integer." z = 2 ** 30 x = x / 2 - 1 if alpha[:-i]: *a, b = (1, 2, 3) def squares(n): return (i ** 2 for i in range(n)) #: autopep8-2.3.2/test/suite/out/E23.py000066400000000000000000000002461474147346600171270ustar00rootroot00000000000000#: E231 a = (1, 2) #: E231 a[b1, :] #: E231 a = [{'a': ''}] #: Okay a = (4,) b = (5, ) c = {'text': text[5:]} result = { 'key1': 'value', 'key2': 'value', } autopep8-2.3.2/test/suite/out/E24.py000066400000000000000000000003211474147346600171220ustar00rootroot00000000000000#: E241 a = (1, 2) #: Okay b = (1, 20) #: E242 a = (1, 2) # tab before 2 #: Okay b = (1, 20) # space before 20 #: E241 E241 E241 # issue 135 more_spaces = [a, b, ef, +h, c, -d] autopep8-2.3.2/test/suite/out/E25.py000066400000000000000000000011261474147346600171270ustar00rootroot00000000000000#: E251 E251 def foo(bar=False): '''Test function with an error in declaration''' pass #: E251 foo(bar=True) #: E251 foo(bar=True) #: E251 E251 foo(bar=True) #: E251 y = bar(root="sdasd") #: E251:2:29 parser.add_argument('--long-option', default="/rather/long/filesystem/path/here/blah/blah/blah") #: E251:1:45 parser.add_argument( '--long-option', default="/rather/long/filesystem/path/here/blah/blah/blah") #: Okay foo(bar=(1 == 1)) foo(bar=(1 != 1)) foo(bar=(1 >= 1)) foo(bar=(1 <= 1)) (options, args) = parser.parse_args() d[type(None)] = _deepcopy_atomic autopep8-2.3.2/test/suite/out/E26.py000066400000000000000000000007351474147346600171350ustar00rootroot00000000000000#: E261 pass # an inline comment #: E262 x = x + 1 # Increment x #: E262 x = x + 1 # Increment x #: E262 x = y + 1 # : Increment x #: E265 # Block comment a = 1 #: E265 m = 42 #! This is important mx = 42 - 42 #: Okay #!/usr/bin/env python pass # an inline comment x = x + 1 # Increment x y = y + 1 #: Increment x # Block comment a = 1 # Block comment1 # Block comment2 aaa = 1 # example of docstring (not parsed) def oof(): """ #foo not parsed """ autopep8-2.3.2/test/suite/out/E27.py000066400000000000000000000012121474147346600171250ustar00rootroot00000000000000#: E275 from w import (e, f) #: E275 from importable.module import (e, f) #: E275 try: from importable.module import (e, f) except ImportError: pass #: Okay True and False #: E271 True and False #: E272 True and False #: E271 if 1: #: E273 True and False #: E273 E274 True and False #: E271 a and b #: E271 1 and b #: E271 a and 2 #: E271 E272 1 and b #: E271 E272 a and 2 #: E272 this and False #: E273 a and b #: E274 a and b #: E273 E274 this and False #: E275 if (foo): pass else: pass #: Okay matched = {"true": True, "false": False} #: E275:2:11 if True: assert (1) #: Okay def f(): print((yield)) x = (yield) autopep8-2.3.2/test/suite/out/E30.py000066400000000000000000000021671474147346600171310ustar00rootroot00000000000000#: E301:5:5 import sys class X: def a(): pass def b(): pass #: E301:6:5 class X: def a(): pass # comment def b(): pass #: #: E302:3:1 #!python # -*- coding: utf-8 -*- def a(): pass #: E302:2:1 """Main module.""" def _main(): pass #: E302:2:1 def get_sys_path(): return sys.path #: E302:4:1 def a(): pass def b(): pass #: E302:6:1 def a(): pass # comment def b(): pass #: #: E303:5:1 print print #: E303:5:1 print # comment print #: E303:5:5 E303:8:5 def a(): print # comment # another comment print #: #: E306 def test_descriptors(arg): class descriptor(object): def __init__(self, fn): self.fn = fn def __get__(self, obj, owner): if obj is not None: return self.fn(obj, obj) else: return self def method(self): return 'method' #: E304:3:1 @decorator def function(): pass #: E303:5:1 #!python """This class docstring comes on line 5. It gives error E303: too many blank lines (3) """ #: autopep8-2.3.2/test/suite/out/E30not.py000066400000000000000000000026061474147346600176500ustar00rootroot00000000000000#: Okay class X: pass #: Okay def foo(): pass #: Okay # -*- coding: utf-8 -*- class X: pass #: Okay # -*- coding: utf-8 -*- def foo(): pass #: Okay class X: def a(): pass # comment def b(): pass # This is a # ... multi-line comment def c(): pass # This is a # ... multi-line comment @some_decorator class Y: def a(): pass # comment def b(): pass @property def c(): pass try: from nonexistent import Bar except ImportError: class Bar(object): """This is a Bar replacement""" def with_feature(f): """Some decorator""" wrapper = f if has_this_feature(f): def wrapper(*args): call_feature(args[0]) return f(*args) return wrapper try: next except NameError: def next(iterator, default): for item in iterator: return item return default def a(): pass class Foo(): """Class Foo""" def b(): pass # comment def c(): pass # comment def d(): pass # This is a # ... multi-line comment # And this one is # ... a second paragraph # ... which spans on 3 lines # Function `e` is below # NOTE: Hey this is a testcase def e(): pass def a(): print # comment print print # Comment 1 # Comment 2 # Comment 3 def b(): pass autopep8-2.3.2/test/suite/out/E40.py000066400000000000000000000003141474147346600171220ustar00rootroot00000000000000#: E401 import os import sys #: Okay import os import sys from subprocess import Popen, PIPE from myclass import MyClass from foo.bar.yourclass import YourClass import myclass import foo.bar.yourclass autopep8-2.3.2/test/suite/out/E50.py000066400000000000000000000043651474147346600171350ustar00rootroot00000000000000#: E501 import this a = '12345678901234567890123456789012345678901234567890123456789012345678901234567890' #: E502 a = ('123456789012345678901234567890123456789012345678901234567890123456789' '01234567890') #: E502 a = ('AAA \ BBB' 'CCC') #: E502 if (foo is None and bar is "e000" and blah == 'yeah'): blah = 'yeahnah' # #: Okay a = ('AAA' 'BBB') a = ('AAA \ BBB' 'CCC') a = 'AAA' \ 'BBB' \ 'CCC' a = ('AAA\ BBBBBBBBB\ CCCCCCCCC\ DDDDDDDDD') # #: Okay if aaa: pass elif bbb or \ ccc: pass ddd = \ ccc ('\ ' + ' \ ') (''' ''' + ' \ ') #: E501 E225 E226 very_long_identifiers = and_terrible_whitespace_habits( are_no_excuse + for_long_lines) # #: E501 '''multiline string with a long long long long long long long long long long long long long long long long line ''' #: E501 '''same thing, but this time without a terminal newline in the string long long long long long long long long long long long long long long long long line''' # # issue 224 (unavoidable long lines in docstrings) #: Okay """ I'm some great documentation. Because I'm some great documentation, I'm going to give you a reference to some valuable information about some API that I'm calling: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx """ #: E501 """ longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces""" #: Okay """ This almost_empty_line """ #: E501 """ This almost_empty_line """ #: E501 # A basic comment # with a long long long long long long long long long long long long long # long long long line # #: Okay # I'm some great comment. Because I'm so great, I'm going to give you a # reference to some valuable information about some API that I'm calling: # # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx # longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces # #: Okay # This # almost_empty_line # #: E501 # This # almost_empty_line autopep8-2.3.2/test/suite/out/E70.py000066400000000000000000000003531474147346600171300ustar00rootroot00000000000000#: E701 if a: a = False #: E701 if not header or header[:6] != 'bytes=': return #: E702 a = False b = True #: E702 print(1) bdist_egg.write_safety_flag(cmd.egg_info, safe) #: E703 print(1) #: E702 E703 del a[:] a.append(42) #: autopep8-2.3.2/test/suite/out/E71.py000066400000000000000000000006651474147346600171370ustar00rootroot00000000000000#: E711 if res is None: pass #: E712 if res: pass #: E712 if res: pass # #: E713 if X not in Y: pass #: E713 if X.B not in Y: pass #: E713 if X not in Y and Z == "zero": pass #: E713 if X == "zero" or Y not in Z: pass # #: E714 if X is not Y: pass #: E714 if X.B is not Y: pass #: Okay if x not in y: pass if not (X in Y or X is Z): pass if not (X in Y): pass if x is not y: pass #: autopep8-2.3.2/test/suite/out/E72.py000066400000000000000000000016661474147346600171420ustar00rootroot00000000000000#: E721 if isinstance(res, type(42)): pass #: E721 if not isinstance(res, type("")): pass #: E721 import types if res == types.IntType: pass #: E721 import types if type(res) is not types.ListType: pass #: E721 assert isinstance(res, type(False)) or isinstance(res, type(None)) #: E721 assert isinstance(res, type([])) #: E721 assert isinstance(res, type(())) #: E721 assert isinstance(res, type((0,))) #: E721 assert isinstance(res, type((0))) #: E721 assert not isinstance(res, type((1, ))) #: Okay assert type(res) is type((1, )) #: Okay assert type(res) is not type((1, )) #: E211 E721 assert isinstance(res, type([2, ])) #: E201 E201 E202 E721 assert isinstance(res, type(())) #: E201 E202 E721 assert isinstance(res, type((0, ))) #: #: Okay if isinstance(res, int): pass if isinstance(res, str): pass if isinstance(res, types.MethodType): pass if not isinstance(a, type(b)) or isinstance(a, type(ccc)): pass autopep8-2.3.2/test/suite/out/E90.py000066400000000000000000000003461474147346600171340ustar00rootroot00000000000000#: E901 = [x #: E901 E101 W191 while True: try: pass except: print 'Whoops' #: Okay # Issue #119 # Do not crash with Python2 if the line endswith '\r\r\n' EMPTY_SET = set() SET_TYPE = type(EMPTY_SET) toto = 0 + 0 #: autopep8-2.3.2/test/suite/out/W19.py000066400000000000000000000053021474147346600171540ustar00rootroot00000000000000#: W191 if False: print # indented with 1 tab #: #: W191 y = x == 2 \ or x == 3 #: E101 W191 if ( x == ( 3 ) or y == 4): pass #: E101 W191 if x == 2 \ or y > 1 \ or x == 3: pass #: E101 W191 if x == 2 \ or y > 1 \ or x == 3: pass #: #: E101 W191 if (foo == bar and baz == frop): pass #: E101 W191 if ( foo == bar and baz == frop ): pass #: #: E101 E101 W191 W191 if start[1] > end_col and not ( over_indent == 4 and indent_next): return (0, "E121 continuation line over-" "indented for visual indent") #: #: E101 W191 def long_function_name( var_one, var_two, var_three, var_four): print(var_one) #: E101 W191 if ((row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col)): raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) #: E101 E101 E101 E101 W191 W191 W191 W191 W191 W191 if bar: return ( start, 'E121 lines starting with a ' 'closing bracket should be indented ' "to match that of the opening " "bracket's line" ) # #: E101 W191 # you want vertical alignment, so use a parens if ((foo.bar("baz") and foo.bar("frop") )): print "yes" #: E101 W191 # also ok, but starting to look like LISP if ((foo.bar("baz") and foo.bar("frop"))): print "yes" #: E101 W191 if (a == 2 or b == "abc def ghi" "jkl mno"): return True #: E101 W191 if (a == 2 or b == """abc def ghi jkl mno"""): return True #: E101 W191 if length > options.max_line_length: return options.max_line_length, \ "E501 line too long (%d characters)" % length # #: E101 W191 W191 if os.path.exists(os.path.join(path, PEP8_BIN)): cmd = ([os.path.join(path, PEP8_BIN)] + self._pep8_options(targetfile)) #: W191 ''' multiline string with tab in it''' #: E101 W191 '''multiline string with tabs and spaces ''' #: Okay '''sometimes, you just need to go nuts in a multiline string and allow all sorts of crap like mixed tabs and spaces or trailing whitespace or long long long long long long long long long long long long long long long long long lines ''' # nopep8 #: Okay '''this one will get no warning even though the noqa comment is not immediately after the string ''' + foo # noqa # #: E101 W191 if foo is None and bar is "frop" and \ blah == 'yeah': blah = 'yeahnah' # #: W191 W191 W191 if True: foo( 1, 2) #: W191 W191 W191 W191 W191 def test_keys(self): """areas.json - All regions are accounted for.""" expected = set([ u'Norrbotten', u'V\xe4sterbotten', ]) #: W191 x = [ 'abc' ] #: autopep8-2.3.2/test/suite/out/W29.py000066400000000000000000000002561474147346600171600ustar00rootroot00000000000000#: Okay # 情 #: W291 print #: W293 class Foo(object): bang = 12 #: W291 '''multiline string with trailing whitespace''' #: W292 # This line doesn't have a linefeed autopep8-2.3.2/test/suite/out/W39.py000066400000000000000000000002201474147346600171500ustar00rootroot00000000000000#: W391 # The next line is blank #: Okay '''there is nothing wrong with a multiline string at EOF that happens to have a blank line in it ''' autopep8-2.3.2/test/suite/out/W60.py000066400000000000000000000001001474147346600171370ustar00rootroot00000000000000#: Okay raise type_, val, tb raise Exception, Exception("f"), t autopep8-2.3.2/test/suite/out/latin-1.py000077700000000000000000000000001474147346600220662../latin-1.pyustar00rootroot00000000000000autopep8-2.3.2/test/suite/out/long_lines.py000066400000000000000000000004371474147346600207310ustar00rootroot00000000000000if True: if True: if True: self.__heap.sort() # pylint: builtin sort probably faster than O(n)-time heapify if True: foo = '( ' + \ array[0] + ' ' autopep8-2.3.2/test/suite/out/noqa.py000077700000000000000000000000001474147346600212502../noqa.pyustar00rootroot00000000000000autopep8-2.3.2/test/suite/out/python3.py000077700000000000000000000000001474147346600223642../python3.pyustar00rootroot00000000000000autopep8-2.3.2/test/suite/out/utf-8-bom.py000077700000000000000000000000001474147346600226102../utf-8-bom.pyustar00rootroot00000000000000autopep8-2.3.2/test/suite/out/utf-8.py000066400000000000000000000047151474147346600175460ustar00rootroot00000000000000# -*- coding: utf-8 -*- class Rectangle(Blob): def __init__(self, width, height, color='black', emphasis=None, highlight=0): if width == 0 and height == 0 and \ color == 'red' and emphasis == 'strong' or \ highlight > 100: raise ValueError("sorry, you lose") if width == 0 and height == 0 and (color == 'red' or emphasis is None): raise ValueError("I don't think so -- values are %s, %s" % (width, height)) Blob.__init__(self, width, height, color, emphasis, highlight) # Some random text with multi-byte characters (utf-8 encoded) # # Εδώ μάτσο κειμένων τη, τρόπο πιθανό διευθυντές ώρα μη. Νέων απλό παράγει ροή # κι, το επί δεδομένη καθορίζουν. Πάντως ζητήσεις περιβάλλοντος ένα με, τη # ξέχασε αρπάζεις φαινόμενο όλη. Τρέξει εσφαλμένη χρησιμοποίησέ νέα τι. Θα όρο # πετάνε φακέλους, άρα με διακοπής λαμβάνουν εφαμοργής. Λες κι μειώσει # καθυστερεί. # 79 narrow chars # 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 [79] # 78 narrow chars (Na) + 1 wide char (W) # 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情 # 3 narrow chars (Na) + 40 wide chars (W) # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 # 3 narrow chars (Na) + 76 wide chars (W) # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 # #: E501 # 80 narrow chars (Na) # 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] # #: E501 # 78 narrow chars (Na) + 2 wide char (W) # 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情情 # #: E501 # 3 narrow chars (Na) + 77 wide chars (W) # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 # autopep8-2.3.2/test/suite/python3.py000066400000000000000000000001431474147346600173670ustar00rootroot00000000000000#!/usr/bin/env python3 # Annotated function (Issue #29) def foo(x: int) -> int: return x + 1 autopep8-2.3.2/test/suite/utf-8-bom.py000066400000000000000000000001231474147346600174770ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- hello = 'こんにちわ' # EOF autopep8-2.3.2/test/suite/utf-8.py000066400000000000000000000047751474147346600167450ustar00rootroot00000000000000# -*- coding: utf-8 -*- class Rectangle(Blob): def __init__(self, width, height, color='black', emphasis=None, highlight=0): if width == 0 and height == 0 and \ color == 'red' and emphasis == 'strong' or \ highlight > 100: raise ValueError("sorry, you lose") if width == 0 and height == 0 and (color == 'red' or emphasis is None): raise ValueError("I don't think so -- values are %s, %s" % (width, height)) Blob.__init__(self, width, height, color, emphasis, highlight) # Some random text with multi-byte characters (utf-8 encoded) # # Εδώ μάτσο κειμένων τη, τρόπο πιθανό διευθυντές ώρα μη. Νέων απλό παράγει ροή # κι, το επί δεδομένη καθορίζουν. Πάντως ζητήσεις περιβάλλοντος ένα με, τη # ξέχασε αρπάζεις φαινόμενο όλη. Τρέξει εσφαλμένη χρησιμοποίησέ νέα τι. Θα όρο # πετάνε φακέλους, άρα με διακοπής λαμβάνουν εφαμοργής. Λες κι μειώσει # καθυστερεί. # 79 narrow chars # 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 [79] # 78 narrow chars (Na) + 1 wide char (W) # 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情 # 3 narrow chars (Na) + 40 wide chars (W) # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 # 3 narrow chars (Na) + 76 wide chars (W) # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 # #: E501 # 80 narrow chars (Na) # 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] # #: E501 # 78 narrow chars (Na) + 2 wide char (W) # 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情情 # #: E501 # 3 narrow chars (Na) + 77 wide chars (W) # 情 情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情情 # autopep8-2.3.2/test/test_autopep8.py000077500000000000000000007571221474147346600174610ustar00rootroot00000000000000"""Test suite for autopep8. Unit tests go in "UnitTests". System tests go in "SystemTests". """ import os import re import sys import time import contextlib import io import shutil import stat from subprocess import Popen, PIPE from tempfile import mkstemp, mkdtemp import tokenize import unittest import warnings from io import StringIO ROOT_DIR = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] sys.path.insert(0, ROOT_DIR) import autopep8 # NOQA: E402 from autopep8 import get_module_imports_on_top_of_file # NOQA: E402 FAKE_CONFIGURATION = os.path.join(ROOT_DIR, 'test', 'fake_configuration') FAKE_PYCODESTYLE_CONFIGURATION = os.path.join( ROOT_DIR, 'test', 'fake_pycodestyle_configuration' ) if 'AUTOPEP8_COVERAGE' in os.environ and int(os.environ['AUTOPEP8_COVERAGE']): AUTOPEP8_CMD_TUPLE = (sys.executable, '-Wignore::DeprecationWarning', '-m', 'coverage', 'run', '--branch', '--parallel', '--omit=*/site-packages/*', os.path.join(ROOT_DIR, 'autopep8.py'),) else: # We need to specify the executable to make sure the correct Python # interpreter gets used. AUTOPEP8_CMD_TUPLE = (sys.executable, '-Wignore::DeprecationWarning', os.path.join(ROOT_DIR, 'autopep8.py'),) # pragma: no cover class UnitTests(unittest.TestCase): def test_compile_value_error(self): source = '"\\xhh" \\' self.assertFalse(autopep8.check_syntax(source)) def test_find_newline_only_cr(self): source = ['print(1)\r', 'print(2)\r', 'print3\r'] self.assertEqual(autopep8.CR, autopep8.find_newline(source)) def test_find_newline_only_lf(self): source = ['print(1)\n', 'print(2)\n', 'print3\n'] self.assertEqual(autopep8.LF, autopep8.find_newline(source)) def test_find_newline_only_crlf(self): source = ['print(1)\r\n', 'print(2)\r\n', 'print3\r\n'] self.assertEqual(autopep8.CRLF, autopep8.find_newline(source)) def test_find_newline_cr1_and_lf2(self): source = ['print(1)\n', 'print(2)\r', 'print3\n'] self.assertEqual(autopep8.LF, autopep8.find_newline(source)) def test_find_newline_cr1_and_crlf2(self): source = ['print(1)\r\n', 'print(2)\r', 'print3\r\n'] self.assertEqual(autopep8.CRLF, autopep8.find_newline(source)) def test_find_newline_should_default_to_lf(self): self.assertEqual(autopep8.LF, autopep8.find_newline([])) self.assertEqual(autopep8.LF, autopep8.find_newline(['', ''])) def test_detect_encoding(self): self.assertEqual( 'utf-8', autopep8.detect_encoding( os.path.join(ROOT_DIR, 'test', 'test_autopep8.py'))) def test_detect_encoding_with_cookie(self): self.assertEqual( 'iso-8859-1', autopep8.detect_encoding( os.path.join(ROOT_DIR, 'test', 'iso_8859_1.py'))) def test_readlines_from_file_with_bad_encoding(self): """Bad encoding should not cause an exception.""" self.assertEqual( ['# -*- coding: zlatin-1 -*-\n'], autopep8.readlines_from_file( os.path.join(ROOT_DIR, 'test', 'bad_encoding.py'))) def test_readlines_from_file_with_bad_encoding2(self): """Bad encoding should not cause an exception.""" # This causes a warning on Python 3. with warnings.catch_warnings(record=True): self.assertTrue(autopep8.readlines_from_file( os.path.join(ROOT_DIR, 'test', 'bad_encoding2.py'))) def test_fix_whitespace(self): self.assertEqual( 'a b', autopep8.fix_whitespace('a b', offset=1, replacement=' ')) def test_fix_whitespace_with_tabs(self): self.assertEqual( 'a b', autopep8.fix_whitespace('a\t \t b', offset=1, replacement=' ')) def test_multiline_string_lines(self): self.assertEqual( {2}, autopep8.multiline_string_lines( """\ ''' ''' """)) def test_multiline_string_lines_with_many(self): self.assertEqual( {2, 7, 10, 11, 12}, autopep8.multiline_string_lines( """\ ''' ''' '''''' '''''' '''''' ''' ''' ''' ''' """)) def test_multiline_string_should_not_report_single_line(self): self.assertEqual( set(), autopep8.multiline_string_lines( """\ '''abc''' """)) def test_multiline_string_should_not_report_docstrings(self): self.assertEqual( {5}, autopep8.multiline_string_lines( """\ def foo(): '''Foo. Bar.''' hello = ''' ''' """)) def test_supported_fixes(self): self.assertIn('E121', [f[0] for f in autopep8.supported_fixes()]) def test_shorten_comment(self): self.assertEqual('# ' + '=' * 72 + '\n', autopep8.shorten_comment('# ' + '=' * 100 + '\n', max_line_length=79)) def test_shorten_comment_should_not_split_numbers(self): line = '# ' + '0' * 100 + '\n' self.assertEqual(line, autopep8.shorten_comment(line, max_line_length=79)) def test_shorten_comment_should_not_split_words(self): line = '# ' + 'a' * 100 + '\n' self.assertEqual(line, autopep8.shorten_comment(line, max_line_length=79)) def test_shorten_comment_should_not_split_urls(self): line = '# http://foo.bar/' + 'abc-' * 100 + '\n' self.assertEqual(line, autopep8.shorten_comment(line, max_line_length=79)) def test_shorten_comment_should_not_modify_special_comments(self): line = '#!/bin/blah ' + ' x' * 90 + '\n' self.assertEqual(line, autopep8.shorten_comment(line, max_line_length=79)) def test_format_block_comments(self): self.assertEqual( '# abc', fix_e265_and_e266('#abc')) self.assertEqual( '# abc', fix_e265_and_e266('####abc')) self.assertEqual( '# abc', fix_e265_and_e266('## # ##abc')) self.assertEqual( '# abc "# noqa"', fix_e265_and_e266('# abc "# noqa"')) self.assertEqual( '# *abc', fix_e265_and_e266('#*abc')) def test_format_block_comments_should_leave_outline_alone(self): line = """\ ################################################################### ## Some people like these crazy things. So leave them alone. ## ################################################################### """ self.assertEqual(line, fix_e265_and_e266(line)) line = """\ ################################################################# # Some people like these crazy things. So leave them alone. # ################################################################# """ self.assertEqual(line, fix_e265_and_e266(line)) def test_format_block_comments_with_multiple_lines(self): self.assertEqual( """\ # abc # blah blah # four space indentation ''' #do not modify strings #do not modify strings #do not modify strings #do not modify strings''' # """, fix_e265_and_e266("""\ # abc #blah blah #four space indentation ''' #do not modify strings #do not modify strings #do not modify strings #do not modify strings''' # """)) def test_format_block_comments_should_not_corrupt_special_comments(self): self.assertEqual( '#: abc', fix_e265_and_e266('#: abc')) self.assertEqual( '#!/bin/bash\n', fix_e265_and_e266('#!/bin/bash\n')) def test_format_block_comments_should_only_touch_real_comments(self): commented_out_code = '#x = 1' self.assertEqual( commented_out_code, fix_e266(commented_out_code)) def test_fix_file(self): ret = autopep8.fix_file( filename=os.path.join(ROOT_DIR, 'test', 'example.py') ) self.assertNotEqual(None, ret) if ret is not None: self.assertIn('import ', ret) def test_fix_file_with_diff(self): filename = os.path.join(ROOT_DIR, 'test', 'example.py') ret = autopep8.fix_file( filename=filename, options=autopep8.parse_args(['--diff', filename]) ) self.assertNotEqual(None, ret) if ret is not None: self.assertIn('@@', ret) def test_fix_lines(self): self.assertEqual( 'print(123)\n', autopep8.fix_lines(['print( 123 )\n'], options=autopep8.parse_args(['']))) def test_fix_code(self): self.assertEqual( 'print(123)\n', autopep8.fix_code('print( 123 )\n')) def test_fix_code_with_empty_string(self): self.assertEqual( '', autopep8.fix_code('')) def test_fix_code_with_multiple_lines(self): self.assertEqual( 'print(123)\nx = 4\n', autopep8.fix_code('print( 123 )\nx =4')) def test_fix_code_byte_string(self): """This feature is here for friendliness to Python 2.""" self.assertEqual( 'print(123)\n', autopep8.fix_code(b'print( 123 )\n')) def test_fix_code_with_options(self): self.assertEqual( 'print(123)\n', autopep8.fix_code('print( 123 )\n', options={'ignore': ['W']})) self.assertEqual( 'print( 123 )\n', autopep8.fix_code('print( 123 )\n', options={'ignore': ['E']})) def test_fix_code_with_bad_options(self): with self.assertRaises(ValueError): autopep8.fix_code('print( 123 )\n', options={'ignor': ['W']}) with self.assertRaises(ValueError): autopep8.fix_code('print( 123 )\n', options={'ignore': 'W'}) def test_normalize_line_endings(self): self.assertEqual( ['abc\n', 'def\n', '123\n', 'hello\n', 'world\n'], autopep8.normalize_line_endings( ['abc\n', 'def\n', '123\n', 'hello\r\n', 'world\r'], '\n')) def test_normalize_line_endings_with_crlf(self): self.assertEqual( ['abc\r\n', 'def\r\n', '123\r\n', 'hello\r\n', 'world\r\n'], autopep8.normalize_line_endings( ['abc\n', 'def\r\n', '123\r\n', 'hello\r\n', 'world\r'], '\r\n')) def test_normalize_multiline(self): self.assertEqual('def foo(): pass', autopep8.normalize_multiline('def foo():')) self.assertEqual('def _(): return 1', autopep8.normalize_multiline('return 1')) self.assertEqual('@decorator\ndef _(): pass', autopep8.normalize_multiline('@decorator\n')) self.assertEqual('class A: pass', autopep8.normalize_multiline('class A:')) def test_code_match(self): self.assertTrue(autopep8.code_match('E2', select=['E2', 'E3'], ignore=[])) self.assertTrue(autopep8.code_match('E26', select=['E2', 'E3'], ignore=[])) self.assertFalse(autopep8.code_match('E26', select=[], ignore=['E'])) self.assertFalse(autopep8.code_match('E2', select=['E2', 'E3'], ignore=['E2'])) self.assertFalse(autopep8.code_match('E26', select=['W'], ignore=[''])) self.assertFalse(autopep8.code_match('E26', select=['W'], ignore=['E1'])) def test_split_at_offsets(self): self.assertEqual([''], autopep8.split_at_offsets('', [0])) self.assertEqual(['1234'], autopep8.split_at_offsets('1234', [0])) self.assertEqual(['1', '234'], autopep8.split_at_offsets('1234', [1])) self.assertEqual(['12', '34'], autopep8.split_at_offsets('1234', [2])) self.assertEqual(['12', '3', '4'], autopep8.split_at_offsets('1234', [2, 3])) def test_split_at_offsets_with_out_of_order(self): self.assertEqual(['12', '3', '4'], autopep8.split_at_offsets('1234', [3, 2])) def test_is_python_file(self): self.assertTrue(autopep8.is_python_file( os.path.join(ROOT_DIR, 'autopep8.py'))) with temporary_file_context('#!/usr/bin/env python') as filename: self.assertTrue(autopep8.is_python_file(filename)) with temporary_file_context('#!/usr/bin/python') as filename: self.assertTrue(autopep8.is_python_file(filename)) with temporary_file_context('#!/usr/bin/python3') as filename: self.assertTrue(autopep8.is_python_file(filename)) with temporary_file_context('#!/usr/bin/pythonic') as filename: self.assertFalse(autopep8.is_python_file(filename)) with temporary_file_context('###!/usr/bin/python') as filename: self.assertFalse(autopep8.is_python_file(filename)) self.assertFalse(autopep8.is_python_file(os.devnull)) self.assertFalse(autopep8.is_python_file('/bin/bash')) def test_match_file(self): with temporary_file_context('', suffix='.py', prefix='.') as filename: self.assertFalse(autopep8.match_file(filename, exclude=[]), msg=filename) self.assertFalse(autopep8.match_file(os.devnull, exclude=[])) with temporary_file_context('', suffix='.py', prefix='') as filename: self.assertTrue(autopep8.match_file(filename, exclude=[]), msg=filename) def test_match_file_with_dummy_file(self): filename = "notexists.dummyfile.dummy" self.assertEqual(autopep8.match_file(filename, exclude=[]), False) def test_find_files(self): temp_directory = mkdtemp() try: target = os.path.join(temp_directory, 'dir') os.mkdir(target) with open(os.path.join(target, 'a.py'), 'w'): pass exclude = os.path.join(target, 'ex') os.mkdir(exclude) with open(os.path.join(exclude, 'b.py'), 'w'): pass sub = os.path.join(exclude, 'sub') os.mkdir(sub) with open(os.path.join(sub, 'c.py'), 'w'): pass # FIXME: Avoid changing directory. This may interfere with parallel # test runs. cwd = os.getcwd() os.chdir(temp_directory) try: files = list(autopep8.find_files( ['dir'], True, [os.path.join('dir', 'ex')])) finally: os.chdir(cwd) file_names = [os.path.basename(f) for f in files] self.assertIn('a.py', file_names) self.assertNotIn('b.py', file_names) self.assertNotIn('c.py', file_names) finally: shutil.rmtree(temp_directory) def test_line_shortening_rank(self): self.assertGreater( autopep8.line_shortening_rank('(1\n+1)\n', indent_word=' ', max_line_length=79), autopep8.line_shortening_rank('(1+\n1)\n', indent_word=' ', max_line_length=79)) self.assertGreaterEqual( autopep8.line_shortening_rank('(1+\n1)\n', indent_word=' ', max_line_length=79), autopep8.line_shortening_rank('(1+1)\n', indent_word=' ', max_line_length=79)) # Do not crash. autopep8.line_shortening_rank('\n', indent_word=' ', max_line_length=79) self.assertGreater( autopep8.line_shortening_rank('[foo(\nx) for x in y]\n', indent_word=' ', max_line_length=79), autopep8.line_shortening_rank('[foo(x)\nfor x in y]\n', indent_word=' ', max_line_length=79)) def test_extract_code_from_function(self): def fix_e123(): pass # pragma: no cover self.assertEqual('e123', autopep8.extract_code_from_function(fix_e123)) def foo(): pass # pragma: no cover self.assertEqual(None, autopep8.extract_code_from_function(foo)) def fix_foo(): pass # pragma: no cover self.assertEqual(None, autopep8.extract_code_from_function(fix_foo)) def e123(): pass # pragma: no cover self.assertEqual(None, autopep8.extract_code_from_function(e123)) def fix_(): pass # pragma: no cover self.assertEqual(None, autopep8.extract_code_from_function(fix_)) def test_reindenter(self): reindenter = autopep8.Reindenter('if True:\n pass\n') self.assertEqual('if True:\n pass\n', reindenter.run()) def test_reindenter_with_non_standard_indent_size(self): reindenter = autopep8.Reindenter('if True:\n pass\n') self.assertEqual('if True:\n pass\n', reindenter.run(3)) def test_reindenter_with_good_input(self): lines = 'if True:\n pass\n' reindenter = autopep8.Reindenter(lines) self.assertEqual(lines, reindenter.run()) def test_reindenter_should_leave_stray_comment_alone(self): lines = ' #\nif True:\n pass\n' reindenter = autopep8.Reindenter(lines) self.assertEqual(' #\nif True:\n pass\n', reindenter.run()) @unittest.skipIf('AUTOPEP8_COVERAGE' in os.environ, 'exists form-feed') def test_reindenter_not_affect_with_formfeed(self): lines = """print('hello') print('python') """ reindenter = autopep8.Reindenter(lines) self.assertEqual(lines, reindenter.run()) def test_fix_e225_avoid_failure(self): fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents=' 1\n') self.assertEqual( [], fix_pep8.fix_e225({'line': 1, 'column': 5})) def test_fix_e271_ignore_redundant(self): fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents='x = 1\n') self.assertEqual( [], fix_pep8.fix_e271({'line': 1, 'column': 2})) def test_fix_e401_avoid_non_import(self): fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents=' 1\n') self.assertEqual( [], fix_pep8.fix_e401({'line': 1, 'column': 5})) def test_fix_e711_avoid_failure(self): fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents='None == x\n') self.assertEqual( None, fix_pep8.fix_e711({'line': 1, 'column': 6})) self.assertEqual( [], fix_pep8.fix_e711({'line': 1, 'column': 700})) fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents='x <> None\n') self.assertEqual( [], fix_pep8.fix_e711({'line': 1, 'column': 3})) def test_fix_e712_avoid_failure(self): fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents='True == x\n') self.assertEqual( [], fix_pep8.fix_e712({'line': 1, 'column': 5})) self.assertEqual( [], fix_pep8.fix_e712({'line': 1, 'column': 700})) fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents='x != True\n') self.assertEqual( [], fix_pep8.fix_e712({'line': 1, 'column': 3})) fix_pep8 = autopep8.FixPEP8(filename='', options=autopep8.parse_args(['']), contents='x == False\n') self.assertEqual( [], fix_pep8.fix_e712({'line': 1, 'column': 3})) def test_get_diff_text(self): # We ignore the first two lines since it differs on Python 2.6. self.assertEqual( """\ -foo +bar """, '\n'.join(autopep8.get_diff_text(['foo\n'], ['bar\n'], '').split('\n')[3:])) def test_get_diff_text_without_newline(self): # We ignore the first two lines since it differs on Python 2.6. self.assertEqual( """\ -foo \\ No newline at end of file +foo """, '\n'.join(autopep8.get_diff_text(['foo'], ['foo\n'], '').split('\n')[3:])) def test_count_unbalanced_brackets(self): self.assertEqual( 0, autopep8.count_unbalanced_brackets('()')) self.assertEqual( 1, autopep8.count_unbalanced_brackets('(')) self.assertEqual( 2, autopep8.count_unbalanced_brackets('([')) self.assertEqual( 1, autopep8.count_unbalanced_brackets('[])')) self.assertEqual( 1, autopep8.count_unbalanced_brackets( "'','.join(['%s=%s' % (col, col)')")) def test_commented_out_code_lines(self): self.assertEqual( [1, 4], autopep8.commented_out_code_lines("""\ #x = 1 #Hello #Hello world. #html_use_index = True """)) def test_standard_deviation(self): self.assertAlmostEqual( 2, autopep8.standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])) self.assertAlmostEqual(0, autopep8.standard_deviation([])) self.assertAlmostEqual(0, autopep8.standard_deviation([1])) self.assertAlmostEqual(.5, autopep8.standard_deviation([1, 2])) def test_priority_key_with_non_existent_key(self): pep8_result = {'id': 'foobar'} self.assertGreater(autopep8._priority_key(pep8_result), 1) def test_decode_filename(self): self.assertEqual('foo.py', autopep8.decode_filename(b'foo.py')) def test_almost_equal(self): self.assertTrue(autopep8.code_almost_equal( """\ [1, 2, 3 4, 5] """, """\ [1, 2, 3 4, 5] """)) self.assertTrue(autopep8.code_almost_equal( """\ [1,2,3 4,5] """, """\ [1, 2, 3 4,5] """)) self.assertFalse(autopep8.code_almost_equal( """\ [1, 2, 3 4, 5] """, """\ [1, 2, 3, 4, 5] """)) def test_token_offsets(self): text = """\ 1 """ string_io = io.StringIO(text) self.assertEqual( [(tokenize.NUMBER, '1', 0, 1), (tokenize.NEWLINE, '\n', 1, 2), (tokenize.ENDMARKER, '', 2, 2)], list(autopep8.token_offsets( tokenize.generate_tokens(string_io.readline)))) def test_token_offsets_with_multiline(self): text = """\ x = ''' 1 2 ''' """ string_io = io.StringIO(text) self.assertEqual( [(tokenize.NAME, 'x', 0, 1), (tokenize.OP, '=', 2, 3), (tokenize.STRING, "'''\n1\n2\n'''", 4, 15), (tokenize.NEWLINE, '\n', 15, 16), (tokenize.ENDMARKER, '', 16, 16)], list(autopep8.token_offsets( tokenize.generate_tokens(string_io.readline)))) def test_token_offsets_with_escaped_newline(self): text = """\ True or \\ False """ string_io = io.StringIO(text) self.assertEqual( [(tokenize.NAME, 'True', 0, 4), (tokenize.NAME, 'or', 5, 7), (tokenize.NAME, 'False', 11, 16), (tokenize.NEWLINE, '\n', 16, 17), (tokenize.ENDMARKER, '', 17, 17)], list(autopep8.token_offsets( tokenize.generate_tokens(string_io.readline)))) def test_shorten_line_candidates_are_valid(self): for text in [ """\ [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, y] = [1, 2] """, """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, y = [1, 2] """, """\ lambda xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: line_shortening_rank(x, indent_word, max_line_length) """, ]: indent = autopep8._get_indentation(text) source = text[len(indent):] assert source.lstrip() == source tokens = list(autopep8.generate_tokens(source)) for candidate in autopep8.shorten_line( tokens, source, indent, indent_word=' ', max_line_length=79, aggressive=10, experimental=True, previous_line=''): self.assertEqual( re.sub(r'\s', '', text), re.sub(r'\s', '', candidate)) def test_get_fixed_long_line_empty(self): line = '' self.assertEqual(line, autopep8.get_fixed_long_line(line, line, line)) class SystemTestsE1(unittest.TestCase): def test_e101(self): line = """\ while True: if True: \t1 """ fixed = """\ while True: if True: 1 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e101_with_indent_size_1(self): line = """\ while True: if True: \t1 """ fixed = """\ while True: if True: 1 """ with autopep8_context(line, options=['--indent-size=1']) as result: self.assertEqual(fixed, result) def test_e101_with_indent_size_2(self): line = """\ while True: if True: \t1 """ fixed = """\ while True: if True: 1 """ with autopep8_context(line, options=['--indent-size=2']) as result: self.assertEqual(fixed, result) def test_e101_with_indent_size_3(self): line = """\ while True: if True: \t1 """ fixed = """\ while True: if True: 1 """ with autopep8_context(line, options=['--indent-size=3']) as result: self.assertEqual(fixed, result) def test_e101_should_not_expand_non_indentation_tabs(self): line = """\ while True: if True: \t1 == '\t' """ fixed = """\ while True: if True: 1 == '\t' """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e101_should_ignore_multiline_strings(self): line = """\ x = ''' while True: if True: \t1 ''' """ fixed = """\ x = ''' while True: if True: \t1 ''' """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e101_should_fix_docstrings(self): line = """\ class Bar(object): def foo(): ''' \tdocstring ''' """ fixed = """\ class Bar(object): def foo(): ''' docstring ''' """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e101_when_pep8_mistakes_first_tab_in_string(self): # pep8 will complain about this even if the tab indentation found # elsewhere is in a multiline string. line = """\ x = ''' \tHello. ''' if True: 123 """ fixed = """\ x = ''' \tHello. ''' if True: 123 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e101_should_ignore_multiline_strings_complex(self): line = """\ print(3 != 4, ''' while True: if True: \t1 \t''', 4 != 5) """ fixed = """\ print(3 != 4, ''' while True: if True: \t1 \t''', 4 != 5) """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e101_with_comments(self): line = """\ while True: # My inline comment # with a hanging # comment. # Hello if True: \t# My comment \t1 \t# My other comment """ fixed = """\ while True: # My inline comment # with a hanging # comment. # Hello if True: # My comment 1 # My other comment """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e101_skip_if_bad_indentation(self): line = """\ try: \t pass except: pass """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e101_skip_innocuous(self): # pep8 will complain about this even if the tab indentation found # elsewhere is in a multiline string. If we don't filter the innocuous # report properly, the below command will take a long time. p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['-vvv', '--select=E101', '--diff', '--global-config={}'.format(os.devnull), os.path.join(ROOT_DIR, 'test', 'e101_example.py')], stdout=PIPE, stderr=PIPE) output = [x.decode('utf-8') for x in p.communicate()][0] setup_cfg_file = os.path.join(ROOT_DIR, "setup.cfg") tox_ini_file = os.path.join(ROOT_DIR, "tox.ini") expected = """\ read config path: /dev/null read config path: {} read config path: {} """.format(setup_cfg_file, tox_ini_file) self.assertEqual(expected, output) def test_e111_short(self): line = 'class Dummy:\n\n def __init__(self):\n pass\n' fixed = 'class Dummy:\n\n def __init__(self):\n pass\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e111_long(self): line = 'class Dummy:\n\n def __init__(self):\n pass\n' fixed = 'class Dummy:\n\n def __init__(self):\n pass\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e111_longer(self): line = """\ while True: if True: 1 elif True: 2 """ fixed = """\ while True: if True: 1 elif True: 2 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e111_multiple_levels(self): line = """\ while True: if True: 1 # My comment print('abc') """ fixed = """\ while True: if True: 1 # My comment print('abc') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e111_with_dedent(self): line = """\ def foo(): if True: 2 1 """ fixed = """\ def foo(): if True: 2 1 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e111_with_other_errors(self): line = """\ def foo(): if True: (2 , 1) 1 if True: print('hello')\t 2 """ fixed = """\ def foo(): if True: (2, 1) 1 if True: print('hello') 2 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e111_should_not_modify_string_contents(self): line = """\ if True: x = ''' 1 ''' """ fixed = """\ if True: x = ''' 1 ''' """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e112_should_leave_bad_syntax_alone(self): line = """\ if True: pass """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e113(self): line = """\ a = 1 b = 2 """ fixed = """\ a = 1 b = 2 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e113_bad_syntax(self): line = """\ pass """ fixed = """\ pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e114(self): line = """\ # a = 1 """ fixed = """\ # a = 1 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e115(self): line = """\ if True: # A comment. pass """ fixed = """\ if True: # A comment. pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e116(self): line = """\ a = 1 # b = 2 """ fixed = """\ a = 1 # b = 2 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e117(self): line = """\ for a in [1, 2, 3]: print('hello world') for b in [1, 2, 3]: print(a, b) """ fixed = """\ for a in [1, 2, 3]: print('hello world') for b in [1, 2, 3]: print(a, b) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e12_reindent(self): line = """\ def foo_bar(baz, frop, fizz, bang): # E128 pass if True: x = { } # E123 #: E121 print "E121", ( "dent") #: E122 print "E122", ( "dent") #: E124 print "E124", ("visual", "indent_two" ) #: E125 if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col): raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) #: E126 print "E126", ( "dent") #: E127 print "E127", ("over-", "over-indent") #: E128 print "E128", ("under-", "under-indent") """ fixed = """\ def foo_bar(baz, frop, fizz, bang): # E128 pass if True: x = { } # E123 #: E121 print "E121", ( "dent") #: E122 print "E122", ( "dent") #: E124 print "E124", ("visual", "indent_two" ) #: E125 if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col): raise Exception("%s,%s - %s" % (row, col, self.moduleCount)) #: E126 print "E126", ( "dent") #: E127 print "E127", ("over-", "over-indent") #: E128 print "E128", ("under-", "under-indent") """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e12_reindent_with_multiple_fixes(self): line = """\ sql = 'update %s set %s %s' % (from_table, ','.join(['%s=%s' % (col, col) for col in cols]), where_clause) """ fixed = """\ sql = 'update %s set %s %s' % (from_table, ','.join(['%s=%s' % (col, col) for col in cols]), where_clause) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e12_tricky(self): line = """\ #: E126 if ( x == ( 3 ) or x == ( 3 ) or y == 4): pass """ fixed = """\ #: E126 if ( x == ( 3 ) or x == ( 3 ) or y == 4): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e12_large(self): line = """\ class BogusController(controller.CementBaseController): class Meta: pass class BogusController2(controller.CementBaseController): class Meta: pass class BogusController3(controller.CementBaseController): class Meta: pass class BogusController4(controller.CementBaseController): class Meta: pass class TestBaseController(controller.CementBaseController): class Meta: pass class TestBaseController2(controller.CementBaseController): class Meta: pass class TestStackedController(controller.CementBaseController): class Meta: arguments = [ ] class TestDuplicateController(controller.CementBaseController): class Meta: config_defaults = dict( foo='bar', ) arguments = [ (['-f2', '--foo2'], dict(action='store')) ] def my_command(self): pass """ fixed = """\ class BogusController(controller.CementBaseController): class Meta: pass class BogusController2(controller.CementBaseController): class Meta: pass class BogusController3(controller.CementBaseController): class Meta: pass class BogusController4(controller.CementBaseController): class Meta: pass class TestBaseController(controller.CementBaseController): class Meta: pass class TestBaseController2(controller.CementBaseController): class Meta: pass class TestStackedController(controller.CementBaseController): class Meta: arguments = [ ] class TestDuplicateController(controller.CementBaseController): class Meta: config_defaults = dict( foo='bar', ) arguments = [ (['-f2', '--foo2'], dict(action='store')) ] def my_command(self): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e12_with_bad_indentation(self): line = r""" def bar(): foo(1, 2) def baz(): pass pass """ fixed = r""" def bar(): foo(1, 2) def baz(): pass pass """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e121_with_multiline_string(self): line = """\ testing = \\ '''inputs: d c b a ''' """ fixed = """\ testing = \\ '''inputs: d c b a ''' """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e122_with_fallback(self): line = """\ foooo('', scripts=[''], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', ]) """ fixed = """\ foooo('', scripts=[''], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', ]) """ with autopep8_context(line, options=[]) as result: self.assertEqual(fixed, result) def test_e123(self): line = """\ if True: foo = ( ) """ fixed = """\ if True: foo = ( ) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e123_with_escaped_newline(self): line = r""" x = \ ( ) """ fixed = r""" x = \ ( ) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e128_with_aaa_option(self): line = """\ def extractBlocks(self): addLine = (self.matchMultiple(linesIncludePatterns, line) and not self.matchMultiple(linesExcludePatterns, line)) or emptyLine """ fixed = """\ def extractBlocks(self): addLine = ( self.matchMultiple( linesIncludePatterns, line) and not self.matchMultiple( linesExcludePatterns, line)) or emptyLine """ with autopep8_context(line, options=['-aaa']) as result: self.assertEqual(fixed, result) def test_e129(self): line = """\ if (a and b in [ 'foo', ] or c): pass """ fixed = """\ if (a and b in [ 'foo', ] or c): pass """ with autopep8_context(line, options=['--select=E129']) as result: self.assertEqual(fixed, result) def test_e125_with_multiline_string(self): line = """\ for foo in ''' abc 123 '''.strip().split(): print(foo) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(line, result) def test_e125_with_multiline_string_okay(self): line = """\ def bar( a='''a'''): print(foo) """ fixed = """\ def bar( a='''a'''): print(foo) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e126(self): line = """\ if True: posted = models.DateField( default=datetime.date.today, help_text="help" ) """ fixed = """\ if True: posted = models.DateField( default=datetime.date.today, help_text="help" ) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e126_should_not_interfere_with_other_fixes(self): line = """\ self.assertEqual('bottom 1', SimpleNamedNode.objects.filter(id__gt=1).exclude( name='bottom 3').filter( name__in=['bottom 3', 'bottom 1'])[0].name) """ fixed = """\ self.assertEqual('bottom 1', SimpleNamedNode.objects.filter(id__gt=1).exclude( name='bottom 3').filter( name__in=['bottom 3', 'bottom 1'])[0].name) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e127(self): line = """\ if True: if True: chksum = (sum([int(value[i]) for i in xrange(0, 9, 2)]) * 7 - sum([int(value[i]) for i in xrange(1, 9, 2)])) % 10 """ fixed = """\ if True: if True: chksum = (sum([int(value[i]) for i in xrange(0, 9, 2)]) * 7 - sum([int(value[i]) for i in xrange(1, 9, 2)])) % 10 """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e127_align_visual_indent(self): line = """\ def draw(self): color = [([0.2, 0.1, 0.3], [0.2, 0.1, 0.3], [0.2, 0.1, 0.3]), ([0.9, 0.3, 0.5], [0.5, 1.0, 0.5], [0.3, 0.3, 0.9]) ][self._p._colored ] self.draw_background(color) """ fixed = """\ def draw(self): color = [([0.2, 0.1, 0.3], [0.2, 0.1, 0.3], [0.2, 0.1, 0.3]), ([0.9, 0.3, 0.5], [0.5, 1.0, 0.5], [0.3, 0.3, 0.9])][self._p._colored] self.draw_background(color) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e127_align_visual_indent_okay(self): """This is for code coverage.""" line = """\ want = (have + _leading_space_count( after[jline - 1]) - _leading_space_count(lines[jline])) """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e127_with_backslash(self): line = r""" if True: if True: self.date = meta.session.query(schedule.Appointment)\ .filter(schedule.Appointment.id == appointment_id).one().agenda.endtime """ fixed = r""" if True: if True: self.date = meta.session.query(schedule.Appointment)\ .filter(schedule.Appointment.id == appointment_id).one().agenda.endtime """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e127_with_bracket_then_parenthesis(self): line = r""" if True: foo = [food(1) for bar in bars] """ fixed = r""" if True: foo = [food(1) for bar in bars] """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e12_with_backslash(self): line = r""" if True: assert reeval == parsed, \ 'Repr gives different object:\n %r !=\n %r' % (parsed, reeval) """ fixed = r""" if True: assert reeval == parsed, \ 'Repr gives different object:\n %r !=\n %r' % (parsed, reeval) """ with autopep8_context(line, options=['--select=E12']) as result: self.assertEqual(fixed, result) def test_e133(self): line = """\ if True: e = [ 1, 2 ] """ fixed = """\ if True: e = [ 1, 2 ] """ with autopep8_context(line, options=['--hang-closing']) as result: self.assertEqual(fixed, result) def test_e133_no_indentation_line(self): line = """\ e = [ 1, 2 ] """ fixed = """\ e = [ 1, 2 ] """ with autopep8_context(line, options=['--hang-closing']) as result: self.assertEqual(fixed, result) def test_e133_not_effected(self): line = """\ if True: e = [ 1, 2 ] """ with autopep8_context(line, options=['--hang-closing']) as result: self.assertEqual(line, result) def test_w191(self): line = """\ while True: \tif True: \t\t1 """ fixed = """\ while True: if True: 1 """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w191_ignore(self): line = """\ while True: \tif True: \t\t1 """ with autopep8_context(line, options=['--aggressive', '--ignore=W191']) as result: self.assertEqual(line, result) def test_e131_with_select_option(self): line = 'd = f(\n a="hello"\n "world",\n b=1)\n' fixed = 'd = f(\n a="hello"\n "world",\n b=1)\n' with autopep8_context(line, options=['--select=E131']) as result: self.assertEqual(fixed, result) def test_e131_invalid_indent_with_select_option(self): line = 'd = (\n "hello"\n "world")\n' fixed = 'd = (\n "hello"\n "world")\n' with autopep8_context(line, options=['--select=E131']) as result: self.assertEqual(fixed, result) class SystemTestsE2(unittest.TestCase): def test_e201(self): line = '( 1)\n' fixed = '(1)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e202(self): line = '(1 )\n[2 ]\n{3 }\n' fixed = '(1)\n[2]\n{3}\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e202_multiline(self): line = """\ (''' a b c ''' ) """ fixed = """\ (''' a b c ''') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e202_skip_multiline_with_escaped_newline(self): line = r""" ('c\ ' ) """ fixed = r""" ('c\ ') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e203_colon(self): line = '{4 : 3}\n' fixed = '{4: 3}\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e203_comma(self): line = '[1 , 2 , 3]\n' fixed = '[1, 2, 3]\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e203_semicolon(self): line = "print(a, end=' ') ; nl = 0\n" fixed = "print(a, end=' '); nl = 0\n" with autopep8_context(line, options=['--select=E203']) as result: self.assertEqual(fixed, result) def test_e203_with_newline(self): line = "print(a\n, end=' ')\n" fixed = "print(a, end=' ')\n" with autopep8_context(line, options=['--select=E203']) as result: self.assertEqual(fixed, result) def test_e204(self): line = '@ decorator\n' fixed = '@decorator\n' with autopep8_context(line, options=['--select=E204']) as result: self.assertEqual(fixed, result) def test_e211(self): line = 'd = [1, 2, 3]\nprint(d [0])\n' fixed = 'd = [1, 2, 3]\nprint(d[0])\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e221(self): line = 'a = 1 + 1\n' fixed = 'a = 1 + 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e221_do_not_skip_multiline(self): line = '''\ def javascript(self): return u""" """ % { } ''' fixed = '''\ def javascript(self): return u""" """ % { } ''' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e222(self): line = 'a = 1 + 1\n' fixed = 'a = 1 + 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e222_with_multiline(self): line = 'a = \"\"\"bar\nbaz\"\"\"\n' fixed = 'a = \"\"\"bar\nbaz\"\"\"\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e223(self): line = 'a = 1 + 1\n' # include TAB fixed = 'a = 1 + 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e223_double(self): line = 'a = 1 + 1\n' # include TAB fixed = 'a = 1 + 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e223_with_tab_indentation(self): line = """\ class Foo(): \tdef __init__(self): \t\tx= 1\t+ 3 """ fixed = """\ class Foo(): \tdef __init__(self): \t\tx = 1 + 3 """ with autopep8_context(line, options=['--ignore=E1,W191']) as result: self.assertEqual(fixed, result) def test_e224(self): line = 'a = 11 + 1\n' # include TAB fixed = 'a = 11 + 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e224_double(self): line = 'a = 11 + 1\n' # include TAB fixed = 'a = 11 + 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e224_with_tab_indentation(self): line = """\ class Foo(): \tdef __init__(self): \t\tx= \t3 """ fixed = """\ class Foo(): \tdef __init__(self): \t\tx = 3 """ with autopep8_context(line, options=['--ignore=E1,W191']) as result: self.assertEqual(fixed, result) def test_e225(self): line = '1+1\n2 +2\n3+ 3\n' fixed = '1 + 1\n2 + 2\n3 + 3\n' with autopep8_context(line, options=['--select=E,W']) as result: self.assertEqual(fixed, result) def test_e225_with_indentation_fix(self): line = """\ class Foo(object): def bar(self): return self.elephant!='test' """ fixed = """\ class Foo(object): def bar(self): return self.elephant != 'test' """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e226(self): line = '1*1\n2*2\n3*3\n' fixed = '1 * 1\n2 * 2\n3 * 3\n' with autopep8_context(line, options=['--select=E22']) as result: self.assertEqual(fixed, result) def test_e227(self): line = '1&1\n2&2\n3&3\n' fixed = '1 & 1\n2 & 2\n3 & 3\n' with autopep8_context(line, options=['--select=E22']) as result: self.assertEqual(fixed, result) def test_e228(self): line = '1%1\n2%2\n3%3\n' fixed = '1 % 1\n2 % 2\n3 % 3\n' with autopep8_context(line, options=['--select=E22']) as result: self.assertEqual(fixed, result) def test_e231(self): line = '[1,2,3]\n' fixed = '[1, 2, 3]\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e231_with_many_commas(self): fixed = str(list(range(200))) + '\n' line = re.sub(', ', ',', fixed) with autopep8_context(line, options=['--select=E231']) as result: self.assertEqual(fixed, result) def test_e231_with_colon_after_comma(self): """ws_comma fixer ignores this case.""" line = 'a[b1,:]\n' fixed = 'a[b1, :]\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e231_should_only_do_ws_comma_once(self): """If we don't check appropriately, we end up doing ws_comma multiple times and skipping all other fixes.""" line = """\ print( 1 ) foo[0,:] bar[zap[0][0]:zig[0][0],:] """ fixed = """\ print(1) foo[0, :] bar[zap[0][0]:zig[0][0], :] """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e241(self): line = 'l = (1, 2)\n' fixed = 'l = (1, 2)\n' with autopep8_context(line, options=['--select=E']) as result: self.assertEqual(fixed, result) def test_e241_should_be_enabled_by_aggressive(self): line = 'l = (1, 2)\n' fixed = 'l = (1, 2)\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e241_double(self): line = 'l = (1, 2)\n' fixed = 'l = (1, 2)\n' with autopep8_context(line, options=['--select=E']) as result: self.assertEqual(fixed, result) def test_e242(self): line = 'l = (1,\t2)\n' fixed = 'l = (1, 2)\n' with autopep8_context(line, options=['--select=E']) as result: self.assertEqual(fixed, result) def test_e242_double(self): line = 'l = (1,\t\t2)\n' fixed = 'l = (1, 2)\n' with autopep8_context(line, options=['--select=E']) as result: self.assertEqual(fixed, result) def test_e251(self): line = 'def a(arg = 1):\n print(arg)\n' fixed = 'def a(arg=1):\n print(arg)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e251_with_escaped_newline(self): line = '1\n\n\ndef a(arg=\\\n1):\n print(arg)\n' fixed = '1\n\n\ndef a(arg=1):\n print(arg)\n' with autopep8_context(line, options=['--select=E251']) as result: self.assertEqual(fixed, result) def test_e251_with_calling(self): line = 'foo(bar= True)\n' fixed = 'foo(bar=True)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e251_with_argument_on_next_line(self): line = 'foo(bar\n=None)\n' fixed = 'foo(bar=None)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e252(self): line = 'def a(arg1: int=1, arg2: int =1, arg3: int= 1):\n print(arg)\n' fixed = 'def a(arg1: int = 1, arg2: int = 1, arg3: int = 1):\n print(arg)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e252_with_argument_on_next_line(self): line = 'def a(arg: int\n=1):\n print(arg)\n' fixed = 'def a(arg: int\n= 1):\n print(arg)\n' with autopep8_context(line, options=['--select=E252']) as result: self.assertEqual(fixed, result) def test_e252_with_escaped_newline(self): line = 'def a(arg: int\\\n=1):\n print(arg)\n' fixed = 'def a(arg: int\\\n= 1):\n print(arg)\n' with autopep8_context(line, options=['--select=E252']) as result: self.assertEqual(fixed, result) def test_e261(self): line = "print('a b ')# comment\n" fixed = "print('a b ') # comment\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e261_with_inline_commented_out_code(self): line = '1 # 0 + 0\n' fixed = '1 # 0 + 0\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e261_with_dictionary(self): line = 'd = {# comment\n1: 2}\n' fixed = 'd = { # comment\n 1: 2}\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e261_with_dictionary_no_space(self): line = 'd = {#comment\n1: 2}\n' fixed = 'd = { # comment\n 1: 2}\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e261_with_comma(self): line = '{1: 2 # comment\n , }\n' fixed = '{1: 2 # comment\n , }\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e262_more_space(self): line = "print('a b ') # comment\n" fixed = "print('a b ') # comment\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e262_none_space(self): line = "print('a b ') #comment\n" fixed = "print('a b ') # comment\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e262_hash_in_string(self): line = "print('a b #string') #comment\n" fixed = "print('a b #string') # comment\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e262_hash_in_string_and_multiple_hashes(self): line = "print('a b #string') #comment #comment\n" fixed = "print('a b #string') # comment #comment\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e262_more_complex(self): line = "print('a b ') #comment\n123\n" fixed = "print('a b ') # comment\n123\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e265(self): line = "#A comment\n123\n" fixed = "# A comment\n123\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e265_ignores_special_comments(self): line = "#!python\n456\n" with autopep8_context(line) as result: self.assertEqual(line, result) def test_e265_ignores_special_comments_in_middle_of_file(self): line = "123\n\n#!python\n456\n" with autopep8_context(line) as result: self.assertEqual(line, result) def test_e265_only(self): line = "##A comment\n#B comment\n123\n" fixed = "## A comment\n# B comment\n123\n" with autopep8_context(line, options=['--select=E265']) as result: self.assertEqual(fixed, result) def test_e265_issue662(self): line = "#print(\" \")\n" fixed = "# print(\" \")\n" with autopep8_context(line, options=['--select=E265']) as result: self.assertEqual(fixed, result) def test_ignore_e265(self): line = "## A comment\n#B comment\n123\n" fixed = "# A comment\n#B comment\n123\n" with autopep8_context(line, options=['--ignore=E265']) as result: self.assertEqual(fixed, result) def test_e266(self): line = "## comment\n123\n" fixed = "# comment\n123\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e266_only(self): line = "## A comment\n#B comment\n123\n" fixed = "# A comment\n#B comment\n123\n" with autopep8_context(line, options=['--select=E266']) as result: self.assertEqual(fixed, result) def test_e266_issue662(self): line = "## comment\n" fixed = "# comment\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_ignore_e266(self): line = "##A comment\n#B comment\n123\n" fixed = "## A comment\n# B comment\n123\n" with autopep8_context(line, options=['--ignore=E266']) as result: self.assertEqual(fixed, result) def test_e271(self): line = 'True and False\n' fixed = 'True and False\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e271_with_multiline(self): line = 'if True and False \\\n True:\n pass\n' fixed = 'if True and False \\\n True:\n pass\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e271_and_w504_with_affects_another_result_line(self): line = """\ cm_opts = ([1] + [d for d in [3,4]]) """ fixed = """\ cm_opts = ([1] + [d for d in [3,4]]) """ with autopep8_context(line, options=["--select=E271,W504"]) as result: self.assertEqual(fixed, result) def test_e272(self): line = 'True and False\n' fixed = 'True and False\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e273(self): line = 'True and\tFalse\n' fixed = 'True and False\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e274(self): line = 'True\tand False\n' fixed = 'True and False\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) class SystemTestsE3(unittest.TestCase): def test_e306(self): line = """ def test_descriptors(self): class descriptor(object): def __init__(self, fn): self.fn = fn def __get__(self, obj, owner): if obj is not None: return self.fn(obj, obj) else: return self def method(self): return 'method' """ fixed = """ def test_descriptors(self): class descriptor(object): def __init__(self, fn): self.fn = fn def __get__(self, obj, owner): if obj is not None: return self.fn(obj, obj) else: return self def method(self): return 'method' """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e301(self): line = 'class k:\n s = 0\n def f():\n print(1)\n' fixed = 'class k:\n s = 0\n\n def f():\n print(1)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e301_extended_with_docstring(self): line = '''\ class Foo(object): """Test.""" def foo(self): """Test.""" def bar(): pass ''' fixed = '''\ class Foo(object): """Test.""" def foo(self): """Test.""" def bar(): pass ''' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_not_e301_extended_with_comment(self): line = '''\ class Foo(object): """Test.""" # A comment. def foo(self): pass ''' with autopep8_context(line) as result: self.assertEqual(line, result) def test_e302(self): line = 'def f():\n print(1)\n\ndef ff():\n print(2)\n' fixed = 'def f():\n print(1)\n\n\ndef ff():\n print(2)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e302_bug(self): """Avoid creating bad syntax.""" line = r"""def repeatable_expr(): return [bracketed_choice, simple_match, rule_ref],\ Optional(repeat_operator) # def match(): return [simple_match , mixin_rule_match] TODO def simple_match(): return [str_match, re_match] """ self.assertTrue(autopep8.check_syntax(line)) with autopep8_context(line) as result: self.assertTrue(autopep8.check_syntax(result)) def test_e303(self): line = '\n\n\n# alpha\n\n1\n' fixed = '\n\n# alpha\n\n1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e303_extended(self): line = '''\ def foo(): """Document.""" ''' fixed = '''\ def foo(): """Document.""" ''' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e303_with_e305(self): line = """\ def foo(): pass # comment (E303) a = 1 # (E305) """ fixed = """\ def foo(): pass # comment (E303) a = 1 # (E305) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e304(self): line = '@contextmanager\n\ndef f():\n print(1)\n' fixed = '@contextmanager\ndef f():\n print(1)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e304_with_comment(self): line = '@contextmanager\n# comment\n\ndef f():\n print(1)\n' fixed = '@contextmanager\n# comment\ndef f():\n print(1)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e305(self): line = 'def a():\n pass\na()\n' fixed = 'def a():\n pass\n\n\na()\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) class SystemTestsE4(unittest.TestCase): def test_e401(self): line = 'import os, sys\n' fixed = 'import os\nimport sys\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e401_with_indentation(self): line = 'def a():\n import os, sys\n' fixed = 'def a():\n import os\n import sys\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e401_should_ignore_commented_comma(self): line = 'import bdist_egg, egg # , not a module, neither is this\n' fixed = 'import bdist_egg\nimport egg # , not a module, neither is this\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e401_should_ignore_commented_comma_with_indentation(self): line = 'if True:\n import bdist_egg, egg # , not a module, neither is this\n' fixed = 'if True:\n import bdist_egg\n import egg # , not a module, neither is this\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e401_should_ignore_false_positive(self): line = 'import bdist_egg; bdist_egg.write_safety_flag(cmd.egg_info, safe)\n' with autopep8_context(line, options=['--select=E401']) as result: self.assertEqual(line, result) def test_e401_with_escaped_newline_case(self): line = 'import foo, \\\n bar\n' fixed = 'import foo\nimport \\\n bar\n' with autopep8_context(line, options=['--select=E401']) as result: self.assertEqual(fixed, result) def test_e402(self): line = 'a = 1\nimport os\n' fixed = 'import os\na = 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_duplicate_module(self): line = 'a = 1\nimport os\nprint(os)\nimport os\n' fixed = 'import os\na = 1\nprint(os)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_with_future_import(self): line = 'from __future__ import print_function\na = 1\nimport os\n' fixed = 'from __future__ import print_function\nimport os\na = 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e401_with_multiline_from_import(self): line = """\ from os import ( chroot ) def f(): pass from a import b from b import c from c import d """ fixed = """\ from a import b from c import d from b import c from os import ( chroot ) def f(): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_with_multiline_from_future_import(self): line = """\ from __future__ import ( absolute_import, print_function ) def f(): pass import os """ fixed = """\ from __future__ import ( absolute_import, print_function ) import os def f(): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_with_module_doc(self): line1 = '"""\nmodule doc\n"""\na = 1\nimport os\n' fixed1 = '"""\nmodule doc\n"""\nimport os\na = 1\n' line2 = '# comment\nr"""\nmodule doc\n"""\na = 1\nimport os\n' fixed2 = '# comment\nr"""\nmodule doc\n"""\nimport os\na = 1\n' line3 = "u'''one line module doc'''\na = 1\nimport os\n" fixed3 = "u'''one line module doc'''\nimport os\na = 1\n" line4 = "'''\n\"\"\"\ndoc'''\na = 1\nimport os\n" fixed4 = "'''\n\"\"\"\ndoc'''\nimport os\na = 1\n" for line, fixed in [(line1, fixed1), (line2, fixed2), (line3, fixed3), (line4, fixed4)]: with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_import_some_modules(self): line = """\ a = 1 from csv import ( reader, writer, ) import os print(os, reader, writer) import os """ fixed = """\ import os from csv import ( reader, writer, ) a = 1 print(os, reader, writer) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_with_dunder(self): line = """\ __all__ = ["a", "b"] def f(): pass import os """ fixed = """\ import os __all__ = ["a", "b"] def f(): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e402_with_dunder_lines(self): line = """\ __all__ = [ "a", "b", ] def f(): pass import os """ fixed = """\ import os __all__ = [ "a", "b", ] def f(): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) class SystemTestsE5(unittest.TestCase): def test_e501_basic(self): line = """\ print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_dictionary(self): line = """\ myDict = { 'kg': 1, 'tonnes': tonne, 't/y': tonne / year, 'Mt/y': 1e6 * tonne / year} """ fixed = """\ myDict = { 'kg': 1, 'tonnes': tonne, 't/y': tonne / year, 'Mt/y': 1e6 * tonne / year} """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_in(self): line = """\ if True: if True: if True: if True: if True: if True: if True: if True: if k_left in ('any', k_curr) and k_right in ('any', k_curr): pass """ fixed = """\ if True: if True: if True: if True: if True: if True: if True: if True: if k_left in ('any', k_curr) and k_right in ('any', k_curr): pass """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_commas_and_colons(self): line = """\ foobar = {'aaaaaaaaaaaa': 'bbbbbbbbbbbbbbbb', 'dddddd': 'eeeeeeeeeeeeeeee', 'ffffffffffff': 'gggggggg'} """ fixed = """\ foobar = {'aaaaaaaaaaaa': 'bbbbbbbbbbbbbbbb', 'dddddd': 'eeeeeeeeeeeeeeee', 'ffffffffffff': 'gggggggg'} """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_inline_comments(self): line = """\ ' ' # Long inline comments should be moved above. if True: ' ' # Long inline comments should be moved above. """ fixed = """\ # Long inline comments should be moved above. ' ' if True: # Long inline comments should be moved above. ' ' """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_inline_comments_should_skip_multiline(self): line = """\ '''This should be left alone. ----------------------------------------------------- ''' # foo '''This should be left alone. ----------------------------------------------------- ''' \\ # foo '''This should be left alone. ----------------------------------------------------- ''' \\ \\ # foo """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(line, result) def test_e501_with_inline_comments_should_skip_keywords(self): line = """\ ' ' # noqa Long inline comments should be moved above. if True: ' ' # pylint: disable-msgs=E0001 ' ' # pragma: no cover ' ' # pragma: no cover """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(line, result) def test_e501_with_inline_comments_should_skip_keywords_without_aggressive( self): line = """\ ' ' # noqa Long inline comments should be moved above. if True: ' ' # pylint: disable-msgs=E0001 ' ' # pragma: no cover ' ' # pragma: no cover """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e501_with_inline_comments_should_skip_edge_cases(self): line = """\ if True: x = \\ ' ' # Long inline comments should be moved above. """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e501_basic_should_prefer_balanced_brackets(self): line = """\ if True: reconstructed = iradon(radon(image), filter="ramp", interpolation="nearest") """ fixed = """\ if True: reconstructed = iradon(radon(image), filter="ramp", interpolation="nearest") """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_very_long_line(self): line = """\ x = [3244234243234, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243] """ fixed = """\ x = [ 3244234243234, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243] """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_lambda(self): line = """\ self.mock_group.modify_state.side_effect = lambda *_: defer.fail(NoSuchScalingGroupError(1, 2)) """ fixed = """\ self.mock_group.modify_state.side_effect = lambda *_: defer.fail( NoSuchScalingGroupError(1, 2)) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_shorten_with_backslash(self): line = """\ class Bar(object): def bar(self, position): if 0 <= position <= self._blocks[-1].position + len(self._blocks[-1].text): pass """ fixed = """\ class Bar(object): def bar(self, position): if 0 <= position <= self._blocks[-1].position + \\ len(self._blocks[-1].text): pass """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_shorten_at_commas_skip(self): line = """\ parser.add_argument('source_corpus', help='corpus name/path relative to an nltk_data directory') parser.add_argument('target_corpus', help='corpus name/path relative to an nltk_data directory') """ fixed = """\ parser.add_argument( 'source_corpus', help='corpus name/path relative to an nltk_data directory') parser.add_argument( 'target_corpus', help='corpus name/path relative to an nltk_data directory') """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_shorter_length(self): line = "foooooooooooooooooo('abcdefghijklmnopqrstuvwxyz')\n" fixed = "foooooooooooooooooo(\n 'abcdefghijklmnopqrstuvwxyz')\n" with autopep8_context(line, options=['--max-line-length=40']) as result: self.assertEqual(fixed, result) def test_e501_with_indent(self): line = """\ def d(): print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ def d(): print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_alone_with_indentation(self): line = """\ if True: print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ if True: print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line, options=['--select=E501']) as result: self.assertEqual(fixed, result) def test_e501_alone_with_tuple(self): line = """\ fooooooooooooooooooooooooooooooo000000000000000000000000 = [1, ('TransferTime', 'FLOAT') ] """ fixed = """\ fooooooooooooooooooooooooooooooo000000000000000000000000 = [1, ('TransferTime', 'FLOAT') ] """ with autopep8_context(line, options=['--select=E501']) as result: self.assertEqual(fixed, result) def test_e501_should_not_try_to_break_at_every_paren_in_arithmetic(self): line = """\ term3 = w6 * c5 * (8.0 * psi4 * (11.0 - 24.0 * t2) - 28 * psi3 * (1 - 6.0 * t2) + psi2 * (1 - 32 * t2) - psi * (2.0 * t2) + t4) / 720.0 this_should_be_shortened = (' ', ' ') """ fixed = """\ term3 = w6 * c5 * (8.0 * psi4 * (11.0 - 24.0 * t2) - 28 * psi3 * (1 - 6.0 * t2) + psi2 * (1 - 32 * t2) - psi * (2.0 * t2) + t4) / 720.0 this_should_be_shortened = ( ' ', ' ') """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_arithmetic_operator_with_indent(self): line = """\ def d(): 111 + 111 + 111 + 111 + 111 + 222 + 222 + 222 + 222 + 222 + 222 + 222 + 222 + 222 + 333 + 333 + 333 + 333 """ fixed = r"""def d(): 111 + 111 + 111 + 111 + 111 + 222 + 222 + 222 + 222 + \ 222 + 222 + 222 + 222 + 222 + 333 + 333 + 333 + 333 """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_more_complicated(self): line = """\ blahblah = os.environ.get('blahblah') or os.environ.get('blahblahblah') or os.environ.get('blahblahblahblah') """ fixed = """\ blahblah = os.environ.get('blahblah') or os.environ.get( 'blahblahblah') or os.environ.get('blahblahblahblah') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_skip_even_more_complicated(self): line = """\ if True: if True: if True: blah = blah.blah_blah_blah_bla_bl(blahb.blah, blah.blah, blah=blah.label, blah_blah=blah_blah, blah_blah2=blah_blah) """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e501_avoid_breaking_at_empty_parentheses_if_possible(self): line = """\ someverylongindenttionwhatnot().foo().bar().baz("and here is a long string 123456789012345678901234567890") """ fixed = """\ someverylongindenttionwhatnot().foo().bar().baz( "and here is a long string 123456789012345678901234567890") """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_logical_fix(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_logical_fix_and_physical_fix(self): line = """\ # ------------------------------------ ------------------------------------------ xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ fixed = """\ # ------------------------------------ ----------------------------------- xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_logical_fix_and_adjacent_strings(self): line = """\ print('a-----------------------' 'b-----------------------' 'c-----------------------' 'd-----------------------''e'"f"r"g") """ fixed = """\ print( 'a-----------------------' 'b-----------------------' 'c-----------------------' 'd-----------------------' 'e' "f" r"g") """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_multiple_lines(self): line = """\ foo_bar_zap_bing_bang_boom(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333) """ fixed = """\ foo_bar_zap_bing_bang_boom( 111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_multiple_lines_and_quotes(self): line = """\ if True: xxxxxxxxxxx = xxxxxxxxxxxxxxxxx(xxxxxxxxxxx, xxxxxxxxxxxxxxxx={'xxxxxxxxxxxx': 'xxxxx', 'xxxxxxxxxxx': xx, 'xxxxxxxx': False, }) """ fixed = """\ if True: xxxxxxxxxxx = xxxxxxxxxxxxxxxxx( xxxxxxxxxxx, xxxxxxxxxxxxxxxx={ 'xxxxxxxxxxxx': 'xxxxx', 'xxxxxxxxxxx': xx, 'xxxxxxxx': False, }) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_do_not_break_on_keyword(self): # We don't want to put a newline after equals for keywords as this # violates PEP 8. line = """\ if True: long_variable_name = tempfile.mkstemp(prefix='abcdefghijklmnopqrstuvwxyz0123456789') """ fixed = """\ if True: long_variable_name = tempfile.mkstemp( prefix='abcdefghijklmnopqrstuvwxyz0123456789') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_do_not_begin_line_with_comma(self): # This fix is incomplete. (The line is still too long.) But it is here # just to confirm that we do not put a comma at the beginning of a # line. line = """\ def dummy(): if True: if True: if True: object = ModifyAction( [MODIFY70.text, OBJECTBINDING71.text, COLON72.text], MODIFY70.getLine(), MODIFY70.getCharPositionInLine() ) """ fixed = """\ def dummy(): if True: if True: if True: object = ModifyAction([MODIFY70.text, OBJECTBINDING71.text, COLON72.text], MODIFY70.getLine( ), MODIFY70.getCharPositionInLine()) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_should_not_break_on_dot(self): line = """\ if True: if True: raise xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx('xxxxxxxxxxxxxxxxx "{d}" xxxxxxxxxxxxxx'.format(d='xxxxxxxxxxxxxxx')) """ fixed = """\ if True: if True: raise xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( 'xxxxxxxxxxxxxxxxx "{d}" xxxxxxxxxxxxxx'.format(d='xxxxxxxxxxxxxxx')) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_comment(self): line = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. pass # http://foo.bar/abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc- # The following is ugly commented-out code and should not be touched. #xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 1 """ fixed = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will # wrap it using textwrap to be within 72 characters. pass # http://foo.bar/abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc- # The following is ugly commented-out code and should not be touched. # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 1 """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_comment_should_not_modify_docstring(self): line = '''\ def foo(): """ # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. """ ''' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(line, result) def test_e501_should_only_modify_last_comment(self): line = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 1. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 2. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 3. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. """ fixed = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 1. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 2. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 3. This is a long comment that should be wrapped. I # will wrap it using textwrap to be within 72 # characters. """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_should_not_interfere_with_non_comment(self): line = ''' """ # not actually a comment %d. 12345678901234567890, 12345678901234567890, 12345678901234567890. """ % (0,) ''' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(line, result) def test_e501_should_cut_comment_pattern(self): line = """123 # -- Useless lines ---------------------------------------------------------------------- 321 """ fixed = """123 # -- Useless lines ------------------------------------------------------- 321 """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_function_should_not_break_on_colon(self): line = r""" class Useless(object): def _table_field_is_plain_widget(self, widget): if widget.__class__ == Widget or\ (widget.__class__ == WidgetMeta and Widget in widget.__bases__): return True return False """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e501_should_break_before_tuple_start(self): line = """\ xxxxxxxxxxxxx(aaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb, cccccccccc, (dddddddddddddddddddddd, eeeeeeeeeeee, fffffffffff, gggggggggg)) """ fixed = """\ xxxxxxxxxxxxx(aaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb, cccccccccc, (dddddddddddddddddddddd, eeeeeeeeeeee, fffffffffff, gggggggggg)) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive(self): line = """\ models = { 'auth.group': { 'Meta': {'object_name': 'Group'}, 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) }, 'auth.permission': { 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) }, } """ fixed = """\ models = { 'auth.group': { 'Meta': { 'object_name': 'Group'}, 'permissions': ( 'django.db.models.fields.related.ManyToManyField', [], { 'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})}, 'auth.permission': { 'Meta': { 'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, 'name': ( 'django.db.models.fields.CharField', [], { 'max_length': '50'})}, } """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_multiple_logical_lines(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_multiple_logical_lines_with_math(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx([-1 + 5 / 10, 100, -3 - 4]) """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( [-1 + 5 / 10, 100, -3 - 4]) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_import(self): line = """\ from . import (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy) """ fixed = """\ from . import ( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_massive_number_of_logical_lines(self): """We do not care about results here. We just want to know that it doesn't take a ridiculous amount of time. Caching is currently required to avoid repeately trying the same line. """ line = """\ # encoding: utf-8 import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models from provider.compat import user_model_label class Migration(SchemaMigration): def forwards(self, orm): # Adding model 'Client' db.create_table('oauth2_client', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), ('url', self.gf('django.db.models.fields.URLField')(max_length=200)), ('redirect_uri', self.gf('django.db.models.fields.URLField')(max_length=200)), ('client_id', self.gf('django.db.models.fields.CharField')(default='37b581bdc702c732aa65', max_length=255)), ('client_secret', self.gf('django.db.models.fields.CharField')(default='5cf90561f7566aa81457f8a32187dcb8147c7b73', max_length=255)), ('client_type', self.gf('django.db.models.fields.IntegerField')()), )) db.send_create_signal('oauth2', ['Client']) # Adding model 'Grant' db.create_table('oauth2_grant', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['oauth2.Client'])), ('code', self.gf('django.db.models.fields.CharField')(default='f0cda1a5f4ae915431ff93f477c012b38e2429c4', max_length=255)), ('expires', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2012, 2, 8, 10, 43, 45, 620301))), ('redirect_uri', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), ('scope', self.gf('django.db.models.fields.IntegerField')(default=0)), )) db.send_create_signal('oauth2', ['Grant']) # Adding model 'AccessToken' db.create_table('oauth2_accesstoken', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), ('token', self.gf('django.db.models.fields.CharField')(default='b10b8f721e95117cb13c', max_length=255)), ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['oauth2.Client'])), ('expires', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2013, 2, 7, 10, 33, 45, 618854))), ('scope', self.gf('django.db.models.fields.IntegerField')(default=0)), )) db.send_create_signal('oauth2', ['AccessToken']) # Adding model 'RefreshToken' db.create_table('oauth2_refreshtoken', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), ('token', self.gf('django.db.models.fields.CharField')(default='84035a870dab7c820c2c501fb0b10f86fdf7a3fe', max_length=255)), ('access_token', self.gf('django.db.models.fields.related.OneToOneField')(related_name='refresh_token', unique=True, to=orm['oauth2.AccessToken'])), ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['oauth2.Client'])), ('expired', self.gf('django.db.models.fields.BooleanField')(default=False)), )) db.send_create_signal('oauth2', ['RefreshToken']) def backwards(self, orm): # Deleting model 'Client' db.delete_table('oauth2_client') # Deleting model 'Grant' db.delete_table('oauth2_grant') # Deleting model 'AccessToken' db.delete_table('oauth2_accesstoken') # Deleting model 'RefreshToken' db.delete_table('oauth2_refreshtoken') models = { 'auth.group': { 'Meta': {'object_name': 'Group'}, 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) }, 'auth.permission': { 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) }, user_model_label: { 'Meta': {'object_name': user_model_label.split('.')[-1]}, 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) }, 'contenttypes.contenttype': { 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) }, 'oauth2.accesstoken': { 'Meta': {'object_name': 'AccessToken'}, 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 2, 7, 10, 33, 45, 624553)'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), 'token': ('django.db.models.fields.CharField', [], {'default': "'d5c1f65020ebdc89f20c'", 'max_length': '255'}), 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) }, 'oauth2.client': { 'Meta': {'object_name': 'Client'}, 'client_id': ('django.db.models.fields.CharField', [], {'default': "'306fb26cbcc87dd33cdb'", 'max_length': '255'}), 'client_secret': ('django.db.models.fields.CharField', [], {'default': "'7e5785add4898448d53767f15373636b918cf0e3'", 'max_length': '255'}), 'client_type': ('django.db.models.fields.IntegerField', [], {}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'redirect_uri': ('django.db.models.fields.URLField', [], {'max_length': '200'}), 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) }, 'oauth2.grant': { 'Meta': {'object_name': 'Grant'}, 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), 'code': ('django.db.models.fields.CharField', [], {'default': "'310b2c63e27306ecf5307569dd62340cc4994b73'", 'max_length': '255'}), 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 2, 8, 10, 43, 45, 625956)'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'redirect_uri': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) }, 'oauth2.refreshtoken': { 'Meta': {'object_name': 'RefreshToken'}, 'access_token': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'refresh_token'", 'unique': 'True', 'to': "orm['oauth2.AccessToken']"}), 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'token': ('django.db.models.fields.CharField', [], {'default': "'ef0ab76037f17769ab2975a816e8f41a1c11d25e'", 'max_length': '255'}), 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) } } complete_apps = ['oauth2'] """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(''.join(line.split()), ''.join(result.split())) def test_e501_shorten_comment_with_aggressive(self): line = """\ # --------- ---------------------------------------------------------------------- """ fixed = """\ # --------- -------------------------------------------------------------- """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_shorten_comment_without_aggressive(self): """Do nothing without aggressive.""" line = """\ def foo(): pass # --------- ---------------------------------------------------------------------- """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e501_with_aggressive_and_escaped_newline(self): line = """\ if True or \\ False: # test test test test test test test test test test test test test test pass """ fixed = """\ if True or \\ False: # test test test test test test test test test test test test test test pass """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_multiline_string(self): line = """\ print('---------------------------------------------------------------------', ('================================================', '====================='), '''-------------------------------------------------------------------------------- ''') """ fixed = """\ print( '---------------------------------------------------------------------', ('================================================', '====================='), '''-------------------------------------------------------------------------------- ''') """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_multiline_string_with_addition(self): line = '''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""" ''' fixed = '''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """ + despot["Nicholas"] + """
Minion: """ + serf["Dmitri"] + """
Residence: """ + palace["Winter"] + """
""" ''' with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_multiline_string_in_parens(self): line = '''\ def f(): email_text += ("""This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""") ''' fixed = '''\ def f(): email_text += ( """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """ + despot["Nicholas"] + """
Minion: """ + serf["Dmitri"] + """
Residence: """ + palace["Winter"] + """
""") ''' with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_indentation(self): line = """\ if True: # comment here print(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,cccccccccccccccccccccccccccccccccccccccccc) """ fixed = """\ if True: # comment here print(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccccccccccccccccc) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_multiple_keys_and_aggressive(self): line = """\ one_two_three_four_five_six = {'one two three four five': 12345, 'asdfsdflsdkfjl sdflkjsdkfkjsfjsdlkfj sdlkfjlsfjs': '343', 1: 1} """ fixed = """\ one_two_three_four_five_six = { 'one two three four five': 12345, 'asdfsdflsdkfjl sdflkjsdkfkjsfjsdlkfj sdlkfjlsfjs': '343', 1: 1} """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_with_aggressive_and_carriage_returns_only(self): """Make sure _find_logical() does not crash.""" line = 'if True:\r from aaaaaaaaaaaaaaaa import bbbbbbbbbbbbbbbbbbb\r \r ccccccccccc = None\r' fixed = 'if True:\r from aaaaaaaaaaaaaaaa import bbbbbbbbbbbbbbbbbbb\r\r ccccccccccc = None\r' with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_should_ignore_imports(self): line = """\ import logging, os, bleach, commonware, urllib2, json, time, requests, urlparse, re """ with autopep8_context(line, options=['--select=E501']) as result: self.assertEqual(line, result) def test_e501_should_not_do_useless_things(self): line = """\ foo(' ') """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e501_aggressive_with_percent(self): line = """\ raise MultiProjectException("Ambiguous workspace: %s=%s, %s" % ( varname, varname_path, os.path.abspath(config_filename))) """ fixed = """\ raise MultiProjectException( "Ambiguous workspace: %s=%s, %s" % (varname, varname_path, os.path.abspath(config_filename))) """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_with_def(self): line = """\ def foo(sldfkjlsdfsdf, kksdfsdfsf,sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf,sdfsdfsfd, sdfsdfdsf): pass """ fixed = """\ def foo(sldfkjlsdfsdf, kksdfsdfsf, sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf, sdfsdfsfd, sdfsdfdsf): pass """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_with_async_def(self): line = """\ async def foo(sldfkjlsdfsdf, kksdfsdfsf,sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf,sdfsdfsfd, sdfsdfdsf): pass """ fixed = """\ async def foo(sldfkjlsdfsdf, kksdfsdfsf, sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf, sdfsdfsfd, sdfsdfdsf): pass """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_more_aggressive_with_def(self): line = """\ def foobar(sldfkjlsdfsdf, kksdfsdfsf,sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf,sdfsdfsfd, sdfsdfdsf): pass """ fixed = """\ def foobar( sldfkjlsdfsdf, kksdfsdfsf, sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf, sdfsdfsfd, sdfsdfdsf): pass """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_more_aggressive_with_async_def(self): line = """\ async def foobar(sldfkjlsdfsdf, kksdfsdfsf,sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf,sdfsdfsfd, sdfsdfdsf): pass """ fixed = """\ async def foobar( sldfkjlsdfsdf, kksdfsdfsf, sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf, sdfsdfsfd, sdfsdfdsf): pass """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_with_tuple(self): line = """\ def f(): man_this_is_a_very_long_function_name(an_extremely_long_variable_name, ('a string that is long: %s'%'bork')) """ fixed = """\ def f(): man_this_is_a_very_long_function_name( an_extremely_long_variable_name, ('a string that is long: %s' % 'bork')) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_with_tuple_in_list(self): line = """\ def f(self): self._xxxxxxxx(aaaaaa, bbbbbbbbb, cccccccccccccccccc, [('mmmmmmmmmm', self.yyyyyyyyyy.zzzzzzz/_DDDDD)], eee, 'ff') """ fixed = """\ def f(self): self._xxxxxxxx(aaaaaa, bbbbbbbbb, cccccccccccccccccc, [ ('mmmmmmmmmm', self.yyyyyyyyyy.zzzzzzz / _DDDDD)], eee, 'ff') """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_decorator(self): line = """\ @foo(('xxxxxxxxxxxxxxxxxxxxxxxxxx', users.xxxxxxxxxxxxxxxxxxxxxxxxxx), ('yyyyyyyyyyyy', users.yyyyyyyyyyyy), ('zzzzzzzzzzzzzz', users.zzzzzzzzzzzzzz)) """ fixed = """\ @foo(('xxxxxxxxxxxxxxxxxxxxxxxxxx', users.xxxxxxxxxxxxxxxxxxxxxxxxxx), ('yyyyyyyyyyyy', users.yyyyyyyyyyyy), ('zzzzzzzzzzzzzz', users.zzzzzzzzzzzzzz)) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_long_class_name(self): line = """\ class AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB): pass """ fixed = """\ class AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA( BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB): pass """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_long_comment_and_long_line(self): line = """\ def foo(): # This is not a novel to be tossed aside lightly. It should be throw with great force. self.xxxxxxxxx(_('yyyyyyyyyyyyy yyyyyyyyyyyy yyyyyyyy yyyyyyyy y'), 'zzzzzzzzzzzzzzzzzzz', bork='urgent') """ fixed = """\ def foo(): # This is not a novel to be tossed aside lightly. It should be throw with # great force. self.xxxxxxxxx( _('yyyyyyyyyyyyy yyyyyyyyyyyy yyyyyyyy yyyyyyyy y'), 'zzzzzzzzzzzzzzzzzzz', bork='urgent') """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_aggressive_intermingled_comments(self): line = """\ A = [ # A comment ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccc'] ] """ fixed = """\ A = [ # A comment ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccc'] ] """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_if_line_over_limit(self): line = """\ if not xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): return 1 """ fixed = """\ if not xxxxxxxxxxxx( aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): return 1 """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_for_line_over_limit(self): line = """\ for aaaaaaaaa in xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ fixed = """\ for aaaaaaaaa in xxxxxxxxxxxx( aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_while_line_over_limit(self): line = """\ while xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ fixed = """\ while xxxxxxxxxxxx( aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e501_avoid_breaking_at_opening_slice(self): """Prevents line break on slice notation, dict access in this example: GYakymOSMc=GYakymOSMW(GYakymOSMJ,GYakymOSMA,GYakymOSMr,GYakymOSMw[ 'abc'],GYakymOSMU,GYakymOSMq,GYakymOSMH,GYakymOSMl,svygreNveyvarf=GYakymOSME) """ line = """\ GYakymOSMc=GYakymOSMW(GYakymOSMJ,GYakymOSMA,GYakymOSMr,GYakymOSMw['abc'],GYakymOSMU,GYakymOSMq,GYakymOSMH,GYakymOSMl,svygreNveyvarf=GYakymOSME) """ fixed = """\ GYakymOSMc = GYakymOSMW(GYakymOSMJ, GYakymOSMA, GYakymOSMr, GYakymOSMw['abc'], GYakymOSMU, GYakymOSMq, GYakymOSMH, GYakymOSMl, svygreNveyvarf=GYakymOSME) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_avoid_breaking_at_multi_level_slice(self): """Prevents line break on slice notation, dict access in this example: GYakymOSMc=GYakymOSMW(GYakymOSMJ,GYakymOSMA,GYakymOSMr,GYakymOSMw['abc'][ 'def'],GYakymOSMU,GYakymOSMq,GYakymOSMH,GYakymOSMl,svygreNveyvarf=GYakymOSME) """ line = """\ GYakymOSMc=GYakymOSMW(GYakymOSMJ,GYakymOSMA,GYakymOSMr,GYakymOSMw['abc']['def'],GYakymOSMU,GYakymOSMq,GYakymOSMH,GYakymOSMl,svygreNveyvarf=GYakymOSME) """ fixed = """\ GYakymOSMc = GYakymOSMW(GYakymOSMJ, GYakymOSMA, GYakymOSMr, GYakymOSMw['abc']['def'], GYakymOSMU, GYakymOSMq, GYakymOSMH, GYakymOSMl, svygreNveyvarf=GYakymOSME) """ with autopep8_context(line) as result: self.assertEqual(fixed, result) @unittest.skipIf( (sys.version_info.major >= 3 and sys.version_info.minor < 8) or sys.version_info.major < 3, "syntax error in Python3.7 and lower version", ) def test_e501_with_pep572_assignment_expressions(self): line = """\ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 1 if bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb := aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: print(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) """ with autopep8_context(line, options=['-aa']) as result: self.assertEqual(line, result) def test_e501_effected_with_fstring(self): line = """\ def foo(): logger.info(f"some string padding some string padding some string padd {somedict['key1']}, more padding more paddin #: {somedict['dictkey2']}") """ fixed = """\ def foo(): logger.info( f"some string padding some string padding some string padd {somedict['key1']}, more padding more paddin #: {somedict['dictkey2']}") """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e501_not_effected_with_fstring(self): line = """\ connector = f"socks5://{user}:{password}:{url}:{port}" """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_e502(self): line = "print('abc'\\\n 'def')\n" fixed = "print('abc'\n 'def')\n" with autopep8_context(line) as result: self.assertEqual(fixed, result) class SystemTestsE7(unittest.TestCase): def test_e701(self): line = 'if True: print(True)\n' fixed = 'if True:\n print(True)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e701_with_escaped_newline(self): line = 'if True:\\\nprint(True)\n' fixed = 'if True:\n print(True)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) @unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+') def test_e701_with_escaped_newline_and_spaces(self): line = 'if True: \\ \nprint(True)\n' fixed = 'if True:\n print(True)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702(self): line = 'print(1); print(2)\n' fixed = 'print(1)\nprint(2)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_after_colon_should_be_untouched(self): # https://docs.python.org/2/reference/compound_stmts.html line = 'def foo(): print(1); print(2)\n' with autopep8_context(line) as result: self.assertEqual(line, result) def test_e702_with_semicolon_at_end(self): line = 'print(1);\n' fixed = 'print(1)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_semicolon_and_space_at_end(self): line = 'print(1); \n' fixed = 'print(1)\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_whitespace(self): line = 'print(1) ; print(2)\n' fixed = 'print(1)\nprint(2)\n' with autopep8_context(line, options=['--select=E702']) as result: self.assertEqual(fixed, result) def test_e702_with_non_ascii_file(self): line = """\ # -*- coding: utf-8 -*- # French comment with accent é # Un commentaire en français avec un accent é import time time.strftime('%d-%m-%Y'); """ fixed = """\ # -*- coding: utf-8 -*- # French comment with accent é # Un commentaire en français avec un accent é import time time.strftime('%d-%m-%Y') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_escaped_newline(self): line = '1; \\\n2\n' fixed = '1\n2\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_escaped_newline_with_indentation(self): line = '1; \\\n 2\n' fixed = '1\n2\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_more_complicated(self): line = """\ def foo(): if bar : bar+=1; bar=bar*bar ; return bar """ fixed = """\ def foo(): if bar: bar += 1 bar = bar * bar return bar """ with autopep8_context(line, options=['--select=E,W']) as result: self.assertEqual(fixed, result) def test_e702_with_semicolon_in_string(self): line = 'print(";");\n' fixed = 'print(";")\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_semicolon_in_string_to_the_right(self): line = 'x = "x"; y = "y;y"\n' fixed = 'x = "x"\ny = "y;y"\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_indent_correctly(self): line = """\ ( 1, 2, 3); 4; 5; 5 # pyflakes """ fixed = """\ ( 1, 2, 3) 4 5 5 # pyflakes """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_triple_quote(self): line = '"""\n hello\n """; 1\n' fixed = '"""\n hello\n """\n1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_triple_quote_and_indent(self): line = 'def f():\n """\n hello\n """; 1\n' fixed = 'def f():\n """\n hello\n """\n 1\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_semicolon_after_string(self): line = """\ raise IOError('abc ' 'def.'); """ fixed = """\ raise IOError('abc ' 'def.') """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_dict_semicolon(self): line = """\ MY_CONST = [ {'A': 1}, {'B': 2} ]; """ fixed = """\ MY_CONST = [ {'A': 1}, {'B': 2} ] """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e702_with_e701_and_only_select_e702_option(self): line = """\ for i in range(3): if i == 1: print(i); continue print(i) """ with autopep8_context(line, options=["--select=E702"]) as result: self.assertEqual(line, result) def test_e703_with_inline_comment(self): line = 'a = 5; # inline comment\n' fixed = 'a = 5 # inline comment\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e703_in_example_of_readme(self): line = """\ def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}; """ fixed = """\ def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True} """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e704(self): line = 'def f(x): return 2*x\n' fixed = 'def f(x):\n return 2 * x\n' with autopep8_context(line, options=['-aaa']) as result: self.assertEqual(fixed, result) def test_e704_not_work_with_aa_option(self): line = 'def f(x): return 2*x\n' with autopep8_context(line, options=['-aa', '--select=E704']) as result: self.assertEqual(line, result) def test_e711(self): line = 'foo == None\n' fixed = 'foo is None\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) line = 'None == foo\n' fixed = 'None is foo\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e711_in_conditional(self): line = 'if foo == None and None == foo:\npass\n' fixed = 'if foo is None and None is foo:\npass\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e711_in_conditional_with_multiple_instances(self): line = 'if foo == None and bar == None:\npass\n' fixed = 'if foo is None and bar is None:\npass\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e711_with_not_equals_none(self): line = 'foo != None\n' fixed = 'foo is not None\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e712(self): line = 'foo == True\n' fixed = 'foo\n' with autopep8_context(line, options=['-aa', '--select=E712']) as result: self.assertEqual(fixed, result) def test_e712_in_conditional_with_multiple_instances(self): line = 'if foo == True and bar == True:\npass\n' fixed = 'if foo and bar:\npass\n' with autopep8_context(line, options=['-aa', '--select=E712']) as result: self.assertEqual(fixed, result) def test_e712_with_false(self): line = 'foo != False\n' fixed = 'foo\n' with autopep8_context(line, options=['-aa', '--select=E712']) as result: self.assertEqual(fixed, result) def test_e712_with_special_case_equal_not_true(self): line = 'if foo != True:\n pass\n' fixed = 'if not foo:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E712']) as result: self.assertEqual(fixed, result) def test_e712_with_special_case_equal_false(self): line = 'if foo == False:\n pass\n' fixed = 'if not foo:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E712']) as result: self.assertEqual(fixed, result) def test_e712_with_dict_value(self): line = 'if d["key"] != True:\n pass\n' fixed = 'if not d["key"]:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E712']) as result: self.assertEqual(fixed, result) def test_e712_only_if_aggressive_level_2(self): line = 'foo == True\n' with autopep8_context(line, options=['-a']) as result: self.assertEqual(line, result) def test_e711_and_e712(self): line = 'if (foo == None and bar == True) or (foo != False and bar != None):\npass\n' fixed = 'if (foo is None and bar) or (foo and bar is not None):\npass\n' with autopep8_context(line, options=['-aa']) as result: self.assertEqual(fixed, result) def test_e713(self): line = 'if not x in y:\n pass\n' fixed = 'if x not in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_more(self): line = 'if not "." in y:\n pass\n' fixed = 'if "." not in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_with_in(self): line = 'if not "." in y and "," in y:\n pass\n' fixed = 'if "." not in y and "," in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_with_tuple(self): line = """ if not role in ("domaincontroller_master", "domaincontroller_backup", "domaincontroller_slave", "memberserver", ): pass """ fixed = """ if role not in ("domaincontroller_master", "domaincontroller_backup", "domaincontroller_slave", "memberserver", ): pass """ with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_chain(self): line = 'if "@" not in x or not "/" in y:\n pass\n' fixed = 'if "@" not in x or "/" not in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_chain2(self): line = 'if "@" not in x or "[" not in x or not "/" in y:\n pass\n' fixed = 'if "@" not in x or "[" not in x or "/" not in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_chain3(self): line = 'if not "@" in x or "[" not in x or not "/" in y:\n pass\n' fixed = 'if "@" not in x or "[" not in x or "/" not in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e713_chain4(self): line = 'if not "." in y and not "," in y:\n pass\n' fixed = 'if "." not in y and "," not in y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E713']) as result: self.assertEqual(fixed, result) def test_e714(self): line = 'if not x is y:\n pass\n' fixed = 'if x is not y:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E714']) as result: self.assertEqual(fixed, result) def test_e714_with_is(self): line = 'if not x is y or x is z:\n pass\n' fixed = 'if x is not y or x is z:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E714']) as result: self.assertEqual(fixed, result) def test_e714_chain(self): line = 'if not x is y or not x is z:\n pass\n' fixed = 'if x is not y or x is not z:\n pass\n' with autopep8_context(line, options=['-aa', '--select=E714']) as result: self.assertEqual(fixed, result) def test_e713_and_e714(self): line = """ if not x is y: pass if not role in ("domaincontroller_master", "domaincontroller_backup", "domaincontroller_slave", "memberserver", ): pass """ fixed = """ if x is not y: pass if role not in ("domaincontroller_master", "domaincontroller_backup", "domaincontroller_slave", "memberserver", ): pass """ with autopep8_context(line, options=['-aa', '--select=E713,E714']) as result: self.assertEqual(fixed, result) def test_e713_with_single_quote(self): line = "if not 'DC IP' in info:\n" fixed = "if 'DC IP' not in info:\n" with autopep8_context(line, options=['-aa', '--select=E713,E714']) as result: self.assertEqual(fixed, result) def test_e714_with_single_quote(self): line = "if not 'DC IP' is info:\n" fixed = "if 'DC IP' is not info:\n" with autopep8_context(line, options=['-aa', '--select=E713,E714']) as result: self.assertEqual(fixed, result) def test_e721(self): line = "type('') == type('')\n" fixed = "isinstance('', type(''))\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_with_str(self): line = "str == type('')\n" fixed = "isinstance('', str)\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_in_conditional(self): line = "if str == type(''):\n pass\n" fixed = "if isinstance('', str):\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_in_conditional_pat2(self): line = "if type(res) == type(42):\n pass\n" fixed = "if isinstance(res, type(42)):\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_in_conditional_pat3(self): line = "if type(res) == str:\n pass\n" fixed = "if isinstance(res, str):\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_in_conditional_with_indent(self): line = "if True:\n if str == type(''):\n pass\n" fixed = "if True:\n if isinstance('', str):\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_in_not_conditional(self): line = "if type(res) != type(''):\n pass\n" fixed = "if not isinstance(res, type('')):\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e721_in_not_conditional_pat2(self): line = "if type(a) != type(b) or type(a) == type(ccc):\n pass\n" fixed = "if not isinstance(a, type(b)) or isinstance(a, type(ccc)):\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e722(self): line = "try:\n print(a)\nexcept:\n pass\n" fixed = "try:\n print(a)\nexcept BaseException:\n pass\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e722_with_if_else_stmt(self): line = "try:\n print(a)\nexcept:\n if a==b:\n print(a)\n else:\n print(b)\n" fixed = "try:\n print(a)\nexcept BaseException:\n if a == b:\n print(a)\n else:\n print(b)\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_e722_non_aggressive(self): line = "try:\n print(a)\nexcept:\n pass\n" with autopep8_context(line, options=[]) as result: self.assertEqual(line, result) def test_e731(self): line = 'a = lambda x: x * 2\n' fixed = 'def a(x): return x * 2\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e731_no_arg(self): line = 'a = lambda: x * 2\n' fixed = 'def a(): return x * 2\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e731_with_tuple_arg(self): line = 'a = lambda (x, y), z: x * 2\n' fixed = 'def a((x, y), z): return x * 2\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e731_with_args(self): line = 'a = lambda x, y: x * 2 + y\n' fixed = 'def a(x, y): return x * 2 + y\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_e731_with_select_option(self): line = 'a = lambda x: x * 2\n' fixed = 'def a(x): return x * 2\n' with autopep8_context(line, options=['--select=E731']) as result: self.assertEqual(fixed, result) def test_e731_with_default_arguments(self): line = 'a = lambda k, d=None: bar.get("%s/%s" % (prefix, k), d)\n' fixed = 'def a(k, d=None): return bar.get("%s/%s" % (prefix, k), d)\n' with autopep8_context(line, options=['--select=E731']) as result: self.assertEqual(fixed, result) class SystemTestsE9(unittest.TestCase): @unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+') def test_e901_should_cause_indentation_screw_up(self): line = """\ def tmp(g): g(4))) if not True: pass pass """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_should_preserve_vertical_tab(self): line = """\ #Memory Bu\vffer Register: """ fixed = """\ # Memory Bu\vffer Register: """ with autopep8_context(line) as result: self.assertEqual(fixed, result) class SystemTestsW1(unittest.TestCase): def test_w191_should_ignore_multiline_strings(self): line = """\ print(3 != 4, ''' while True: if True: \t1 \t''', 4 != 5) if True: \t123 """ fixed = """\ print(3 != 4, ''' while True: if True: \t1 \t''', 4 != 5) if True: 123 """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w191_should_ignore_tabs_in_strings(self): line = """\ if True: \tx = ''' \t\tblah \tif True: \t1 \t''' if True: \t123 else: \t32 """ fixed = """\ if True: x = ''' \t\tblah \tif True: \t1 \t''' if True: 123 else: 32 """ with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) class SystemTestsW2(unittest.TestCase): def test_w291(self): line = "print('a b ')\t \n" fixed = "print('a b ')\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w291_with_comment(self): line = "print('a b ') # comment\t \n" fixed = "print('a b ') # comment\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w292(self): line = '1\n2' fixed = '1\n2\n' with autopep8_context(line, options=['--aggressive', '--select=W292']) as result: self.assertEqual(fixed, result) def test_w292_ignore(self): line = "1\n2" with autopep8_context(line, options=['--aggressive', '--ignore=W292']) as result: self.assertEqual(line, result) def test_w293(self): line = '1\n \n2\n' fixed = '1\n\n2\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) class SystemTestsW3(unittest.TestCase): def test_w391(self): line = ' \n' fixed = '' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w391_more_complex(self): line = '123\n456\n \n' fixed = '123\n456\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) class SystemTestsW5(unittest.TestCase): def test_w503(self): line = '(width == 0\n + height == 0)\n' fixed = '(width == 0 +\n height == 0)\n' with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_with_ignore_w504(self): line = '(width == 0\n + height == 0)\n' fixed = '(width == 0 +\n height == 0)\n' with autopep8_context(line, options=['--ignore=E,W504']) as result: self.assertEqual(fixed, result) def test_w504_with_ignore_w503(self): line = '(width == 0 +\n height == 0)\n' fixed = '(width == 0\n + height == 0)\n' with autopep8_context(line, options=['--ignore=E,W503']) as result: self.assertEqual(fixed, result) def test_w503_w504_none_ignored(self): line = '(width == 0 +\n height == 0\n+ depth == 0)\n' fixed = '(width == 0 +\n height == 0\n+ depth == 0)\n' with autopep8_context(line, options=['--ignore=E']) as result: self.assertEqual(fixed, result) def test_w503_w504_both_ignored(self): line = '(width == 0 +\n height == 0\n+ depth == 0)\n' fixed = '(width == 0 +\n height == 0\n+ depth == 0)\n' with autopep8_context( line, options=['--ignore=E,W503, W504'], ) as result: self.assertEqual(fixed, result) def test_w503_skip_default(self): line = '(width == 0\n + height == 0)\n' with autopep8_context(line) as result: self.assertEqual(line, result) def test_w503_and_or(self): line = '(width == 0\n and height == 0\n or name == "")\n' fixed = '(width == 0 and\n height == 0 or\n name == "")\n' with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_with_comment(self): line = '(width == 0 # this is comment\n + height == 0)\n' fixed = '(width == 0 + # this is comment\n height == 0)\n' with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_with_comment_into_point_out_line(self): line = """\ def test(): return ( True not in [] and False # comment required ) """ fixed = """\ def test(): return ( True not in [] and False # comment required ) """ with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_with_comment_double(self): line = """\ ( 1111 # C1 and 22222222 # C2 and 333333333333 # C3 ) """ fixed = """\ ( 1111 and # C1 22222222 and # C2 333333333333 # C3 ) """ with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_with_comment_with_only_comment_block_charactor(self): line = """\ if (True # and True and True): print(1) """ fixed = """\ if (True and # True and True): print(1) """ with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_over_5lines(self): line = """\ X = ( 1 # 1 + 2 # 2 + 3 # 3 + 4 # 4 + 5 # 5 + 6 # 6 + 7 # 7 ) """ fixed = """\ X = ( 1 + # 1 2 + # 2 3 + # 3 4 + # 4 5 + # 5 6 + # 6 7 # 7 ) """ with autopep8_context(line, options=['--select=W503']) as result: self.assertEqual(fixed, result) def test_w503_with_line_comment(self): line = '(width == 0\n # this is comment\n + height == 0)\n' fixed = '(width == 0 +\n # this is comment\n height == 0)\n' with autopep8_context(line, options=['--select=W503', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_w503_with_empty_line(self): line = """\ # this is comment a = 2 b = (1 + 2 + 3) / 2.0 """ fixed = """\ # this is comment a = 2 b = (1 + 2 + 3) / 2.0 """ with autopep8_context(line, options=['--ignore=E721']) as result: self.assertEqual(fixed, result) def test_w503_with_line_comments(self): line = '(width == 0\n # this is comment\n # comment2\n + height == 0)\n' fixed = '(width == 0 +\n # this is comment\n # comment2\n height == 0)\n' with autopep8_context(line, options=['--select=W503', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_ignore_only_w503_with_select_w(self): line = """\ a = ( 11 + 22 + 33 + 44 + 55 ) """ fixed = """\ a = ( 11 + 22 + 33 + 44 + 55 ) """ with autopep8_context(line, options=['--select=W', '--ignore=W503']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['--select=W5', '--ignore=W503']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['--select=W50', '--ignore=W503']) as result: self.assertEqual(fixed, result) def test_ignore_only_w504_with_select_w(self): line = """\ a = ( 11 + 22 + 33 + 44 + 55 ) """ fixed = """\ a = ( 11 + 22 + 33 + 44 + 55 ) """ with autopep8_context(line, options=['--select=W', '--ignore=W504']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['--select=W5', '--ignore=W504']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['--select=W50', '--ignore=W504']) as result: self.assertEqual(fixed, result) def test_ignore_w503_and_w504_with_select_w(self): line = """\ a = ( 11 + 22 + 33 + 44 + 55 ) """ with autopep8_context(line, options=['--select=W', '--ignore=W503,W504']) as result: self.assertEqual(line, result) with autopep8_context(line, options=['--select=W5', '--ignore=W503,W504']) as result: self.assertEqual(line, result) with autopep8_context(line, options=['--select=W50', '--ignore=W503,W504']) as result: self.assertEqual(line, result) def test_w504(self): line = '(width == 0 +\n height == 0)\n' fixed = '(width == 0\n + height == 0)\n' with autopep8_context(line, options=['--select=W504', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_w504_comment_on_first_line(self): line = 'x = (1 | # test\n2)\n' fixed = 'x = (1 # test\n| 2)\n' with autopep8_context(line, options=['--select=W504', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_w504_comment_on_second_line(self): line = 'x = (1 |\n2) # test\n' fixed = 'x = (1\n| 2) # test\n' with autopep8_context(line, options=['--select=W504', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_w504_comment_on_each_lines(self): line = 'x = (1 |# test\n2 |# test\n3) # test\n' fixed = 'x = (1# test\n| 2# test\n| 3) # test\n' with autopep8_context(line, options=['--select=W504', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_w504_with_e265_ignore_option(self): line = '(width == 0 +\n height == 0)\n' with autopep8_context(line, options=['--ignore=E265']) as result: self.assertEqual(line, result) def test_w504_with_e265_ignore_option_regression(self): line = """\ if True: if True: if ( link.is_wheel and isinstance(link.comes_from, HTMLPage) and link.comes_from.url.startswith(index_url) ): _store_wheel_in_cache(file_path, index_url) """ with autopep8_context(line, options=['--ignore=E265']) as result: self.assertEqual(line, result) def test_w504_with_line_comment(self): line = '(width == 0 +\n # this is comment\n height == 0)\n' fixed = '(width == 0\n # this is comment\n + height == 0)\n' with autopep8_context(line, options=['--select=W504', '--ignore=E']) as result: self.assertEqual(fixed, result) def test_w504_not_applied_by_default_when_modifying_with_ignore(self): line = """\ q = 1 def x(y, z): if ( y and z ): pass """ fixed = line.replace('\n\n\n\n', '\n\n') with autopep8_context(line, options=['--ignore=E265']) as result: self.assertEqual(fixed, result) def test_w503_and_w504_conflict(self): line = """\ if True: if True: assert_equal(self.nodes[0].getbalance( ), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx """ fixed = """\ if True: if True: assert_equal( self.nodes[0].getbalance(), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx """ with autopep8_context(line, options=['-aa', '--select=E,W']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['-aa', '--select=E,W5']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['-aa', '--select=E,W50']) as result: self.assertEqual(fixed, result) class SystemTestsW6(unittest.TestCase): def test_w605_simple(self): line = "escape = '\\.jpg'\n" fixed = "escape = '\\\\.jpg'\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w605_identical_token(self): # ***NOTE***: The --pep8-passes option is required to prevent an infinite loop in # the old, failing code. DO NOT REMOVE. line = "escape = foo('\\.bar', '\\.kilroy')\n" fixed = "escape = foo('\\\\.bar', '\\\\.kilroy')\n" with autopep8_context(line, options=['--aggressive', '--pep8-passes', '5']) as result: self.assertEqual(fixed, result, "Two tokens get r added") line = "escape = foo('\\.bar', '\\\\.kilroy')\n" fixed = "escape = foo('\\\\.bar', '\\\\.kilroy')\n" with autopep8_context(line, options=['--aggressive', '--pep8-passes', '5']) as result: self.assertEqual(fixed, result, "r not added if already there") # Test Case to catch bad behavior reported in Issue #449 line = "escape = foo('\\.bar', '\\.bar')\n" fixed = "escape = foo('\\\\.bar', '\\\\.bar')\n" with autopep8_context(line, options=['--aggressive', '--pep8-passes', '5']) as result: self.assertEqual(fixed, result) def test_w605_with_invalid_syntax(self): line = "escape = rr'\\.jpg'\n" fixed = "escape = rr'\\\\.jpg'\n" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_w605_with_multilines(self): line = """\ regex = '\\d+(\\.\\d+){3}$' foo = validators.RegexValidator( regex='\\d+(\\.\\d+){3}$')\n""" # noqa fixed = """\ regex = '\\\\d+(\\\\.\\\\d+){3}$' foo = validators.RegexValidator( regex='\\\\d+(\\\\.\\\\d+){3}$')\n""" with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_trailing_whitespace_in_multiline_string(self): line = 'x = """ \nhello""" \n' fixed = 'x = """ \nhello"""\n' with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_trailing_whitespace_in_multiline_string_aggressive(self): line = 'x = """ \nhello""" \n' fixed = 'x = """\nhello"""\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(fixed, result) def test_execfile_in_lambda_should_not_be_modified(self): """Modifying this to the exec() form is invalid in Python 2.""" line = 'lambda: execfile("foo.py")\n' with autopep8_context(line, options=['--aggressive']) as result: self.assertEqual(line, result) # FIXME: These tests should use multiline strings for readability. def test_range(self): line = 'print( 1 )\nprint( 2 )\n print( 3 )\n' fixed = 'print( 1 )\nprint(2)\n print( 3 )\n' with autopep8_context(line, options=['--line-range', '2', '2']) as result: self.assertEqual(fixed, result) def test_range_line_number_changes_from_one_line(self): line = 'a=12\na=1; b=2;c=3\nd=4;\n\ndef f(a = 1):\n pass\n' fixed = 'a=12\na = 1\nb = 2\nc = 3\nd=4;\n\ndef f(a = 1):\n pass\n' with autopep8_context(line, options=['--line-range', '2', '2']) as result: self.assertEqual(fixed, result) def test_range_indent_changes_small_range(self): line = '\nif True:\n (1, \n 2,\n3)\nelif False:\n a = 1\nelse:\n a = 2\n\nc = 1\nif True:\n c = 2\n a = (1,\n2)\n' fixed2_5 = '\nif True:\n (1,\n 2,\n 3)\nelif False:\n a = 1\nelse:\n a = 2\n\nc = 1\nif True:\n c = 2\n a = (1,\n2)\n' with autopep8_context(line, options=['--line-range', '2', '5']) as result: self.assertEqual(fixed2_5, result) def test_range_indent_deep_if_blocks_first_block(self): line = '\nif a:\n if a = 1:\n b = 1\n else:\n b = 2\nelif a == 0:\n b = 3\nelse:\n b = 4\n' with autopep8_context(line, options=['--line-range', '2', '5']) as result: self.assertEqual(line, result) def test_range_indent_deep_if_blocks_second_block(self): line = '\nif a:\n if a = 1:\n b = 1\n else:\n b = 2\nelif a == 0:\n b = 3\nelse:\n b = 4\n' with autopep8_context(line, options=['--line-range', '6', '9']) as result: self.assertEqual(line, result) def test_range_indent_continued_statements_partial(self): line = '\nif a == 1:\n\ttry:\n\t foo\n\texcept AttributeError:\n\t pass\n\telse:\n\t "nooo"\n\tb = 1\n' with autopep8_context(line, options=['--line-range', '2', '6']) as result: self.assertEqual(line, result) def test_range_indent_continued_statements_last_block(self): line = '\nif a == 1:\n\ttry:\n\t foo\n\texcept AttributeError:\n\t pass\n\telse:\n\t "nooo"\n\tb = 1\n' with autopep8_context(line, options=['--line-range', '6', '9']) as result: self.assertEqual(line, result) def test_range_with_broken_syntax(self): line = """\ if True: if True: pass else: pass """ with autopep8_context(line, options=['--line-range', '1', '1']) as result: self.assertEqual(line, result) def test_long_import_line(self): line = """\ s from t import a, \ bbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddddddddddddddd """ fixed = """\ from t import a, \ bbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddddddddddddddd s """ with autopep8_context(line) as result: self.assertEqual(fixed, result) def test_exchange_multiple_imports_with_def(self): line = """\ def f(n): return n from a import fa from b import fb from c import fc """ with autopep8_context(line) as result: self.assertEqual(result[:4], 'from') @unittest.skipIf( (sys.version_info.major >= 3 and sys.version_info.minor < 8) or sys.version_info.major < 3, "syntax error in Python3.7 and lower version", ) def test_with_walrus_operator(self): """check pycodestyle 2.6.0+""" line = """\ sql_stmt = "" with open(filename) as f: while line := f.readline(): sql_stmt += line """ with autopep8_context(line) as result: self.assertEqual(line, result) def test_autopep8_disable(self): test_code = """\ # autopep8: off def f(): aaaaaaaaaaa.bbbbbbb([ ('xxxxxxxxxx', 'yyyyyy', 'Heaven hath no wrath like love to hatred turned. Nor hell a fury like a woman scorned.'), ('xxxxxxx', 'yyyyyyyyyyy', "To the last I grapple with thee. From hell's heart I stab at thee. For hate's sake I spit my last breath at thee!")]) # autopep8: on """ expected_output = """\ # autopep8: off def f(): aaaaaaaaaaa.bbbbbbb([ ('xxxxxxxxxx', 'yyyyyy', 'Heaven hath no wrath like love to hatred turned. Nor hell a fury like a woman scorned.'), ('xxxxxxx', 'yyyyyyyyyyy', "To the last I grapple with thee. From hell's heart I stab at thee. For hate's sake I spit my last breath at thee!")]) # autopep8: on """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_autopep8_disable_multi(self): test_code = """\ fix=1 # autopep8: off skip=1 # autopep8: on fix=2 # autopep8: off skip=2 # autopep8: on fix=3 """ expected_output = """\ fix = 1 # autopep8: off skip=1 # autopep8: on fix = 2 # autopep8: off skip=2 # autopep8: on fix = 3 """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_disable(self): test_code = """\ # fmt: off def f(): aaaaaaaaaaa.bbbbbbb([ ('xxxxxxxxxx', 'yyyyyy', 'Heaven hath no wrath like love to hatred turned. Nor hell a fury like a woman scorned.'), ('xxxxxxx', 'yyyyyyyyyyy', "To the last I grapple with thee. From hell's heart I stab at thee. For hate's sake I spit my last breath at thee!")]) # fmt: on """ expected_output = """\ # fmt: off def f(): aaaaaaaaaaa.bbbbbbb([ ('xxxxxxxxxx', 'yyyyyy', 'Heaven hath no wrath like love to hatred turned. Nor hell a fury like a woman scorned.'), ('xxxxxxx', 'yyyyyyyyyyy', "To the last I grapple with thee. From hell's heart I stab at thee. For hate's sake I spit my last breath at thee!")]) # fmt: on """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_disable_without_reenable(self): test_code = """\ # fmt: off print(123) """ expected_output = """\ # fmt: off print(123) """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_disable_with_double_reenable(self): test_code = """\ # fmt: off print( 123 ) # fmt: on print( 123 ) # fmt: on print( 123 ) """ expected_output = """\ # fmt: off print( 123 ) # fmt: on print(123) # fmt: on print(123) """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_double_disable_and_reenable(self): test_code = """\ # fmt: off print( 123 ) # fmt: off print( 123 ) # fmt: on print( 123 ) """ expected_output = """\ # fmt: off print( 123 ) # fmt: off print( 123 ) # fmt: on print(123) """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_multi_disable_and_reenable(self): test_code = """\ fix=1 # fmt: off skip=1 # fmt: on fix=2 # fmt: off skip=2 # fmt: on fix=3 """ expected_output = """\ fix = 1 # fmt: off skip=1 # fmt: on fix = 2 # fmt: off skip=2 # fmt: on fix = 3 """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_multi_disable_complex(self): test_code = """\ fix=1 # fmt: off skip=1 # fmt: off fix=2 # fmt: off skip=2 # fmt: on fix=3 """ expected_output = """\ fix = 1 # fmt: off skip=1 # fmt: off fix=2 # fmt: off skip=2 # fmt: on fix = 3 """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_fmt_multi_disable_complex_multi(self): test_code = """\ fix=1 # fmt: off skip=1 # fmt: off fix=2 # fmt: on fix=22 # fmt: on fix=222 # fmt: off skip=2 # fmt: on fix=3 """ expected_output = """\ fix = 1 # fmt: off skip=1 # fmt: off fix=2 # fmt: on fix = 22 # fmt: on fix = 222 # fmt: off skip=2 # fmt: on fix = 3 """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) def test_general_disable(self): test_code = """\ # fmt: off import math, sys; def example1(): # This is a long comment. This should be wrapped to fit within 72 characters. some_tuple=( 1,2, 3,'a' ); some_variable={'long':'Long code lines should be wrapped within 79 characters.', 'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'], 'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1, 20,300,40000,500000000,60000000000000000]}} return (some_tuple, some_variable) def example2(): return {'has_key() is deprecated':True}.has_key( {'f':2}.has_key('')); class Example3( object ): def __init__ ( self, bar ): # Comments should have a space after the hash. if bar : bar+=1; bar=bar* bar ; return bar else: some_string = ''' Indentation in multiline strings should not be touched. Only actual code should be reindented. ''' return (sys.path, some_string) # fmt: on import math, sys; def example1(): # This is a long comment. This should be wrapped to fit within 72 characters. some_tuple=( 1,2, 3,'a' ); some_variable={'long':'Long code lines should be wrapped within 79 characters.', 'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'], 'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1, 20,300,40000,500000000,60000000000000000]}} return (some_tuple, some_variable) def example2(): return {'has_key() is deprecated':True}.has_key( {'f':2}.has_key('')); class Example3( object ): def __init__ ( self, bar ): # Comments should have a space after the hash. if bar : bar+=1; bar=bar* bar ; return bar else: some_string = ''' Indentation in multiline strings should not be touched. Only actual code should be reindented. ''' return (sys.path, some_string) """ expected_output = """\ # fmt: off import sys import math import math, sys; def example1(): # This is a long comment. This should be wrapped to fit within 72 characters. some_tuple=( 1,2, 3,'a' ); some_variable={'long':'Long code lines should be wrapped within 79 characters.', 'other':[math.pi, 100,200,300,9876543210,'This is a long string that goes on'], 'more':{'inner':'This whole logical line should be wrapped.',some_tuple:[1, 20,300,40000,500000000,60000000000000000]}} return (some_tuple, some_variable) def example2(): return {'has_key() is deprecated':True}.has_key( {'f':2}.has_key('')); class Example3( object ): def __init__ ( self, bar ): # Comments should have a space after the hash. if bar : bar+=1; bar=bar* bar ; return bar else: some_string = ''' Indentation in multiline strings should not be touched. Only actual code should be reindented. ''' return (sys.path, some_string) # fmt: on def example1(): # This is a long comment. This should be wrapped to fit within 72 characters. some_tuple = (1, 2, 3, 'a') some_variable = {'long': 'Long code lines should be wrapped within 79 characters.', 'other': [math.pi, 100, 200, 300, 9876543210, 'This is a long string that goes on'], 'more': {'inner': 'This whole logical line should be wrapped.', some_tuple: [1, 20, 300, 40000, 500000000, 60000000000000000]}} return (some_tuple, some_variable) def example2(): return {'has_key() is deprecated': True}.has_key( {'f': 2}.has_key('')) class Example3(object): def __init__(self, bar): # Comments should have a space after the hash. if bar: bar += 1 bar = bar * bar return bar else: some_string = ''' Indentation in multiline strings should not be touched. Only actual code should be reindented. ''' return (sys.path, some_string) """ with autopep8_context(test_code) as result: self.assertEqual(expected_output, result) class UtilityFunctionTests(unittest.TestCase): def test_get_module_imports(self): line = """\ import os import sys if True: print(1) """ target_line_index = 8 result = get_module_imports_on_top_of_file(line.splitlines(), target_line_index) self.assertEqual(result, 0) def test_get_module_imports_case_of_autopep8(self): line = """\ #!/usr/bin/python # comment # comment '''this module ... this module ... ''' import os import sys if True: print(1) """ target_line_index = 11 result = get_module_imports_on_top_of_file(line.splitlines(), target_line_index) self.assertEqual(result, 10) class CommandLineTests(unittest.TestCase): def test_e122_and_e302_with_backslash(self): line = """\ import sys \\ def f(): pass """ fixed = """\ import sys \\ def f(): pass """ with autopep8_subprocess(line, [], timeout=3) as (result, retcode): self.assertEqual(fixed, result) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_diff(self): line = "'abc' \n" fixed = "-'abc' \n+'abc'\n" with autopep8_subprocess(line, ['--diff']) as (result, retcode): self.assertEqual(fixed, '\n'.join(result.split('\n')[3:])) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_diff_with_exit_code_option(self): line = "'abc' \n" fixed = "-'abc' \n+'abc'\n" with autopep8_subprocess(line, ['--diff', '--exit-code']) as (result, retcode): self.assertEqual(fixed, '\n'.join(result.split('\n')[3:])) self.assertEqual(retcode, autopep8.EXIT_CODE_EXISTS_DIFF) def test_non_diff_with_exit_code_option(self): line = "'abc'\n" with autopep8_subprocess(line, ['--diff', '--exit-code']) as (result, retcode): self.assertEqual('', '\n'.join(result.split('\n')[3:])) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_non_diff_with_exit_code_and_jobs_options(self): line = "'abc'\n" with autopep8_subprocess(line, ['-j0', '--diff', '--exit-code']) as (result, retcode): self.assertEqual('', '\n'.join(result.split('\n')[3:])) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_diff_with_empty_file(self): with autopep8_subprocess('', ['--diff']) as (result, retcode): self.assertEqual('\n'.join(result.split('\n')[3:]), '') self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_diff_with_nonexistent_file(self): p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['--diff', 'non_existent_file'], stdout=PIPE, stderr=PIPE) error = p.communicate()[1].decode('utf-8') self.assertIn('non_existent_file', error) def test_diff_with_standard_in(self): p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['--diff', '-'], stdout=PIPE, stderr=PIPE) error = p.communicate()[1].decode('utf-8') self.assertIn('cannot', error) def test_indent_size_is_zero(self): line = "'abc'\n" p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['--indent-size=0', '-'], stdout=PIPE, stderr=PIPE) _, _err = p.communicate(line.encode('utf-8')) self.assertEqual(p.returncode, autopep8.EXIT_CODE_ARGPARSE_ERROR) self.assertIn('indent-size must be greater than 0\n', _err.decode('utf-8')) self.assertIn('usage: autopep8', _err.decode('utf-8')) def test_exit_code_with_io_error(self): line = "import sys\ndef a():\n print(1)\n" with readonly_temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['--in-place', filename], stdout=PIPE, stderr=PIPE) p.communicate() self.assertEqual(p.returncode, autopep8.EXIT_CODE_ERROR) def test_pep8_passes(self): line = "'abc' \n" fixed = "'abc'\n" with autopep8_subprocess(line, ['--pep8-passes', '0']) as (result, retcode): self.assertEqual(fixed, result) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_pep8_ignore(self): line = "'abc' \n" with autopep8_subprocess(line, ['--ignore=E,W']) as (result, retcode): self.assertEqual(line, result) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_pep8_ignore_should_handle_trailing_comma_gracefully(self): line = "'abc' \n" fixed = "'abc'\n" with autopep8_subprocess(line, ['--ignore=,']) as (result, retcode): self.assertEqual(fixed, result) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_help(self): p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['-h'], stdout=PIPE) self.assertIn('usage:', p.communicate()[0].decode('utf-8').lower()) @unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+') def test_verbose(self): line = 'bad_syntax)' with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '-vvv'], stdout=PIPE, stderr=PIPE) verbose_error = p.communicate()[1].decode('utf-8') self.assertIn("'fix_e901' is not defined", verbose_error) def test_verbose_diff(self): line = '+'.join(100 * ['323424234234']) with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '-vvvv', '--diff'], stdout=PIPE, stderr=PIPE) verbose_error = p.communicate()[1].decode('utf-8') self.assertIn('------------', verbose_error) def test_verbose_with_select_e702(self): line = """\ for i in range(3): if i == 1: print(i); continue print(i) """ with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '-vvv', '--select=E702'], stdout=PIPE, stderr=PIPE) verbose_error = p.communicate()[1].decode('utf-8') self.assertIn(" with other compound statements", verbose_error) def test_in_place(self): line = "'abc' \n" fixed = "'abc'\n" with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place']) p.wait() with open(filename) as f: self.assertEqual(fixed, f.read()) self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_in_place_no_modifications_no_writes(self): with temporary_file_context('import os\n') as filename: # ensure that noops do not do writes by making writing an error os.chmod(filename, 0o444) p = Popen( list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place'], stderr=PIPE, ) _, err = p.communicate() self.assertEqual(err, b'') self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_in_place_no_modifications_no_writes_with_empty_file(self): with temporary_file_context('') as filename: # ensure that noops do not do writes by making writing an error os.chmod(filename, 0o444) p = Popen( list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place'], stderr=PIPE, ) _, err = p.communicate() self.assertEqual(err, b'') self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_in_place_with_w292(self): line = "import os" fixed = "import os\n" with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place']) p.wait() with open(filename) as f: self.assertEqual(fixed, f.read()) def test_in_place_with_exit_code_option(self): line = "'abc' \n" fixed = "'abc'\n" with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place', '--exit-code']) p.wait() with open(filename) as f: self.assertEqual(fixed, f.read()) self.assertEqual(p.returncode, autopep8.EXIT_CODE_EXISTS_DIFF) def test_in_place_with_exit_code_option_with_w391(self): line = "\n\n\n" fixed = "" with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place', '--exit-code']) p.wait() with open(filename) as f: self.assertEqual(fixed, f.read()) self.assertEqual(p.returncode, autopep8.EXIT_CODE_EXISTS_DIFF) def test_parallel_jobs(self): line = "'abc' \n" fixed = "'abc'\n" with temporary_file_context(line) as filename_a: with temporary_file_context(line) as filename_b: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename_a, filename_b, '--jobs=3', '--in-place']) p.wait() with open(filename_a) as f: self.assertEqual(fixed, f.read()) with open(filename_b) as f: self.assertEqual(fixed, f.read()) def test_parallel_jobs_with_diff_option(self): line = "'abc' \n" with temporary_file_context(line) as filename_a: with temporary_file_context(line) as filename_b: files = list({filename_a, filename_b}) p = Popen(list(AUTOPEP8_CMD_TUPLE) + files + ['--jobs=3', '--diff'], stdout=PIPE) p.wait() output = p.stdout.read().decode() output = output.replace("\r\n","\n") # windows compatibility p.stdout.close() actual_diffs = [] for filename in files: actual_diffs.append("""\ --- original/{filename} +++ fixed/{filename} @@ -1 +1 @@ -'abc' {blank} +'abc' """.format(filename=filename, blank="")) # in case the users IDE trims leaning whitespace self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) for actual_diff in actual_diffs: self.assertIn(actual_diff, output) def test_parallel_jobs_with_inplace_option_and_io_error(self): temp_directory = mkdtemp(dir='.') try: file_a = os.path.join(temp_directory, 'a.py') with open(file_a, 'w') as output: output.write("'abc' \n") os.chmod(file_a, stat.S_IRUSR) # readonly os.mkdir(os.path.join(temp_directory, 'd')) file_b = os.path.join(temp_directory, 'd', 'b.py') with open(file_b, 'w') as output: output.write('123 \n') os.chmod(file_b, stat.S_IRUSR) p = Popen(list(AUTOPEP8_CMD_TUPLE) + [temp_directory, '--recursive', '--in-place'], stdout=PIPE, stderr=PIPE) p.communicate()[0].decode('utf-8') self.assertEqual(p.returncode, autopep8.EXIT_CODE_ERROR) finally: shutil.rmtree(temp_directory) def test_parallel_jobs_with_automatic_cpu_count(self): line = "'abc' \n" fixed = "'abc'\n" with temporary_file_context(line) as filename_a: with temporary_file_context(line) as filename_b: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename_a, filename_b, '--jobs=0', '--in-place']) p.wait() with open(filename_a) as f: self.assertEqual(fixed, f.read()) with open(filename_b) as f: self.assertEqual(fixed, f.read()) def test_in_place_with_empty_file(self): line = '' with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place']) p.wait() self.assertEqual(0, p.returncode) with open(filename) as f: self.assertEqual(f.read(), line) def test_in_place_and_diff(self): line = "'abc' \n" with temporary_file_context(line) as filename: p = Popen( list(AUTOPEP8_CMD_TUPLE) + [filename, '--in-place', '--diff'], stderr=PIPE) result = p.communicate()[1].decode('utf-8') self.assertIn('--in-place and --diff are mutually exclusive', result) def test_recursive(self): temp_directory = mkdtemp(dir='.') try: with open(os.path.join(temp_directory, 'a.py'), 'w') as output: output.write("'abc' \n") os.mkdir(os.path.join(temp_directory, 'd')) with open(os.path.join(temp_directory, 'd', 'b.py'), 'w') as output: output.write('123 \n') p = Popen(list(AUTOPEP8_CMD_TUPLE) + [temp_directory, '--recursive', '--diff'], stdout=PIPE) result = p.communicate()[0].decode('utf-8') self.assertEqual( "-'abc' \n+'abc'", '\n'.join(result.split('\n')[3:5])) self.assertEqual( '-123 \n+123', '\n'.join(result.split('\n')[8:10])) finally: shutil.rmtree(temp_directory) def test_recursive_should_not_crash_on_unicode_filename(self): temp_directory = mkdtemp(dir='.') try: for filename in ['x.py', 'é.py', 'é.txt']: with open(os.path.join(temp_directory, filename), 'w'): pass p = Popen(list(AUTOPEP8_CMD_TUPLE) + [temp_directory, '--recursive', '--diff'], stdout=PIPE) self.assertFalse(p.communicate()[0]) self.assertEqual(0, p.returncode) finally: shutil.rmtree(temp_directory) def test_recursive_should_ignore_hidden(self): temp_directory = mkdtemp(dir='.') temp_subdirectory = mkdtemp(prefix='.', dir=temp_directory) try: with open(os.path.join(temp_subdirectory, 'a.py'), 'w') as output: output.write("'abc' \n") p = Popen(list(AUTOPEP8_CMD_TUPLE) + [temp_directory, '--recursive', '--diff'], stdout=PIPE) result = p.communicate()[0].decode('utf-8') self.assertEqual(0, p.returncode) self.assertEqual('', result) finally: shutil.rmtree(temp_directory) def test_exclude(self): temp_directory = mkdtemp(dir='.') try: with open(os.path.join(temp_directory, 'a.py'), 'w') as output: output.write("'abc' \n") os.mkdir(os.path.join(temp_directory, 'd')) with open(os.path.join(temp_directory, 'd', 'b.py'), 'w') as output: output.write('123 \n') p = Popen(list(AUTOPEP8_CMD_TUPLE) + [temp_directory, '--recursive', '--exclude=a*', '--diff'], stdout=PIPE) result = p.communicate()[0].decode('utf-8') self.assertNotIn('abc', result) self.assertIn('123', result) finally: shutil.rmtree(temp_directory) def test_exclude_with_directly_file_args(self): temp_directory = mkdtemp(dir='.') try: filepath_a = os.path.join(temp_directory, 'a.py') with open(filepath_a, 'w') as output: output.write("'abc' \n") os.mkdir(os.path.join(temp_directory, 'd')) filepath_b = os.path.join(temp_directory, 'd', 'b.py') with open(os.path.join(filepath_b), 'w') as output: output.write('123 \n') p = Popen(list(AUTOPEP8_CMD_TUPLE) + ['--exclude=*/a.py', '--diff', filepath_a, filepath_b], stdout=PIPE) result = p.communicate()[0].decode('utf-8') self.assertNotIn('abc', result) self.assertIn('123', result) finally: shutil.rmtree(temp_directory) def test_invalid_option_combinations(self): line = "'abc' \n" with temporary_file_context(line) as filename: for options in [['--recursive', filename], # without --diff ['--jobs=2', filename], # without --diff ['--max-line-length=0', filename], [], # no argument ['-', '--in-place'], ['-', '--recursive'], ['-', filename], ['--line-range', '0', '2', filename], ['--line-range', '2', '1', filename], ['--line-range', '-1', '-1', filename], ]: p = Popen(list(AUTOPEP8_CMD_TUPLE) + options, stderr=PIPE) result = p.communicate()[1].decode('utf-8') self.assertNotEqual(0, p.returncode, msg=str(options)) self.assertTrue(len(result)) def test_list_fixes(self): with autopep8_subprocess('', options=['--list-fixes']) as (result, retcode): self.assertIn('E121', result) self.assertEqual(retcode, autopep8.EXIT_CODE_OK) def test_fixpep8_class_constructor(self): line = 'print(1)\nprint(2)\n' with temporary_file_context(line) as filename: pep8obj = autopep8.FixPEP8(filename, None) self.assertEqual(''.join(pep8obj.source), line) def test_inplace_with_multi_files(self): exception = None with disable_stderr(): try: autopep8.parse_args(['test.py', 'dummy.py']) except SystemExit as e: exception = e self.assertTrue(exception) self.assertEqual(exception.code, autopep8.EXIT_CODE_ARGPARSE_ERROR) def test_standard_out_should_use_native_line_ending(self): line = '1\r\n2\r\n3\r\n' with temporary_file_context(line) as filename: process = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename], stdout=PIPE) self.assertEqual( os.linesep.join(['1', '2', '3', '']), process.communicate()[0].decode('utf-8')) def test_standard_out_should_use_native_line_ending_with_cr_input(self): line = '1\r2\r3\r' with temporary_file_context(line) as filename: process = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename], stdout=PIPE) self.assertEqual( os.linesep.join(['1', '2', '3', '']), process.communicate()[0].decode('utf-8')) def test_standard_in(self): line = 'print( 1 )\n' fixed = 'print(1)' + os.linesep process = Popen(list(AUTOPEP8_CMD_TUPLE) + ['-'], stdout=PIPE, stdin=PIPE) self.assertEqual( fixed, process.communicate(line.encode('utf-8'))[0].decode('utf-8')) def test_exit_code_should_be_set_when_standard_in(self): line = 'print( 1 )\n' process = Popen(list(AUTOPEP8_CMD_TUPLE) + ['--exit-code', '-'], stdout=PIPE, stdin=PIPE) process.communicate(line.encode('utf-8'))[0].decode('utf-8') self.assertEqual( process.returncode, autopep8.EXIT_CODE_EXISTS_DIFF) def test_non_args(self): process = Popen(list(AUTOPEP8_CMD_TUPLE) + [], stderr=PIPE, stdout=PIPE, stdin=PIPE) _output, _error = process.communicate() self.assertEqual( process.returncode, autopep8.EXIT_CODE_ARGPARSE_ERROR) self.assertEqual(_output.decode("utf-8"), "") self.assertIn( "incorrect number of arguments\n", _error.decode("utf-8"), ) class ConfigurationTests(unittest.TestCase): def test_local_config(self): args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config={}'.format(os.devnull), '-vvv'], apply_config=True) self.assertEqual(args.indent_size, 2) def test_config_override(self): args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--indent-size=7'], apply_config=True) self.assertEqual(args.indent_size, 7) def test_config_false_with_local(self): args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config=False'], apply_config=True) self.assertEqual(args.global_config, 'False') self.assertEqual(args.indent_size, 2) def test_config_false_with_local_space(self): args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config', 'False'], apply_config=True) self.assertEqual(args.global_config, 'False') self.assertEqual(args.indent_size, 2) def test_local_pycodestyle_config_line_length(self): args = autopep8.parse_args( [os.path.join(FAKE_PYCODESTYLE_CONFIGURATION, 'foo.py'), '--global-config={}'.format(os.devnull)], apply_config=True) self.assertEqual(args.max_line_length, 40) def test_config_false_with_local_autocomplete(self): args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--g', 'False'], apply_config=True) self.assertEqual(args.global_config, 'False') self.assertEqual(args.indent_size, 2) def test_config_false_without_local(self): args = autopep8.parse_args(['/nowhere/foo.py', '--global-config={}'.format(os.devnull)], apply_config=True) self.assertEqual(args.indent_size, 4) def test_global_config_with_locals(self): with temporary_file_context('[pep8]\nindent-size=3\n') as filename: args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config={}'.format(filename)], apply_config=True) self.assertEqual(args.indent_size, 2) def test_global_config_ignore_locals(self): with temporary_file_context('[pep8]\nindent-size=3\n') as filename: args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config={}'.format(filename), '--ignore-local-config'], apply_config=True) self.assertEqual(args.indent_size, 3) def test_global_config_without_locals(self): with temporary_file_context('[pep8]\nindent-size=3\n') as filename: args = autopep8.parse_args( ['/nowhere/foo.py', '--global-config={}'.format(filename)], apply_config=True) self.assertEqual(args.indent_size, 3) def test_config_local_int_value(self): with temporary_file_context('[pep8]\naggressive=1\n') as filename: args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config={}'.format(filename)], apply_config=True) self.assertEqual(args.aggressive, 1) def test_config_local_inclue_invalid_key(self): configstr = """\ [pep8] count=True aggressive=1 """ with temporary_file_context(configstr) as filename: args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--global-config={}'.format(filename)], apply_config=True) self.assertEqual(args.aggressive, 1) def test_pyproject_toml_config_local_int_value(self): with temporary_file_context('[tool.autopep8]\naggressive=2\n') as filename: args = autopep8.parse_args( [os.path.join(FAKE_CONFIGURATION, 'foo.py'), '--ignore-local-config', '--global-config={}'.format(filename)], apply_config=True) self.assertEqual(args.aggressive, 2) class ConfigurationFileTests(unittest.TestCase): def test_pyproject_toml_with_flake8_config(self): """override to flake8 config""" line = "a = 1\n" dot_flake8 = """[pep8]\naggressive=0\n""" pyproject_toml = """[tool.autopep8]\naggressvie=2\nignore="E,W"\n""" with temporary_project_directory() as dirname: with open(os.path.join(dirname, "pyproject.toml"), "w") as fp: fp.write(pyproject_toml) with open(os.path.join(dirname, ".flake8"), "w") as fp: fp.write(dot_flake8) target_filename = os.path.join(dirname, "foo.py") with open(target_filename, "w") as fp: fp.write(line) p = Popen(list(AUTOPEP8_CMD_TUPLE) + [target_filename], stdout=PIPE) self.assertEqual(p.communicate()[0].decode("utf-8"), line) self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_pyproject_toml_with_verbose_option(self): """override to flake8 config""" line = "a = 1\n" verbose_line = "enable pyproject.toml config: key=ignore, value=E,W\n" pyproject_toml = """[tool.autopep8]\naggressvie=2\nignore="E,W"\n""" with temporary_project_directory() as dirname: with open(os.path.join(dirname, "pyproject.toml"), "w") as fp: fp.write(pyproject_toml) target_filename = os.path.join(dirname, "foo.py") with open(target_filename, "w") as fp: fp.write(line) p = Popen(list(AUTOPEP8_CMD_TUPLE) + [target_filename, "-vvv"], stdout=PIPE) output = p.communicate()[0].decode("utf-8") self.assertTrue(line in output) self.assertTrue(verbose_line in output) self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_pyproject_toml_with_iterable_value(self): line = "a = 1\n" pyproject_toml = """[tool.autopep8]\naggressvie=2\nignore=["E","W"]\n""" with temporary_project_directory() as dirname: with open(os.path.join(dirname, "pyproject.toml"), "w") as fp: fp.write(pyproject_toml) target_filename = os.path.join(dirname, "foo.py") with open(target_filename, "w") as fp: fp.write(line) p = Popen(list(AUTOPEP8_CMD_TUPLE) + [target_filename, ], stdout=PIPE) output = p.communicate()[0].decode("utf-8") self.assertTrue(line in output) self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_setupcfg_with_flake8_config(self): line = "a = 1\n" fixed = "a = 1\n" setupcfg_flake8 = """[flake8]\njobs=auto\n""" with temporary_project_directory() as dirname: with open(os.path.join(dirname, "setup.cfg"), "w") as fp: fp.write(setupcfg_flake8) target_filename = os.path.join(dirname, "foo.py") with open(target_filename, "w") as fp: fp.write(line) p = Popen(list(AUTOPEP8_CMD_TUPLE) + [target_filename, "-v"], stdout=PIPE) output = p.communicate()[0].decode("utf-8") self.assertTrue(fixed in output) self.assertTrue("ignore config: jobs=auto" in output) self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) def test_setupcfg_with_pycodestyle_config(self): line = "a = 1\n" fixed = "a = 1\n" setupcfg_flake8 = """[pycodestyle]\ndiff=True\nignore="E,W"\n""" with temporary_project_directory() as dirname: with open(os.path.join(dirname, "setup.cfg"), "w") as fp: fp.write(setupcfg_flake8) target_filename = os.path.join(dirname, "foo.py") with open(target_filename, "w") as fp: fp.write(line) p = Popen(list(AUTOPEP8_CMD_TUPLE) + [target_filename, "-v"], stdout=PIPE) output = p.communicate()[0].decode("utf-8") self.assertTrue(fixed in output) self.assertEqual(p.returncode, autopep8.EXIT_CODE_OK) class ExperimentalSystemTests(unittest.TestCase): def test_e501_experimental_basic(self): line = """\ print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_commas_and_colons(self): line = """\ foobar = {'aaaaaaaaaaaa': 'bbbbbbbbbbbbbbbb', 'dddddd': 'eeeeeeeeeeeeeeee', 'ffffffffffff': 'gggggggg'} """ fixed = """\ foobar = {'aaaaaaaaaaaa': 'bbbbbbbbbbbbbbbb', 'dddddd': 'eeeeeeeeeeeeeeee', 'ffffffffffff': 'gggggggg'} """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_inline_comments(self): line = """\ ' ' # Long inline comments should be moved above. if True: ' ' # Long inline comments should be moved above. """ fixed = """\ # Long inline comments should be moved above. ' ' if True: # Long inline comments should be moved above. ' ' """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_inline_comments_should_skip_multiline( self): line = """\ '''This should be left alone. ----------------------------------------------------- ''' # foo '''This should be left alone. ----------------------------------------------------- ''' \\ # foo '''This should be left alone. ----------------------------------------------------- ''' \\ \\ # foo """ fixed = """\ '''This should be left alone. ----------------------------------------------------- ''' # foo '''This should be left alone. ----------------------------------------------------- ''' # foo '''This should be left alone. ----------------------------------------------------- ''' # foo """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_inline_comments_should_skip_keywords(self): line = """\ ' ' # noqa Long inline comments should be moved above. if True: ' ' # pylint: disable-msgs=E0001 ' ' # pragma: no cover ' ' # pragma: no cover """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(line, result) def test_e501_experimental_with_inline_comments_should_skip_edge_cases( self): line = """\ if True: x = \\ ' ' # Long inline comments should be moved above. """ fixed = """\ if True: # Long inline comments should be moved above. x = ' ' """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_basic_should_prefer_balanced_brackets(self): line = """\ if True: reconstructed = iradon(radon(image), filter="ramp", interpolation="nearest") """ fixed = """\ if True: reconstructed = iradon( radon(image), filter="ramp", interpolation="nearest") """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_very_long_line(self): line = """\ x = [3244234243234, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243] """ fixed = """\ x = [3244234243234, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243, 234234234324, 234234324, 23424234, 234234234, 234234, 234243, 234243] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_shorten_at_commas_skip(self): line = """\ parser.add_argument('source_corpus', help='corpus name/path relative to an nltk_data directory') parser.add_argument('target_corpus', help='corpus name/path relative to an nltk_data directory') """ fixed = """\ parser.add_argument( 'source_corpus', help='corpus name/path relative to an nltk_data directory') parser.add_argument( 'target_corpus', help='corpus name/path relative to an nltk_data directory') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_shorter_length(self): line = """\ foooooooooooooooooo('abcdefghijklmnopqrstuvwxyz') """ fixed = """\ foooooooooooooooooo( 'abcdefghijklmnopqrstuvwxyz') """ with autopep8_context(line, options=['--max-line-length=40', '--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_indent(self): line = """\ def d(): print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ def d(): print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_alone_with_indentation(self): line = """\ if True: print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ if True: print(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line, options=['--select=E501', '--experimental']) as result: self.assertEqual(fixed, result) @unittest.skip('Not sure why space is not removed anymore') def test_e501_experimental_alone_with_tuple(self): line = """\ fooooooooooooooooooooooooooooooo000000000000000000000000 = [1, ('TransferTime', 'FLOAT') ] """ fixed = """\ fooooooooooooooooooooooooooooooo000000000000000000000000 = [ 1, ('TransferTime', 'FLOAT')] """ with autopep8_context(line, options=['--select=E501', '--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_should_not_try_to_break_at_every_paren_in_arithmetic( self): line = """\ term3 = w6 * c5 * (8.0 * psi4 * (11.0 - 24.0 * t2) - 28 * psi3 * (1 - 6.0 * t2) + psi2 * (1 - 32 * t2) - psi * (2.0 * t2) + t4) / 720.0 this_should_be_shortened = (' ', ' ') """ fixed = """\ term3 = w6 * c5 * (8.0 * psi4 * (11.0 - 24.0 * t2) - 28 * psi3 * (1 - 6.0 * t2) + psi2 * (1 - 32 * t2) - psi * (2.0 * t2) + t4) / 720.0 this_should_be_shortened = ( ' ', ' ') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_arithmetic_operator_with_indent(self): line = """\ def d(): 111 + 111 + 111 + 111 + 111 + 222 + 222 + 222 + 222 + 222 + 222 + 222 + 222 + 222 + 333 + 333 + 333 + 333 """ fixed = """\ def d(): 111 + 111 + 111 + 111 + 111 + 222 + 222 + 222 + 222 + \\ 222 + 222 + 222 + 222 + 222 + 333 + 333 + 333 + 333 """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_more_complicated(self): line = """\ blahblah = os.environ.get('blahblah') or os.environ.get('blahblahblah') or os.environ.get('blahblahblahblah') """ fixed = """\ blahblah = os.environ.get('blahblah') or os.environ.get( 'blahblahblah') or os.environ.get('blahblahblahblah') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_skip_even_more_complicated(self): line = """\ if True: if True: if True: blah = blah.blah_blah_blah_bla_bl(blahb.blah, blah.blah, blah=blah.label, blah_blah=blah_blah, blah_blah2=blah_blah) """ fixed = """\ if True: if True: if True: blah = blah.blah_blah_blah_bla_bl( blahb.blah, blah.blah, blah=blah.label, blah_blah=blah_blah, blah_blah2=blah_blah) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_logical_fix(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_logical_fix_and_physical_fix(self): line = """\ # ------ ------------------------------------------------------------------------ xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ fixed = """\ # ------ ----------------------------------------------------------------- xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_logical_fix_and_adjacent_strings(self): line = """\ print('a-----------------------' 'b-----------------------' 'c-----------------------' 'd-----------------------''e'"f"r"g") """ fixed = """\ print( 'a-----------------------' 'b-----------------------' 'c-----------------------' 'd-----------------------' 'e' "f" r"g") """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_multiple_lines(self): line = """\ foo_bar_zap_bing_bang_boom(111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333) """ fixed = """\ foo_bar_zap_bing_bang_boom( 111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333, 111, 111, 111, 111, 222, 222, 222, 222, 222, 222, 222, 222, 222, 333, 333) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_do_not_break_on_keyword(self): # We don't want to put a newline after equals for keywords as this # violates PEP 8. line = """\ if True: long_variable_name = tempfile.mkstemp(prefix='abcdefghijklmnopqrstuvwxyz0123456789') """ fixed = """\ if True: long_variable_name = tempfile.mkstemp( prefix='abcdefghijklmnopqrstuvwxyz0123456789') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_do_not_begin_line_with_comma(self): line = """\ def dummy(): if True: if True: if True: object = ModifyAction( [MODIFY70.text, OBJECTBINDING71.text, COLON72.text], MODIFY70.getLine(), MODIFY70.getCharPositionInLine() ) """ fixed = """\ def dummy(): if True: if True: if True: object = ModifyAction( [MODIFY70.text, OBJECTBINDING71.text, COLON72.text], MODIFY70.getLine(), MODIFY70.getCharPositionInLine()) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_should_not_break_on_dot(self): line = """\ if True: if True: raise xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx('xxxxxxxxxxxxxxxxx "{d}" xxxxxxxxxxxxxx'.format(d='xxxxxxxxxxxxxxx')) """ fixed = """\ if True: if True: raise xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( 'xxxxxxxxxxxxxxxxx "{d}" xxxxxxxxxxxxxx'.format( d='xxxxxxxxxxxxxxx')) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_comment(self): line = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. pass # http://foo.bar/abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc- # The following is ugly commented-out code and should not be touched. #xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 1 """ fixed = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will # wrap it using textwrap to be within 72 characters. pass # http://foo.bar/abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc-abc- # The following is ugly commented-out code and should not be touched. # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 1 """ with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_comment_should_not_modify_docstring(self): line = '''\ def foo(): """ # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. """ ''' with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(line, result) def test_e501_experimental_should_only_modify_last_comment(self): line = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 1. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 2. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 3. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. """ fixed = """123 if True: if True: if True: if True: if True: if True: # This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 1. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 2. This is a long comment that should be wrapped. I will wrap it using textwrap to be within 72 characters. # 3. This is a long comment that should be wrapped. I # will wrap it using textwrap to be within 72 # characters. """ with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_experimental_should_not_interfere_with_non_comment(self): line = ''' """ # not actually a comment %d. 12345678901234567890, 12345678901234567890, 12345678901234567890. """ % (0,) ''' with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(line, result) def test_e501_experimental_should_cut_comment_pattern(self): line = """123 # -- Useless lines ---------------------------------------------------------------------- 321 """ fixed = """123 # -- Useless lines ------------------------------------------------------- 321 """ with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_function_should_not_break_on_colon(self): line = r""" class Useless(object): def _table_field_is_plain_widget(self, widget): if widget.__class__ == Widget or\ (widget.__class__ == WidgetMeta and Widget in widget.__bases__): return True return False """ fixed = r""" class Useless(object): def _table_field_is_plain_widget(self, widget): if widget.__class__ == Widget or ( widget.__class__ == WidgetMeta and Widget in widget.__bases__): return True return False """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental(self): line = """\ models = { 'auth.group': { 'Meta': {'object_name': 'Group'}, 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) }, 'auth.permission': { 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) }, } """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(line, result) def test_e501_experimental_and_multiple_logical_lines(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) xxxxxxxxxxxxxxxxxxxxxxxxxxxx(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) xxxxxxxxxxxxxxxxxxxxxxxxxxxx( aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccc, dddddddddddddddddddddddd) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_and_multiple_logical_lines_with_math(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx([-1 + 5 / -10, 100, -3 - 4]) """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( [-1 + 5 / -10, 100, -3 - 4]) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_and_import(self): line = """\ from . import (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy) """ fixed = """\ from . import ( xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_shorten_comment_with_experimental(self): line = """\ # ------ ------------------------------------------------------------------------- """ fixed = """\ # ------ ----------------------------------------------------------------- """ with autopep8_context(line, options=['--experimental', '--aggressive']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental_and_escaped_newline(self): line = """\ if True or \\ False: # test test test test test test test test test test test test test test pass """ fixed = """\ if True or \\ False: # test test test test test test test test test test test test test test pass """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental_and_multiline_string(self): line = """\ print('---------------------------------------------------------------------', ('================================================', '====================='), '''-------------------------------------------------------------------------------- ''') """ fixed = """\ print( '---------------------------------------------------------------------', ('================================================', '====================='), '''-------------------------------------------------------------------------------- ''') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental_and_multiline_string_with_addition(self): line = '''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""" ''' fixed = '''\ def f(): email_text += """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""" ''' with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental_and_multiline_string_in_parens(self): line = '''\ def f(): email_text += ("""This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""") ''' fixed = '''\ def f(): email_text += ( """This is a really long docstring that goes over the column limit and is multi-line.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""") ''' with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental_and_indentation(self): line = """\ if True: # comment here print(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,cccccccccccccccccccccccccccccccccccccccccc) """ fixed = """\ if True: # comment here print(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccccccccccccccccc) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_multiple_keys_and_experimental(self): line = """\ one_two_three_four_five_six = {'one two three four five': 12345, 'asdfsdflsdkfjl sdflkjsdkfkjsfjsdlkfj sdlkfjlsfjs': '343', 1: 1} """ fixed = """\ one_two_three_four_five_six = { 'one two three four five': 12345, 'asdfsdflsdkfjl sdflkjsdkfkjsfjsdlkfj sdlkfjlsfjs': '343', 1: 1} """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_with_experimental_and_carriage_returns_only(self): """Make sure _find_logical() does not crash.""" line = 'if True:\r from aaaaaaaaaaaaaaaa import bbbbbbbbbbbbbbbbbbb\r \r ccccccccccc = None\r' fixed = 'if True:\r from aaaaaaaaaaaaaaaa import bbbbbbbbbbbbbbbbbbb\r\r ccccccccccc = None\r' with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_should_ignore_imports(self): line = """\ import logging, os, bleach, commonware, urllib2, json, time, requests, urlparse, re """ with autopep8_context(line, options=['--select=E501', '--experimental']) as result: self.assertEqual(line, result) def test_e501_experimental_should_not_do_useless_things(self): line = """\ foo(' ') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(line, result) def test_e501_experimental_with_percent(self): line = """\ raise MultiProjectException("Ambiguous workspace: %s=%s, %s" % ( varname, varname_path, os.path.abspath(config_filename))) """ fixed = """\ raise MultiProjectException( "Ambiguous workspace: %s=%s, %s" % (varname, varname_path, os.path.abspath(config_filename))) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_def(self): line = """\ def foobar(sldfkjlsdfsdf, kksdfsdfsf,sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf,sdfsdfsfd, sdfsdfdsf): pass """ fixed = """\ def foobar(sldfkjlsdfsdf, kksdfsdfsf, sdfsdfsdf, sdfsdfkdk, szdfsdfsdf, sdfsdfsdfsdlkfjsdlf, sdfsdfddf, sdfsdfsfd, sdfsdfdsf): pass """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_tuple(self): line = """\ def f(): man_this_is_a_very_long_function_name(an_extremely_long_variable_name, ('a string that is long: %s'%'bork')) """ fixed = """\ def f(): man_this_is_a_very_long_function_name( an_extremely_long_variable_name, ('a string that is long: %s' % 'bork')) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_tuple_in_list(self): line = """\ def f(self): self._xxxxxxxx(aaaaaa, bbbbbbbbb, cccccccccccccccccc, [('mmmmmmmmmm', self.yyyyyyyyyy.zzzzzzzz/_DDDDDD)], eee, 'ff') """ fixed = """\ def f(self): self._xxxxxxxx( aaaaaa, bbbbbbbbb, cccccccccccccccccc, [('mmmmmmmmmm', self.yyyyyyyyyy.zzzzzzzz / _DDDDDD)], eee, 'ff') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_complex_reformat(self): line = """\ bork(111, 111, 111, 111, 222, 222, 222, { 'foo': 222, 'qux': 222 }, ((['hello', 'world'], ['yo', 'stella', "how's", 'it'], ['going']), {str(i): i for i in range(10)}, {'bork':((x, x**x) for x in range(10))}), 222, 222, 222, 222, 333, 333, 333, 333) """ fixed = """\ bork( 111, 111, 111, 111, 222, 222, 222, {'foo': 222, 'qux': 222}, ((['hello', 'world'], ['yo', 'stella', "how's", 'it'], ['going']), {str(i): i for i in range(10)}, {'bork': ((x, x ** x) for x in range(10))}), 222, 222, 222, 222, 333, 333, 333, 333) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_dot_calls(self): line = """\ if True: logging.info('aaaaaa bbbbb dddddd ccccccc eeeeeee fffffff gg: %s', xxxxxxxxxxxxxxxxx.yyyyyyyyyyyyyyyyyyyyy(zzzzzzzzzzzzzzzzz.jjjjjjjjjjjjjjjjj())) """ fixed = """\ if True: logging.info( 'aaaaaa bbbbb dddddd ccccccc eeeeeee fffffff gg: %s', xxxxxxxxxxxxxxxxx.yyyyyyyyyyyyyyyyyyyyy( zzzzzzzzzzzzzzzzz.jjjjjjjjjjjjjjjjj())) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_avoid_breaking_at_empty_parentheses_if_possible( self): line = """\ someverylongindenttionwhatnot().foo().bar().baz("and here is a long string 123456789012345678901234567890") """ fixed = """\ someverylongindenttionwhatnot().foo().bar().baz( "and here is a long string 123456789012345678901234567890") """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_unicode(self): line = """\ someverylongindenttionwhatnot().foo().bar().baz("and here is a l안녕하세요 123456789012345678901234567890") """ fixed = """\ someverylongindenttionwhatnot().foo().bar().baz( "and here is a l안녕하세요 123456789012345678901234567890") """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_tuple_assignment(self): line = """\ if True: (xxxxxxx,) = xxxx.xxxxxxx.xxxxx(xxxxxxxxxxxx.xx).xxxxxx(xxxxxxxxxxxx.xxxx == xxxx.xxxx).xxxxx() """ fixed = """\ if True: (xxxxxxx,) = xxxx.xxxxxxx.xxxxx(xxxxxxxxxxxx.xx).xxxxxx( xxxxxxxxxxxx.xxxx == xxxx.xxxx).xxxxx() """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) @unittest.skip('To do') def test_e501_experimental_tuple_on_line(self): line = """\ def f(): self.aaaaaaaaa(bbbbbb, ccccccccc, dddddddddddddddd, ((x, y/eeeeeee) for x, y in self.outputs.total.iteritems()), fff, 'GG') """ fixed = """\ def f(): self.aaaaaaaaa( bbbbbb, ccccccccc, dddddddddddddddd, ((x, y / eeeeeee) for x, y in self.outputs.total.iteritems()), fff, 'GG') """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_tuple_on_line_two_space_indent(self): line = """\ def f(): self.aaaaaaaaa(bbbbbb, ccccccccc, dddddddddddddddd, ((x, y/eeeeeee) for x, y in self.outputs.total.iteritems()), fff, 'GG') """ fixed = """\ def f(): self.aaaaaaaaa(bbbbbb, ccccccccc, dddddddddddddddd, ((x, y/eeeeeee) for x, y in self.outputs.total.iteritems()), fff, 'GG') """ with autopep8_context(line, options=['--experimental', '--indent-size=2']) as result: self.assertEqual(fixed, result) def test_e501_experimental_oversized_default_initializer(self): line = """\ aaaaaaaaaaaaaaaaaaaaa(lllll,mmmmmmmm,nnn,fffffffffff,ggggggggggg,hhh,ddddddddddddd=eeeeeeeee,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=ccccccccccccccccccccccccccccccccccccccccccccccccc,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=cccccccccccccccccccccccccccccccccccccccccccccccc) """ fixed = """\ aaaaaaaaaaaaaaaaaaaaa( lllll, mmmmmmmm, nnn, fffffffffff, ggggggggggg, hhh, ddddddddddddd=eeeeeeeee, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=ccccccccccccccccccccccccccccccccccccccccccccccccc, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=cccccccccccccccccccccccccccccccccccccccccccccccc) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_decorator(self): line = """\ @foo(('xxxxxxxxxxxxxxxxxxxxxxxxxx', users.xxxxxxxxxxxxxxxxxxxxxxxxxx), ('yyyyyyyyyyyy', users.yyyyyyyyyyyy), ('zzzzzzzzzzzzzz', users.zzzzzzzzzzzzzz)) """ fixed = """\ @foo(('xxxxxxxxxxxxxxxxxxxxxxxxxx', users.xxxxxxxxxxxxxxxxxxxxxxxxxx), ('yyyyyyyyyyyy', users.yyyyyyyyyyyy), ('zzzzzzzzzzzzzz', users.zzzzzzzzzzzzzz)) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_long_class_name(self): line = """\ class AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB): pass """ fixed = """\ class AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA( BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB): pass """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_no_line_change(self): line = """\ def f(): return 'Copy Link' % url """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(line, result) def test_e501_experimental_splitting_small_arrays(self): line = """\ def foo(): unspecified[service] = ('# The %s brown fox jumped over the lazy, good for nothing ' 'dog until it grew tired and set its sights upon the cat!' % adj) """ fixed = """\ def foo(): unspecified[service] = ( '# The %s brown fox jumped over the lazy, good for nothing ' 'dog until it grew tired and set its sights upon the cat!' % adj) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_no_splitting_in_func_call(self): line = """\ def foo(): if True: if True: function.calls('%r (%s): aaaaaaaa bbbbbbbbbb ccccccc ddddddd eeeeee (%d, %d)', xxxxxx.yy, xxxxxx.yyyy, len(mmmmmmmmmmmmm['fnord']), len(mmmmmmmmmmmmm['asdfakjhdsfkj'])) """ fixed = """\ def foo(): if True: if True: function.calls( '%r (%s): aaaaaaaa bbbbbbbbbb ccccccc ddddddd eeeeee (%d, %d)', xxxxxx.yy, xxxxxx.yyyy, len(mmmmmmmmmmmmm['fnord']), len(mmmmmmmmmmmmm['asdfakjhdsfkj'])) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_no_splitting_at_dot(self): line = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx = [yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.MMMMMM_NNNNNNN_OOOOO, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.PPPPPP_QQQQQQQ_RRRRR, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.SSSSSS_TTTTTTT_UUUUU] """ fixed = """\ xxxxxxxxxxxxxxxxxxxxxxxxxxxx = [ yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.MMMMMM_NNNNNNN_OOOOO, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.PPPPPP_QQQQQQQ_RRRRR, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.SSSSSS_TTTTTTT_UUUUU] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_no_splitting_before_arg_list(self): line = """\ xxxxxxxxxxxx = [yyyyyy['yyyyyy'].get('zzzzzzzzzzz') for yyyyyy in x.get('aaaaaaaaaaa') if yyyyyy['yyyyyy'].get('zzzzzzzzzzz')] """ fixed = """\ xxxxxxxxxxxx = [yyyyyy['yyyyyy'].get('zzzzzzzzzzz') for yyyyyy in x.get('aaaaaaaaaaa') if yyyyyy['yyyyyy'].get('zzzzzzzzzzz')] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_dont_split_if_looks_bad(self): line = """\ def f(): if True: BAD(('xxxxxxxxxxxxx', 42), 'I died for beauty, but was scarce / Adjusted in the tomb %s', yyyyyyyyyyyyy) """ fixed = """\ def f(): if True: BAD(('xxxxxxxxxxxxx', 42), 'I died for beauty, but was scarce / Adjusted in the tomb %s', yyyyyyyyyyyyy) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_list_comp(self): line = """\ xxxxxxxxxxxs = [xxxxxxxxxxx for xxxxxxxxxxx in xxxxxxxxxxxs if not yyyyyyyyyyyy[xxxxxxxxxxx] or not yyyyyyyyyyyy[xxxxxxxxxxx].zzzzzzzzzz] """ fixed = """\ xxxxxxxxxxxs = [ xxxxxxxxxxx for xxxxxxxxxxx in xxxxxxxxxxxs if not yyyyyyyyyyyy[xxxxxxxxxxx] or not yyyyyyyyyyyy[xxxxxxxxxxx].zzzzzzzzzz] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) line = """\ def f(): xxxxxxxxxx = [f for f in yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.zzzzzzzzzzzzzzzzzzzzzzzz.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] """ fixed = """\ def f(): xxxxxxxxxx = [ f for f in yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.zzzzzzzzzzzzzzzzzzzzzzzz.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_dict(self): line = """\ def f(): zzzzzzzzzzzzz = { 'aaaaaa/bbbbbb/ccccc/dddddddd/eeeeeeeee/fffffffffff/ggggggggg/hhhhhhhh.py': yyyyyyyyyyy.xxxxxxxxxxx( 'aa/bbbbbbb/cc/ddddddd/eeeeeeeeeee/fffffffffff/ggggggggg/hhhhhhh/ggggg.py', '00000000', yyyyyyyyyyy.xxxxxxxxx.zzzz), } """ fixed = """\ def f(): zzzzzzzzzzzzz = { 'aaaaaa/bbbbbb/ccccc/dddddddd/eeeeeeeee/fffffffffff/ggggggggg/hhhhhhhh.py': yyyyyyyyyyy.xxxxxxxxxxx( 'aa/bbbbbbb/cc/ddddddd/eeeeeeeeeee/fffffffffff/ggggggggg/hhhhhhh/ggggg.py', '00000000', yyyyyyyyyyy.xxxxxxxxx.zzzz), } """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_indentation(self): line = """\ class Klass(object): '''Class docstring.''' def Quote(self, parameter_1, parameter_2, parameter_3, parameter_4, parameter_5): pass """ fixed = """\ class Klass(object): '''Class docstring.''' def Quote( self, parameter_1, parameter_2, parameter_3, parameter_4, parameter_5): pass """ with autopep8_context(line, options=['--experimental', '--indent-size=2']) as result: self.assertEqual(fixed, result) def test_e501_experimental_long_function_call_elements(self): line = """\ def g(): pppppppppppppppppppppppppp1, pppppppppppppppppppppppp2 = ( zzzzzzzzzzzz.yyyyyyyyyyyyyy(aaaaaaaaa=10, bbbbbbbbbbbbbbbb='2:3', cccccccc='{1:2}', dd=1, eeeee=0), zzzzzzzzzzzz.yyyyyyyyyyyyyy(dd=7, aaaaaaaaa=16, bbbbbbbbbbbbbbbb='2:3', cccccccc='{1:2}', eeeee=xxxxxxxxxxxxxxxxx.wwwwwwwwwwwww.vvvvvvvvvvvvvvvvvvvvvvvvv)) """ fixed = """\ def g(): pppppppppppppppppppppppppp1, pppppppppppppppppppppppp2 = ( zzzzzzzzzzzz.yyyyyyyyyyyyyy( aaaaaaaaa=10, bbbbbbbbbbbbbbbb='2:3', cccccccc='{1:2}', dd=1, eeeee=0), zzzzzzzzzzzz.yyyyyyyyyyyyyy( dd=7, aaaaaaaaa=16, bbbbbbbbbbbbbbbb='2:3', cccccccc='{1:2}', eeeee=xxxxxxxxxxxxxxxxx.wwwwwwwwwwwww.vvvvvvvvvvvvvvvvvvvvvvvvv)) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_long_nested_tuples_in_arrays(self): line = """\ def f(): aaaaaaaaaaa.bbbbbbb([ ('xxxxxxxxxx', 'yyyyyy', 'Heaven hath no wrath like love to hatred turned. Nor hell a fury like a woman scorned.'), ('xxxxxxx', 'yyyyyyyyyyy', "To the last I grapple with thee. From hell's heart I stab at thee. For hate's sake I spit my last breath at thee!")]) """ fixed = """\ def f(): aaaaaaaaaaa.bbbbbbb( [('xxxxxxxxxx', 'yyyyyy', 'Heaven hath no wrath like love to hatred turned. Nor hell a fury like a woman scorned.'), ('xxxxxxx', 'yyyyyyyyyyy', "To the last I grapple with thee. From hell's heart I stab at thee. For hate's sake I spit my last breath at thee!")]) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_func_call_open_paren_not_separated(self): # Don't separate the opening paren of a function call from the # function's name. line = """\ def f(): owned_list = [o for o in owned_list if self.display['zzzzzzzzzzzzzz'] in aaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbb(o.qq, ccccccccccccccccccccccccccc.ddddddddd.eeeeeee)] """ fixed = """\ def f(): owned_list = [ o for o in owned_list if self.display['zzzzzzzzzzzzzz'] in aaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbb( o.qq, ccccccccccccccccccccccccccc.ddddddddd.eeeeeee)] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_long_dotted_object(self): # Don't separate a long dotted object too soon. Otherwise, it may end # up with most of its elements on separate lines. line = """\ def f(self): return self.xxxxxxxxxxxxxxx(aaaaaaa.bbbbb.ccccccc.ddd.eeeeee.fffffffff.ggggg.hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh) """ fixed = """\ def f(self): return self.xxxxxxxxxxxxxxx( aaaaaaa.bbbbb.ccccccc.ddd.eeeeee.fffffffff.ggggg. hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh) """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) @unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+') def test_e501_experimental_parsing_dict_with_comments(self): line = """\ self.display['xxxxxxxxxxxx'] = [{'title': _('Library'), #. This is the first comment. 'flag': aaaaaaaaaa.bbbbbbbbb.cccccccccc }, {'title': _('Original'), #. This is the second comment. 'flag': aaaaaaaaaa.bbbbbbbbb.dddddddddd }, {'title': _('Unknown'), #. This is the third comment. 'flag': aaaaaaaaaa.bbbbbbbbb.eeeeeeeeee}] """ fixed = """\ self.display['xxxxxxxxxxxx'] = [{'title': _('Library'), # . This is the first comment. 'flag': aaaaaaaaaa.bbbbbbbbb.cccccccccc # . This is the second comment. }, {'title': _('Original'), 'flag': aaaaaaaaaa.bbbbbbbbb.dddddddddd # . This is the third comment. }, {'title': _('Unknown'), 'flag': aaaaaaaaaa.bbbbbbbbb.eeeeeeeeee}] """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) @unittest.skipIf(sys.version_info >= (3, 12), 'not detect in Python3.12+') def test_e501_experimental_if_line_over_limit(self): line = """\ if not xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): return 1 """ fixed = """\ if not xxxxxxxxxxxx( aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): return 1 """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_for_line_over_limit(self): line = """\ for aaaaaaaaa in xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ fixed = """\ for aaaaaaaaa in xxxxxxxxxxxx( aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_while_line_over_limit(self): line = """\ while xxxxxxxxxxxx(aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ fixed = """\ while xxxxxxxxxxxx( aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccc, dddddddddddddddddddddd): pass """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) def test_e501_experimental_with_in(self): line = """\ if True: if True: if True: if True: if True: if True: if True: if True: if k_left in ('any', k_curr) and k_right in ('any', k_curr): pass """ fixed = """\ if True: if True: if True: if True: if True: if True: if True: if True: if k_left in ( 'any', k_curr) and k_right in ( 'any', k_curr): pass """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(fixed, result) @unittest.skipIf(sys.version_info < (3, 12), 'not support in Python3.11 and lower version') def test_e501_experimental_not_effect_with_fstring(self): line = """\ fstring = {"some_key": f"There is a string value inside of an f string, which itself is a dictionary value {s})"} """ with autopep8_context(line, options=['--experimental']) as result: self.assertEqual(line, result) def fix_e266(source): with autopep8_context(source, options=['--select=E266']) as result: return result def fix_e265_and_e266(source): with autopep8_context(source, options=['--select=E265,E266']) as result: return result @contextlib.contextmanager def autopep8_context(line, options=None): if not options: options = [] with temporary_file_context(line) as filename: options = autopep8.parse_args([filename] + list(options)) yield autopep8.fix_file(filename=filename, options=options) @contextlib.contextmanager def autopep8_subprocess(line, options, timeout=None): with temporary_file_context(line) as filename: p = Popen(list(AUTOPEP8_CMD_TUPLE) + [filename] + options, stdout=PIPE) if timeout is None: _stdout, _ = p.communicate() else: try: _stdout, _ = p.communicate(timeout=timeout) except TypeError: # for Python2 while p.poll() is None and timeout > 0: time.sleep(0.5) timeout -= 0.5 if p.poll() is None: p.kill() raise Exception("subprocess is timed out") _stdout, _ = p.communicate() yield _stdout.decode('utf-8'), p.returncode @contextlib.contextmanager def temporary_file_context(text, suffix='', prefix=''): temporary = mkstemp(suffix=suffix, prefix=prefix) os.close(temporary[0]) with autopep8.open_with_encoding(temporary[1], encoding='utf-8', mode='w') as temp_file: temp_file.write(text) yield temporary[1] os.remove(temporary[1]) @contextlib.contextmanager def readonly_temporary_file_context(text, suffix='', prefix=''): temporary = mkstemp(suffix=suffix, prefix=prefix) os.close(temporary[0]) with autopep8.open_with_encoding(temporary[1], encoding='utf-8', mode='w') as temp_file: temp_file.write(text) os.chmod(temporary[1], stat.S_IRUSR) yield temporary[1] os.remove(temporary[1]) @contextlib.contextmanager def temporary_project_directory(prefix="autopep8test"): temporary = mkdtemp(prefix=prefix) yield temporary shutil.rmtree(temporary) @contextlib.contextmanager def disable_stderr(): sio = StringIO() with capture_stderr(sio): yield @contextlib.contextmanager def capture_stderr(sio): _tmp = sys.stderr sys.stderr = sio try: yield finally: sys.stderr = _tmp if __name__ == '__main__': unittest.main() autopep8-2.3.2/test/test_suite.py000077500000000000000000000055731474147346600170410ustar00rootroot00000000000000#!/usr/bin/env python """Run autopep8 against test file and check against expected output.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import argparse import os import sys ROOT_DIR = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] sys.path.insert(0, ROOT_DIR) import autopep8 if sys.stdout.isatty(): GREEN = '\x1b[32m' RED = '\x1b[31m' END = '\x1b[0m' else: GREEN = '' RED = '' END = '' def check(expected_filename, input_filename, aggressive): """Test and compare output. Return True on success. """ got = autopep8.fix_file( input_filename, options=autopep8.parse_args([''] + aggressive * ['--aggressive'])) try: with autopep8.open_with_encoding(expected_filename) as expected_file: expected = expected_file.read() except IOError: expected = None if expected == got: return True else: got_filename = expected_filename + '.err' encoding = autopep8.detect_encoding(input_filename) with autopep8.open_with_encoding(got_filename, encoding=encoding, mode='w') as got_file: got_file.write(got) print( '{begin}{got} does not match expected {expected}{end}'.format( begin=RED, got=got_filename, expected=expected_filename, end=END), file=sys.stdout) return False def run(filename, aggressive): """Test against a specific file. Return True on success. Expected output should have the same base filename, but live in an "out" directory: foo/bar.py foo/out/bar.py Failed output will go to: foo/out/bar.py.err """ return check( expected_filename=os.path.join( os.path.dirname(filename), 'out', os.path.basename(filename) ), input_filename=filename, aggressive=aggressive ) def suite(aggressive): """Run against pep8 test suite.""" result = True path = os.path.join(os.path.dirname(__file__), 'suite') for filename in os.listdir(path): filename = os.path.join(path, filename) if filename.endswith('.py'): print(filename, file=sys.stderr) result = run(filename, aggressive=aggressive) and result if result: print(GREEN + 'Okay' + END) return result def main(): parser = argparse.ArgumentParser() parser.add_argument('--aggression-level', default=2, type=int, help='run autopep8 in aggression level') args = parser.parse_args() return int(not suite(aggressive=args.aggression_level)) if __name__ == '__main__': sys.exit(main()) autopep8-2.3.2/test/vectors_example.py000066400000000000000000001052201474147346600200340ustar00rootroot00000000000000# vectors - a simple vector, complex, quaternion, and 4d matrix math module ''' http://www.halley.cc/code/python/vectors.py A simple vector, complex, quaternion, and 4d matrix math module. ABSTRACT This module gives a simple way of doing lightweight 2D, 3D or other vector math tasks without the heavy clutter of doing tuple/list/vector conversions yourself, or the burden of installing some high-performance native math routine module. Included are: V(...) - mathematical real vector C(...) - mathematical complex number (same as python "complex" type) Q(...) - hypercomplex number, also known as a quaternion M(...) - a fixed 4x4 matrix commonly used in graphics SYNOPSIS >>> import vectors ; from vectors import * Vectors: >>> v = V(1,2,3) ; w = V(4,5,6) >>> v+w, (v+w == w+v), v*2 V(5.0, 7.0, 9.0), True, V(2.0, 4.0, 6.0) >>> v.dot(w), v.cross(w), v.normalize().magnitude() 32.0, V(-3.0, 6.0, -3.0), 1.0 Quaternions: >>> q = Q.rotate('X', vectors.radians(30)) Q(0.7071067811, 0.0, 0.0, 0.7071067811) >>> q*q*q*q*q*q == Q.rotate('X', math.pi) == Q(1,0,0,0) True AUTHOR Ed Halley (ed@halley.cc) 12 February 2005 REFERENCES Many libraries implement a host of 4x4 matrix math and vector routines, usually related to the historical SGI GL implementation. A common problem is whether matrix element formulas are transposed. One useful FAQ on matrix math can be found at this address: http://www.j3d.org/matrix_faq/matrfaq_latest.html ''' __all__ = [ 'V', 'C', 'Q', 'M', 'zero', 'equal', 'radians', 'degrees', 'angle', 'track', 'distance', 'nearest', 'farthest' ] #---------------------------------------------------------------------------- import math import random EPSILON = 0.00000001 __deg2rad = math.pi / 180.0 __rad2deg = 180.0 / math.pi def zero(a): return abs(a) < EPSILON def equal(a, b): return abs(a - b) < EPSILON def degrees(rad): return rad * __rad2deg def radians(deg): return deg * __deg2rad def sign(a): if a < 0: return -1 if a > 0: return +1 return 0 def isseq(x): return isinstance(x, (list, tuple)) def collapse(*args): it = [] for i in range(len(args)): if isinstance(args[i], V): it.extend(args[i]._v) else: it.extend(args[i]) return it #---------------------------------------------------------------------------- class V: '''A mathematical vector of arbitrary number of scalar number elements. ''' O = None X = None Y = None Z = None __slots__ = [ '_v', '_l' ] @classmethod def __constants__(cls): if V.O: return V.O = V() ; V.O._v = (0.,0.,0.) ; V.O._l = 0. V.X = V() ; V.X._v = (1.,0.,0.) ; V.X._l = 1. V.Y = V() ; V.Y._v = (0.,1.,0.) ; V.Y._l = 1. V.Z = V() ; V.Z._v = (0.,0.,1.) ; V.Z._l = 1. def __init__(self, *args): l = len(args) if not l: self._v = [0.,0.,0.] self._l = 0. return if l > 1: self._v = map(float, args) self._l = None return arg = args[0] if isinstance(arg, (list, tuple)): self._v = map(float, arg) self._l = None elif isinstance(arg, V): self._v = list(arg._v[:]) self._l = arg._l else: arg = float(arg) self._v = [ arg ] self._l = arg def __len__(self): '''The len of a vector is the dimensionality.''' return len(self._v) def __list__(self): '''Accessing the list() will return all elements as a list.''' if isinstance(self._v, tuple): return list(self._v[:]) return self._v[:] list = __list__ def __getitem__(self, key): '''Vector elements can be accessed directly.''' return self._v[key] def __setitem__(self, key, value): '''Vector elements can be accessed directly.''' self._v[key] = value def __str__(self): return self.__repr__() def __repr__(self): return self.__class__.__name__ + repr(tuple(self._v)) def __eq__(self, other): '''Vectors can be checked for equality. Uses epsilon floating comparison; tiny differences are still equal. ''' for i in range(len(self._v)): if not equal(self._v[i], other._v[i]): return False return True def __cmp__(self, other): '''Vectors can be compared, returning -1,0,+1. Elements are compared in order, using epsilon floating comparison. ''' for i in range(len(self._v)): if not equal(self._v[i], other._v[i]): if self._v[i] > other._v[i]: return 1 return -1 return 0 def __pos__(self): return V(self) def __neg__(self): '''The inverse of a vector is a negative in all elements.''' v = V(self) for i in range(len(v._v)): v[i] = -v[i] v._l = self._l return v def __nonzero__(self): '''A vector is nonzero if any of its elements are nonzero.''' for i in range(len(self._v)): if self._v[i]: return True return False def zero(self): '''A vector is zero if none of its elements are nonzero.''' return not self.__nonzero__() @classmethod def random(cls, order=3): '''Returns a unit vector in a random direction.''' # distribution is not without bias, need to use polar coords? v = V(range(order)) v._l = None short = True while short: for i in range(order): v._v[i] = 2.0*random.random() - 1.0 if not zero(v._v[i]): short = False return v.normalize() # Vector or scalar addition. def __add__(self, other): return self.__class__(self).__iadd__(other) def __radd__(self, other): return self.__class__(self).__iadd__(other) def __iadd__(self, other): '''Vectors can be added to each other, or a scalar added to them.''' if isinstance(other, V): if len(other._v) != len(self._v): raise ValueError, 'mismatched dimensions' for i in range(len(self._v)): self._v[i] += other._v[i] else: for i in range(len(self._v)): self._v[i] += other self._l = None return self # Vector or scalar subtraction. def __sub__(self, other): return self.__class__(self).__isub__(other) def __rsub__(self, other): return (-self.__class__(self)).__iadd__(other) def __isub__(self, other): '''Vectors can be subtracted, or a scalar subtracted from them.''' if isinstance(other, V): if len(other._v) != len(self._v): raise ValueError, 'mismatched dimensions' for i in range(len(self._v)): self._v[i] -= other._v[i] else: for i in range(len(self._v)): self._v[i] -= other self._l = None return self # Cross product or magnification. See dot() for dot product. def __mul__(self, other): if isinstance(other, M): return other.__rmul__(self) return self.__class__(self).__imul__(other) def __rmul__(self, other): # The __rmul__ is called in scalar * vector case; it's commutative. return self.__class__(self).__imul__(other) def __imul__(self, other): '''Vectors can be multipled by a scalar. Two 3d vectors can cross.''' if isinstance(other, V): self._v = self.cross(other)._v else: for i in range(len(self._v)): self._v[i] *= other self._l = None return self def __div__(self, other): return self.__class__(self).__idiv__(other) def __rdiv__(self, other): raise TypeError, 'cannot divide scalar by non-scalar value' def __idiv__(self, other): '''Vectors can be divided by scalars; each element is divided.''' other = 1.0 / other for i in range(len(self._v)): self._v[i] *= other self._l = None return self def cross(self, other): '''Find the vector cross product between two 3d vectors.''' if len(self._v) != 3 or len(other._v) != 3: raise ValueError, 'cross multiplication only for 3d vectors' p, q = self._v, other._v r = [ p[1] * q[2] - p[2] * q[1], p[2] * q[0] - p[0] * q[2], p[0] * q[1] - p[1] * q[0] ] return V(r) def dot(self, other): '''Find the scalar dot product between this vector and another.''' s = 0 for i in range(len(self._v)): s += self._v[i] * other._v[i] return s def __mag(self): if self._l is not None: return self._l m = 0 for i in range(len(self._v)): m += self._v[i] * self._v[i] self._l = math.sqrt(m) return self._l def magnitude(self, value=None): '''Find the magnitude (spatial length) of this vector. With a value, return a vector with same direction but of given length. ''' mag = self.__mag() if value is None: return mag if zero(mag): raise ValueError, 'Zero-magnitude vector cannot be scaled.' v = self.__class__(self) v.__imul__(value / mag) v._l = value return v def dsquared(self, other): m = 0 for i in range(len(self._v)): d = self._v[i] - other._v[i] m += d * d return m def distance(self, other): '''Compare this vector with another, for distance.''' return math.sqrt(self.dsquared(other)) def normalize(self): '''Return a vector with the same direction but of unit length.''' return self.magnitude(1.0) def order(self, order): '''Remove elements from the end, or extend with new elements.''' order = int(order) if order < 1: raise ValueError, 'cannot reduce a vector to zero elements' v = V(self) while order < len(v._v): v._v.pop() while order > len(v._v): v._v.append(1.0) v._l = None return v #---------------------------------------------------------------------------- class C (V): # python has a built-in complex() type which is pretty good, # but we provide this class for completeness and consistency O = None j = None __slots__ = [ '_v', '_l' ] @classmethod def __constants__(cls): if C.O: return C.O = C(0+0j) ; C.O._v = tuple(C.O._v) C.j = C(0+1j) ; C.j._v = tuple(C.j._v) def __init__(self, *args): if not args: args = (0, 0) a = args[0] if isinstance(a, complex): a = (a.real, a.imag) if isinstance(a, V): if len(a) != 2: raise TypeError, 'C() takes exactly 2 elements' self._v = list(a._v[:]) elif isseq(a): if len(a) != 2: raise TypeError, 'C() takes exactly 2 elements' self._v = map(float, a) else: if len(args) != 2: raise TypeError, 'C() takes exactly 2 elements' self._v = map(float, args) #def __repr__(self): # return 'C(%s+%sj)' % (repr(self._v[0]), repr(self._v[1])) # addition and subtraction of C() work the same as V() def dot(self): raise AttributeError, "C instance has no attribute 'dot'" def __imul__(self, other): if isinstance(other, C): sx,sj = self._v ox,oj = other._v self._v = [ sx*ox - sj*oj, sx*oj + ox*sj ] else: V.__imul__(self, other) return self def conjugate(self): twin = C(self) twin._v[0] = -twin._v[0] return twin #---------------------------------------------------------------------------- class Q (V): I = None __slots__ = [ '_v', '_l' ] @classmethod def __constants__(cls): if Q.O: return Q.I = Q() ; Q.I._v = tuple(Q.I._v) def __init__(self, *args): # x, y, z, w if not args: args = (0, 0, 0, 1) a = args[0] if isinstance(a, V): if len(a) != 4: raise TypeError, 'Q() takes exactly 4 elements' self._v = list(a._v[:]) elif isseq(a): if len(a) != 4: raise TypeError, 'Q() takes exactly 4 elements' self._v = map(float, a) else: if len(args) != 4: raise TypeError, 'Q() takes exactly 4 elements' self._v = map(float, args) self._l = None # addition and subtraction of Q() work the same as V() def dot(self): raise AttributeError, "Q instance has no attribute 'dot'" #TODO: extra methods to convert euler vectors and quaternions def conjugate(self): '''The conjugate of a quaternion has its X, Y and Z negated.''' twin = Q(self) for i in range(3): twin._v[i] = -twin._v[i] twin._l = twin._l return twin def inverse(self): '''The quaternion inverse is the conjugate with reciprocal W.''' twin = self.conjugate() if twin._v[3] != 1.0: twin._v[3] = 1.0 / twin._v[3] twin._l = None return twin @classmethod def rotate(cls, axis, theta): '''Prepare a quaternion that represents a rotation on a given axis.''' if isinstance(axis, str): if axis in ('x','X'): axis = V.X elif axis in ('y','Y'): axis = V.Y elif axis in ('z','Z'): axis = V.Z axis = axis.normalize() s = math.sin(theta / 2.) c = math.cos(theta / 2.) return Q( axis._v[0] * s, axis._v[1] * s, axis._v[2] * s, c ) def __imul__(self, other): if isinstance(other, Q): sx,sy,sz,sw = self._v ox,oy,oz,ow = other._v self._v = [ sw*ox + sx*ow + sy*oz - sz*oy, sw*oy + sy*ow + sz*ox - sx*oz, sw*oz + sz*ow + sx*oy - sy*ox, sw*ow - sx*ox - sy*oy - sz*oz ] else: V.__imul__(self, other) return self #---------------------------------------------------------------------------- class M (V): I = None Z = None __slots__ = [ '_v' ] @classmethod def __constants__(cls): if M.I: return M.I = M() ; M.I._v = tuple(M.I._v) M.Z = M() ; M.Z._v = (0,)*16 def __init__(self, *args): '''Constructs a new 4x4 matrix. If no arguments are given, an identity matrix is constructed. Any combination of V vectors, tuples, lists or scalars may be given, but taken together in order, they must have 16 number values total. ''' # no args gives identity matrix # 16 scalars collapsed from any combination of lists, tuples, vectors if not args: args = (1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1) if len(args) == 4: args = collapse(*args) a = args[0] if isinstance(a, V): if len(a) != 16: raise TypeError, 'M() takes exactly 16 elements' self._v = list(a._v[:]) elif isseq(a): if len(a) != 16: raise TypeError, 'M() takes exactly 16 elements' self._v = map(float, a) else: if len(args) != 16: raise TypeError, 'M() takes exactly 16 elements' self._v = map(float, args) @classmethod def rotate(cls, axis, theta=0.0): if isinstance(axis, str): if axis in ('x','X'): c = math.cos(theta) ; s = math.sin(theta) return cls( [ 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1 ] ) if axis in ('y','Y'): c = math.cos(theta) ; s = math.sin(theta) return cls( [ c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1 ] ) if axis in ('z','Z'): c = math.cos(theta) ; s = math.sin(theta) return cls( [ c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] ) if isinstance(axis, V): axis = Q.rotate(axis, theta) if isinstance(axis, Q): return cls.twist(axis) raise ValueError, 'unknown rotation axis' @classmethod def twist(cls, torsion): # quaternion to matrix torsion = torsion.normalize() (X,Y,Z,W) = torsion._v xx = X * X ; xy = X * Y ; xz = X * Z ; xw = X * W yy = Y * Y ; yz = Y * Z ; yw = Y * W ; zz = Z * Z ; zw = Z * W a = 1 - 2*(yy + zz) ; b = 2*(xy - zw) ; c = 2*(xz + yw) e = 2*(xy + zw) ; f = 1 - 2*(xx + zz) ; g = 2*(yz - xw) i = 2*(xz - yw) ; j = 2*(yz + xw) ; k = 1 - 2*(xx + yy) return cls( [ a, b, c, 0, e, f, g, 0, i, j, k, 0, 0, 0, 0, 1 ] ) @classmethod def scale(cls, factor): m = cls() if isinstance(factor, (V, list, tuple)): for i in (0,1,2): m[(i,i)] = factor[i] else: for i in (0,1,2): m[(i,i)] = factor return m @classmethod def translate(cls, offset): m = cls() for i in (0,1,2): m[(3,i)] = offset[i] return m @classmethod def reflect(cls, normal, dist=0.0): (x,y,z,w) = normal.normalize()._v (n2x,n2y,n2z) = (-2*x, -2*y, -2*z) return cls( [ 1+n2x*x, n2x*y, n2x*z, 0, n2y*x, 1+n2y*y, n2y*z, 0, n2z*x, n2z*y, 1+n2z*z, 0, d*x, d*y, d*y, 1 ] ) @classmethod def shear(cls, amount): # | 1. yx zx 0. | # | xy 1. zy 0. | # | xz yz 1. 0. | # | 0. 0. 0. 1. | pass @classmethod def frustrum(cls, l, r, b, t, n, f): rl = 1/(r-l) ; tb = 1/(t-b) ; fn = 1/(f-n) return cls( [ 2*n*rl, 0, (r+l)*rl, 0, 0, 2*n*tb, 0, 0, 0, 0, -(f+n)*fn, -2*f*n*fn, 0, 0, -1, 0 ] ) @classmethod def perspective(cls, yfov, aspect, n, f): t = math.tan(yfov/2)*n b = -t r = aspect * t l = -r return cls.frustrum(l, r, b, t, n, f) def __str__(self): '''Returns a multiple-line string representation of the matrix.''' # prettier on multiple lines n = self.__class__.__name__ ns = ' '*len(n) t = n+'('+', '.join([ repr(self._v[i]) for i in 0,1,2,3 ])+',\n' t += ns+' '+', '.join([ repr(self._v[i]) for i in 4,5,6,7 ])+',\n' t += ns+' '+', '.join([ repr(self._v[i]) for i in 8,9,10,11 ])+',\n' t += ns+' '+', '.join([ repr(self._v[i]) for i in 12,13,14,15 ])+')' return t def __getitem__(self, rc): '''Returns a single element of the matrix. May index 0-15, or with tuples of (row,column) 0-3 each. Indexing goes across first, so m[3] is m[0,3] and m[7] is m[1,3]. ''' if not isinstance(rc, tuple): return V.__getitem__(self, rc) return self._v[rc[0]*4+rc[1]] def __setitem__(self, rc, value): '''Injects a single element into the matrix. May index 0-15, or with tuples of (row,column) 0-3 each. Indexing goes across first, so m[3] is m[0,3] and m[7] is m[1,3]. ''' if not isinstance(rc, tuple): return V.__getitem__(self, rc) self._v[rc[0]*4+rc[1]] = float(value) def dot(self): raise AttributeError, "M instance has no attribute 'dot'" def magnitude(self): raise AttributeError, "M instance has no attribute 'magnitude'" def row(self, r, v=None): '''Returns or replaces a vector representing a row of the matrix. Rows are counted 0-3. If given, new vector must be four numbers. ''' if r < 0 or r > 3: raise IndexError, 'row index out of range' if v is None: return V(self._v[r*4:(r+1)*4]) e = v if isinstance(v, V): e = v._v if len(e) != 4: raise ValueError, 'new row must include 4 values' self._v[r*4:(r+1)*4] = e return v def col(self, c, v=None): '''Returns or replaces a vector representing a column of the matrix. Columns are counted 0-3. If given, new vector must be four numbers. ''' if c < 0 or c > 3: raise IndexError, 'column index out of range' if v is None: return V([ self._v[c+4*i] for i in range(4) ]) e = v if isinstance(v, V): e = v._v if len(e) != 4: raise ValueError, 'new row must include 4 values' for i in range(4): self._v[c+4*i] = e[i] return v def translation(self): '''Extracts the translation component from this matrix.''' (a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p) = self._v return V(m,n,o) def rotation(self): '''Extracts Euler angles of rotation from this matrix. This attempts to find alternate rotations in case of gimbal lock, but all of the usual problems with Euler angles apply here. All Euler angles are in radians. ''' (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) = self._v rotY = D = math.asin(c) C = math.cos(rotY) if (abs(C) > 0.005): trX = k/C ; trY = -g/C ; rotX = math.atan2(trY, trX) trX = a/C ; trY = -b/C ; rotZ = math.atan2(trY, trX) else: rotX = 0 trX = f ; trY = e ; rotZ = math.atan2(trY, trX) return V(rotX,rotY,rotZ) def scaling(self): '''Extracts the scaling component from this matrix.''' (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) = self._v return V(a,f,k) def determinant(self): (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) = self._v # determinants of 2x2 submatrices kplo = k*p-l*o ; jpln = j*p-l*n ; jokn = j*o-k*n iplm = i*p-l*m ; iokm = i*o-k*m ; injm = i*n-j*m # determinants of 3x3 submatrices d00 = (f*kplo - g*jpln + h*jokn) d01 = (e*kplo - g*iplm + h*iokm) d02 = (e*jpln - f*iplm + h*injm) d03 = (e*jokn - f*iokm + g*injm) # reciprocal of the determinant of the 4x4 dr = a*d00 - b*d01 + c*d02 - d*d03 return dr def inverse(self): (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) = self._v # determinants of 2x2 submatrices kplo = k*p-l*o ; jpln = j*p-l*n ; jokn = j*o-k*n iplm = i*p-l*m ; iokm = i*o-k*m ; injm = i*n-j*m gpho = g*p-h*o ; ifhn = f*p-h*n ; fogn = f*o-g*n ephm = e*p-h*m ; eogm = e*o-g*m ; enfm = e*n-f*m glhk = g*l-h*k ; flhj = f*l-h*j ; fkgj = f*k-g*j elhi = e*l-h*i ; ekgi = e*k-g*i ; ejfi = e*j-f*i # determinants of 3x3 submatrices d00 = (f*kplo - g*jpln + h*jokn) d01 = (e*kplo - g*iplm + h*iokm) d02 = (e*jpln - f*iplm + h*injm) d03 = (e*jokn - f*iokm + g*injm) d10 = (b*kplo - c*jpln + d*jokn) d11 = (a*kplo - c*iplm + d*iokm) d12 = (a*jpln - b*iplm + d*injm) d13 = (a*jokn - b*iokm + c*injm) d20 = (b*gpho - c*ifhn + d*fogn) d21 = (a*gpho - c*ephm + d*eogm) d22 = (a*ifhn - b*ephm + d*enfm) d23 = (a*fogn - b*eogm + c*enfm) d30 = (b*glhk - c*flhj + d*fkgj) d31 = (a*glhk - c*elhi + d*ekgi) d32 = (a*flhj - b*elhi + d*ejfi) d33 = (a*fkgj - b*ekgi + c*ejfi) # reciprocal of the determinant of the 4x4 dr = 1.0 / (a*d00 - b*d01 + c*d02 - d*d03) # inverse return self.__class__( [ d00*dr, -d10*dr, d20*dr, -d30*dr, -d01*dr, d11*dr, -d21*dr, d31*dr, d02*dr, -d12*dr, d22*dr, -d32*dr, -d03*dr, d13*dr, -d23*dr, d33*dr ] ) def transpose(self): return M( [ self._v[i] for i in [ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 ] ] ) def __mul__(self, other): # called in case of m *m, m * v, m * s # support 3d m * v by extending to 4d v if isinstance(other, V): if len(other._v) == 3: other = V(other._v[0], other._v[1], other._v[2], 1) if len(other._v) == 4: a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p = self._v X,Y,Z,W = other._v return V( a*X + b*Y + c*Z + d*W, e*X + f*Y + g*Z + h*W, i*X + j*Y + k*Z + l*W, m*X + n*Y + o*Z + p*W ) return self.__class__(self).__imul__(other) def __rmul__(self, other): # called in case of s * m or v * m # support 3d v * m by extending to 4d v if isinstance(other, V): if len(other._v) == 3: other = V(other._v[0], other._v[1], other._v[2], 1) if len(other._v) == 4: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P = self._v x,y,z,w = other._v return V( x*A + y*E + z*I + w*M, x*B + y*F + z*J + w*N, x*C + y*G + z*K + w*O, x*D + y*H + z*L + w*P ) return self.__class__(self).__imul__(other) def __imul__(self, other): # can m *= s # can't m *= v since answer is vector if not isinstance(other, V): other = float(other) self._v = [ self._v[i]*other for i in range(len(self._v)) ] elif len(other._v) == 16: s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,sA,sB,sC,sD,sE,sF = self._v o0,o1,o2,o3,o4,o5,o6,o7,o8,o9,oA,oB,oC,oD,oE,oF = other._v self._v = [ o0*s0 + o1*s4 + o2*s8 + o3*sC, # o0*s1 + o1*s5 + o2*s9 + o3*sD, o0*s2 + o1*s6 + o2*sA + o3*sE, o0*s3 + o1*s7 + o2*sB + o3*sF, o4*s0 + o5*s4 + o6*s8 + o7*sC, # o4*s1 + o5*s5 + o6*s9 + o7*sD, o4*s2 + o5*s6 + o6*sA + o7*sE, o4*s3 + o5*s7 + o6*sB + o7*sF, o8*s0 + o9*s4 + oA*s8 + oB*sC, # o8*s1 + o9*s5 + oA*s9 + oB*sD, o8*s2 + o9*s6 + oA*sA + oB*sE, o8*s3 + o9*s7 + oA*sB + oB*sF, oC*s0 + oD*s4 + oE*s8 + oF*sC, # oC*s1 + oD*s5 + oE*s9 + oF*sD, oC*s2 + oD*s6 + oE*sA + oF*sE, oC*s3 + oD*s7 + oE*sB + oF*sF ] else: raise ValueError, 'multiply by 4d matrix or 4d vector or scalar' return self #---------------------------------------------------------------------------- V.__constants__() C.__constants__() Q.__constants__() M.__constants__() def angle(a, b): '''Find the angle (scalar value in radians) between two 3d vectors.''' a = a.normalize() b = b.normalize() if a == b: return 0.0 return math.acos(a.dot(b)) def track(v): '''Find the track (direction in positive radians) of a 2d vector. E.g., track(V(1,0)) == 0 radians; track(V(0,1) == math.pi/2 radians; track(V(-1,0)) == math.pi radians; and track(V(0,-1) is math.pi*3/2. ''' t = math.atan2(v[1], v[0]) if t < 0: return t + 2.*math.pi return t def quangle(a, b): '''Find a quaternion that rotates one 3d vector to parallel another.''' x = a.cross(b) w = a.magnitude() * b.magnitude() + a.dot(b) return Q(x[0], x[1], x[2], w) def dsquared(one, two): '''Find the square of the distance between two points.''' # working with squared distances is common to avoid slow sqrt() calls m = 0 for i in range(len(one._v)): d = one._v[i] - two._v[i] m += d * d return m def distance(one, two): '''Find the distance between two points. Equivalent to (one-two).magnitude(). ''' return math.sqrt(dsquared(one, two)) def nearest(point, neighbors): '''Find the nearest neighbor point to a given point.''' best = None for other in neighbors: d = dsquared(point, other) if best is None or d < best[1]: best = (other, d) return best[0] def farthest(point, neighbors): '''Find the farthest neighbor point to a given point.''' best = None for other in neighbors: d = dsquared(point, other) if best is None or d > best[1]: best = (other, d) return best[0] #---------------------------------------------------------------------------- def __test__(): from testing import __ok__, __report__ print 'Testing basic math...' __ok__(equal(1.0, 1.0), True) __ok__(equal(1.0, 1.01), False) __ok__(equal(1.0, 1.0001), False) __ok__(equal(1.0, 0.9999), False) __ok__(equal(1.0, 1.0000001), False) __ok__(equal(1.0, 0.9999999), False) __ok__(equal(1.0, 1.0000000001), True) __ok__(equal(1.0, 0.9999999999), True) __ok__(equal(degrees(0), 0.0)) __ok__(equal(degrees(math.pi/2), 90.0)) __ok__(equal(degrees(math.pi), 180.0)) __ok__(equal(radians(0.0), 0.0)) __ok__(equal(radians(90.0), math.pi/2)) __ok__(equal(radians(180.0), math.pi)) print 'Testing V vector class...' # structural construction __ok__(V.O is not None, True) __ok__(V.O._v is not None, True) __ok__(V.O._v, (0., 0., 0.)) ; __ok__(V.O._l, 0.) __ok__(V.X._v, (1., 0., 0.)) ; __ok__(V.X._l, 1.) __ok__(V.Y._v, (0., 1., 0.)) ; __ok__(V.Y._l, 1.) __ok__(V.Z._v, (0., 0., 1.)) ; __ok__(V.Z._l, 1.) a = V(3., 2., 1.) ; __ok__(a._v, [3., 2., 1.]) a = V((1., 2., 3.)) ; __ok__(a._v, [1., 2., 3.]) a = V([1., 1., 1.]) ; __ok__(a._v, [1., 1., 1.]) a = V(0.) ; __ok__(a._v, [0.]) ; __ok__(a._l, 0.) a = V(3.) ; __ok__(a._v, [3.]) ; __ok__(a._l, 3.) # constants and direct comparisons __ok__(V.O, V(0.,0.,0.)) __ok__(V.X, V(1.,0.,0.)) __ok__(V.Y, V(0.,1.,0.)) __ok__(V.Z, V(0.,0.,1.)) # formatting and elements __ok__(repr(V.X), 'V(1.0, 0.0, 0.0)') __ok__(V.X[0], 1.) __ok__(V.X[1], 0.) __ok__(V.X[2], 0.) # simple addition __ok__(V.X + V.Y, V(1.,1.,0.)) __ok__(V.Y + V.Z, V(0.,1.,1.)) __ok__(V.X + V.Z, V(1.,0.,1.)) # didn't overwrite our constants, did we? __ok__(V.X, V(1.,0.,0.)) __ok__(V.Y, V(0.,1.,0.)) __ok__(V.Z, V(0.,0.,1.)) a = V(3.,2.,1.) b = a.normalize() __ok__(a != b) __ok__(a == V(3.,2.,1.)) __ok__(b.magnitude(), 1) b = a.magnitude(5) __ok__(a == V(3.,2.,1.)) __ok__(b.magnitude(), 5) __ok__(equal(b.dsquared(V.O), 25)) a = V(3.,2.,1.).normalize() __ok__(equal(a[0], 0.80178372573727319)) b = V(1.,3.,2.).normalize() __ok__(equal(b[2], 0.53452248382484879)) d = a.dot(b) __ok__(equal(d, 0.785714285714), True) __ok__(V(2., 2., 1.) * 3, V(6, 6, 3)) __ok__(3 * V(2., 2., 1.), V(6, 6, 3)) __ok__(V(2., 2., 1.) / 2, V(1, 1, 0.5)) v = V(1,2,3) w = V(4,5,6) __ok__(v.cross(w), V(-3,6,-3)) __ok__(v.cross(w), v*w) __ok__(v*w, -(w*v)) __ok__(v.dot(w), 32) __ok__(v.dot(w), w.dot(v)) __ok__(zero(angle(V(1,1,1), V(2,2,2))), True) __ok__(equal(90.0, degrees(angle(V(1,0,0), V(0,1,0)))), True) __ok__(equal(180.0, degrees(angle(V(1,0,0), V(-1,0,0)))), True) __ok__(equal( 0.0, degrees(track(V( 1, 0)))), True) __ok__(equal( 90.0, degrees(track(V( 0, 1)))), True) __ok__(equal(180.0, degrees(track(V(-1, 0)))), True) __ok__(equal(270.0, degrees(track(V( 0,-1)))), True) __ok__(equal( 45.0, degrees(track(V( 1, 1)))), True) __ok__(equal(135.0, degrees(track(V(-1, 1)))), True) __ok__(equal(225.0, degrees(track(V(-1,-1)))), True) __ok__(equal(315.0, degrees(track(V( 1,-1)))), True) print 'Testing C complex number class...' __ok__(C(1,2) is not None, True) __ok__(C(1,2)[0], 1.0) __ok__(C(1+2j)[0], 1.0) __ok__(C((1,2))[1], 2.0) __ok__(C(V([1,2]))[1], 2.0) __ok__(C(3+2j) * C(1+4j), C(-5+14j)) try: __ok__(C(1,2,3) is not None, True) except TypeError: # takes exactly 2 elements __ok__(True, True) try: __ok__(C([1,2,3]) is not None, True) except TypeError: # takes exactly 2 elements __ok__(True, True) except TypeError: # takes exactly 2 elements __ok__(True, True) print 'Testing Q quaternion class...' __ok__(Q(1,2,3,4) is not None, True) __ok__(Q(1,2,3,4)[1], 2.0) __ok__(Q((1,2,3,4))[2], 3.0) __ok__(Q(V(1,2,3,4))[3], 4.0) __ok__(Q(), Q(0,0,0,1)) __ok__(Q(1,2,3,4).conjugate(), Q(-1,-2,-3,4)) print 'Testing M matrix class...' m = M() __ok__(V(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1), m) __ok__(m.row(0), V(1,0,0,0)) __ok__(m.row(2), V(0,0,1,0)) __ok__(m.col(1), V(0,1,0,0)) __ok__(m.col(3), V(0,0,0,1)) __ok__(m[5], 1.0) __ok__(m[1,1], 1.0) __ok__(m[6], 0.0) __ok__(m[1,2], 0.0) __ok__(m * V(1,2,3,4), V(1,2,3,4)) __ok__(V(1,2,3,4) * m, V(1,2,3,4)) mm = m * m __ok__(mm.__class__, M) __ok__(mm, M.I) mm = m * 2 __ok__(mm.__class__, M) __ok__(mm, 2.0 * m) __ok__(mm[3,3], 2) __ok__(mm[3,2], 0) __ok__(M.rotate('X',radians(90)), M.twist(Q.rotate('X',radians(90)))) __ok__(M.twist(Q(0,0,0,1)), M.I) __ok__(M.twist(Q(.5,0,0,1)), M.twist(Q(.5,0,0,1).normalize())) __ok__(V.O * M.translate(V(1,2,3)), V(1,2,3,1)) __ok__((V.X+V.Y+V.Z) * M.translate(V(1,2,3)), V(2,3,4,1)) # need some tests on m.determinant() m = M() m = m.translate(V(1,2,3)) __ok__(m.inverse(), M().translate(-V(1,2,3))) m = m.rotate('Y', radians(30)) __ok__(m * m.inverse(), M.I) __report__() def __time__(): from testing import __time__ __time__("(V.X+V.Y).magnitude() memo", "import vectors; x=(vectors.V.X+vectors.V.Y)", "x._l = x._l ; x.magnitude()") __time__("(V.X+V.Y).magnitude() unmemo", "import vectors; x=(vectors.V.X+vectors.V.Y)", "x._l = None ; x.magnitude()") import psyco psyco.full() __time__("(V.X+V.Y).magnitude() memo [psyco]", "import vectors; x=(vectors.V.X+vectors.V.Y)", "x._l = x._l ; x.magnitude()") __time__("(V.X+V.Y).magnitude() unmemo [psyco]", "import vectors; x=(vectors.V.X+vectors.V.Y)", "x._l = None ; x.magnitude()") if __name__ == '__main__': import sys if 'test' in sys.argv: __test__() elif 'time' in sys.argv: __time__() else: raise Exception, \ 'This module is not a stand-alone script. Import it in a program.' autopep8-2.3.2/test/vim_autopep8.py000066400000000000000000000021751474147346600172610ustar00rootroot00000000000000"""Run autopep8 on the selected buffer in Vim. map :pyfile /vim_autopep8.py Replace ":pyfile" with ":py3file" if Vim is built with Python 3 support. """ from __future__ import unicode_literals import sys import vim ENCODING = vim.eval('&fileencoding') def encode(text): if sys.version_info.major >= 3: return text else: return text.encode(ENCODING) def decode(text): if sys.version_info.major >= 3: return text else: return text.decode(ENCODING) def main(): if vim.eval('&syntax') != 'python': return source = '\n'.join(decode(line) for line in vim.current.buffer) + '\n' import autopep8 formatted = autopep8.fix_code( source, options={'line_range': [1 + vim.current.range.start, 1 + vim.current.range.end]}) if source != formatted: if formatted.endswith('\n'): formatted = formatted[:-1] vim.current.buffer[:] = [encode(line) for line in formatted.splitlines()] if __name__ == '__main__': main() autopep8-2.3.2/tox.ini000066400000000000000000000004371474147346600146220ustar00rootroot00000000000000[tox] envlist=py38,py39,py310,py311,py312 skip_missing_interpreters=True [testenv] commands= python test/test_autopep8.py python test/acid.py --aggressive test/example.py python test/acid.py --compare-bytecode test/example.py deps= pycodestyle>=2.12.0 pydiff>=0.1.2 autopep8-2.3.2/update_readme.py000077500000000000000000000045351474147346600164660ustar00rootroot00000000000000#!/usr/bin/env python """Update example in readme.""" import io import os import sys import textwrap import pyflakes.api import pyflakes.messages import pyflakes.reporter import autopep8 def split_readme(readme_path, before_key, after_key, options_key, end_key): """Return split readme.""" with open(readme_path) as readme_file: readme = readme_file.read() top, rest = readme.split(before_key) before, rest = rest.split(after_key) _, rest = rest.split(options_key) _, bottom = rest.split(end_key) return (top.rstrip('\n'), before.strip('\n'), end_key + '\n\n' + bottom.lstrip('\n')) def indent_line(line): """Indent non-empty lines.""" if line: return 4 * ' ' + line return line def indent(text): """Indent text by four spaces.""" return '\n'.join(indent_line(line) for line in text.split('\n')) def help_message(): """Return help output.""" parser = autopep8.create_parser() string_io = io.StringIO() parser.print_help(string_io) # Undo home directory expansion. return string_io.getvalue().replace(os.path.expanduser('~'), '~') def check(source): """Check code.""" compile(source, '', 'exec', dont_inherit=True) reporter = pyflakes.reporter.Reporter(sys.stderr, sys.stderr) pyflakes.api.check(source, filename='', reporter=reporter) def main(): readme_path = 'README.rst' before_key = 'Before running autopep8.\n\n.. code-block:: python' after_key = 'After running autopep8.\n\n.. code-block:: python' options_key = 'Options::' (top, before, bottom) = split_readme(readme_path, before_key=before_key, after_key=after_key, options_key=options_key, end_key='Features\n========') input_code = textwrap.dedent(before) output_code = autopep8.fix_code( input_code, options={'aggressive': 2}) check(output_code) new_readme = '\n\n'.join([ top, before_key, before, after_key, indent(output_code).rstrip(), options_key, indent(help_message()), bottom]) with open(readme_path, 'w') as output_file: output_file.write(new_readme) if __name__ == '__main__': main()