├── pyupgrade_directories ├── py.typed ├── __main__.py └── __init__.py ├── requirements.txt ├── tests ├── conftest.py ├── requirements.txt └── test_pyup_dirs.py ├── .imgbotconfig ├── .dependabot └── config.yml ├── .github ├── dependabot.yml ├── auto_assign.yml ├── workflows │ ├── octocheese.yml │ ├── flake8.yml │ ├── mypy.yml │ ├── python_ci_macos.yml │ ├── python_ci.yml │ └── python_ci_linux.yml ├── milestones.py ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── stale.yml ├── .readthedocs.yml ├── .bumpversion.cfg ├── justfile ├── formate.toml ├── LICENSE ├── .gitignore ├── CONTRIBUTING.rst ├── repo_helper.yml ├── pyproject.toml ├── .pre-commit-config.yaml ├── README.rst ├── tox.ini ├── .style.yapf └── .pylintrc /pyupgrade_directories/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyupgrade>=2.5.0 2 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | pytest_plugins = ("coincidence", ) 2 | -------------------------------------------------------------------------------- /.imgbotconfig: -------------------------------------------------------------------------------- 1 | { 2 | "schedule": "weekly", 3 | "ignoredFiles": [ 4 | "**/*.svg" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | coincidence>=0.2.0 2 | coverage>=5.1 3 | coverage-pyver-pragma>=0.2.1 4 | importlib-metadata>=3.6.0 5 | pytest>=6.0.0 6 | pytest-cov>=2.8.1 7 | pytest-randomly>=3.7.0 8 | pytest-timeout>=1.4.2 9 | -------------------------------------------------------------------------------- /.dependabot/config.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | version: 1 4 | update_configs: 5 | - package_manager: python 6 | directory: / 7 | update_schedule: weekly 8 | default_reviewers: 9 | - domdfcoding 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | version: 2 4 | updates: 5 | - package-ecosystem: pip 6 | directory: / 7 | schedule: 8 | interval: weekly 9 | reviewers: 10 | - domdfcoding 11 | -------------------------------------------------------------------------------- /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | addReviewers: true 4 | addAssignees: true 5 | reviewers: 6 | - domdfcoding 7 | numberOfReviewers: 0 8 | 9 | # more settings at https://github.com/marketplace/actions/auto-assign-action 10 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | # Read the Docs configuration file 3 | --- 4 | version: 2 5 | sphinx: 6 | builder: html 7 | configuration: doc-source/conf.py 8 | formats: all 9 | python: 10 | version: 3.8 11 | install: 12 | - requirements: requirements.txt 13 | - requirements: doc-source/requirements.txt 14 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.3.0 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:README.rst] 7 | 8 | [bumpversion:file:pyupgrade_directories/__init__.py] 9 | 10 | search = : str = "{current_version}" 11 | replace = : str = "{new_version}" 12 | 13 | [bumpversion:file:repo_helper.yml] 14 | 15 | [bumpversion:file:pyproject.toml] 16 | search = version = "{current_version}" 17 | replace = version = "{new_version}" 18 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | default: lint 2 | 3 | pdf-docs: latex-docs 4 | make -C doc-source/build/latex/ 5 | 6 | latex-docs: 7 | SPHINX_BUILDER=latex tox -e docs 8 | 9 | unused-imports: 10 | tox -e lint -- --select F401 11 | 12 | incomplete-defs: 13 | tox -e lint -- --select MAN 14 | 15 | vdiff: 16 | git diff $(repo-helper show version -q)..HEAD 17 | 18 | bare-ignore: 19 | greppy '# type:? *ignore(?!\[|\w)' -s 20 | 21 | lint: unused-imports incomplete-defs bare-ignore 22 | tox -n qa 23 | -------------------------------------------------------------------------------- /.github/workflows/octocheese.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | 4 | name: "GitHub Releases" 5 | on: 6 | schedule: 7 | - cron: 0 12 * * * 8 | 9 | jobs: 10 | Run: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: domdfcoding/octocheese@master 14 | with: 15 | pypi_name: "pyupgrade-directories" 16 | env: 17 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 18 | if: startsWith(github.ref, 'refs/tags/') != true 19 | -------------------------------------------------------------------------------- /.github/milestones.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # stdlib 4 | import os 5 | import sys 6 | 7 | # 3rd party 8 | from github3 import GitHub 9 | from github3.repos import Repository 10 | from packaging.version import InvalidVersion, Version 11 | 12 | latest_tag = os.environ["GITHUB_REF_NAME"] 13 | 14 | try: 15 | current_version = Version(latest_tag) 16 | except InvalidVersion: 17 | sys.exit() 18 | 19 | gh: GitHub = GitHub(token=os.environ["GITHUB_TOKEN"]) 20 | repo: Repository = gh.repository(*os.environ["GITHUB_REPOSITORY"].split('/', 1)) 21 | 22 | for milestone in repo.milestones(state="open"): 23 | try: 24 | milestone_version = Version(milestone.title) 25 | except InvalidVersion: 26 | continue 27 | if milestone_version == current_version: 28 | sys.exit(not milestone.update(state="closed")) 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | labels: "enhancement" 5 | assignees: domdfcoding 6 | 7 | --- 8 | 9 | 11 | 12 | 13 | ## Description 14 | 15 | 16 | 17 | 18 | 19 | ## Version 20 | 21 | * Operating System: 22 | * Python: 23 | * pyupgrade-directories: 24 | 25 | 26 | ## Other Additional Information: 27 | 28 | -------------------------------------------------------------------------------- /formate.toml: -------------------------------------------------------------------------------- 1 | [hooks] 2 | dynamic_quotes = 10 3 | collections-import-rewrite = 20 4 | reformat-generics = 40 5 | noqa-reformat = 60 6 | ellipsis-reformat = 70 7 | squish_stubs = 80 8 | 9 | [config] 10 | indent = "\t" 11 | line_length = 115 12 | 13 | [hooks.yapf] 14 | priority = 30 15 | 16 | [hooks.isort] 17 | priority = 50 18 | 19 | [hooks.yapf.kwargs] 20 | yapf_style = ".style.yapf" 21 | 22 | [hooks.isort.kwargs] 23 | indent = "\t\t" 24 | multi_line_output = 8 25 | import_heading_stdlib = "stdlib" 26 | import_heading_thirdparty = "3rd party" 27 | import_heading_firstparty = "this package" 28 | import_heading_localfolder = "this package" 29 | balanced_wrapping = false 30 | lines_between_types = 0 31 | use_parentheses = true 32 | remove_redundant_aliases = true 33 | default_section = "THIRDPARTY" 34 | known_third_party = [ 35 | "coincidence", 36 | "coverage", 37 | "coverage_pyver_pragma", 38 | "github", 39 | "importlib_metadata", 40 | "pytest", 41 | "pytest_cov", 42 | "pytest_randomly", 43 | "pytest_timeout", 44 | "pyupgrade", 45 | "requests", 46 | ] 47 | known_first_party = "pyupgrade_directories" 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Dominic Davis-Foster 2 | Copyright (c) 2017 Anthony Sottile 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: bug 5 | assignees: domdfcoding 6 | 7 | --- 8 | 9 | 14 | 15 | ## Description 16 | 17 | 18 | 19 | ## Steps to Reproduce 20 | 24 | 25 | 1. 26 | 2. 27 | 3. 28 | 29 | ## Actual result: 30 | 31 | 32 | 33 | ## Expected result: 34 | 35 | 36 | ## Reproduces how often: 37 | 38 | 39 | 40 | ## Version 41 | 42 | * Operating System: 43 | * Python: 44 | * pyupgrade-directories: 45 | 46 | ## Installation source 47 | 48 | 49 | 50 | ## Other Additional Information: 51 | 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.so 6 | .Python 7 | build/ 8 | develop-eggs/ 9 | dist/ 10 | downloads/ 11 | eggs/ 12 | .eggs/ 13 | lib/ 14 | lib64/ 15 | parts/ 16 | sdist/ 17 | var/ 18 | wheels/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | *.egg* 23 | *.manifest 24 | *.spec 25 | pip-log.txt 26 | pip-delete-this-directory.txt 27 | htmlcov/ 28 | .tox/ 29 | .coverage 30 | .coverage.* 31 | .cache 32 | nosetests.xml 33 | coverage.xml 34 | *.cover 35 | .hypothesis/ 36 | .pytest_cache/ 37 | cover/ 38 | *.mo 39 | *.pot 40 | *.log 41 | local_settings.py 42 | db.sqlite3 43 | instance/ 44 | .webassets-cache 45 | .scrapy 46 | docs/_build/ 47 | doc/build 48 | target/ 49 | .ipynb_checkpoints 50 | .python-version 51 | celerybeat-schedule 52 | celerybeat.pid 53 | *.sage.py 54 | .env 55 | .venv 56 | env/ 57 | venv/ 58 | ENV/ 59 | env.bak/ 60 | venv.bak/ 61 | .spyderproject 62 | .spyproject 63 | .ropeproject 64 | /site 65 | .mypy_cache/ 66 | .dmypy.json 67 | dmypy.json 68 | *.iml 69 | *.ipr 70 | cmake-build-*/ 71 | .idea/**/mongoSettings.xml 72 | *.iws 73 | out/ 74 | atlassian-ide-plugin.xml 75 | com_crashlytics_export_strings.xml 76 | crashlytics.properties 77 | crashlytics-build.properties 78 | fabric.properties 79 | .idea 80 | build 81 | **/__pycache__ 82 | **/conda 83 | __pypackages__/ 84 | profile_default/ 85 | ipython_config.py 86 | Pipfile.lock 87 | .pyre/ 88 | -------------------------------------------------------------------------------- /pyupgrade_directories/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # __main__.py 4 | """ 5 | Run pyupgrade on all files in a directory, and optionally recursively. 6 | """ 7 | # 8 | # Copyright (c) 2020-2021 Dominic Davis-Foster 9 | # Based on pyupgrade 10 | # https://github.com/asottile/pyupgrade 11 | # Copyright (c) 2017 Anthony Sottile 12 | # MIT Licensed 13 | # 14 | 15 | # stdlib 16 | import argparse 17 | import pathlib 18 | import sys 19 | from typing import Optional, Sequence 20 | 21 | # this package 22 | from pyupgrade_directories import iter_py_files 23 | 24 | try: 25 | # < 2.8.0 26 | 27 | # 3rd party 28 | from pyupgrade import main as _pyup_main # type: ignore 29 | 30 | except ImportError: # pragma: no cover 31 | # 2.8.0+ 32 | 33 | # 3rd party 34 | from pyupgrade._main import main as _pyup_main # type: ignore 35 | 36 | __all__ = ["main"] 37 | 38 | 39 | def main(argv: Optional[Sequence[str]] = None) -> int: 40 | """ 41 | Entry point for ``pyupgrade_directories``. 42 | """ 43 | 44 | parser = argparse.ArgumentParser(add_help=False) 45 | parser.add_argument("filenames", nargs='*', type=pathlib.Path) 46 | parser.add_argument("--recursive", action="store_true", help="recurse subdirectories") 47 | 48 | args, argv = parser.parse_known_args(argv) 49 | 50 | return _pyup_main([*map(str, iter_py_files(args.filenames, args.recursive)), *argv]) 51 | 52 | 53 | if __name__ == "__main__": 54 | sys.exit(main()) 55 | -------------------------------------------------------------------------------- /.github/workflows/flake8.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | name: Flake8 4 | 5 | on: 6 | push: 7 | branches-ignore: 8 | - 'repo-helper-update' 9 | - 'pre-commit-ci-update-config' 10 | - 'imgbot' 11 | pull_request: 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | Run: 18 | name: "Flake8" 19 | runs-on: "ubuntu-20.04" 20 | 21 | steps: 22 | - name: Checkout 🛎️ 23 | uses: "actions/checkout@v2" 24 | 25 | - name: Check for changed files 26 | uses: dorny/paths-filter@v2 27 | id: changes 28 | with: 29 | list-files: "json" 30 | filters: | 31 | code: 32 | - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' 33 | 34 | - name: Setup Python 🐍 35 | if: steps.changes.outputs.code == 'true' 36 | uses: "actions/setup-python@v2" 37 | with: 38 | python-version: "3.6" 39 | 40 | - name: Install dependencies 🔧 41 | if: steps.changes.outputs.code == 'true' 42 | run: | 43 | python -VV 44 | python -m site 45 | python -m pip install --upgrade pip setuptools wheel 46 | python -m pip install tox 47 | 48 | - name: "Run Flake8" 49 | if: steps.changes.outputs.code == 'true' 50 | run: "python -m tox -e lint -s false -- --format github" 51 | -------------------------------------------------------------------------------- /.github/workflows/mypy.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | name: mypy 4 | 5 | on: 6 | push: 7 | branches-ignore: 8 | - 'repo-helper-update' 9 | - 'pre-commit-ci-update-config' 10 | - 'imgbot' 11 | pull_request: 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | Run: 18 | name: "mypy / ${{ matrix.os }}" 19 | runs-on: ${{ matrix.os }} 20 | 21 | strategy: 22 | matrix: 23 | os: ['ubuntu-20.04', 'windows-2019'] 24 | fail-fast: false 25 | 26 | steps: 27 | - name: Checkout 🛎️ 28 | uses: "actions/checkout@v2" 29 | 30 | - name: Check for changed files 31 | uses: dorny/paths-filter@v2 32 | id: changes 33 | with: 34 | list-files: "json" 35 | filters: | 36 | code: 37 | - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' 38 | 39 | - name: Setup Python 🐍 40 | if: steps.changes.outputs.code == 'true' 41 | uses: "actions/setup-python@v2" 42 | with: 43 | python-version: "3.6" 44 | 45 | - name: Install dependencies 🔧 46 | run: | 47 | python -VV 48 | python -m site 49 | python -m pip install --upgrade pip setuptools wheel 50 | python -m pip install --upgrade tox virtualenv!=20.16.0 51 | 52 | - name: "Run mypy" 53 | if: steps.changes.outputs.code == 'true' 54 | run: "python -m tox -e mypy -s false" 55 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Contributing 3 | ============== 4 | 5 | .. This file based on https://github.com/PyGithub/PyGithub/blob/master/CONTRIBUTING.md 6 | 7 | ``pyupgrade-directories`` uses `tox `_ to automate testing and packaging, 8 | and `pre-commit `_ to maintain code quality. 9 | 10 | Install ``pre-commit`` with ``pip`` and install the git hook: 11 | 12 | .. code-block:: bash 13 | 14 | $ python -m pip install pre-commit 15 | $ pre-commit install 16 | 17 | 18 | Coding style 19 | -------------- 20 | 21 | `formate `_ is used for code formatting. 22 | 23 | It can be run manually via ``pre-commit``: 24 | 25 | .. code-block:: bash 26 | 27 | $ pre-commit run formate -a 28 | 29 | 30 | Or, to run the complete autoformatting suite: 31 | 32 | .. code-block:: bash 33 | 34 | $ pre-commit run -a 35 | 36 | 37 | Automated tests 38 | ------------------- 39 | 40 | Tests are run with ``tox`` and ``pytest``. 41 | To run tests for a specific Python version, such as Python 3.6: 42 | 43 | .. code-block:: bash 44 | 45 | $ tox -e py36 46 | 47 | 48 | To run tests for all Python versions, simply run: 49 | 50 | .. code-block:: bash 51 | 52 | $ tox 53 | 54 | 55 | Type Annotations 56 | ------------------- 57 | 58 | Type annotations are checked using ``mypy``. Run ``mypy`` using ``tox``: 59 | 60 | .. code-block:: bash 61 | 62 | $ tox -e mypy 63 | 64 | 65 | 66 | Build documentation locally 67 | ------------------------------ 68 | 69 | The documentation is powered by Sphinx. A local copy of the documentation can be built with ``tox``: 70 | 71 | .. code-block:: bash 72 | 73 | $ tox -e docs 74 | -------------------------------------------------------------------------------- /pyupgrade_directories/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # __init__.py 4 | """ 5 | Run pyupgrade on all files in a directory, and optionally recursively. 6 | """ 7 | # 8 | # Copyright (c) 2020 Dominic Davis-Foster 9 | # MIT Licensed 10 | # 11 | 12 | # stdlib 13 | import pathlib 14 | from typing import Iterable, List 15 | 16 | __author__ = "Dominic Davis-Foster" 17 | __copyright__ = "2020 Dominic Davis-Foster" 18 | __license__ = "MIT" 19 | __version__ = "0.2.0" 20 | __email__ = "dominic@davis-foster.co.uk" 21 | 22 | __all__ = ["iter_py_files"] 23 | 24 | 25 | def iter_py_files( 26 | files_and_dirs: Iterable[pathlib.Path], 27 | recursive: bool = False, 28 | ) -> Iterable[pathlib.Path]: 29 | """ 30 | Iterate over all ``.py`` files in the given directories. 31 | 32 | .. TODO:: Wildcards in filename/directory 33 | 34 | :param files_and_dirs: An iterable of filenames and directories 35 | :param recursive: Whether subdirectories should be recursed. 36 | """ 37 | 38 | all_py_files: List[pathlib.Path] = [] 39 | 40 | for filename in files_and_dirs: 41 | 42 | if filename.suffix.startswith(".py") and filename.is_file(): 43 | all_py_files.append(filename) 44 | 45 | elif filename.is_dir(): 46 | if recursive: 47 | all_py_files += list(filename.rglob("*.py*")) 48 | else: 49 | all_py_files += list(filename.glob("*.py*")) 50 | 51 | for filename in all_py_files: 52 | if not filename.is_file(): 53 | continue 54 | 55 | if not filename.suffix.startswith(".py"): 56 | continue 57 | 58 | if filename.suffix in {".pyd", ".pyc", ".pyo"}: 59 | continue 60 | 61 | filename = filename.absolute() 62 | 63 | if any( 64 | exclude_dir in str(filename.parent) 65 | for exclude_dir in {".mypy_cache", ".pytest_cache", "venv", ".venv", ".tox", "__pycache__"} 66 | ): 67 | continue 68 | 69 | yield filename 70 | -------------------------------------------------------------------------------- /repo_helper.yml: -------------------------------------------------------------------------------- 1 | modname: pyupgrade-directories 2 | copyright_years: "2020" 3 | author: "Dominic Davis-Foster" 4 | email: "dominic@davis-foster.co.uk" 5 | version: "0.3.0" 6 | username: "domdfcoding" 7 | license: 'MIT' 8 | short_desc: 'Run pyupgrade on all files in a directory, and optionally recursively.' 9 | 10 | use_whey: true 11 | enable_conda: false 12 | enable_docs: False 13 | min_coverage: 95 14 | 15 | python_deploy_version: 3.6 16 | 17 | # Versions to run tests for 18 | python_versions: 19 | '3.6': 20 | matrix_exclude: 21 | pyupgrade: 22 | - 2.32 23 | - 2.33 24 | - 2.34 25 | - 2.35 26 | - 2.36 27 | - 2.37 28 | '3.7': 29 | "3.8": 30 | "3.9": 31 | "3.10": 32 | "3.11-dev": 33 | "pypy36": 34 | matrix_exclude: 35 | pyupgrade: 36 | - 2.32 37 | - 2.33 38 | - 2.34 39 | - 2.35 40 | - 2.36 41 | - 2.37 42 | "pypy37": 43 | "pypy38": 44 | "pypy39": 45 | 46 | 47 | classifiers: 48 | - 'Development Status :: 4 - Beta' 49 | - 'Environment :: Console' 50 | - 'Intended Audience :: Developers' 51 | - 'Operating System :: OS Independent' 52 | - 'Programming Language :: Python' 53 | - 'Topic :: Utilities' 54 | - "Topic :: Software Development" 55 | 56 | console_scripts: 57 | - pyup-dirs=pyupgrade_directories.__main__:main 58 | - pyup_dirs=pyupgrade_directories.__main__:main 59 | 60 | keywords: 61 | - pyupgrade 62 | - utility 63 | - linting 64 | 65 | third_party_version_matrix: 66 | pyupgrade: 67 | - "2.5" 68 | - "2.6" 69 | - "2.7" 70 | - "2.8" 71 | - "2.9" 72 | - "2.10" 73 | - "2.11" 74 | - "2.12" 75 | - "2.13" 76 | - "2.14" 77 | - "2.15" 78 | - "2.16" 79 | - "2.17" 80 | - "2.18" 81 | - "2.19" 82 | - "2.20" 83 | - "2.21" 84 | - "2.22" 85 | - "2.23" 86 | - "2.24" 87 | - "2.25" 88 | - "2.26" 89 | - "2.27" 90 | - "2.28" 91 | - "2.29" 92 | - "2.30" 93 | - "2.31" 94 | - "2.32" 95 | - "2.33" 96 | - "2.34" 97 | - "2.35" 98 | - "2.36" 99 | - "2.37" 100 | - latest 101 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | # Configuration for probot-stale - https://github.com/probot/stale 3 | --- 4 | 5 | # Number of days of inactivity before an Issue or Pull Request becomes stale 6 | daysUntilStale: 180 7 | 8 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 9 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 10 | daysUntilClose: false 11 | 12 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 13 | onlyLabels: [] 14 | 15 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 16 | exemptLabels: 17 | - pinned 18 | - security 19 | - "[Status] Maybe Later" 20 | 21 | # Set to true to ignore issues in a project (defaults to false) 22 | exemptProjects: false 23 | 24 | # Set to true to ignore issues in a milestone (defaults to false) 25 | exemptMilestones: false 26 | 27 | # Set to true to ignore issues with an assignee (defaults to false) 28 | exemptAssignees: false 29 | 30 | # Label to use when marking as stale 31 | staleLabel: stale 32 | 33 | # Comment to post when marking as stale. Set to `false` to disable 34 | markComment: false 35 | # This issue has been automatically marked as stale because it has not had 36 | # recent activity. It will be closed if no further activity occurs. Thank you 37 | # for your contributions. 38 | 39 | # Comment to post when removing the stale label. 40 | # unmarkComment: > 41 | # Your comment here. 42 | 43 | # Comment to post when closing a stale Issue or Pull Request. 44 | # closeComment: > 45 | # Your comment here. 46 | 47 | # Limit the number of actions per hour, from 1-30. Default is 30 48 | limitPerRun: 30 49 | 50 | # Limit to only `issues` or `pulls` 51 | # only: issues 52 | 53 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 54 | # pulls: 55 | # daysUntilStale: 30 56 | # markComment: > 57 | # This pull request has been automatically marked as stale because it has not had 58 | # recent activity. It will be closed if no further activity occurs. Thank you 59 | # for your contributions. 60 | 61 | # issues: 62 | # exemptLabels: 63 | # - confirmed 64 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ "whey",] 3 | build-backend = "whey" 4 | 5 | [project] 6 | name = "pyupgrade-directories" 7 | version = "0.3.0" 8 | description = "Run pyupgrade on all files in a directory, and optionally recursively." 9 | readme = "README.rst" 10 | keywords = [ "linting", "pyupgrade", "utility",] 11 | dynamic = [ "requires-python", "classifiers", "dependencies",] 12 | 13 | [[project.authors]] 14 | name = "Dominic Davis-Foster" 15 | email = "dominic@davis-foster.co.uk" 16 | 17 | 18 | [project.license] 19 | file = "LICENSE" 20 | 21 | [project.urls] 22 | Homepage = "https://github.com/domdfcoding/pyupgrade-directories" 23 | "Issue Tracker" = "https://github.com/domdfcoding/pyupgrade-directories/issues" 24 | "Source Code" = "https://github.com/domdfcoding/pyupgrade-directories" 25 | 26 | [project.scripts] 27 | pyup-dirs = "pyupgrade_directories.__main__:main" 28 | pyup_dirs = "pyupgrade_directories.__main__:main" 29 | 30 | [tool.importcheck] 31 | always = [ "pyupgrade_directories", "pyupgrade_directories.__main__",] 32 | 33 | [tool.whey] 34 | base-classifiers = [ 35 | "Development Status :: 4 - Beta", 36 | "Environment :: Console", 37 | "Intended Audience :: Developers", 38 | "Operating System :: OS Independent", 39 | "Programming Language :: Python", 40 | "Topic :: Software Development", 41 | "Topic :: Utilities", 42 | "Typing :: Typed", 43 | ] 44 | python-versions = [ "3.6", "3.7", "3.8", "3.9", "3.10",] 45 | python-implementations = [ "CPython", "PyPy",] 46 | platforms = [ "Windows", "macOS", "Linux",] 47 | license-key = "MIT" 48 | package = "pyupgrade_directories" 49 | 50 | [tool.mypy] 51 | python_version = "3.6" 52 | namespace_packages = true 53 | check_untyped_defs = true 54 | warn_unused_ignores = true 55 | no_implicit_optional = true 56 | show_error_codes = true 57 | 58 | [tool.snippet-fmt] 59 | directives = [ "code-block",] 60 | 61 | [tool.dep_checker] 62 | allowed_unused = [ "pyupgrade",] 63 | 64 | [tool.importcheck.config] 65 | show = true 66 | count = true 67 | 68 | [tool.dependency-dash."requirements.txt"] 69 | order = 10 70 | 71 | [tool.dependency-dash."tests/requirements.txt"] 72 | order = 20 73 | include = false 74 | 75 | [tool.snippet-fmt.languages.python] 76 | reformat = true 77 | 78 | [tool.snippet-fmt.languages.TOML] 79 | reformat = true 80 | 81 | [tool.snippet-fmt.languages.ini] 82 | 83 | [tool.snippet-fmt.languages.json] 84 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | 4 | exclude: ^$ 5 | 6 | ci: 7 | autoupdate_schedule: quarterly 8 | 9 | repos: 10 | - repo: https://github.com/repo-helper/pyproject-parser 11 | rev: v0.7.0 12 | hooks: 13 | - id: reformat-pyproject 14 | 15 | - repo: https://github.com/pre-commit/pre-commit-hooks 16 | rev: v3.4.0 17 | hooks: 18 | - id: check-added-large-files 19 | - id: check-ast 20 | - id: fix-byte-order-marker 21 | - id: check-byte-order-marker 22 | - id: check-case-conflict 23 | - id: check-executables-have-shebangs 24 | - id: check-json 25 | - id: check-toml 26 | - id: check-yaml 27 | - id: check-merge-conflict 28 | - id: check-symlinks 29 | - id: check-vcs-permalinks 30 | - id: detect-private-key 31 | - id: trailing-whitespace 32 | - id: mixed-line-ending 33 | - id: end-of-file-fixer 34 | 35 | - repo: https://github.com/domdfcoding/pre-commit-hooks 36 | rev: v0.4.0 37 | hooks: 38 | - id: requirements-txt-sorter 39 | args: 40 | - --allow-git 41 | - id: check-docstring-first 42 | exclude: ^(doc-source/conf|__pkginfo__|setup|tests/.*)\.py$ 43 | - id: bind-requirements 44 | 45 | - repo: https://github.com/domdfcoding/flake8-dunder-all 46 | rev: v0.2.2 47 | hooks: 48 | - id: ensure-dunder-all 49 | files: ^pyupgrade_directories/.*\.py$ 50 | 51 | - repo: https://github.com/domdfcoding/flake2lint 52 | rev: v0.4.2 53 | hooks: 54 | - id: flake2lint 55 | 56 | - repo: https://github.com/pre-commit/pygrep-hooks 57 | rev: v1.9.0 58 | hooks: 59 | - id: python-no-eval 60 | - id: rst-backticks 61 | - id: rst-directive-colons 62 | - id: rst-inline-touching-normal 63 | 64 | - repo: https://github.com/asottile/pyupgrade 65 | rev: v2.12.0 66 | hooks: 67 | - id: pyupgrade 68 | args: 69 | - --py36-plus 70 | - --keep-runtime-typing 71 | 72 | - repo: https://github.com/Lucas-C/pre-commit-hooks 73 | rev: v1.3.1 74 | hooks: 75 | - id: remove-crlf 76 | - id: forbid-crlf 77 | 78 | - repo: https://github.com/python-formate/snippet-fmt 79 | rev: v0.1.4 80 | hooks: 81 | - id: snippet-fmt 82 | 83 | - repo: https://github.com/python-formate/formate 84 | rev: v0.4.10 85 | hooks: 86 | - id: formate 87 | exclude: ^(doc-source/conf|__pkginfo__|setup)\.(_)?py$ 88 | 89 | - repo: https://github.com/domdfcoding/dep_checker 90 | rev: v0.7.0 91 | hooks: 92 | - id: dep_checker 93 | args: 94 | - pyupgrade_directories 95 | 96 | # Custom hooks can be added below this comment 97 | -------------------------------------------------------------------------------- /tests/test_pyup_dirs.py: -------------------------------------------------------------------------------- 1 | # stdlib 2 | from contextlib import contextmanager 3 | from pathlib import Path 4 | from typing import Iterator 5 | 6 | # 3rd party 7 | from domdf_python_tools.paths import PathPlus, in_directory 8 | 9 | # this package 10 | import pyupgrade_directories 11 | import pyupgrade_directories.__main__ 12 | 13 | 14 | @contextmanager 15 | def fail_on_systemexit() -> Iterator[None]: 16 | try: 17 | yield 18 | except SystemExit as e: 19 | raise ValueError(f"Process exited with code {e.code}") 20 | 21 | 22 | def test_iter_py_files(tmp_pathplus: PathPlus): 23 | (tmp_pathplus / "code.py").write_text("print('Hello World')\n") 24 | (tmp_pathplus / "code.pyi").write_text("def foo(): ...\n") 25 | (tmp_pathplus / "code.pyd").touch() 26 | (tmp_pathplus / "code.pyc").touch() 27 | (tmp_pathplus / "code.pyo").touch() 28 | (tmp_pathplus / "README.txt").write_text("This is the readme") 29 | 30 | (tmp_pathplus / "package").mkdir() 31 | (tmp_pathplus / "package" / "submodule.py").write_text("print('A submodule')\n") 32 | 33 | (tmp_pathplus / "venv" / "lib" / "python3.6" / "site-packages").mkdir(parents=True) 34 | (tmp_pathplus / "venv" / "lib" / "python3.6" / "site-packages" 35 | / "installed.py").write_text("print('An installed module')\n") 36 | 37 | with in_directory(tmp_pathplus), fail_on_systemexit(): 38 | assert list( 39 | pyupgrade_directories.iter_py_files([Path("code.py"), Path("README.txt"), Path("i.dont.exist")]) 40 | ) == [tmp_pathplus / "code.py"] 41 | 42 | with in_directory(tmp_pathplus), fail_on_systemexit(): 43 | assert sorted(pyupgrade_directories.iter_py_files([tmp_pathplus])) == [ 44 | tmp_pathplus / "code.py", 45 | tmp_pathplus / "code.pyi", 46 | ] 47 | 48 | with in_directory(tmp_pathplus), fail_on_systemexit(): 49 | assert sorted(pyupgrade_directories.iter_py_files([tmp_pathplus], recursive=True)) == [ 50 | tmp_pathplus / "code.py", 51 | tmp_pathplus / "code.pyi", 52 | tmp_pathplus / "package/submodule.py", 53 | ] 54 | 55 | 56 | def test_main(tmp_pathplus: PathPlus): 57 | (tmp_pathplus / "code.py").write_text("print('Hello World')\n") 58 | (tmp_pathplus / "code.pyi").write_text("def foo(): ...\n") 59 | (tmp_pathplus / "code.pyd").touch() 60 | (tmp_pathplus / "code.pyc").touch() 61 | (tmp_pathplus / "code.pyo").touch() 62 | (tmp_pathplus / "README.txt").write_text("This is the readme") 63 | 64 | (tmp_pathplus / "package").mkdir() 65 | (tmp_pathplus / "submodule.py").write_text("print('A submodule')\n") 66 | 67 | (tmp_pathplus / "venv" / "lib" / "python3.6" / "site-packages").mkdir(parents=True) 68 | (tmp_pathplus / "venv" / "lib" / "python3.6" / "site-packages" 69 | / "installed.py").write_text("print('An installed module')\n") 70 | 71 | with in_directory(tmp_pathplus), fail_on_systemexit(): 72 | assert pyupgrade_directories.__main__.main(["code.py", "README.txt", "i.dont.exist"]) == 0 73 | 74 | with in_directory(tmp_pathplus), fail_on_systemexit(): 75 | assert pyupgrade_directories.__main__.main([tmp_pathplus.as_posix()]) == 0 76 | 77 | with in_directory(tmp_pathplus), fail_on_systemexit(): 78 | assert pyupgrade_directories.__main__.main([tmp_pathplus.as_posix(), "--recursive"]) == 0 79 | 80 | assert (tmp_pathplus / "code.py").read_text() == "print('Hello World')\n" 81 | assert (tmp_pathplus / "code.pyi").read_text() == "def foo(): ...\n" 82 | assert (tmp_pathplus / "README.txt").read_text() == "This is the readme" 83 | assert (tmp_pathplus / "submodule.py").read_text() == "print('A submodule')\n" 84 | -------------------------------------------------------------------------------- /.github/workflows/python_ci_macos.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | name: macOS 4 | 5 | on: 6 | push: 7 | branches-ignore: 8 | - 'repo-helper-update' 9 | - 'pre-commit-ci-update-config' 10 | - 'imgbot' 11 | 12 | pull_request: 13 | 14 | permissions: 15 | actions: write 16 | issues: write 17 | contents: read 18 | 19 | jobs: 20 | tests: 21 | name: "macos-latest / Python ${{ matrix.config.python-version }}" 22 | runs-on: "macos-latest" 23 | continue-on-error: ${{ matrix.config.experimental }} 24 | env: 25 | USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10,3.11.0-rc.2,pypy-3.7,pypy-3.8,pypy-3.9' 26 | 27 | strategy: 28 | fail-fast: False 29 | matrix: 30 | config: 31 | - {python-version: "3.6", testenvs: "py36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest},build", experimental: False} 32 | - {python-version: "3.7", testenvs: "py37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 33 | - {python-version: "3.8", testenvs: "py38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 34 | - {python-version: "3.9", testenvs: "py39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 35 | - {python-version: "3.10", testenvs: "py310-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 36 | - {python-version: "3.11.0-rc.2", testenvs: "py311-dev-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 37 | - {python-version: "pypy-3.7", testenvs: "pypy37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 38 | - {python-version: "pypy-3.8", testenvs: "pypy38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 39 | - {python-version: "pypy-3.9", testenvs: "pypy39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest}", experimental: True} 40 | 41 | steps: 42 | - name: Checkout 🛎️ 43 | uses: "actions/checkout@v2" 44 | 45 | - name: Check for changed files 46 | if: startsWith(github.ref, 'refs/tags/') != true 47 | uses: dorny/paths-filter@v2 48 | id: changes 49 | with: 50 | list-files: "json" 51 | filters: | 52 | code: 53 | - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' 54 | 55 | - name: Setup Python 🐍 56 | id: setup-python 57 | if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} 58 | uses: "actions/setup-python@v2" 59 | with: 60 | python-version: "${{ matrix.config.python-version }}" 61 | 62 | - name: Install dependencies 🔧 63 | if: steps.setup-python.outcome == 'success' 64 | run: | 65 | python -VV 66 | python -m site 67 | python -m pip install --upgrade pip setuptools wheel 68 | python -m pip install --upgrade tox virtualenv!=20.16.0 69 | 70 | - name: "Run Tests for Python ${{ matrix.config.python-version }}" 71 | if: steps.setup-python.outcome == 'success' 72 | run: python -m tox -e "${{ matrix.config.testenvs }}" -s false 73 | 74 | - name: "Upload Coverage 🚀" 75 | uses: actions/upload-artifact@v2 76 | if: ${{ always() && steps.setup-python.outcome == 'success' }} 77 | with: 78 | name: "coverage-${{ matrix.config.python-version }}" 79 | path: .coverage 80 | -------------------------------------------------------------------------------- /.github/workflows/python_ci.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | name: Windows 4 | 5 | on: 6 | push: 7 | branches-ignore: 8 | - 'repo-helper-update' 9 | - 'pre-commit-ci-update-config' 10 | - 'imgbot' 11 | 12 | pull_request: 13 | 14 | permissions: 15 | actions: write 16 | issues: write 17 | contents: read 18 | 19 | jobs: 20 | tests: 21 | name: "windows-2019 / Python ${{ matrix.config.python-version }}" 22 | runs-on: "windows-2019" 23 | continue-on-error: ${{ matrix.config.experimental }} 24 | env: 25 | USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10,3.11.0-rc.2,pypy-3.6,pypy-3.7,pypy-3.8,pypy-3.9' 26 | 27 | strategy: 28 | fail-fast: False 29 | matrix: 30 | config: 31 | - {python-version: "3.6", testenvs: "py36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest},build", experimental: False} 32 | - {python-version: "3.7", testenvs: "py37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 33 | - {python-version: "3.8", testenvs: "py38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 34 | - {python-version: "3.9", testenvs: "py39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 35 | - {python-version: "3.10", testenvs: "py310-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 36 | - {python-version: "3.11.0-rc.2", testenvs: "py311-dev-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 37 | - {python-version: "pypy-3.6", testenvs: "pypy36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest},build", experimental: False} 38 | - {python-version: "pypy-3.7", testenvs: "pypy37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 39 | - {python-version: "pypy-3.8", testenvs: "pypy38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 40 | - {python-version: "pypy-3.9", testenvs: "pypy39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest}", experimental: True} 41 | 42 | steps: 43 | - name: Checkout 🛎️ 44 | uses: "actions/checkout@v2" 45 | 46 | - name: Check for changed files 47 | if: startsWith(github.ref, 'refs/tags/') != true 48 | uses: dorny/paths-filter@v2 49 | id: changes 50 | with: 51 | list-files: "json" 52 | filters: | 53 | code: 54 | - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' 55 | 56 | - name: Setup Python 🐍 57 | id: setup-python 58 | if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} 59 | uses: "actions/setup-python@v2" 60 | with: 61 | python-version: "${{ matrix.config.python-version }}" 62 | 63 | - name: Install dependencies 🔧 64 | if: steps.setup-python.outcome == 'success' 65 | run: | 66 | python -VV 67 | python -m site 68 | python -m pip install --upgrade pip setuptools wheel 69 | python -m pip install --upgrade tox virtualenv!=20.16.0 70 | 71 | - name: "Run Tests for Python ${{ matrix.config.python-version }}" 72 | if: steps.setup-python.outcome == 'success' 73 | run: python -m tox -e "${{ matrix.config.testenvs }}" -s false 74 | 75 | - name: "Upload Coverage 🚀" 76 | uses: actions/upload-artifact@v2 77 | if: ${{ always() && steps.setup-python.outcome == 'success' }} 78 | with: 79 | name: "coverage-${{ matrix.config.python-version }}" 80 | path: .coverage 81 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | pyupgrade-directories 3 | ========================== 4 | 5 | .. start short_desc 6 | 7 | **Run pyupgrade on all files in a directory, and optionally recursively.** 8 | 9 | .. end short_desc 10 | 11 | 12 | .. start shields 13 | 14 | .. list-table:: 15 | :stub-columns: 1 16 | :widths: 10 90 17 | 18 | * - Tests 19 | - |actions_linux| |actions_windows| |actions_macos| |coveralls| 20 | * - PyPI 21 | - |pypi-version| |supported-versions| |supported-implementations| |wheel| 22 | * - Activity 23 | - |commits-latest| |commits-since| |maintained| |pypi-downloads| 24 | * - QA 25 | - |codefactor| |actions_flake8| |actions_mypy| 26 | * - Other 27 | - |license| |language| |requires| 28 | 29 | .. |actions_linux| image:: https://github.com/domdfcoding/pyupgrade-directories/workflows/Linux/badge.svg 30 | :target: https://github.com/domdfcoding/pyupgrade-directories/actions?query=workflow%3A%22Linux%22 31 | :alt: Linux Test Status 32 | 33 | .. |actions_windows| image:: https://github.com/domdfcoding/pyupgrade-directories/workflows/Windows/badge.svg 34 | :target: https://github.com/domdfcoding/pyupgrade-directories/actions?query=workflow%3A%22Windows%22 35 | :alt: Windows Test Status 36 | 37 | .. |actions_macos| image:: https://github.com/domdfcoding/pyupgrade-directories/workflows/macOS/badge.svg 38 | :target: https://github.com/domdfcoding/pyupgrade-directories/actions?query=workflow%3A%22macOS%22 39 | :alt: macOS Test Status 40 | 41 | .. |actions_flake8| image:: https://github.com/domdfcoding/pyupgrade-directories/workflows/Flake8/badge.svg 42 | :target: https://github.com/domdfcoding/pyupgrade-directories/actions?query=workflow%3A%22Flake8%22 43 | :alt: Flake8 Status 44 | 45 | .. |actions_mypy| image:: https://github.com/domdfcoding/pyupgrade-directories/workflows/mypy/badge.svg 46 | :target: https://github.com/domdfcoding/pyupgrade-directories/actions?query=workflow%3A%22mypy%22 47 | :alt: mypy status 48 | 49 | .. |requires| image:: https://dependency-dash.repo-helper.uk/github/domdfcoding/pyupgrade-directories/badge.svg 50 | :target: https://dependency-dash.repo-helper.uk/github/domdfcoding/pyupgrade-directories/ 51 | :alt: Requirements Status 52 | 53 | .. |coveralls| image:: https://img.shields.io/coveralls/github/domdfcoding/pyupgrade-directories/master?logo=coveralls 54 | :target: https://coveralls.io/github/domdfcoding/pyupgrade-directories?branch=master 55 | :alt: Coverage 56 | 57 | .. |codefactor| image:: https://img.shields.io/codefactor/grade/github/domdfcoding/pyupgrade-directories?logo=codefactor 58 | :target: https://www.codefactor.io/repository/github/domdfcoding/pyupgrade-directories 59 | :alt: CodeFactor Grade 60 | 61 | .. |pypi-version| image:: https://img.shields.io/pypi/v/pyupgrade-directories 62 | :target: https://pypi.org/project/pyupgrade-directories/ 63 | :alt: PyPI - Package Version 64 | 65 | .. |supported-versions| image:: https://img.shields.io/pypi/pyversions/pyupgrade-directories?logo=python&logoColor=white 66 | :target: https://pypi.org/project/pyupgrade-directories/ 67 | :alt: PyPI - Supported Python Versions 68 | 69 | .. |supported-implementations| image:: https://img.shields.io/pypi/implementation/pyupgrade-directories 70 | :target: https://pypi.org/project/pyupgrade-directories/ 71 | :alt: PyPI - Supported Implementations 72 | 73 | .. |wheel| image:: https://img.shields.io/pypi/wheel/pyupgrade-directories 74 | :target: https://pypi.org/project/pyupgrade-directories/ 75 | :alt: PyPI - Wheel 76 | 77 | .. |license| image:: https://img.shields.io/github/license/domdfcoding/pyupgrade-directories 78 | :target: https://github.com/domdfcoding/pyupgrade-directories/blob/master/LICENSE 79 | :alt: License 80 | 81 | .. |language| image:: https://img.shields.io/github/languages/top/domdfcoding/pyupgrade-directories 82 | :alt: GitHub top language 83 | 84 | .. |commits-since| image:: https://img.shields.io/github/commits-since/domdfcoding/pyupgrade-directories/v0.3.0 85 | :target: https://github.com/domdfcoding/pyupgrade-directories/pulse 86 | :alt: GitHub commits since tagged version 87 | 88 | .. |commits-latest| image:: https://img.shields.io/github/last-commit/domdfcoding/pyupgrade-directories 89 | :target: https://github.com/domdfcoding/pyupgrade-directories/commit/master 90 | :alt: GitHub last commit 91 | 92 | .. |maintained| image:: https://img.shields.io/maintenance/yes/2022 93 | :alt: Maintenance 94 | 95 | .. |pypi-downloads| image:: https://img.shields.io/pypi/dm/pyupgrade-directories 96 | :target: https://pypi.org/project/pyupgrade-directories/ 97 | :alt: PyPI - Downloads 98 | 99 | .. end shields 100 | 101 | 102 | Installation 103 | -------------- 104 | 105 | .. start installation 106 | 107 | ``pyupgrade-directories`` can be installed from PyPI. 108 | 109 | To install with ``pip``: 110 | 111 | .. code-block:: bash 112 | 113 | $ python -m pip install pyupgrade-directories 114 | 115 | .. end installation 116 | 117 | 118 | Usage 119 | -------------- 120 | 121 | ``pyupgrade-directories`` is called from the command line with ``pyup_dirs``. 122 | 123 | Basic usage is the same as ``pyupgrade``. 124 | See https://github.com/asottile/pyupgrade/blob/master/README.md for more information. 125 | 126 | The key difference is that passing a directory to ``pyup_dir`` will process all ``.py`` files in the directory. 127 | There is also ``--recursive`` flag that will recurse subdirectories. 128 | 129 | Any ``.pyd``, ``.pyc`` and ``.pyo`` files are excluded, along with any files in 130 | ``__pycache__``, ``.tox``, ``.mypy_cache``, ``.pytest_cache`` and ``venv`` directories. 131 | -------------------------------------------------------------------------------- /.github/workflows/python_ci_linux.yml: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. Don't edit it directly. 2 | --- 3 | name: Linux 4 | 5 | on: 6 | push: 7 | branches-ignore: 8 | - 'repo-helper-update' 9 | - 'pre-commit-ci-update-config' 10 | - 'imgbot' 11 | tags: 12 | - '*' 13 | pull_request: 14 | 15 | permissions: 16 | actions: write 17 | issues: write 18 | contents: read 19 | 20 | jobs: 21 | tests: 22 | name: "ubuntu-20.04 / Python ${{ matrix.config.python-version }}" 23 | runs-on: "ubuntu-20.04" 24 | continue-on-error: ${{ matrix.config.experimental }} 25 | env: 26 | USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10,3.11.0-rc.2,pypy-3.6,pypy-3.7,pypy-3.8,pypy-3.9' 27 | 28 | strategy: 29 | fail-fast: False 30 | matrix: 31 | config: 32 | - {python-version: "3.6", testenvs: "py36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest},build", experimental: False} 33 | - {python-version: "3.7", testenvs: "py37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 34 | - {python-version: "3.8", testenvs: "py38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 35 | - {python-version: "3.9", testenvs: "py39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 36 | - {python-version: "3.10", testenvs: "py310-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: False} 37 | - {python-version: "3.11.0-rc.2", testenvs: "py311-dev-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 38 | - {python-version: "pypy-3.6", testenvs: "pypy36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest},build", experimental: False} 39 | - {python-version: "pypy-3.7", testenvs: "pypy37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 40 | - {python-version: "pypy-3.8", testenvs: "pypy38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest},build", experimental: True} 41 | - {python-version: "pypy-3.9", testenvs: "pypy39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest}", experimental: True} 42 | 43 | steps: 44 | - name: Checkout 🛎️ 45 | uses: "actions/checkout@v2" 46 | 47 | - name: Check for changed files 48 | if: startsWith(github.ref, 'refs/tags/') != true 49 | uses: dorny/paths-filter@v2 50 | id: changes 51 | with: 52 | list-files: "json" 53 | filters: | 54 | code: 55 | - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' 56 | 57 | - name: Setup Python 🐍 58 | id: setup-python 59 | if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} 60 | uses: "actions/setup-python@v2" 61 | with: 62 | python-version: "${{ matrix.config.python-version }}" 63 | 64 | - name: Install dependencies 🔧 65 | if: steps.setup-python.outcome == 'success' 66 | run: | 67 | python -VV 68 | python -m site 69 | python -m pip install --upgrade pip setuptools wheel 70 | python -m pip install --upgrade tox virtualenv!=20.16.0 71 | python -m pip install --upgrade coverage_pyver_pragma 72 | 73 | - name: "Run Tests for Python ${{ matrix.config.python-version }}" 74 | if: steps.setup-python.outcome == 'success' 75 | run: python -m tox -e "${{ matrix.config.testenvs }}" -s false 76 | 77 | - name: "Upload Coverage 🚀" 78 | uses: actions/upload-artifact@v2 79 | if: ${{ always() && steps.setup-python.outcome == 'success' }} 80 | with: 81 | name: "coverage-${{ matrix.config.python-version }}" 82 | path: .coverage 83 | 84 | 85 | Coverage: 86 | needs: tests 87 | runs-on: "ubuntu-20.04" 88 | steps: 89 | - name: Checkout 🛎️ 90 | uses: "actions/checkout@v2" 91 | 92 | - name: Setup Python 🐍 93 | uses: "actions/setup-python@v2" 94 | with: 95 | python-version: 3.8 96 | 97 | - name: Install dependencies 🔧 98 | run: | 99 | python -m pip install --upgrade pip setuptools wheel 100 | python -m pip install --upgrade "coveralls>=3.0.0" coverage_pyver_pragma 101 | 102 | - name: "Download Coverage 🪂" 103 | uses: actions/download-artifact@v2 104 | with: 105 | path: coverage 106 | 107 | - name: Display structure of downloaded files 108 | id: show 109 | run: ls -R 110 | working-directory: coverage 111 | continue-on-error: true 112 | 113 | - name: Combine Coverage 👷 114 | if: ${{ steps.show.outcome != 'failure' }} 115 | run: | 116 | shopt -s globstar 117 | python -m coverage combine coverage/**/.coverage 118 | 119 | - name: "Upload Combined Coverage Artefact 🚀" 120 | if: ${{ steps.show.outcome != 'failure' }} 121 | uses: actions/upload-artifact@v2 122 | with: 123 | name: "combined-coverage" 124 | path: .coverage 125 | 126 | - name: "Upload Combined Coverage to Coveralls" 127 | if: ${{ steps.show.outcome != 'failure' }} 128 | env: 129 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 130 | run: | 131 | coveralls --service=github 132 | 133 | Deploy: 134 | needs: tests 135 | 136 | runs-on: "ubuntu-20.04" 137 | steps: 138 | - name: Checkout 🛎️ 139 | uses: "actions/checkout@v2" 140 | if: startsWith(github.ref, 'refs/tags/') 141 | 142 | - name: Setup Python 🐍 143 | uses: "actions/setup-python@v2" 144 | if: startsWith(github.ref, 'refs/tags/') 145 | with: 146 | python-version: 3.8 147 | 148 | - name: Install dependencies 🔧 149 | if: startsWith(github.ref, 'refs/tags/') 150 | run: | 151 | python -m pip install --upgrade pip setuptools wheel 152 | python -m pip install --upgrade tox 153 | 154 | - name: Build distributions 📦 155 | if: startsWith(github.ref, 'refs/tags/') 156 | run: | 157 | tox -e build 158 | 159 | 160 | - name: Upload distribution to PyPI 🚀 161 | if: startsWith(github.ref, 'refs/tags/') 162 | uses: pypa/gh-action-pypi-publish@v1.4.2 163 | with: 164 | user: __token__ 165 | password: ${{ secrets.PYPI_TOKEN }} 166 | skip_existing: true 167 | 168 | - name: Close milestone 🚪 169 | if: startsWith(github.ref, 'refs/tags/') 170 | run: | 171 | python -m pip install --upgrade github3.py packaging 172 | python .github/milestones.py 173 | env: 174 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 175 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # This file is managed by 'repo_helper'. 2 | # You may add new sections, but any changes made to the following sections will be lost: 3 | # * tox 4 | # * envlists 5 | # * testenv 6 | # * testenv:docs 7 | # * testenv:build 8 | # * testenv:lint 9 | # * testenv:perflint 10 | # * testenv:mypy 11 | # * testenv:pyup 12 | # * testenv:coverage 13 | # * flake8 14 | # * coverage:run 15 | # * coverage:report 16 | # * check-wheel-contents 17 | # * pytest 18 | 19 | [tox] 20 | envlist = 21 | py36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest} 22 | py37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 23 | py38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 24 | py39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 25 | py310-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 26 | py311-dev-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 27 | pypy36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest} 28 | pypy37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 29 | pypy38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 30 | pypy39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 31 | mypy 32 | build 33 | skip_missing_interpreters = True 34 | isolated_build = True 35 | requires = 36 | pip>=21,!=22.2 37 | tox-envlist>=0.2.1 38 | virtualenv!=20.16.0 39 | 40 | [envlists] 41 | test = 42 | py36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest} 43 | py37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 44 | py38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 45 | py39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 46 | py310-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 47 | py311-dev-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 48 | pypy36-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,latest} 49 | pypy37-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 50 | pypy38-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 51 | pypy39-pyupgrade{2.5,2.6,2.7,2.8,2.9,2.10,2.11,2.12,2.13,2.14,2.15,2.16,2.17,2.18,2.19,2.20,2.21,2.22,2.23,2.24,2.25,2.26,2.27,2.28,2.29,2.30,2.31,2.32,2.33,2.34,2.35,2.36,2.37,latest} 52 | qa = mypy, lint 53 | cov = py36-pyupgrade2.5, coverage 54 | 55 | [testenv] 56 | setenv = 57 | PYTHONDEVMODE=1 58 | PIP_DISABLE_PIP_VERSION_CHECK=1 59 | SETUPTOOLS_USE_DISTUTILS=stdlib 60 | deps = 61 | -r{toxinidir}/tests/requirements.txt 62 | pyupgrade2.5: pyupgrade~=2.5.0 63 | pyupgrade2.6: pyupgrade~=2.6.0 64 | pyupgrade2.7: pyupgrade~=2.7.0 65 | pyupgrade2.8: pyupgrade~=2.8.0 66 | pyupgrade2.9: pyupgrade~=2.9.0 67 | pyupgrade2.10: pyupgrade~=2.10.0 68 | pyupgrade2.11: pyupgrade~=2.11.0 69 | pyupgrade2.12: pyupgrade~=2.12.0 70 | pyupgrade2.13: pyupgrade~=2.13.0 71 | pyupgrade2.14: pyupgrade~=2.14.0 72 | pyupgrade2.15: pyupgrade~=2.15.0 73 | pyupgrade2.16: pyupgrade~=2.16.0 74 | pyupgrade2.17: pyupgrade~=2.17.0 75 | pyupgrade2.18: pyupgrade~=2.18.0 76 | pyupgrade2.19: pyupgrade~=2.19.0 77 | pyupgrade2.20: pyupgrade~=2.20.0 78 | pyupgrade2.21: pyupgrade~=2.21.0 79 | pyupgrade2.22: pyupgrade~=2.22.0 80 | pyupgrade2.23: pyupgrade~=2.23.0 81 | pyupgrade2.24: pyupgrade~=2.24.0 82 | pyupgrade2.25: pyupgrade~=2.25.0 83 | pyupgrade2.26: pyupgrade~=2.26.0 84 | pyupgrade2.27: pyupgrade~=2.27.0 85 | pyupgrade2.28: pyupgrade~=2.28.0 86 | pyupgrade2.29: pyupgrade~=2.29.0 87 | pyupgrade2.30: pyupgrade~=2.30.0 88 | pyupgrade2.31: pyupgrade~=2.31.0 89 | pyupgrade2.32: pyupgrade~=2.32.0 90 | pyupgrade2.33: pyupgrade~=2.33.0 91 | pyupgrade2.34: pyupgrade~=2.34.0 92 | pyupgrade2.35: pyupgrade~=2.35.0 93 | pyupgrade2.36: pyupgrade~=2.36.0 94 | pyupgrade2.37: pyupgrade~=2.37.0 95 | pyupgradelatest: pyupgrade 96 | commands = 97 | python --version 98 | python -m pytest --cov=pyupgrade_directories -r aR tests/ {posargs} 99 | 100 | [testenv:build] 101 | skip_install = True 102 | changedir = {toxinidir} 103 | deps = 104 | build[virtualenv]>=0.3.1 105 | check-wheel-contents>=0.1.0 106 | twine>=3.2.0 107 | commands = 108 | python -m build --sdist --wheel "{toxinidir}" 109 | twine check dist/*.tar.gz dist/*.whl 110 | check-wheel-contents dist/ 111 | 112 | [testenv:lint] 113 | basepython = python3.6 114 | changedir = {toxinidir} 115 | ignore_errors = True 116 | skip_install = True 117 | deps = 118 | flake8>=3.8.2,<5 119 | flake8-2020>=1.6.0 120 | flake8-builtins>=1.5.3 121 | flake8-docstrings>=1.5.0 122 | flake8-dunder-all>=0.1.1 123 | flake8-encodings>=0.1.0 124 | flake8-github-actions>=0.1.0 125 | flake8-noqa>=1.1.0,<=1.2.2 126 | flake8-pyi>=20.10.0,<=22.8.0 127 | flake8-pytest-style>=1.3.0 128 | flake8-quotes>=3.3.0 129 | flake8-slots>=0.1.0 130 | flake8-sphinx-links>=0.0.4 131 | flake8-strftime>=0.1.1 132 | flake8-typing-imports>=1.10.0 133 | git+https://github.com/domdfcoding/flake8-rst-docstrings-sphinx.git 134 | git+https://github.com/domdfcoding/flake8-rst-docstrings.git 135 | git+https://github.com/python-formate/flake8-unused-arguments.git@magic-methods 136 | git+https://github.com/python-formate/flake8-missing-annotations.git 137 | pydocstyle>=6.0.0 138 | pygments>=2.7.1 139 | importlib_metadata<4.5.0; python_version<'3.8' 140 | commands = python3 -m flake8_rst_docstrings_sphinx pyupgrade_directories tests --allow-toolbox {posargs} 141 | 142 | [testenv:perflint] 143 | basepython = python3.6 144 | changedir = {toxinidir} 145 | ignore_errors = True 146 | skip_install = True 147 | deps = perflint 148 | commands = python3 -m perflint pyupgrade_directories {posargs} 149 | 150 | [testenv:mypy] 151 | basepython = python3.6 152 | ignore_errors = True 153 | changedir = {toxinidir} 154 | deps = 155 | mypy==0.971 156 | -r{toxinidir}/tests/requirements.txt 157 | commands = mypy pyupgrade_directories tests {posargs} 158 | 159 | [testenv:pyup] 160 | basepython = python3.6 161 | skip_install = True 162 | ignore_errors = True 163 | changedir = {toxinidir} 164 | deps = pyupgrade-directories 165 | commands = pyup_dirs pyupgrade_directories tests --py36-plus --recursive 166 | 167 | [testenv:coverage] 168 | basepython = python3.6 169 | skip_install = True 170 | ignore_errors = True 171 | whitelist_externals = /bin/bash 172 | passenv = 173 | COV_PYTHON_VERSION 174 | COV_PLATFORM 175 | COV_PYTHON_IMPLEMENTATION 176 | * 177 | changedir = {toxinidir} 178 | deps = 179 | coverage>=5 180 | coverage_pyver_pragma>=0.2.1 181 | commands = 182 | /bin/bash -c "rm -rf htmlcov" 183 | coverage html 184 | /bin/bash -c "DISPLAY=:0 firefox 'htmlcov/index.html'" 185 | 186 | [flake8] 187 | max-line-length = 120 188 | select = E111 E112 E113 E121 E122 E125 E127 E128 E129 E131 E133 E201 E202 E203 E211 E222 E223 E224 E225 E225 E226 E227 E228 E231 E241 E242 E251 E261 E262 E265 E271 E272 E303 E304 E306 E402 E502 E703 E711 E712 E713 E714 E721 W291 W292 W293 W391 W504 YTT101 YTT102 YTT103 YTT201 YTT202 YTT203 YTT204 YTT301 YTT302 YTT303 STRFTIME001 STRFTIME002 SXL001 PT001 PT002 PT003 PT006 PT007 PT008 PT009 PT010 PT011 PT012 PT013 PT014 PT015 PT016 PT017 PT018 PT019 PT020 PT021 RST201 RST202 RST203 RST204 RST205 RST206 RST207 RST208 RST210 RST211 RST212 RST213 RST214 RST215 RST216 RST217 RST218 RST219 RST299 RST301 RST302 RST303 RST304 RST305 RST306 RST399 RST401 RST499 RST900 RST901 RST902 RST903 Q001 Q002 Q003 A001 A002 A003 TYP001 TYP002 TYP003 TYP004 TYP005 TYP006 ENC001 ENC002 ENC003 ENC004 ENC011 ENC012 ENC021 ENC022 ENC023 ENC024 ENC025 ENC026 Y001,Y002 Y003 Y004 Y005 Y006 Y007 Y008 Y009 Y010 Y011 Y012 Y013 Y014 Y015 Y090 Y091 NQA001 NQA002 NQA003 NQA004 NQA005 NQA102 NQA103 E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 189 | extend-exclude = doc-source,old,build,dist,__pkginfo__.py,setup.py,venv 190 | rst-directives = 191 | TODO 192 | envvar 193 | extras-require 194 | license 195 | license-info 196 | rst-roles = choosealicense 197 | per-file-ignores = 198 | tests/*: D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 199 | */*.pyi: E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 200 | pytest-parametrize-names-type = csv 201 | inline-quotes = " 202 | multiline-quotes = """ 203 | docstring-quotes = """ 204 | count = True 205 | min_python_version = 3.6.1 206 | unused-arguments-ignore-abstract-functions = True 207 | unused-arguments-ignore-overload-functions = True 208 | unused-arguments-ignore-magic-methods = True 209 | unused-arguments-ignore-variadic-names = True 210 | 211 | [coverage:run] 212 | plugins = coverage_pyver_pragma 213 | 214 | [coverage:report] 215 | fail_under = 95 216 | exclude_lines = 217 | raise AssertionError 218 | raise NotImplementedError 219 | if 0: 220 | if False: 221 | if TYPE_CHECKING: 222 | if typing.TYPE_CHECKING: 223 | if __name__ == .__main__.: 224 | 225 | [check-wheel-contents] 226 | ignore = W002 227 | toplevel = pyupgrade_directories 228 | package = pyupgrade_directories 229 | 230 | [pytest] 231 | addopts = --color yes --durations 25 232 | timeout = 300 233 | -------------------------------------------------------------------------------- /.style.yapf: -------------------------------------------------------------------------------- 1 | [style] 2 | # Align closing bracket with visual indentation. 3 | align_closing_bracket_with_visual_indent=True 4 | 5 | # Allow dictionary keys to exist on multiple lines. For example: 6 | # 7 | # x = { 8 | # ('this is the first element of a tuple', 9 | # 'this is the second element of a tuple'): 10 | # value, 11 | # } 12 | allow_multiline_dictionary_keys=True 13 | 14 | # Allow lambdas to be formatted on more than one line. 15 | allow_multiline_lambdas=False 16 | 17 | # Allow splitting before a default / named assignment in an argument list. 18 | allow_split_before_default_or_named_assigns=True 19 | 20 | # Allow splits before the dictionary value. 21 | allow_split_before_dict_value=True 22 | 23 | # Let spacing indicate operator precedence. For example: 24 | # 25 | # a = 1 * 2 + 3 / 4 26 | # b = 1 / 2 - 3 * 4 27 | # c = (1 + 2) * (3 - 4) 28 | # d = (1 - 2) / (3 + 4) 29 | # e = 1 * 2 - 3 30 | # f = 1 + 2 + 3 + 4 31 | # 32 | # will be formatted as follows to indicate precedence: 33 | # 34 | # a = 1*2 + 3/4 35 | # b = 1/2 - 3*4 36 | # c = (1+2) * (3-4) 37 | # d = (1-2) / (3+4) 38 | # e = 1*2 - 3 39 | # f = 1 + 2 + 3 + 4 40 | # 41 | arithmetic_precedence_indication=False 42 | 43 | # Number of blank lines surrounding top-level function and class 44 | # definitions. 45 | blank_lines_around_top_level_definition=2 46 | 47 | # Insert a blank line before a class-level docstring. 48 | blank_line_before_class_docstring=False 49 | 50 | # Insert a blank line before a module docstring. 51 | blank_line_before_module_docstring=False 52 | 53 | # Insert a blank line before a 'def' or 'class' immediately nested 54 | # within another 'def' or 'class'. For example: 55 | # 56 | # class Foo: 57 | # # <------ this blank line 58 | # def method(): 59 | # ... 60 | blank_line_before_nested_class_or_def=True 61 | 62 | # Do not split consecutive brackets. Only relevant when 63 | # dedent_closing_brackets is set. For example: 64 | # 65 | # call_func_that_takes_a_dict( 66 | # { 67 | # 'key1': 'value1', 68 | # 'key2': 'value2', 69 | # } 70 | # ) 71 | # 72 | # would reformat to: 73 | # 74 | # call_func_that_takes_a_dict({ 75 | # 'key1': 'value1', 76 | # 'key2': 'value2', 77 | # }) 78 | coalesce_brackets=True 79 | 80 | # The column limit. 81 | column_limit=115 82 | 83 | # The style for continuation alignment. Possible values are: 84 | # 85 | # - SPACE: Use spaces for continuation alignment. This is default behavior. 86 | # - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns 87 | # (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or 88 | # CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. 89 | # - VALIGN-RIGHT: Vertically align continuation lines to multiple of 90 | # INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if 91 | # cannot vertically align continuation lines with indent characters. 92 | continuation_align_style=VALIGN-RIGHT 93 | 94 | # Indent width used for line continuations. 95 | continuation_indent_width=8 96 | 97 | # Put closing brackets on a separate line, dedented, if the bracketed 98 | # expression can't fit in a single line. Applies to all kinds of brackets, 99 | # including function definitions and calls. For example: 100 | # 101 | # config = { 102 | # 'key1': 'value1', 103 | # 'key2': 'value2', 104 | # } # <--- this bracket is dedented and on a separate line 105 | # 106 | # time_series = self.remote_client.query_entity_counters( 107 | # entity='dev3246.region1', 108 | # key='dns.query_latency_tcp', 109 | # transform=Transformation.AVERAGE(window=timedelta(seconds=60)), 110 | # start_ts=now()-timedelta(days=3), 111 | # end_ts=now(), 112 | # ) # <--- this bracket is dedented and on a separate line 113 | dedent_closing_brackets=False 114 | 115 | # Disable the heuristic which places each list element on a separate line 116 | # if the list is comma-terminated. 117 | disable_ending_comma_heuristic=False 118 | 119 | # Place each dictionary entry onto its own line. 120 | each_dict_entry_on_separate_line=False 121 | 122 | # Require multiline dictionary even if it would normally fit on one line. 123 | # For example: 124 | # 125 | # config = { 126 | # 'key1': 'value1' 127 | # } 128 | force_multiline_dict=False 129 | 130 | # The regex for an i18n comment. The presence of this comment stops 131 | # reformatting of that line, because the comments are required to be 132 | # next to the string they translate. 133 | ;i18n_comment= 134 | 135 | # The i18n function call names. The presence of this function stops 136 | # reformattting on that line, because the string it has cannot be moved 137 | # away from the i18n comment. 138 | ;i18n_function_call= 139 | 140 | # Indent blank lines. 141 | indent_blank_lines=False 142 | 143 | # Put closing brackets on a separate line, indented, if the bracketed 144 | # expression can't fit in a single line. Applies to all kinds of brackets, 145 | # including function definitions and calls. For example: 146 | # 147 | # config = { 148 | # 'key1': 'value1', 149 | # 'key2': 'value2', 150 | # } # <--- this bracket is indented and on a separate line 151 | # 152 | # time_series = self.remote_client.query_entity_counters( 153 | # entity='dev3246.region1', 154 | # key='dns.query_latency_tcp', 155 | # transform=Transformation.AVERAGE(window=timedelta(seconds=60)), 156 | # start_ts=now()-timedelta(days=3), 157 | # end_ts=now(), 158 | # ) # <--- this bracket is indented and on a separate line 159 | indent_closing_brackets=True 160 | 161 | # Indent the dictionary value if it cannot fit on the same line as the 162 | # dictionary key. For example: 163 | # 164 | # config = { 165 | # 'key1': 166 | # 'value1', 167 | # 'key2': value1 + 168 | # value2, 169 | # } 170 | indent_dictionary_value=True 171 | 172 | # The number of columns to use for indentation. 173 | indent_width=4 174 | 175 | # Join short lines into one line. E.g., single line 'if' statements. 176 | join_multiple_lines=False 177 | 178 | # Do not include spaces around selected binary operators. For example: 179 | # 180 | # 1 + 2 * 3 - 4 / 5 181 | # 182 | # will be formatted as follows when configured with "*,/": 183 | # 184 | # 1 + 2*3 - 4/5 185 | ;no_spaces_around_selected_binary_operators= 186 | 187 | # Use spaces around default or named assigns. 188 | spaces_around_default_or_named_assign=False 189 | 190 | # Adds a space after the opening '{' and before the ending '}' dict delimiters. 191 | # 192 | # {1: 2} 193 | # 194 | # will be formatted as: 195 | # 196 | # { 1: 2 } 197 | spaces_around_dict_delimiters=False 198 | 199 | # Adds a space after the opening '[' and before the ending ']' list delimiters. 200 | # 201 | # [1, 2] 202 | # 203 | # will be formatted as: 204 | # 205 | # [ 1, 2 ] 206 | spaces_around_list_delimiters=False 207 | 208 | # Use spaces around the power operator. 209 | spaces_around_power_operator=False 210 | 211 | # Use spaces around the subscript / slice operator. For example: 212 | # 213 | # my_list[1 : 10 : 2] 214 | spaces_around_subscript_colon=False 215 | 216 | # Adds a space after the opening '(' and before the ending ')' tuple delimiters. 217 | # 218 | # (1, 2, 3) 219 | # 220 | # will be formatted as: 221 | # 222 | # ( 1, 2, 3 ) 223 | spaces_around_tuple_delimiters=False 224 | 225 | # The number of spaces required before a trailing comment. 226 | # This can be a single value (representing the number of spaces 227 | # before each trailing comment) or list of values (representing 228 | # alignment column values; trailing comments within a block will 229 | # be aligned to the first column value that is greater than the maximum 230 | # line length within the block). For example: 231 | # 232 | # With spaces_before_comment=5: 233 | # 234 | # 1 + 1 # Adding values 235 | # 236 | # will be formatted as: 237 | # 238 | # 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment 239 | # 240 | # With spaces_before_comment=15, 20: 241 | # 242 | # 1 + 1 # Adding values 243 | # two + two # More adding 244 | # 245 | # longer_statement # This is a longer statement 246 | # short # This is a shorter statement 247 | # 248 | # a_very_long_statement_that_extends_beyond_the_final_column # Comment 249 | # short # This is a shorter statement 250 | # 251 | # will be formatted as: 252 | # 253 | # 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 254 | # two + two # More adding 255 | # 256 | # longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 257 | # short # This is a shorter statement 258 | # 259 | # a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length 260 | # short # This is a shorter statement 261 | # 262 | spaces_before_comment=2 263 | 264 | # Insert a space between the ending comma and closing bracket of a list, 265 | # etc. 266 | space_between_ending_comma_and_closing_bracket=True 267 | 268 | # Use spaces inside brackets, braces, and parentheses. For example: 269 | # 270 | # method_call( 1 ) 271 | # my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] 272 | # my_set = { 1, 2, 3 } 273 | space_inside_brackets=False 274 | 275 | # Split before arguments 276 | split_all_comma_separated_values=False 277 | 278 | # Split before arguments, but do not split all subexpressions recursively 279 | # (unless needed). 280 | split_all_top_level_comma_separated_values=True 281 | 282 | # Split before arguments if the argument list is terminated by a 283 | # comma. 284 | split_arguments_when_comma_terminated=False 285 | 286 | # Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' 287 | # rather than after. 288 | split_before_arithmetic_operator=True 289 | 290 | # Set to True to prefer splitting before '&', '|' or '^' rather than 291 | # after. 292 | split_before_bitwise_operator=True 293 | 294 | # Split before the closing bracket if a list or dict literal doesn't fit on 295 | # a single line. 296 | split_before_closing_bracket=True 297 | 298 | # Split before a dictionary or set generator (comp_for). For example, note 299 | # the split before the 'for': 300 | # 301 | # foo = { 302 | # variable: 'Hello world, have a nice day!' 303 | # for variable in bar if variable != 42 304 | # } 305 | split_before_dict_set_generator=True 306 | 307 | # Split before the '.' if we need to split a longer expression: 308 | # 309 | # foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) 310 | # 311 | # would reformat to something like: 312 | # 313 | # foo = ('This is a really long string: {}, {}, {}, {}' 314 | # .format(a, b, c, d)) 315 | split_before_dot=False 316 | 317 | # Split after the opening paren which surrounds an expression if it doesn't 318 | # fit on a single line. 319 | split_before_expression_after_opening_paren=True 320 | 321 | # If an argument / parameter list is going to be split, then split before 322 | # the first argument. 323 | split_before_first_argument=False 324 | 325 | # Set to True to prefer splitting before 'and' or 'or' rather than 326 | # after. 327 | split_before_logical_operator=True 328 | 329 | # Split named assignments onto individual lines. 330 | split_before_named_assigns=True 331 | 332 | # Set to True to split list comprehensions and generators that have 333 | # non-trivial expressions and multiple clauses before each of these 334 | # clauses. For example: 335 | # 336 | # result = [ 337 | # a_long_var + 100 for a_long_var in xrange(1000) 338 | # if a_long_var % 10] 339 | # 340 | # would reformat to something like: 341 | # 342 | # result = [ 343 | # a_long_var + 100 344 | # for a_long_var in xrange(1000) 345 | # if a_long_var % 10] 346 | split_complex_comprehension=True 347 | 348 | # The penalty for splitting right after the opening bracket. 349 | split_penalty_after_opening_bracket=100 350 | 351 | # The penalty for splitting the line after a unary operator. 352 | split_penalty_after_unary_operator=10000 353 | 354 | # The penalty of splitting the line around the '+', '-', '*', '/', '//', 355 | # ``%``, and '@' operators. 356 | split_penalty_arithmetic_operator=300 357 | 358 | # The penalty for splitting right before an if expression. 359 | split_penalty_before_if_expr=0 360 | 361 | # The penalty of splitting the line around the '&', '|', and '^' 362 | # operators. 363 | split_penalty_bitwise_operator=300 364 | 365 | # The penalty for splitting a list comprehension or generator 366 | # expression. 367 | split_penalty_comprehension=80 368 | 369 | # The penalty for characters over the column limit. 370 | split_penalty_excess_character=7000 371 | 372 | # The penalty incurred by adding a line split to the unwrapped line. The 373 | # more line splits added the higher the penalty. 374 | split_penalty_for_added_line_split=30 375 | 376 | # The penalty of splitting a list of "import as" names. For example: 377 | # 378 | # from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, 379 | # long_argument_2, 380 | # long_argument_3) 381 | # 382 | # would reformat to something like: 383 | # 384 | # from a_very_long_or_indented_module_name_yada_yad import ( 385 | # long_argument_1, long_argument_2, long_argument_3) 386 | split_penalty_import_names=0 387 | 388 | # The penalty of splitting the line around the 'and' and 'or' 389 | # operators. 390 | split_penalty_logical_operator=300 391 | 392 | # Use the Tab character for indentation. 393 | use_tabs=True 394 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Specify a configuration file. 4 | #rcfile= 5 | 6 | # Python code to execute, usually for sys.path manipulation such as 7 | # pygtk.require(). 8 | #init-hook= 9 | 10 | # Add files or directories to the blacklist. They should be base names, not 11 | # paths. 12 | ignore=CVS 13 | 14 | # Add files or directories matching the regex patterns to the blacklist. The 15 | # regex matches against base names, not paths. 16 | ignore-patterns= 17 | 18 | # Pickle collected data for later comparisons. 19 | persistent=yes 20 | 21 | # List of plugins (as comma separated values of python modules names) to load, 22 | # usually to register additional checkers. 23 | load-plugins= 24 | 25 | # Use multiple processes to speed up Pylint. 26 | jobs=1 27 | 28 | # Allow loading of arbitrary C extensions. Extensions are imported into the 29 | # active Python interpreter and may run arbitrary code. 30 | unsafe-load-any-extension=no 31 | 32 | # A comma-separated list of package or module names from where C extensions may 33 | # be loaded. Extensions are loading into the active Python interpreter and may 34 | # run arbitrary code 35 | extension-pkg-whitelist= 36 | 37 | # Allow optimization of some AST trees. This will activate a peephole AST 38 | # optimizer, which will apply various small optimizations. For instance, it can 39 | # be used to obtain the result of joining multiple strings with the addition 40 | # operator. Joining a lot of strings can lead to a maximum recursion error in 41 | # Pylint and this flag can prevent that. It has one side effect, the resulting 42 | # AST will be different than the one from reality. This option is deprecated 43 | # and it will be removed in Pylint 2.0. 44 | optimize-ast=no 45 | 46 | 47 | [MESSAGES CONTROL] 48 | 49 | # Only show warnings with the listed confidence levels. Leave empty to show 50 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 51 | confidence= 52 | 53 | # Enable the message, report, category or checker with the given id(s). You can 54 | # either give multiple identifier separated by comma (,) or put this option 55 | # multiple time (only on the command line, not in the configuration file where 56 | # it should appear only once). See also the "--disable" option for examples. 57 | #enable= 58 | 59 | # Disable the message, report, category or checker with the given id(s). You 60 | # can either give multiple identifiers separated by comma (,) or put this 61 | # option multiple times (only on the command line, not in the configuration 62 | # file where it should appear only once).You can also use "--disable=all" to 63 | # disable everything first and then reenable specific checks. For example, if 64 | # you want to run only the similarities checker, you can use "--disable=all 65 | # --enable=similarities". If you want to run only the classes checker, but have 66 | # no Warning level messages displayed, use"--disable=all --enable=classes 67 | # --disable=W" 68 | disable=all 69 | enable=assert-on-tuple,astroid-error,bad-except-order,bad-inline-option,bad-option-value,bad-reversed-sequence,bare-except,binary-op-exception,boolean-datetime,catching-non-exception,cell-var-from-loop,confusing-with-statement,consider-merging-isinstance,consider-using-enumerate,consider-using-ternary,continue-in-finally,deprecated-pragma,django-not-available,duplicate-except,duplicate-key,eval-used,exec-used,expression-not-assigned,fatal,file-ignored,fixme,global-at-module-level,global-statement,global-variable-not-assigned,global-variable-undefined,http-response-with-content-type-json,http-response-with-json-dumps,invalid-all-object,invalid-characters-in-docstring,len-as-condition,literal-comparison,locally-disabled,locally-enabled,lost-exception,lowercase-l-suffix,misplaced-bare-raise,missing-kwoa,mixed-line-endings,model-has-unicode,model-missing-unicode,model-no-explicit-unicode,model-unicode-not-callable,multiple-imports,new-db-field-with-default,non-ascii-bytes-literals,nonexistent-operator,not-in-loop,notimplemented-raised,overlapping-except,parse-error,pointless-statement,pointless-string-statement,raising-bad-type,raising-non-exception,raw-checker-failed,redefine-in-handler,redefined-argument-from-local,redefined-builtin,redundant-content-type-for-json-response,reimported,relative-import,return-outside-function,simplifiable-if-statement,singleton-comparison,syntax-error,trailing-comma-tuple,trailing-newlines,unbalanced-tuple-unpacking,undefined-all-variable,undefined-loop-variable,unexpected-line-ending-format,unidiomatic-typecheck,unnecessary-lambda,unnecessary-pass,unnecessary-semicolon,unneeded-not,unpacking-non-sequence,unreachable,unrecognized-inline-option,used-before-assignment,useless-else-on-loop,using-constant-test,wildcard-import,yield-outside-function,useless-return 70 | 71 | [REPORTS] 72 | 73 | # Set the output format. Available formats are text, parseable, colorized, msvs 74 | # (visual studio) and html. You can also give a reporter class, eg 75 | # mypackage.mymodule.MyReporterClass. 76 | output-format=text 77 | 78 | # Put messages in a separate file for each module / package specified on the 79 | # command line instead of printing them on stdout. Reports (if any) will be 80 | # written in a file name "pylint_global.[txt|html]". This option is deprecated 81 | # and it will be removed in Pylint 2.0. 82 | files-output=no 83 | 84 | # Tells whether to display a full report or only the messages 85 | reports=no 86 | 87 | # Python expression which should return a note less than 10 (10 is the highest 88 | # note). You have access to the variables errors warning, statement which 89 | # respectively contain the number of errors / warnings messages and the total 90 | # number of statements analyzed. This is used by the global evaluation report 91 | # (RP0004). 92 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 93 | 94 | # Template used to display messages. This is a python new-style format string 95 | # used to format the message information. See doc for all details 96 | #msg-template= 97 | 98 | 99 | [BASIC] 100 | 101 | # Good variable names which should always be accepted, separated by a comma 102 | good-names=i,j,k,ex,Run,_ 103 | 104 | # Bad variable names which should always be refused, separated by a comma 105 | bad-names=foo,bar,baz,toto,tutu,tata 106 | 107 | # Colon-delimited sets of names that determine each other's naming style when 108 | # the name regexes allow several styles. 109 | name-group= 110 | 111 | # Include a hint for the correct naming format with invalid-name 112 | include-naming-hint=no 113 | 114 | # List of decorators that produce properties, such as abc.abstractproperty. Add 115 | # to this list to register other decorators that produce valid properties. 116 | property-classes=abc.abstractproperty 117 | 118 | # Regular expression matching correct function names 119 | function-rgx=[a-z_][a-z0-9_]{2,30}$ 120 | 121 | # Naming hint for function names 122 | function-name-hint=[a-z_][a-z0-9_]{2,30}$ 123 | 124 | # Regular expression matching correct variable names 125 | variable-rgx=[a-z_][a-z0-9_]{2,30}$ 126 | 127 | # Naming hint for variable names 128 | variable-name-hint=[a-z_][a-z0-9_]{2,30}$ 129 | 130 | # Regular expression matching correct constant names 131 | const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 132 | 133 | # Naming hint for constant names 134 | const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 135 | 136 | # Regular expression matching correct attribute names 137 | attr-rgx=[a-z_][a-z0-9_]{2,30}$ 138 | 139 | # Naming hint for attribute names 140 | attr-name-hint=[a-z_][a-z0-9_]{2,30}$ 141 | 142 | # Regular expression matching correct argument names 143 | argument-rgx=[a-z_][a-z0-9_]{2,30}$ 144 | 145 | # Naming hint for argument names 146 | argument-name-hint=[a-z_][a-z0-9_]{2,30}$ 147 | 148 | # Regular expression matching correct class attribute names 149 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 150 | 151 | # Naming hint for class attribute names 152 | class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 153 | 154 | # Regular expression matching correct inline iteration names 155 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 156 | 157 | # Naming hint for inline iteration names 158 | inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ 159 | 160 | # Regular expression matching correct class names 161 | class-rgx=[A-Z_][a-zA-Z0-9]+$ 162 | 163 | # Naming hint for class names 164 | class-name-hint=[A-Z_][a-zA-Z0-9]+$ 165 | 166 | # Regular expression matching correct module names 167 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 168 | 169 | # Naming hint for module names 170 | module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 171 | 172 | # Regular expression matching correct method names 173 | method-rgx=[a-z_][a-z0-9_]{2,30}$ 174 | 175 | # Naming hint for method names 176 | method-name-hint=[a-z_][a-z0-9_]{2,30}$ 177 | 178 | # Regular expression which should only match function or class names that do 179 | # not require a docstring. 180 | no-docstring-rgx=^_ 181 | 182 | # Minimum line length for functions/classes that require docstrings, shorter 183 | # ones are exempt. 184 | docstring-min-length=-1 185 | 186 | 187 | [ELIF] 188 | 189 | # Maximum number of nested blocks for function / method body 190 | max-nested-blocks=5 191 | 192 | 193 | [FORMAT] 194 | 195 | # Maximum number of characters on a single line. 196 | max-line-length=159 197 | 198 | # Regexp for a line that is allowed to be longer than the limit. 199 | ignore-long-lines=^\s*(# )??$ 200 | 201 | # Allow the body of an if to be on the same line as the test if there is no 202 | # else. 203 | single-line-if-stmt=no 204 | 205 | # List of optional constructs for which whitespace checking is disabled. `dict- 206 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 207 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 208 | # `empty-line` allows space-only lines. 209 | no-space-check=trailing-comma,dict-separator 210 | 211 | # Maximum number of lines in a module 212 | max-module-lines=1000 213 | 214 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 215 | # tab). 216 | indent-string=' ' 217 | 218 | # Number of spaces of indent required inside a hanging or continued line. 219 | indent-after-paren=4 220 | 221 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 222 | expected-line-ending-format= 223 | 224 | 225 | [LOGGING] 226 | 227 | # Logging modules to check that the string format arguments are in logging 228 | # function parameter format 229 | logging-modules=logging 230 | 231 | 232 | [MISCELLANEOUS] 233 | 234 | # List of note tags to take in consideration, separated by a comma. 235 | notes=FIXME,XXX,TODO 236 | 237 | 238 | [SIMILARITIES] 239 | 240 | # Minimum lines number of a similarity. 241 | min-similarity-lines=4 242 | 243 | # Ignore comments when computing similarities. 244 | ignore-comments=yes 245 | 246 | # Ignore docstrings when computing similarities. 247 | ignore-docstrings=yes 248 | 249 | # Ignore imports when computing similarities. 250 | ignore-imports=no 251 | 252 | 253 | [SPELLING] 254 | 255 | # Spelling dictionary name. Available dictionaries: none. To make it working 256 | # install python-enchant package. 257 | spelling-dict= 258 | 259 | # List of comma separated words that should not be checked. 260 | spelling-ignore-words= 261 | 262 | # A path to a file that contains private dictionary; one word per line. 263 | spelling-private-dict-file= 264 | 265 | # Tells whether to store unknown words to indicated private dictionary in 266 | # --spelling-private-dict-file option instead of raising a message. 267 | spelling-store-unknown-words=no 268 | 269 | 270 | [TYPECHECK] 271 | 272 | # Tells whether missing members accessed in mixin class should be ignored. A 273 | # mixin class is detected if its name ends with "mixin" (case insensitive). 274 | ignore-mixin-members=yes 275 | 276 | # List of module names for which member attributes should not be checked 277 | # (useful for modules/projects where namespaces are manipulated during runtime 278 | # and thus existing member attributes cannot be deduced by static analysis. It 279 | # supports qualified module names, as well as Unix pattern matching. 280 | ignored-modules= 281 | 282 | # List of class names for which member attributes should not be checked (useful 283 | # for classes with dynamically set attributes). This supports the use of 284 | # qualified names. 285 | ignored-classes=optparse.Values,thread._local,_thread._local 286 | 287 | # List of members which are set dynamically and missed by pylint inference 288 | # system, and so shouldn't trigger E1101 when accessed. Python regular 289 | # expressions are accepted. 290 | generated-members= 291 | 292 | # List of decorators that produce context managers, such as 293 | # contextlib.contextmanager. Add to this list to register other decorators that 294 | # produce valid context managers. 295 | contextmanager-decorators=contextlib.contextmanager 296 | 297 | 298 | [VARIABLES] 299 | 300 | # Tells whether we should check for unused import in __init__ files. 301 | init-import=no 302 | 303 | # A regular expression matching the name of dummy variables (i.e. expectedly 304 | # not used). 305 | dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy 306 | 307 | # List of additional names supposed to be defined in builtins. Remember that 308 | # you should avoid to define new builtins when possible. 309 | additional-builtins= 310 | 311 | # List of strings which can identify a callback function by name. A callback 312 | # name must start or end with one of those strings. 313 | callbacks=cb_,_cb 314 | 315 | # List of qualified module names which can have objects that can redefine 316 | # builtins. 317 | redefining-builtins-modules=six.moves,future.builtins 318 | 319 | 320 | [CLASSES] 321 | 322 | # List of method names used to declare (i.e. assign) instance attributes. 323 | defining-attr-methods=__init__,__new__,setUp 324 | 325 | # List of valid names for the first argument in a class method. 326 | valid-classmethod-first-arg=cls 327 | 328 | # List of valid names for the first argument in a metaclass class method. 329 | valid-metaclass-classmethod-first-arg=mcs 330 | 331 | # List of member names, which should be excluded from the protected access 332 | # warning. 333 | exclude-protected=_asdict,_fields,_replace,_source,_make 334 | 335 | 336 | [DESIGN] 337 | 338 | # Maximum number of arguments for function / method 339 | max-args=5 340 | 341 | # Argument names that match this expression will be ignored. Default to name 342 | # with leading underscore 343 | ignored-argument-names=_.* 344 | 345 | # Maximum number of locals for function / method body 346 | max-locals=15 347 | 348 | # Maximum number of return / yield for function / method body 349 | max-returns=6 350 | 351 | # Maximum number of branch for function / method body 352 | max-branches=12 353 | 354 | # Maximum number of statements in function / method body 355 | max-statements=60 356 | 357 | # Maximum number of parents for a class (see R0901). 358 | max-parents=7 359 | 360 | # Maximum number of attributes for a class (see R0902). 361 | max-attributes=7 362 | 363 | # Minimum number of public methods for a class (see R0903). 364 | min-public-methods=2 365 | 366 | # Maximum number of public methods for a class (see R0904). 367 | max-public-methods=20 368 | 369 | # Maximum number of boolean expressions in a if statement 370 | max-bool-expr=5 371 | 372 | 373 | [IMPORTS] 374 | 375 | # Deprecated modules which should not be used, separated by a comma 376 | deprecated-modules=regsub,TERMIOS,Bastion,rexec 377 | 378 | # Create a graph of every (i.e. internal and external) dependencies in the 379 | # given file (report RP0402 must not be disabled) 380 | import-graph= 381 | 382 | # Create a graph of external dependencies in the given file (report RP0402 must 383 | # not be disabled) 384 | ext-import-graph= 385 | 386 | # Create a graph of internal dependencies in the given file (report RP0402 must 387 | # not be disabled) 388 | int-import-graph= 389 | 390 | # Force import order to recognize a module as part of the standard 391 | # compatibility libraries. 392 | known-standard-library= 393 | 394 | # Force import order to recognize a module as part of a third party library. 395 | known-third-party=enchant 396 | 397 | # Analyse import fallback blocks. This can be used to support both Python 2 and 398 | # 3 compatible code, which means that the block might have code that exists 399 | # only in one or another interpreter, leading to false positives when analysed. 400 | analyse-fallback-blocks=no 401 | 402 | 403 | [EXCEPTIONS] 404 | 405 | # Exceptions that will emit a warning when being caught. Defaults to 406 | # "Exception" 407 | overgeneral-exceptions=Exception 408 | --------------------------------------------------------------------------------