├── .bumpversion.cfg ├── .codeclimate.yml ├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-request.md ├── pull_request_template.md ├── renovate.json5 └── workflows │ └── python.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .pre-commit-hooks.yaml ├── .prettierignore ├── .prettierrc.toml ├── .pylintrc ├── .readthedocs.yaml ├── .tool-versions ├── AUTHORS.rst ├── CHANGELOG.md ├── CONTRIBUTING.rst ├── LICENSE ├── Makefile ├── README.rst ├── ci-prepare-cmd.sh ├── docs ├── authors.rst ├── autofix_docs.py ├── cli.rst ├── conf.py ├── configuration.rst ├── contributing.rst ├── flake8_plugin.rst ├── ideas │ ├── Makefile │ │ ├── 0-main.toml │ │ ├── 1-pre-commit.toml │ │ ├── 2-poetry.toml │ │ ├── 3-pytest.toml │ │ └── 4-sphinx.toml │ ├── ini.toml │ ├── lab.py │ ├── semantic-release.toml │ ├── text.toml │ ├── toml.toml │ └── yaml │ │ ├── contains.toml │ │ ├── formatted-yaml.toml │ │ ├── jmespath.toml │ │ ├── lists.toml │ │ ├── merge_lists │ │ ├── merged_style.toml │ │ ├── os_macos.toml │ │ ├── os_ubuntu.toml │ │ ├── os_windows.toml │ │ ├── py310.toml │ │ ├── py311.toml │ │ ├── py312.toml │ │ ├── py38.toml │ │ └── py39.toml │ │ └── present-keys.toml ├── index.rst ├── library.rst ├── nitpick_section.rst ├── plugins.rst ├── quickstart.rst ├── requirements.txt ├── source │ ├── modules.rst │ ├── nitpick.blender.rst │ ├── nitpick.cli.rst │ ├── nitpick.compat.rst │ ├── nitpick.config.rst │ ├── nitpick.constants.rst │ ├── nitpick.core.rst │ ├── nitpick.exceptions.rst │ ├── nitpick.fields.rst │ ├── nitpick.flake8.rst │ ├── nitpick.generic.rst │ ├── nitpick.plugins.base.rst │ ├── nitpick.plugins.info.rst │ ├── nitpick.plugins.ini.rst │ ├── nitpick.plugins.json.rst │ ├── nitpick.plugins.rst │ ├── nitpick.plugins.text.rst │ ├── nitpick.plugins.toml.rst │ ├── nitpick.plugins.yaml.rst │ ├── nitpick.resources.any.rst │ ├── nitpick.resources.javascript.rst │ ├── nitpick.resources.kotlin.rst │ ├── nitpick.resources.markdown.rst │ ├── nitpick.resources.presets.rst │ ├── nitpick.resources.proto.rst │ ├── nitpick.resources.python.rst │ ├── nitpick.resources.rst │ ├── nitpick.resources.shell.rst │ ├── nitpick.resources.toml.rst │ ├── nitpick.rst │ ├── nitpick.schemas.rst │ ├── nitpick.style.rst │ ├── nitpick.tomlkit_ext.rst │ ├── nitpick.typedefs.rst │ └── nitpick.violations.rst ├── styles.rst ├── targets.rst └── troubleshooting.rst ├── mega-linter-plugin-nitpick └── nitpick.megalinter-descriptor.yml ├── nitpick-style.toml ├── package.json ├── poetry.lock ├── poetry.toml ├── pyproject.toml ├── setup.cfg ├── src └── nitpick │ ├── __init__.py │ ├── __main__.py │ ├── blender.py │ ├── cli.py │ ├── compat.py │ ├── config.py │ ├── constants.py │ ├── core.py │ ├── exceptions.py │ ├── fields.py │ ├── flake8.py │ ├── generic.py │ ├── plugins │ ├── __init__.py │ ├── base.py │ ├── info.py │ ├── ini.py │ ├── json.py │ ├── text.py │ ├── toml.py │ └── yaml.py │ ├── resources │ ├── __init__.py │ ├── any │ │ ├── __init__.py │ │ ├── codeclimate.toml │ │ ├── commitizen.toml │ │ ├── commitlint.toml │ │ ├── editorconfig.toml │ │ ├── git-legal.toml │ │ ├── pre-commit-hooks.toml │ │ └── prettier.toml │ ├── javascript │ │ ├── __init__.py │ │ └── package-json.toml │ ├── kotlin │ │ ├── __init__.py │ │ └── ktlint.toml │ ├── markdown │ │ ├── __init__.py │ │ └── markdownlint.toml │ ├── presets │ │ ├── __init__.py │ │ └── nitpick.toml │ ├── proto │ │ ├── __init__.py │ │ └── protolint.toml │ ├── python │ │ ├── 310.toml │ │ ├── 311.toml │ │ ├── 312.toml │ │ ├── 313.toml │ │ ├── 314.toml │ │ ├── __init__.py │ │ ├── absent.toml │ │ ├── autoflake.toml │ │ ├── bandit.toml │ │ ├── black.toml │ │ ├── flake8.toml │ │ ├── github-workflow.toml │ │ ├── ipython.toml │ │ ├── isort.toml │ │ ├── mypy.toml │ │ ├── poetry-editable.toml │ │ ├── poetry-venv.toml │ │ ├── poetry.toml │ │ ├── pre-commit-hooks.toml │ │ ├── pylint.toml │ │ ├── radon.toml │ │ ├── readthedocs.toml │ │ ├── sonar-python.toml │ │ └── tox.toml │ ├── shell │ │ ├── __init__.py │ │ ├── bashate.toml │ │ ├── shellcheck.toml │ │ └── shfmt.toml │ └── toml │ │ ├── __init__.py │ │ └── toml-sort.toml │ ├── schemas.py │ ├── style.py │ ├── tomlkit_ext.py │ ├── typedefs.py │ └── violations.py ├── tasks.py ├── tests ├── __init__.py ├── conftest.py ├── data │ ├── hello.py │ ├── pre-commit-config-with-old-repos-yaml-key.toml │ └── typed-style-dir │ │ ├── any │ │ └── editorconfig.toml │ │ ├── markdown │ │ └── markdownlint.toml │ │ └── python │ │ └── black.toml ├── helpers.py ├── resources │ ├── __init__.py │ ├── empty-style.toml │ └── nested_package │ │ ├── __init__.py │ │ └── empty_style.toml ├── test_builtin.py ├── test_builtin │ ├── any │ │ ├── codeclimate │ │ │ └── .codeclimate.yml │ │ ├── commitizen │ │ │ └── .pre-commit-config.yaml │ │ ├── commitlint │ │ │ ├── .pre-commit-config.yaml │ │ │ └── package.json │ │ ├── editorconfig │ │ │ ├── .codeclimate.yml │ │ │ └── .editorconfig │ │ ├── git-legal │ │ │ └── .codeclimate.yml │ │ ├── pre-commit-hooks │ │ │ └── .pre-commit-config.yaml │ │ └── prettier │ │ │ └── .pre-commit-config.yaml │ ├── javascript │ │ └── package-json │ │ │ └── package.json │ ├── kotlin │ │ └── ktlint │ │ │ └── .pre-commit-config.yaml │ ├── markdown │ │ └── markdownlint │ │ │ └── .codeclimate.yml │ ├── preset │ │ └── nitpick │ │ │ ├── .editorconfig │ │ │ ├── .pylintrc │ │ │ ├── setup.cfg │ │ │ └── tox.ini │ ├── proto │ │ └── protolint │ │ │ └── .pre-commit-config.yaml │ ├── python │ │ ├── 310 │ │ │ └── pyproject.toml │ │ ├── 311 │ │ │ └── pyproject.toml │ │ ├── 312 │ │ │ └── pyproject.toml │ │ ├── 313 │ │ │ └── pyproject.toml │ │ ├── 314 │ │ │ └── pyproject.toml │ │ ├── autoflake │ │ │ └── .pre-commit-config.yaml │ │ ├── bandit │ │ │ ├── .codeclimate.yml │ │ │ └── .pre-commit-config.yaml │ │ ├── black │ │ │ ├── .pre-commit-config.yaml │ │ │ └── pyproject.toml │ │ ├── flake8 │ │ │ ├── .codeclimate.yml │ │ │ ├── .pre-commit-config.yaml │ │ │ └── setup.cfg │ │ ├── github-workflow │ │ │ └── .github │ │ │ │ └── workflows │ │ │ │ └── python.yaml │ │ ├── ipython │ │ │ └── pyproject.toml │ │ ├── isort │ │ │ ├── .pre-commit-config.yaml │ │ │ └── setup.cfg │ │ ├── mypy │ │ │ ├── .pre-commit-config.yaml │ │ │ └── setup.cfg │ │ ├── poetry-editable │ │ │ └── pyproject.toml │ │ ├── poetry-venv │ │ │ └── poetry.toml │ │ ├── poetry │ │ │ └── pyproject.toml │ │ ├── pre-commit-hooks │ │ │ └── .pre-commit-config.yaml │ │ ├── pylint │ │ │ ├── .codeclimate.yml │ │ │ ├── .pre-commit-config.yaml │ │ │ ├── .pylintrc │ │ │ └── pyproject.toml │ │ ├── radon │ │ │ └── .codeclimate.yml │ │ ├── readthedocs │ │ │ └── .readthedocs.yaml │ │ ├── sonar-python │ │ │ └── .codeclimate.yml │ │ └── tox │ │ │ └── tox.ini │ ├── real.toml │ ├── real.yaml │ ├── shell │ │ ├── bashate │ │ │ └── .pre-commit-config.yaml │ │ ├── shellcheck │ │ │ ├── .codeclimate.yml │ │ │ └── .pre-commit-config.yaml │ │ └── shfmt │ │ │ └── .pre-commit-config.yaml │ └── toml │ │ └── toml-sort │ │ ├── .pre-commit-config.yaml │ │ └── pyproject.toml ├── test_cache.py ├── test_cli.py ├── test_generic.py ├── test_ini.py ├── test_ini │ ├── 2-actual-editorconfig.ini │ ├── 2-expected-editorconfig.ini │ ├── 2-style.toml │ ├── 3-actual-setup.cfg │ └── 3-expected-setup.cfg ├── test_json.py ├── test_json │ ├── 1-expected-package.json │ ├── 2-actual-package.json │ ├── 2-expected-package.json │ ├── 3-expected.json │ ├── 3-style.toml │ ├── 4-style.toml │ └── package-json-style.toml ├── test_meta.py ├── test_plugin.py ├── test_project.py ├── test_style.py ├── test_text.py ├── test_toml.py ├── test_tomlkit_ext.py ├── test_violations.py ├── test_yaml.py ├── test_yaml │ ├── existing-actual.yaml │ ├── existing-desired.toml │ ├── existing-expected.yaml │ ├── jmes-list-key-desired.toml │ ├── jmes-list-key-expected.yaml │ ├── list-by-hash-desired.toml │ ├── list-by-hash-expected.yaml │ ├── multiple-lists.yaml │ ├── new-desired.toml │ └── new-expected.yaml ├── test_yaml_github_workflows.py ├── test_yaml_github_workflows │ ├── any-order.toml │ ├── any-order.yaml │ ├── dict-search-by-key-actual.yaml │ ├── dict-search-by-key-desired.toml │ ├── dict-search-by-key-expected.yaml │ ├── same-key-actual.yaml │ ├── same-key-desired.toml │ ├── same-key-expected.yaml │ ├── scalar-add-elements-that-do-not-exist-actual.yaml │ ├── scalar-add-elements-that-do-not-exist-desired.toml │ ├── scalar-add-elements-that-do-not-exist-expected.yaml │ ├── wildcard-actual.yaml │ ├── wildcard-desired.toml │ └── wildcard-expected.yaml ├── test_yaml_old_pre_commit.py ├── test_yaml_old_pre_commit │ ├── 1-black.toml │ ├── 1-isort.toml │ └── 2-untouched-pre-commit.yaml ├── test_yaml_pre_commit.py └── test_yaml_pre_commit │ ├── hook-args-add.toml │ ├── hook-args-add.yaml │ ├── hook-args-change.toml │ ├── hook-args-change.yaml │ ├── hook-args.yaml │ ├── uk-actual.yaml │ ├── uk-default-expected.yaml │ ├── uk-default.toml │ ├── uk-empty-expected.yaml │ ├── uk-empty.toml │ ├── uk-override-expected.yaml │ └── uk-override.toml └── tox.ini /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.38.0 3 | commit = False 4 | tag = False 5 | 6 | [bumpversion:file:README.rst] 7 | search = {current_version} 8 | replace = {new_version} 9 | 10 | [bumpversion:file:docs/conf.py] 11 | search = version = "{current_version}" 12 | replace = version = "{new_version}" 13 | 14 | [bumpversion:file:docs/configuration.rst] 15 | search = {current_version} 16 | replace = {new_version} 17 | 18 | [bumpversion:file:docs/quickstart.rst] 19 | search = {current_version} 20 | replace = {new_version} 21 | 22 | [bumpversion:file:nitpick-style.toml] 23 | search = {current_version} 24 | replace = {new_version} 25 | 26 | [bumpversion:file:package.json] 27 | search = "version": "{current_version}", 28 | replace = "version": "{new_version}", 29 | 30 | [bumpversion:file:pyproject.toml] 31 | search = version = "{current_version}" 32 | replace = version = "{new_version}" 33 | 34 | [bumpversion:file:src/nitpick/__init__.py] 35 | search = __version__ = "{current_version}" 36 | replace = __version__ = "{new_version}" 37 | 38 | [bumpversion:file:mega-linter-plugin-nitpick/nitpick.megalinter-descriptor.yml] 39 | search = {current_version} 40 | replace = {new_version} 41 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | # https://codeclimate.com/ 4 | # https://docs.codeclimate.com/docs/maintainability#section-checks 5 | # https://docs.codeclimate.com/docs/advanced-configuration#default-checks 6 | checks: 7 | file-lines: 8 | config: 9 | # Pylint's default is also 1000: https://github.com/PyCQA/pylint/blob/master/pylint/checkers/format.py#L294-L300 10 | threshold: 1000 11 | method-complexity: 12 | config: 13 | threshold: 10 # Same as [flake8]max-complexity 14 | plugins: 15 | bandit: # https://docs.codeclimate.com/docs/bandit 16 | enabled: true 17 | editorconfig: # https://docs.codeclimate.com/docs/editorconfig 18 | enabled: true 19 | fixme: # https://docs.codeclimate.com/docs/fixme 20 | enabled: false 21 | git-legal: # https://docs.codeclimate.com/docs/git-legal 22 | enabled: true 23 | markdownlint: # https://docs.codeclimate.com/docs/markdownlint # TODO: style: enable markdownlint after configuring it 24 | # https://github.com/markdownlint/markdownlint 25 | enabled: false 26 | pep8: # https://docs.codeclimate.com/docs/pep8 PEP8 already being checked by flake8 plugins on pre-commit 27 | enabled: false 28 | pylint: # https://docs.codeclimate.com/docs/pylint Already checked by pre-commit 29 | enabled: false 30 | radon: # https://docs.codeclimate.com/docs/radon 31 | enabled: false 32 | config: 33 | # https://radon.readthedocs.io/en/latest/commandline.html#the-cc-command 34 | threshold: "C" 35 | shellcheck: # https://docs.codeclimate.com/docs/shellcheck 36 | enabled: true 37 | sonar-python: # https://docs.codeclimate.com/docs/sonar-python 38 | enabled: true 39 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org/ 2 | # top-most EditorConfig file 3 | root = true 4 | 5 | # Unix-style newlines with a newline ending every file 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | indent_size = 4 10 | indent_style = space 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.{bat,cmd,ps1}] 15 | end_of_line = crlf 16 | 17 | [*.{js,json,json5,yml,yaml,md,rb}] 18 | indent_size = 2 19 | 20 | [Makefile] 21 | indent_style = tab 22 | 23 | [*.{rst,toml}] 24 | # Unset indentation for some files, so codeclimate doesn't complain 25 | # https://docs.codeclimate.com/docs/editorconfig 26 | # rst: auto-generated Sphinx files 27 | # toml: style files than contain YAML indented with 2 spaces 28 | indent_size = unset 29 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository 3 | 4 | github: [andreoliwa] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 5 | # patreon: # Replace with a single Patreon username 6 | # open_collective: andreoliwa # Replace with a single Open Collective username 7 | ko_fi: andreoliwa # Replace with a single Ko-fi username 8 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | liberapay: andreoliwa # Replace with a single Liberapay username 11 | # issuehunt: # Replace with a single IssueHunt username 12 | # otechie: # Replace with a single Otechie username 13 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 14 | custom: [ 15 | "https://www.paypal.me/andreoliwa", 16 | "https://www.buymeacoffee.com/andreoliwa", 17 | ] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report 4 | title: "" 5 | labels: "bug" 6 | assignees: "" 7 | --- 8 | 9 | Your bug may already be reported! 10 | Please search on the [issue tracker](https://github.com/andreoliwa/nitpick/issues) before creating one. 11 | If you found an issue, write a comment or upvote it with a thumbs-up 👍🏻. 12 | 13 | ## Expected behavior 14 | 15 | 16 | 17 | ## Current behavior 18 | 19 | 20 | 21 | ## Steps to reproduce 22 | 23 | 24 | 25 | 26 | 1. 27 | 1. 28 | 1. 29 | 1. 30 | 31 | ## Possible Solution 32 | 33 | 34 | 35 | ## Context 36 | 37 | 38 | 39 | 40 | ## Your environment 41 | 42 | 43 | 44 | - `nitpick` version used: 45 | - Python version: 46 | - Operating System and version: 47 | - Link to your project: 48 | - Run the following commands and paste the output: 49 | 50 | ```shell script 51 | which python3 52 | python3 -V 53 | pip freeze 54 | cat $(which flake8) 55 | ``` 56 | 57 | For more information, see the [CONTRIBUTING](https://github.com/andreoliwa/nitpick/blob/master/CONTRIBUTING.rst) guide. 58 | 59 | 60 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature 4 | title: "" 5 | labels: "enhancement" 6 | assignees: "" 7 | --- 8 | 9 | Your feature may already be reported! 10 | Please search on the [issue tracker](https://github.com/andreoliwa/nitpick/issues) before creating one. 11 | If you found an issue, write a comment or upvote it with a thumbs-up 👍🏻. 12 | 13 | ## Problem 14 | 15 | 16 | 17 | 18 | 19 | ## Possible solution 20 | 21 | 22 | 23 | 24 | 25 | For more information, see the [CONTRIBUTING](https://github.com/andreoliwa/nitpick/blob/master/CONTRIBUTING.rst) guide. 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Issues fixed by this pull request: 2 | 3 | - Fix # 4 | 5 | ## Proposed changes 6 | 7 | 1. 8 | 9 | ## Checklist 10 | 11 | - [ ] Read the [contribution guidelines](https://nitpick.rtfd.io/en/latest/contributing.html) 12 | - [ ] Run `make` locally before pushing commits 13 | - [ ] Add tests for the relevant parts: 14 | - [ ] API 15 | - [ ] CLI 16 | - [ ] `flake8` plugin (normal mode) 17 | - [ ] `flake8` plugin (offline mode) 18 | - [ ] Write documentation when there's a new API or functionality 19 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | extends: ["config:base"], 3 | // https://docs.renovatebot.com/configuration-options/#automerge 4 | automerge: true, 5 | // https://docs.renovatebot.com/configuration-options/#automergetype 6 | automergeType: "branch", 7 | // https://docs.renovatebot.com/modules/manager/pre-commit/ 8 | "pre-commit": { 9 | enabled: true, 10 | }, 11 | ignoreDeps: ["jedi"], 12 | // https://docs.renovatebot.com/configuration-options/#prconcurrentlimit 13 | prConcurrentLimit: 3, 14 | // https://docs.renovatebot.com/configuration-options/#branchconcurrentlimit 15 | branchConcurrentLimit: 5, 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest/ 50 | # pytest-testmon 51 | .testmondata* 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # dotenv 87 | .env 88 | 89 | # virtualenv 90 | .venv 91 | venv/ 92 | ENV/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | 107 | # Temporary files 108 | .temp* 109 | 110 | # Editors 111 | .idea/ 112 | .vscode/ 113 | 114 | # direnv 115 | .envrc 116 | 117 | # macOS 118 | .DS_Store 119 | 120 | # pytest-testmon 121 | .testmondata* 122 | -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | # https://pre-commit.com/#creating-new-hooks 2 | 3 | # This is the new default: to fix all files, NOT passing filenames to the hook. 4 | # The usage of "pass_filenames: false`` is not recommended by the authors of pre-commit, 5 | # but it's the only way to make Nitpick work as intended. 6 | # See this comment for more context: https://github.com/andreoliwa/nitpick/pull/673/files#r1714086075 7 | # If this breaks your workflow, choose one of the other hooks below with "pass_filenames: true". 8 | 9 | - id: nitpick 10 | name: "nitpick fix (all files)" 11 | description: "Fix configuration files (TOML/INI/JSON/etc.) directly, according to the Nitpick style. All files are considered by pre-commit." 12 | entry: nitpick fix 13 | pass_filenames: false 14 | language: python 15 | 16 | # Same as nitpick, but with a more explicit name. 17 | - id: nitpick-fix-all 18 | name: "nitpick fix (all files)" 19 | description: "Fix configuration files (TOML/INI/JSON/etc.) directly, according to the Nitpick style. All files are considered by pre-commit." 20 | entry: nitpick fix 21 | pass_filenames: false 22 | language: python 23 | 24 | - id: nitpick-fix 25 | name: "nitpick fix (modified files only)" 26 | description: "Fix configuration files (TOML/INI/JSON/etc.) directly, according to the Nitpick style. Only modified files are considered by pre-commit." 27 | entry: nitpick fix 28 | pass_filenames: true 29 | language: python 30 | 31 | - id: nitpick-check-all 32 | name: "nitpick check (all files)" 33 | description: "Only check configuration files (TOML/INI/JSON/etc.) and print the violations, according to the Nitpick style. All files are considered by pre-commit." 34 | entry: nitpick check 35 | pass_filenames: false 36 | language: python 37 | 38 | - id: nitpick-check 39 | name: "nitpick check (modified files only)" 40 | description: "Only check configuration files (TOML/INI/JSON/etc.) and print the violations, according to the Nitpick style. Only modified files are considered by pre-commit." 41 | entry: nitpick check 42 | pass_filenames: true 43 | language: python 44 | 45 | - id: nitpick-suggest 46 | name: "nitpick init --suggest (auto fixing files)" 47 | description: "Suggest new Nitpick styles based on the files in the project root (skipping Git ignored files)" 48 | entry: nitpick init --fix --suggest 49 | language: python 50 | # This hook should NOT be run for changed Git files, otherwise they will be considered style URLS 51 | # and will be added to [tool.nitpick]style in pyproject.toml 52 | pass_filenames: false 53 | always_run: true 54 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # https://prettier.io/docs/en/configuration.html 2 | index.html 3 | _includes/* 4 | *.min.css 5 | README.md 6 | 7 | # Prettier uses double quotes, ruamel.yaml uses single quotes 8 | tests/test_yaml*/*.yaml 9 | 10 | # The JSON generated with json.dumps() should not be prettified in tests, otherwise they fail 11 | tests/test_json/*.json 12 | 13 | tests/test_builtin/* 14 | -------------------------------------------------------------------------------- /.prettierrc.toml: -------------------------------------------------------------------------------- 1 | # https://prettier.io/docs/en/configuration.html 2 | 3 | # https://prettier.io/docs/en/options.html#end-of-line 4 | endOfLine = "lf" 5 | # https://prettier.io/docs/en/options.html#print-width 6 | printWidth = 120 7 | # https://prettier.io/docs/en/options.html#semicolons 8 | semi = false 9 | # https://prettier.io/docs/en/options.html#quotes 10 | singleQuote = false 11 | # https://prettier.io/docs/en/options.html#tab-width 12 | tabWidth = 2 13 | # https://prettier.io/docs/en/options.html#trailing-commas 14 | trailingComma = "es5" 15 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Pickle collected data for later comparisons. 4 | persistent=yes 5 | 6 | # List of plugins (as comma separated values of python modules names) to load, 7 | # usually to register additional checkers. 8 | load-plugins= 9 | 10 | # Use multiple processes to speed up Pylint. 11 | jobs=1 12 | 13 | # https://github.com/samuelcolvin/pydantic/issues/1961#issuecomment-759522422 14 | extension-pkg-whitelist=pydantic 15 | 16 | [REPORTS] 17 | 18 | # Set the output format. Available formats are text, parseable, colorized, msvs 19 | # (visual studio) and html. You can also give a reporter class, eg 20 | # mypackage.mymodule.MyReporterClass. 21 | output-format=colorized 22 | 23 | [MESSAGES CONTROL] 24 | 25 | # Disable the message, report, category or checker with the given id(s). You 26 | # can either give multiple identifiers separated by comma (,) or put this 27 | # option multiple times (only on the command line, not in the configuration 28 | # file where it should appear only once).You can also use "--disable=all" to 29 | # disable everything first and then reenable specific checks. For example, if 30 | # you want to run only the similarities checker, you can use "--disable=all 31 | # --enable=similarities". If you want to run only the classes checker, but have 32 | # no Warning level messages displayed, use"--disable=all --enable=classes 33 | # --disable=W" 34 | # Configurations for the black formatter 35 | disable=fixme,cyclic-import,line-too-long 36 | 37 | [BASIC] 38 | # Good variable names which should always be accepted, separated by a comma 39 | good-names = i,j,k,e,ex,Run,_,id,rv,c 40 | 41 | # Regular expression matching correct constant names 42 | const-rgx=(([A-Z_][A-Z0-9_]*)|([a-z_][a-z0-9_]*)|(__.*__)|register|urlpatterns)$ 43 | 44 | bad-functions = map,filter 45 | 46 | [FORMAT] 47 | 48 | # Maximum number of characters on a single line. 49 | max-line-length=120 50 | 51 | # Regexp for a line that is allowed to be longer than the limit. 52 | ignore-long-lines=^\s*(# )??$ 53 | 54 | # Maximum number of lines in a module 55 | max-module-lines=1000 56 | 57 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 58 | # tab). 59 | indent-string=' ' 60 | 61 | # Number of spaces of indent required inside a hanging or continued line. 62 | indent-after-paren=4 63 | 64 | [SIMILARITIES] 65 | 66 | # Minimum lines number of a similarity. 67 | min-similarity-lines=4 68 | 69 | # Ignore comments when computing similarities. 70 | ignore-comments=yes 71 | 72 | # Ignore docstrings when computing similarities. 73 | ignore-docstrings=yes 74 | 75 | # Ignore imports when computing similarities. 76 | ignore-imports=no 77 | 78 | [TYPECHECK] 79 | 80 | # List of classes names for which member attributes should not be checked 81 | # (useful for classes with attributes dynamically set). 82 | ignored-classes=SQLAlchemy,scoped_session 83 | 84 | # List of members which are set dynamically and missed by pylint inference 85 | # system, and so shouldn't trigger E0201 when accessed. Python regular 86 | # expressions are accepted. 87 | generated-members=REQUEST,acl_users,aq_parent,query 88 | 89 | [VARIABLES] 90 | 91 | # A regular expression matching the name of dummy variables (i.e. expectedly 92 | # not used). 93 | dummy-variables-rgx=_$|dummy 94 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.readthedocs.io/en/stable/config-file/v2.html 2 | # https://blog.readthedocs.com/migrate-configuration-v2/ 3 | version: 2 4 | sphinx: 5 | configuration: docs/conf.py 6 | formats: all 7 | 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.11" 12 | 13 | python: 14 | install: 15 | # Needed to force RTD to install the latest Sphinx version 16 | - requirements: docs/requirements.txt 17 | - method: pip 18 | path: . 19 | extra_requirements: 20 | - doc 21 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | poetry 2.1.4 2 | pre-commit 4.2.0 3 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Authors 2 | ======= 3 | 4 | * W. Augusto Andreoli 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! 8 | Every little bit helps, and credit will always be given. 9 | 10 | Check the `projects on GitHub `_, you might help coding a planned feature. 11 | 12 | Bug reports or feature requests 13 | =============================== 14 | 15 | * First, search the `GitHub issue tracker `_ to see if your bug/feature is already there. 16 | * If nothing is found, just :issue:`add a new issue and follow the instructions `. 17 | 18 | Documentation improvements 19 | ========================== 20 | 21 | Nitpick_ could always use more documentation, whether as part of the 22 | official docs, in docstrings, or even on the web in blog posts, 23 | articles, and such. 24 | 25 | Development 26 | =========== 27 | 28 | To set up Nitpick_ for local development: 29 | 30 | 1. Fork Nitpick_ (look for the "Fork" button). 31 | 32 | 2. Clone your fork locally:: 33 | 34 | cd ~/Code 35 | git clone git@github.com:your_name_here/nitpick.git 36 | cd nitpick 37 | 38 | 3. Install Poetry_ globally using `the recommended way `_. 39 | 40 | 4. Install Invoke_. You can use pipx_ to install it globally: ``pipx install invoke``. 41 | 42 | 5. Install dependencies and pre-commit_ hooks:: 43 | 44 | invoke install --hooks 45 | 46 | 6. Create a branch for local development:: 47 | 48 | git checkout -b name-of-your-bugfix-or-feature 49 | 50 | Now you can make your changes locally. 51 | 52 | 7. When you're done making changes, run tests and checks locally with:: 53 | 54 | # Quick tests and checks 55 | make 56 | # Or use this to simulate a full CI build with tox 57 | invoke ci-build 58 | 59 | 8. Commit your changes and push your branch to GitHub:: 60 | 61 | git add . 62 | 63 | # For a feature: 64 | git commit -m "feat: short description of your feature" 65 | # For a bug fix: 66 | git commit -m "fix: short description of what you fixed" 67 | 68 | git push origin name-of-your-bugfix-or-feature 69 | 70 | 9. Submit a pull request through the GitHub website. 71 | 72 | Commit convention 73 | ----------------- 74 | 75 | Nitpick_ follows `Conventional Commits `_ 76 | 77 | No need to rebase the commits in your branch. 78 | If your pull request is accepted, all your commits will be squashed into a single one, and the commit message will be adjusted to follow the current standard. 79 | 80 | Pull Request Guidelines 81 | ----------------------- 82 | 83 | If you need some code review or feedback while you're developing the code, just make a draft pull request. 84 | 85 | For merging, follow the checklist on the pull request template itself. 86 | 87 | When running ``invoke test``: if you don't have all the necessary Python versions available locally (needed by tox_), you can rely on GitHub Workflows. 88 | `Tests will run `_ for each change you add in the pull request. 89 | It will be slower though... 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Wagner Augusto Andreoli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := build 2 | .PHONY: Makefile 3 | 4 | SRC := $(shell find docs src -type f -a -iname '*.py') 5 | DOCS := docs/* *.rst *.md 6 | STYLES := $(shell find src/nitpick/resources -type f) 7 | TESTS := $(shell find tests -type f -iname '*.py') 8 | GITHUB = $(shell find .github -type f) 9 | ANY := $(SRC) $(DOCS) $(STYLES) $(TESTS) $(GITHUB) 10 | 11 | # Create the cache dir if it doesn't exist 12 | $(shell mkdir -p .cache/make) 13 | 14 | help: 15 | @echo "Make targets (run 'make -B' or 'make --always-make' to force):" 16 | @cat Makefile | egrep '^[a-z0-9 ./-]*:.*#' | sed -E -e 's/:.+# */@ /g' -e 's/ .+@/@/g' | sort | awk -F@ '{printf " \033[1;34m%-18s\033[0m %s\n", $$1, $$2}' 17 | @echo 18 | @echo 'Use invoke to run other tasks that were previously make targets:' 19 | invoke --list 20 | .PHONY: help 21 | 22 | build: .cache/make/doc .cache/make/pytest .cache/make/pre-commit # Quick build for local development 23 | .PHONY: build 24 | 25 | .delete-cache: 26 | # Force a cache update before running "nitpick fix" in pre-commit 27 | # TODO: fix: the cache doesn't detect changes in TOML style files 28 | rm -rf .cache/nitpick 29 | .PHONY: .delete-cache 30 | 31 | .cache/make/pytest: .delete-cache $(SRC) $(TESTS) 32 | invoke test 33 | touch .cache/make/pytest 34 | 35 | .cache/make/pre-commit: .delete-cache $(ANY) 36 | pre-commit run -a 37 | touch .cache/make/pre-commit 38 | 39 | .cache/make/doc: $(DOCS) $(STYLES) 40 | invoke doc 41 | touch .cache/make/doc 42 | -------------------------------------------------------------------------------- /ci-prepare-cmd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -x 3 | set -e 4 | 5 | VERSION=$1 6 | bumpversion --allow-dirty --no-commit --no-tag --new-version "$VERSION" patch 7 | 8 | # Clean up the files touched by bumpversion 9 | set +e # Allow failure; if files are modified, pre-commit returns an exit code > 0 10 | pre-commit run --all-files end-of-file-fixer 11 | pre-commit run --all-files trailing-whitespace 12 | pre-commit run --all-files prettier 13 | set -e 14 | 15 | rm -rf dist/ 16 | poetry build 17 | 18 | # https://twine.readthedocs.io/en/latest/#twine-check 19 | twine check dist/* 20 | 21 | # The slash at the end is important 22 | # https://github.com/python-poetry/poetry/issues/742#issuecomment-609642943 23 | poetry config repositories.testpypi https://test.pypi.org/legacy/ 24 | poetry config --list 25 | 26 | # Hide the password 27 | set +x 28 | poetry publish --repository testpypi --username __token__ --password "$PYPI_TEST_PASSWORD" 29 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | .. include:: ../CONTRIBUTING.rst 4 | -------------------------------------------------------------------------------- /docs/flake8_plugin.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | .. note:: 4 | 5 | Try running Nitpick with the new :ref:`cli` instead of a flake8 plugin. 6 | 7 | In the future, there are plans to :issue:`make flake8 an optional dependency <166>`. 8 | 9 | .. _flake8_plugin: 10 | 11 | Flake8_ plugin 12 | ============== 13 | 14 | Nitpick_ is not a proper flake8_ plugin; it piggybacks on flake8's messaging system though. 15 | 16 | Flake8 lints Python files; Nitpick "lints" configuration (text) files instead. 17 | 18 | To act like a flake8 plugin, Nitpick does the following: 19 | 20 | 1. Find `any Python file in your project
`_; 21 | 2. Use the first Python file found and ignore other Python files in the project. 22 | 3. Check the style file and compare with the configuration/text files. 23 | 4. Report violations on behalf of that Python file, and not on the configuration file that's actually wrong. 24 | 25 | So, if you have a violation on ``setup.cfg``, it will be reported like this:: 26 | 27 | ./tasks.py:0:1: NIP323 File setup.cfg: [flake8]max-line-length is 80 but it should be like this: 28 | [flake8] 29 | max-line-length = 120 30 | 31 | Notice the ``tasks.py`` at the beginning of the line, and not ``setup.cfg``. 32 | 33 | .. note:: 34 | 35 | To run Nitpick as a Flake8 plugin, the project must have *at least one* Python file*. 36 | 37 | If your project is not a Python project, creating a ``dummy.py`` file on the root of the project is enough. 38 | 39 | Pre-commit hook and flake8 40 | -------------------------- 41 | 42 | Currently, the default pre-commit_ hook uses flake8_ in an `unconventional and not recommended way `_. 43 | 44 | :gitref:`It calls flake8 directly <.pre-commit-hooks.yaml#L5>`:: 45 | 46 | flake8 --select=NIP 47 | 48 | This current default pre-commit hook (called ``nitpick``) is a placeholder for the future, :issue:`when flake8 will be only an optional dependency <166>`. 49 | 50 | Why ``always_run: true``? 51 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 52 | 53 | This in intentional, because `Nitpick is not a conventional flake8 plugin `_. 54 | 55 | Since flake8 only lints Python files, the pre-commit hook will only run when a Python file is modified. 56 | It won't run when a config/text changes. 57 | 58 | An example: suppose you're using a remote Nitpick style (`like the style from WeMake `_). 59 | 60 | At the moment, their style currently checks ``setup.cfg`` only. 61 | 62 | Suppose they change or add an option on their `isort.toml `_ file. 63 | 64 | If the nitpick pre-commit hook had ``always_run: false`` and ``pass_filenames: true``, your local ``setup.cfg`` would only be verified: 65 | 66 | 1. If a Python file was changed. 67 | 2. If you ran ``pre-commit run --all-files``. 68 | 69 | So basically the pre-commit hook would be useless to guarantee that your config files would always match the remote style... which is precisely the purpose of Nitpick. 70 | 71 | .. note:: 72 | 73 | To avoid this, use the :gitref:`other pre-commit hooks <.pre-commit-hooks.yaml#L10>`, the ones that call the Nitpick CLI directly instead of running ``flake8``. 74 | 75 | Root dir of the project 76 | ----------------------- 77 | 78 | You should run Nitpick_ in the *root dir* of your project. 79 | 80 | A directory is considered a root dir if it contains one of the following files: 81 | 82 | - ``.pre-commit-config.yaml`` (pre-commit_) 83 | - ``pyproject.toml`` 84 | - ``setup.py`` 85 | - ``setup.cfg`` 86 | - ``requirements*.txt`` 87 | - ``Pipfile`` (Pipenv_) 88 | - ``tox.ini`` (tox_) 89 | - ``package.json`` (JavaScript, NodeJS) 90 | - ``Cargo.*`` (Rust) 91 | - ``go.mod``, ``go.sum`` (Golang) 92 | - ``app.py`` and ``wsgi.py`` (`Flask CLI`_) 93 | - ``autoapp.py`` (Flask_) 94 | - ``manage.py`` (Django_) 95 | 96 | Main Python file 97 | ---------------- 98 | 99 | On the `root dir of the project`_ Nitpick searches for a main Python file. 100 | Every project must have at least one ``*.py`` file, otherwise flake8_ won't even work. 101 | 102 | Those are the Python files that are considered: 103 | 104 | - ``setup.py`` 105 | - ``app.py`` and ``wsgi.py`` (`Flask CLI`_) 106 | - ``autoapp.py`` 107 | - ``manage.py`` 108 | - any ``*.py`` file 109 | -------------------------------------------------------------------------------- /docs/ideas/Makefile/0-main.toml: -------------------------------------------------------------------------------- 1 | # https://www.gnu.org/software/make/manual/make.html#Introduction 2 | 3 | [[Makefile.contains]] 4 | block = """ 5 | REFRESH_AFTER = 1h 6 | """ 7 | 8 | [[Makefile.rules]] 9 | target = ".PHONY" 10 | prerequisites = ["help Makefile always-run"] 11 | 12 | [[Makefile.rules]] 13 | target = "dev" 14 | prerequisites = ["always-run .cache/make/auto-pre-commit .cache/make/auto-poetry .cache/make/sphinx .cache/make/run .cache/make/pytest"] 15 | 16 | [[Makefile.rules]] 17 | target = "always-run" 18 | recipes_contains_block = """ 19 | @mkdir -p .cache/make 20 | @# Remove files named auto* if they are older than 1 hour, so the targets will be rebuilt 21 | @fd --changed-before $(RERUN_AFTER) auto .cache/make --exec-batch rm '{}' ; 22 | """ 23 | 24 | [[Makefile.rules]] 25 | target = ".cache/make/run" 26 | recipes_contains_block = """ 27 | pre-commit run --all-files 28 | touch .cache/make/run 29 | """ 30 | -------------------------------------------------------------------------------- /docs/ideas/Makefile/1-pre-commit.toml: -------------------------------------------------------------------------------- 1 | [[Makefile.rules]] 2 | target = ".PHONY" 3 | prerequisites = ["pre-commit"] 4 | 5 | [[Makefile.rules]] 6 | target = "help" 7 | recipes_contains_block = """ 8 | @echo ' pre-commit to install and update pre-commit hooks' 9 | """ 10 | 11 | [[Makefile.contains]] 12 | block = """ 13 | pre-commit: 14 | -rm .cache/make/auto-pre-commit 15 | $(MAKE) 16 | 17 | .cache/make/auto-pre-commit: .pre-commit-config.yaml .pre-commit-hooks.yaml 18 | pre-commit install 19 | pre-commit install --hook-type commit-msg 20 | pre-commit autoupdate 21 | pre-commit gc 22 | touch .cache/make/auto-pre-commit 23 | -rm .cache/make/run 24 | """ 25 | -------------------------------------------------------------------------------- /docs/ideas/Makefile/2-poetry.toml: -------------------------------------------------------------------------------- 1 | [[Makefile.rules]] 2 | target = ".PHONY" 3 | prerequisites = ["poetry"] 4 | 5 | [[Makefile.rules]] 6 | target = "help" 7 | recipes_contains_block = """ 8 | @echo ' poetry to update dependencies' 9 | """ 10 | 11 | [[Makefile.contains]] 12 | block = """ 13 | poetry: 14 | -rm .cache/make/auto-poetry 15 | $(MAKE) 16 | 17 | .cache/make/auto-poetry: pyproject.toml 18 | poetry update 19 | touch .cache/make/auto-poetry 20 | -rm .cache/make/run 21 | """ 22 | -------------------------------------------------------------------------------- /docs/ideas/Makefile/3-pytest.toml: -------------------------------------------------------------------------------- 1 | [[Makefile.rules]] 2 | target = ".PHONY" 3 | prerequisites = ["pytest"] 4 | 5 | [[Makefile.rules]] 6 | target = "help" 7 | recipes_contains_block = """ 8 | @echo ' pytest to run tests' 9 | """ 10 | 11 | [[Makefile.contains]] 12 | block = """ 13 | pytest: 14 | -rm .cache/make/pytest 15 | $(MAKE) 16 | 17 | .cache/make/pytest: nitpick/* styles/* tests/* 18 | pytest 19 | touch .cache/make/pytest 20 | """ 21 | -------------------------------------------------------------------------------- /docs/ideas/Makefile/4-sphinx.toml: -------------------------------------------------------------------------------- 1 | [[Makefile.rules]] 2 | target = ".PHONY" 3 | prerequisites = ["sphinx"] 4 | 5 | [[Makefile.rules]] 6 | target = "help" 7 | recipes_contains_block = """ 8 | @echo ' sphinx to build docs' 9 | """ 10 | 11 | [[Makefile.contains]] 12 | block = """ 13 | sphinx: 14 | -rm .cache/make/sphinx 15 | $(MAKE) 16 | 17 | # $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | .cache/make/sphinx: docs *.rst *.md 19 | -rm -rf docs/source 20 | sphinx-apidoc --force --module-first --separate --implicit-namespaces --output-dir docs/source nitpick/ 21 | @$(SPHINXBUILD) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 22 | touch .cache/make/sphinx 23 | """ 24 | -------------------------------------------------------------------------------- /docs/ideas/ini.toml: -------------------------------------------------------------------------------- 1 | # Keys should be present 2 | # [Enforce presence of keys (with any values) · Issue #218 · andreoliwa/nitpick](https://github.com/andreoliwa/nitpick/issues/218) 3 | ["setup.cfg".flake8] 4 | ignore__exists = "str" 5 | max-line-length__exists = "int" 6 | exclude__exists = "str" 7 | max-complexity__exists = "int" 8 | inline-quotes__exists = "str" 9 | 10 | # https://github.com/andreoliwa/nitpick/issues/271 11 | ignore__separators = "," 12 | exclude__separators = "," 13 | 14 | # Keys should be absent 15 | ["setup.cfg".some-section] 16 | ignore__exists = true 17 | max-line-length__exists = true 18 | exclude__exists = true 19 | max-complexity__exists = true 20 | inline-quotes__exists = true 21 | 22 | # Section should be absent 23 | ["setup.cfg".darglint] 24 | __exists = false 25 | blabla = "{{ nit.section_absent() }}" 26 | 27 | # Section should be absent 28 | ["setup.cfg"."tox:tox"] 29 | __exists = false 30 | ["setup.cfg"."gh-actions"] 31 | __exists = false 32 | 33 | # Section should be present 34 | ["tox.ini"."tox"] 35 | __exists = true 36 | ["tox.ini".gh-actions] 37 | __exists = true 38 | 39 | # Keys should be present using Jinja 40 | ["setup.cfg".flake8-jinja] 41 | ignore = "{{ nit.present(str, validators=[comma_separated_str]) }}" 42 | max-line-length = "{{ nit.present(int, validators=[range(80, 120)]) }}" 43 | exclude = "{{ nit.present(str, validators=[comma_separated_str]) }}" 44 | max-complexity = "{{ nit.present(int) }}" 45 | inline-quotes = "{{ nit.present(str, choices=['double', 'single']) }}" 46 | 47 | ["setup.cfg".isort] 48 | # https://github.com/andreoliwa/nitpick/issues/271 49 | skip__separators = "," 50 | known_first_party__separators = "," 51 | 52 | ["tox.ini".pytest] 53 | # https://github.com/andreoliwa/nitpick/issues/271 54 | addopts__separators = " " 55 | norecursedirs__separators = " " 56 | testpaths__separators = " \n" 57 | -------------------------------------------------------------------------------- /docs/ideas/lab.py: -------------------------------------------------------------------------------- 1 | """Laboratory of Nitpick ideas.""" 2 | 3 | import json 4 | from pathlib import Path 5 | from pprint import pprint 6 | 7 | import click 8 | import jmespath 9 | from identify import identify 10 | 11 | from nitpick.blender import TomlDoc, YamlDoc, flatten_quotes, search_json 12 | 13 | workflow = YamlDoc(path=Path(".github/workflows/python.yaml")) 14 | 15 | 16 | def find(expression): 17 | """Find with JMESpath.""" 18 | print(f"\nExpression: {expression}") 19 | rv = search_json(workflow.as_object, jmespath.compile(expression), {}) 20 | print(f"Type: {type(rv)}") 21 | pprint(rv) 22 | 23 | 24 | @click.group() 25 | def cli_lab(): 26 | """Laboratory of experiments and ideas.""" 27 | 28 | 29 | @cli_lab.command() 30 | @click.argument("path_from_root") 31 | def convert(path_from_root: str): 32 | """Convert file to a TOML config.""" 33 | tags = identify.tags_from_path(path_from_root) 34 | if "yaml" in tags: 35 | which_doc = YamlDoc(path=path_from_root) 36 | else: 37 | msg = f"No conversion for these types: {tags}" 38 | raise NotImplementedError(msg) 39 | 40 | toml_doc = TomlDoc(obj={path_from_root: which_doc.as_object}, use_tomlkit=True) 41 | print(toml_doc.reformatted) 42 | return toml_doc.reformatted 43 | 44 | 45 | def main() -> None: 46 | """Play around.""" 47 | for path in sorted(Path("docs/ideas/yaml").glob("*.toml")): 48 | click.secho(str(path), fg="green") 49 | 50 | toml_doc = TomlDoc(path=path) 51 | config: dict = toml_doc.as_object[".github/workflows/python.yaml"] 52 | 53 | # config.pop("contains") 54 | # config.pop("contains_sorted") 55 | 56 | click.secho("JSON", fg="yellow") 57 | print(json.dumps(config, indent=2)) 58 | 59 | click.secho("Flattened JSON", fg="yellow") 60 | print(json.dumps(flatten_quotes(config), indent=2)) 61 | 62 | # find("jobs.build") 63 | # find("jobs.build.strategy.matrix") 64 | # find('jobs.build.strategy.matrix."python-version"') 65 | # find("jobs.build.strategy.matrix.os") 66 | # find("jobs.build.steps[]") 67 | # find("jobs.build.steps[0]") 68 | # find("jobs.build.steps[1]") 69 | # find('jobs.build."runs-on"') 70 | # find("jobs.build.steps[].name") 71 | # find("jobs.build.steps[].uses") 72 | # find("jobs.build.steps[].[name, uses]") 73 | # find("jobs.build.steps[].{name: name, uses: uses}") 74 | 75 | 76 | if __name__ == "__main__": 77 | cli_lab() 78 | -------------------------------------------------------------------------------- /docs/ideas/semantic-release.toml: -------------------------------------------------------------------------------- 1 | # semantic-release needs a special checker 2 | release = """{ 3 | "plugins": [ 4 | "@semantic-release/commit-analyzer", 5 | "@semantic-release/release-notes-generator", 6 | [ 7 | "@semantic-release/changelog", 8 | { 9 | "changelogFile": "CHANGELOG.md" 10 | } 11 | ], 12 | [ 13 | "@semantic-release/exec", 14 | { 15 | "prepareCmd": "bumpversion --allow-dirty --no-commit --no-tag --new-version ${nextRelease.version} patch" 16 | } 17 | ], 18 | "@semantic-release/github", 19 | "@semantic-release/git" 20 | ] 21 | } 22 | """ 23 | -------------------------------------------------------------------------------- /docs/ideas/toml.toml: -------------------------------------------------------------------------------- 1 | # Keys are absent 2 | # See [Enforce absence of keys · Issue #10 · andreoliwa/nitpick](https://github.com/andreoliwa/nitpick/issues/10) 3 | ["pyproject.toml".tool.poetry.group.dev.dependencies] 4 | pep257__exists = false 5 | pycodestyle__exists = false 6 | pur__exists = false 7 | pep257 = "{{ nit.absent() }}" # Jinja 8 | pycodestyle = "{{ nit.absent() }}" # Jinja 9 | pur = "{{ nit.absent() }}" # Jinja 10 | 11 | # Keys are absent 12 | ["pyproject.toml".tool.poetry.dependencies] 13 | pep257__exists = false 14 | pycodestyle__exists = false 15 | pur__exists = false 16 | pep257 = "{{ nit.absent() }}" # Jinja 17 | pycodestyle = "{{ nit.absent() }}" # Jinja 18 | pur = "{{ nit.absent() }}" # Jinja 19 | 20 | # Pre-processing with Jinja to generate multiple sections with the same config? ["pyproject.toml".tool.poetry.{{ ['dependencies', 'dev-dependencies'] }}] 21 | # https://github.com/andreoliwa/nitpick/issues/283 22 | 23 | # Keys are present, with the expected types 24 | ["pyproject.toml".build-system] 25 | requires__exists = "List[str]" 26 | build-backend__exists = "str" 27 | requires = "{{ nit.present(List[str]) }}" # Jinja 28 | build-backend = "{{ nit.present(str) }}" # Jinja 29 | 30 | # Integer key exists 31 | ["pyproject.toml".tool.black] 32 | line-length__exists = "int" 33 | line-length = "{{ nit.present(int) }}" # Jinja 34 | 35 | # Section exists with anything inside 36 | # [Enforce presence of keys (with any values) · Issue #218 · andreoliwa/nitpick](https://github.com/andreoliwa/nitpick/issues/218) 37 | ["pyproject.toml".tool.black2] 38 | __exists = true 39 | blabla = "{{ nit.section_present() }}" # Jinja 40 | -------------------------------------------------------------------------------- /docs/ideas/yaml/contains.toml: -------------------------------------------------------------------------------- 1 | # 1. Same effect as items 1, 2 and 3 on "jmespath-on-section.toml", but with a different syntax. 2 | # 2. Everything that is not a dunder key ("__") will be a dict to be enforced. 3 | [[".github/workflows/python.yaml".contains]] 4 | __jmespath = "jobs.build.strategy.matrix" 5 | os = ["ubuntu-latest", "macos-latest", "windows-latest"] 6 | "python-version" = ["3.12", "3.11", "3.10", "3.9", "3.8"] 7 | 8 | # 3. Same as item 4 on "jmespath-on-section.toml", but with a different syntax. 9 | [[".github/workflows/python.yaml".contains]] 10 | __jmespath = "jobs.build" 11 | "runs-on" = "${{ matrix.os }}" 12 | 13 | # 4. "jobs.build.steps" can have multiple dicts; each one is a "contains" table 14 | [[".github/workflows/python.yaml".contains]] 15 | __jmespath = "jobs.build.steps" 16 | uses = "actions/checkout@v2" 17 | 18 | # 5. The "problem" with the "contains" table is that "__jmespath" will be repeated many times 19 | [[".github/workflows/python.yaml".contains]] 20 | __jmespath = "jobs.build.steps" 21 | name = "Set up Python ${{ matrix.python-version }}" 22 | uses = "actions/setup-python@v2" 23 | with = {"python-version" = "${{ matrix.python-version }}"} 24 | 25 | # 6. Alternative to 5 with a multiline YAML string 26 | [[".github/workflows/python.yaml".contains]] 27 | __jmespath = "jobs.build.steps" 28 | __yaml = """ 29 | - name: Set up Python ${{ matrix.python-version }} 30 | uses: actions/setup-python@v2 31 | with: 32 | python-version: ${{ matrix.python-version }} 33 | """ 34 | 35 | # 7. Alternative to 6, YAML without the whitespace. 36 | # Check if this is possible. 37 | # It would be best to ignored the initial whitespace and add the parsed data 38 | # directly under the "__jmespath" 39 | [[".github/workflows/python.yaml".contains]] 40 | __jmespath = "jobs.build.steps" 41 | __yaml = """ 42 | - name: Set up Python ${{ matrix.python-version }} 43 | uses: actions/setup-python@v2 44 | with: 45 | python-version: ${{ matrix.python-version }} 46 | """ 47 | 48 | # 8. Alternative to 4, but with formatted YAML in a single line string. 49 | [[".github/workflows/python.yaml".contains]] 50 | __jmespath = "jobs.build.steps" 51 | __yaml = "- uses: actions/checkout@v2" 52 | 53 | # 9. Same as items 1, 2 and 3, but asserting that they are ordered 54 | # in the sequence they appear here on the TOML file. 55 | # "contains_sorted" is an idea for a distant future, taken from text.toml, still not implemented 56 | [[".github/workflows/python.yaml".contains_sorted]] 57 | __jmespath = "jobs.build.strategy.matrix" 58 | os = ["ubuntu-latest", "macos-latest", "windows-latest"] 59 | "python-version" = ["3.12", "3.11", "3.10", "3.9", "3.8"] 60 | 61 | [[".github/workflows/python.yaml".contains_sorted]] 62 | __jmespath = "jobs.build" 63 | "runs-on" = "${{ matrix.os }}" 64 | -------------------------------------------------------------------------------- /docs/ideas/yaml/formatted-yaml.toml: -------------------------------------------------------------------------------- 1 | # Multiline YAML string 2 | [".github/workflows/python.yaml".jobs.build.steps] 3 | __yaml = """ 4 | - name: Set up Python ${{ matrix.python-version }} 5 | uses: actions/setup-python@v2 6 | with: 7 | python-version: ${{ matrix.python-version }} 8 | """ 9 | 10 | # Alternative to the above YAML without the whitespace. 11 | # Check if this is possible. 12 | # It would be best to ignored the initial whitespace and add the parsed data 13 | # directly under the "__jmespath" 14 | [".github/workflows/python.yaml".jobs.build.steps.alternative] 15 | __yaml = """ 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | """ 21 | -------------------------------------------------------------------------------- /docs/ideas/yaml/jmespath.toml: -------------------------------------------------------------------------------- 1 | # JMESPath as part of the section name, after the file name. 2 | # Everything after the file name is considered a JMESPath https://jmespath.org/ 3 | # Format: ["path/to/file.ext".jmes.path.expression] 4 | # The values below were taken from .github/workflows/python.yaml in this repo 5 | 6 | # 1. Complex JMESPath expressions should be quoted 7 | # (I still don't know how to deal with JMESPath that matches multiple items) 8 | [[".github/workflows/python.yaml"."jobs.build.steps[].{name: name, uses: uses}"]] 9 | uses = "actions/checkout@v2" 10 | 11 | # 2. JMESPath expression that has double quotes, wrapped in single quotes for TOML 12 | [[".github/workflows/python.yaml".'jobs.build.strategy.matrix."python-version"']] 13 | name = "Set up Python ${{ matrix.python-version }}" 14 | uses = "actions/setup-python@v2" 15 | with = {"python-version" = "${{ matrix.python-version }}"} 16 | 17 | # 3. It allows Jinja tuning in https://github.com/andreoliwa/nitpick/issues/283 18 | name__jinja = "Set up Python ${{ matrix.python-version }}" 19 | name__no_jinja = "Set up Python ${{ matrix.python-version }}" 20 | name__jinja_off = "Set up Python ${{ matrix.python-version }}" 21 | 22 | # 4. "{{" and "}}" will conflict with Jinja https://github.com/andreoliwa/nitpick/issues/283 23 | # So we need a way to turn on/off Jinja templating. 24 | # Probably "false" will be the default, to keep compatibility. 25 | # Whoever wants to use Jinja will need to set "true" either here or as a global config on .nitpick.toml 26 | [".github/workflows/python.yaml".jobs.build] 27 | __jinja = false 28 | 29 | # 5. Another way to turn off Jinja for a specific key only, not the whole dict 30 | # (using the "__" syntax from Django filters, SQLAlchemy, factoryboy...) 31 | "runs-on__no_jinja" = "${{ matrix.os }}" 32 | 33 | # 6. Simplified API, having JMESPath as direct keys 34 | # Read the discussion: https://github.com/andreoliwa/nitpick/pull/353/files#r613816390 35 | [".github/workflows/jmespath-simple.yaml"] 36 | "jobs.build.strategy.matrix.os" = "foo" 37 | "jobs.build.steps" = ["bar"] 38 | "jobs.build.steps.regex" = "baz d+" 39 | "jobs.build.steps.contains" = "baz" 40 | -------------------------------------------------------------------------------- /docs/ideas/yaml/lists.toml: -------------------------------------------------------------------------------- 1 | # List behaviours that are still not implemented in YAML (maybe they can be used in other formats too) 2 | 3 | # 1. List behaviour: Exact list (dict or scalar) __exact 4 | # The whole list will be replaced exactly by what's defined in the style 5 | # Use the "__exact" suffix on the list name 6 | [[".pre-commit-config.yaml".repos]] 7 | repo = "https://github.com/alessandrojcm/commitlint-pre-commit-hook" 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | additional_dependencies__exact = ["@commitlint/config-conventional"] 10 | id = "commitlint" 11 | stages = ["commit-msg"] 12 | 13 | # 2. List behaviour: Define the fields that should be part of the hash 14 | ["some-file.yaml".__list_hash_fields] 15 | # Hash all fields (default) 16 | some_list = "*" 17 | # Hash only specific fields 18 | person_list = "name,age,gender" 19 | # Hash all fields except these 20 | another_list = "-price,size" 21 | 22 | # 3. List behaviour: Custom function (dict or scalar) 23 | # Search using a custom function. 24 | # A custom function called by Nitpick that receives X, Y, Z arguments (to be defined) 25 | # And returns the new element and its index it should be in the list: 26 | # - 0 to len(list) 27 | # - or -1 to append the element at the end 28 | ["another-file.yaml".__search_custom] 29 | my_fancy_list = "path.to.module.and.function" 30 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/merged_style.toml: -------------------------------------------------------------------------------- 1 | # This should be the result of a parent style including all the styles in this directory 2 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 3 | os = ["ubuntu-latest", "macos-latest", "windows-latest"] 4 | "python-version" = ["3.12", "3.11", "3.10", "3.9", "3.8"] 5 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/os_macos.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | os = ["macos-latest"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/os_ubuntu.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | os = ["ubuntu-latest"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/os_windows.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | os = ["windows-latest"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/py310.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | "python-version" = ["3.10"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/py311.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | "python-version" = ["3.11"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/py312.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | "python-version" = ["3.12"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/py38.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | "python-version" = ["3.8"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/merge_lists/py39.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | "python-version" = ["3.9"] 3 | -------------------------------------------------------------------------------- /docs/ideas/yaml/present-keys.toml: -------------------------------------------------------------------------------- 1 | # Keys should be present 2 | # See [Enforce presence of keys (with any values) · Issue #218 · andreoliwa/nitpick](https://github.com/andreoliwa/nitpick/issues/218) 3 | [[".pre-commit-config.yaml".repos.hooks]] 4 | entry__exists = true 5 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | Nitpick 4 | ======= 5 | 6 | .. image:: https://img.shields.io/pypi/v/nitpick.svg 7 | :target: https://pypi.org/project/nitpick/ 8 | :alt: PyPI 9 | .. image:: https://github.com/andreoliwa/nitpick/actions/workflows/python.yaml/badge.svg 10 | :target: https://github.com/andreoliwa/nitpick/actions/workflows/python.yaml 11 | :alt: GitHub Workflow 12 | .. image:: https://readthedocs.org/projects/nitpick/badge/?version=latest 13 | :target: https://nitpick.rtfd.io/en/latest/?badge=latest 14 | :alt: Documentation Status 15 | .. image:: https://coveralls.io/repos/github/andreoliwa/nitpick/badge.svg 16 | :target: https://coveralls.io/github/andreoliwa/nitpick 17 | :alt: Coveralls 18 | .. image:: https://api.codeclimate.com/v1/badges/61e0cdc48e24e76a0460/maintainability 19 | :target: https://codeclimate.com/github/andreoliwa/nitpick 20 | :alt: Maintainability 21 | .. image:: https://api.codeclimate.com/v1/badges/61e0cdc48e24e76a0460/test_coverage 22 | :target: https://codeclimate.com/github/andreoliwa/nitpick 23 | :alt: Test Coverage 24 | .. image:: https://img.shields.io/pypi/pyversions/nitpick.svg 25 | :target: https://pypi.org/project/nitpick/ 26 | :alt: Supported Python versions 27 | .. image:: https://img.shields.io/pypi/l/nitpick.svg 28 | :target: https://pypi.org/project/nitpick/ 29 | :alt: Project License 30 | .. image:: https://img.shields.io/badge/code%20style-black-000000.svg 31 | :target: https://github.com/psf/black 32 | :alt: Code style: black 33 | .. image:: https://img.shields.io/badge/renovate-enabled-brightgreen.svg 34 | :target: https://renovatebot.com 35 | :alt: Renovate 36 | .. image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg 37 | :target: https://github.com/semantic-release/semantic-release 38 | :alt: semantic-release 39 | 40 | Command-line tool and flake8_ plugin to enforce the same settings across multiple language-independent projects. 41 | 42 | Useful if you maintain multiple projects and are tired of copying/pasting the same INI/TOML/YAML/JSON keys and values over and over, in all of them. 43 | 44 | The CLI now has a ``nitpick fix`` command that modifies configuration files directly (pretty much like black_ and isort_ do with Python files). 45 | See :ref:`cli` for more info. 46 | 47 | Many more features are planned for the future, check `the roadmap `_. 48 | 49 | .. note:: 50 | 51 | This project is still a work in progress, so the API is not fully defined: 52 | 53 | - :ref:`the-style-file` syntax might have changes before the 1.0 stable release; 54 | - The numbers in the ``NIP*`` error codes might change; don't fully rely on them; 55 | - See also :ref:`breaking-changes`. 56 | 57 | .. toctree:: 58 | :caption: Contents: 59 | 60 | quickstart 61 | styles 62 | configuration 63 | library 64 | nitpick_section 65 | cli 66 | flake8_plugin 67 | plugins 68 | troubleshooting 69 | contributing 70 | authors 71 | 72 | .. toctree:: 73 | :maxdepth: 1 74 | :caption: API Reference: 75 | 76 | source/modules 77 | 78 | Indices and tables 79 | ================== 80 | 81 | * :ref:`genindex` 82 | * :ref:`modindex` 83 | * :ref:`search` 84 | 85 | To Do List 86 | ========== 87 | 88 | .. todolist:: 89 | -------------------------------------------------------------------------------- /docs/nitpick_section.rst: -------------------------------------------------------------------------------- 1 | .. _nitpick_section: 2 | 3 | The [nitpick] table 4 | =================== 5 | 6 | The [nitpick] table in :ref:`the style file ` contains global settings for the style. 7 | 8 | Those are settings that either don't belong to any specific config file, or can be applied to all config files. 9 | 10 | Minimum version 11 | --------------- 12 | 13 | Show an upgrade message to the developer if Nitpick's version is below ``minimum_version``: 14 | 15 | .. code-block:: toml 16 | 17 | [nitpick] 18 | minimum_version = "0.10.0" 19 | 20 | [nitpick.files] 21 | --------------- 22 | 23 | Files that should exist 24 | ^^^^^^^^^^^^^^^^^^^^^^^ 25 | 26 | To enforce that certain files should exist in the project, you can add them to the style file as a dictionary of "file name" and "extra message". 27 | 28 | Use an empty string to not display any extra message. 29 | 30 | .. code-block:: toml 31 | 32 | [nitpick.files.present] 33 | ".editorconfig" = "" 34 | "CHANGELOG.md" = "A project should have a changelog" 35 | 36 | Files that should be deleted 37 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 38 | 39 | To enforce that certain files should not exist in the project, you can add them to the style file. 40 | 41 | .. code-block:: toml 42 | 43 | [nitpick.files.absent] 44 | "some_file.txt" = "This is an optional extra string to display after the warning" 45 | "another_file.env" = "" 46 | 47 | Multiple files can be configured as above. 48 | The message is optional. 49 | 50 | Comma separated values 51 | ^^^^^^^^^^^^^^^^^^^^^^ 52 | 53 | On ``setup.cfg``, some keys are lists of multiple values separated by commas, like ``flake8.ignore``. 54 | 55 | On the style file, it's possible to indicate which key/value pairs should be treated as multiple values instead of an exact string. 56 | Multiple keys can be added. 57 | 58 | .. code-block:: toml 59 | 60 | [nitpick.files."setup.cfg"] 61 | comma_separated_values = ["flake8.ignore", "isort.some_key", "another_section.another_key"] 62 | 63 | [nitpick.styles] 64 | ---------------- 65 | 66 | Styles can include other styles. Just provide a list of styles to include. 67 | 68 | Example of usage: :gitref:`Nitpick's default style `. 69 | 70 | .. code-block:: toml 71 | 72 | [nitpick.styles] 73 | include = ["styles/python38", "styles/poetry"] 74 | 75 | The styles will be merged following the sequence in the list. The ``.toml`` 76 | extension for each referenced file can be onitted. 77 | 78 | Relative references are resolved relative to the URI of the style doument they 79 | are included in according to the `normal rules of RFC 3986 `_. 80 | 81 | E.g. for a style file located at 82 | ``gh://$GITHUB_TOKEN@foo_dev/bar_project@branchname/styles/foobar.toml`` the following 83 | strings all reference the exact same canonical location to include: 84 | 85 | .. code-block:: toml 86 | 87 | [nitpick.styles] 88 | include = [ 89 | "foobar.toml", 90 | "../styles/foobar.toml", 91 | "/bar_project@branchname/styles/foobar.toml", 92 | "//$GITHUB_TOKEN@foo_dev/bar_project@branchname/styles/foobar.toml", 93 | ] 94 | 95 | For style files on the local filesystem, the canonical path 96 | (after symbolic links have been resolved) of the style file is used as the 97 | base. 98 | 99 | If a key/value pair appears in more than one sub-style, it will be overridden; the last declared key/pair will prevail. 100 | -------------------------------------------------------------------------------- /docs/plugins.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | Plugins 4 | ======= 5 | 6 | Nitpick uses plugins to handle configuration files. 7 | 8 | There are plans to add plugins that handle certain file types, specific files, and user plugins. 9 | Check `the roadmap `_. 10 | 11 | Below are the currently included plugins. 12 | 13 | .. auto-generated-from-here 14 | 15 | .. _iniplugin: 16 | 17 | INI files 18 | --------- 19 | 20 | Enforce configurations and autofix INI files. 21 | 22 | Examples of ``.ini`` files handled by this plugin: 23 | 24 | - `setup.cfg `_ 25 | - `.editorconfig `_ 26 | - `tox.ini `_ 27 | - `.pylintrc `_ 28 | 29 | Style examples enforcing values on INI files: :gitref:`flake8 configuration 30 | `. 31 | 32 | .. _jsonplugin: 33 | 34 | JSON files 35 | ---------- 36 | 37 | Enforce configurations and autofix JSON files. 38 | 39 | Add the configurations for the file name you wish to check. 40 | Style example: :gitref:`the default config for package.json `. 41 | 42 | .. _textplugin: 43 | 44 | Text files 45 | ---------- 46 | 47 | Enforce configuration on text files. 48 | 49 | To check if ``some.txt`` file contains the lines ``abc`` and ``def`` (in any order): 50 | 51 | .. code-block:: toml 52 | 53 | [["some.txt".contains]] 54 | line = "abc" 55 | 56 | [["some.txt".contains]] 57 | line = "def" 58 | 59 | .. _tomlplugin: 60 | 61 | TOML files 62 | ---------- 63 | 64 | Enforce configurations and autofix TOML files. 65 | 66 | E.g.: `pyproject.toml (PEP 518) `_. 67 | 68 | See also `the [tool.poetry] section of the pyproject.toml file 69 | `_. 70 | 71 | Style example: :gitref:`Python 3.10 version constraint `. 72 | There are :ref:`many other examples here `. 73 | 74 | .. _yamlplugin: 75 | 76 | YAML files 77 | ---------- 78 | 79 | Enforce configurations and autofix YAML files. 80 | 81 | - Example: `.pre-commit-config.yaml `_. 82 | - Style example: :gitref:`the default pre-commit hooks `. 83 | 84 | .. warning:: 85 | 86 | The plugin tries to preserve comments in the YAML file by using the ``ruamel.yaml`` package. 87 | It works for most cases. 88 | If your comment was removed, place them in a different place of the fil and try again. 89 | If it still doesn't work, please :issue:`report a bug `. 90 | 91 | Known issue: lists like ``args`` and ``additional_dependencies`` might be joined in a single line, 92 | and comments between items will be removed. 93 | Move your comments outside these lists, and they should be preserved. 94 | 95 | .. note:: 96 | 97 | No validation of ``.pre-commit-config.yaml`` will be done anymore in this generic YAML plugin. 98 | Nitpick will not validate hooks and missing keys as it did before; it's not the purpose of this package. 99 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | Quickstart 4 | ========== 5 | 6 | Install 7 | ------- 8 | 9 | Install in an isolated environment with pipx_:: 10 | 11 | # Latest PyPI release 12 | pipx install nitpick 13 | 14 | # Development branch from GitHub 15 | pipx install git+https://github.com/andreoliwa/nitpick 16 | 17 | On macOS/Linux, install the latest release with Homebrew_:: 18 | 19 | brew install andreoliwa/formulae/nitpick 20 | 21 | # Development branch from GitHub 22 | brew install andreoliwa/formulae/nitpick --HEAD 23 | 24 | On Arch Linux, install with yay:: 25 | 26 | yay -Syu nitpick 27 | 28 | Add to your project with Poetry_:: 29 | 30 | poetry add --dev nitpick 31 | 32 | Or install it with pip:: 33 | 34 | pip install -U nitpick 35 | 36 | Run 37 | --- 38 | 39 | Nitpick_ will fail if no style is explicitly configured. 40 | Run this command to download and use the opinionated :gitref:`default style file `: 41 | 42 | nitpick init 43 | 44 | You can use it as a template to :ref:`configure-your-own-style`. 45 | 46 | To fix and modify your files directly:: 47 | 48 | nitpick fix 49 | 50 | To check for errors only:: 51 | 52 | nitpick check 53 | 54 | Nitpick is also a flake8_ plugin, so you can run this on a project with at least one Python (``.py``) file:: 55 | 56 | flake8 . 57 | 58 | Run as a pre-commit hook 59 | ------------------------ 60 | 61 | If you use pre-commit_ on your project, add this to the ``.pre-commit-config.yaml`` in your repository: 62 | 63 | .. code-block:: yaml 64 | 65 | repos: 66 | - repo: https://github.com/andreoliwa/nitpick 67 | rev: v0.38.0 68 | hooks: 69 | - id: nitpick-suggest 70 | - id: nitpick 71 | 72 | There are a few hook IDs available: 73 | 74 | - ``nitpick``, ``nitpick-fix`` and ``nitpick-fix-all`` run the ``nitpick fix`` command; 75 | - ``nitpick-check`` and ``nitpick-check-all`` runs ``nitpick check``; 76 | - ``nitpick-suggest`` runs ``nitpick init --fix --suggest``; 77 | 78 | If you want to run Nitpick_ as a flake8_ plugin instead: 79 | 80 | .. code-block:: yaml 81 | 82 | repos: 83 | - repo: https://github.com/PyCQA/flake8 84 | rev: 4.0.1 85 | hooks: 86 | - id: flake8 87 | additional_dependencies: [nitpick] 88 | 89 | To install the ``pre-commit`` and ``commit-msg`` Git hooks: 90 | 91 | .. code-block:: shell 92 | 93 | pre-commit install --install-hooks 94 | pre-commit install -t commit-msg 95 | 96 | To start checking all your code against the default rules: 97 | 98 | .. code-block:: shell 99 | 100 | pre-commit run --all-files 101 | 102 | Run as a MegaLinter plugin 103 | --------------------------- 104 | 105 | If you use `MegaLinter `_ you can run Nitpick as a plugin. Add the following two entries to your ``.mega-linter.yml`` configuration file: 106 | 107 | .. code-block:: yaml 108 | 109 | PLUGINS: 110 | - https://raw.githubusercontent.com/andreoliwa/nitpick/v0.38.0/mega-linter-plugin-nitpick/nitpick.megalinter-descriptor.yml 111 | ENABLE_LINTERS: 112 | - NITPICK 113 | 114 | Modify files directly 115 | --------------------- 116 | 117 | Nitpick_ includes a CLI to apply your style and modify the configuration files directly: 118 | 119 | .. code-block:: shell 120 | 121 | nitpick fix 122 | 123 | Read more details here: :ref:`cli`. 124 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | nitpick 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | nitpick 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.blender.rst: -------------------------------------------------------------------------------- 1 | nitpick.blender module 2 | ====================== 3 | 4 | .. automodule:: nitpick.blender 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.cli.rst: -------------------------------------------------------------------------------- 1 | nitpick.cli module 2 | ================== 3 | 4 | .. automodule:: nitpick.cli 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.compat.rst: -------------------------------------------------------------------------------- 1 | nitpick.compat module 2 | ===================== 3 | 4 | .. automodule:: nitpick.compat 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.config.rst: -------------------------------------------------------------------------------- 1 | nitpick.config module 2 | ===================== 3 | 4 | .. automodule:: nitpick.config 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.constants.rst: -------------------------------------------------------------------------------- 1 | nitpick.constants module 2 | ======================== 3 | 4 | .. automodule:: nitpick.constants 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.core.rst: -------------------------------------------------------------------------------- 1 | nitpick.core module 2 | =================== 3 | 4 | .. automodule:: nitpick.core 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.exceptions.rst: -------------------------------------------------------------------------------- 1 | nitpick.exceptions module 2 | ========================= 3 | 4 | .. automodule:: nitpick.exceptions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.fields.rst: -------------------------------------------------------------------------------- 1 | nitpick.fields module 2 | ===================== 3 | 4 | .. automodule:: nitpick.fields 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.flake8.rst: -------------------------------------------------------------------------------- 1 | nitpick.flake8 module 2 | ===================== 3 | 4 | .. automodule:: nitpick.flake8 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.generic.rst: -------------------------------------------------------------------------------- 1 | nitpick.generic module 2 | ====================== 3 | 4 | .. automodule:: nitpick.generic 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.base.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.base module 2 | =========================== 3 | 4 | .. automodule:: nitpick.plugins.base 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.info.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.info module 2 | =========================== 3 | 4 | .. automodule:: nitpick.plugins.info 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.ini.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.ini module 2 | ========================== 3 | 4 | .. automodule:: nitpick.plugins.ini 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.json.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.json module 2 | =========================== 3 | 4 | .. automodule:: nitpick.plugins.json 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins package 2 | ======================= 3 | 4 | .. automodule:: nitpick.plugins 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | nitpick.plugins.base 16 | nitpick.plugins.info 17 | nitpick.plugins.ini 18 | nitpick.plugins.json 19 | nitpick.plugins.text 20 | nitpick.plugins.toml 21 | nitpick.plugins.yaml 22 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.text.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.text module 2 | =========================== 3 | 4 | .. automodule:: nitpick.plugins.text 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.toml.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.toml module 2 | =========================== 3 | 4 | .. automodule:: nitpick.plugins.toml 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.plugins.yaml.rst: -------------------------------------------------------------------------------- 1 | nitpick.plugins.yaml module 2 | =========================== 3 | 4 | .. automodule:: nitpick.plugins.yaml 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.any.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.any package 2 | ============================= 3 | 4 | .. automodule:: nitpick.resources.any 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.javascript.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.javascript package 2 | ==================================== 3 | 4 | .. automodule:: nitpick.resources.javascript 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.kotlin.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.kotlin package 2 | ================================ 3 | 4 | .. automodule:: nitpick.resources.kotlin 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.markdown.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.markdown package 2 | ================================== 3 | 4 | .. automodule:: nitpick.resources.markdown 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.presets.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.presets package 2 | ================================= 3 | 4 | .. automodule:: nitpick.resources.presets 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.proto.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.proto package 2 | =============================== 3 | 4 | .. automodule:: nitpick.resources.proto 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.python.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.python package 2 | ================================ 3 | 4 | .. automodule:: nitpick.resources.python 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources package 2 | ========================= 3 | 4 | .. automodule:: nitpick.resources 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | nitpick.resources.any 16 | nitpick.resources.javascript 17 | nitpick.resources.kotlin 18 | nitpick.resources.markdown 19 | nitpick.resources.presets 20 | nitpick.resources.proto 21 | nitpick.resources.python 22 | nitpick.resources.shell 23 | nitpick.resources.toml 24 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.shell.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.shell package 2 | =============================== 3 | 4 | .. automodule:: nitpick.resources.shell 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.resources.toml.rst: -------------------------------------------------------------------------------- 1 | nitpick.resources.toml package 2 | ============================== 3 | 4 | .. automodule:: nitpick.resources.toml 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.rst: -------------------------------------------------------------------------------- 1 | nitpick package 2 | =============== 3 | 4 | .. automodule:: nitpick 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | nitpick.plugins 16 | nitpick.resources 17 | 18 | Submodules 19 | ---------- 20 | 21 | .. toctree:: 22 | :maxdepth: 4 23 | 24 | nitpick.blender 25 | nitpick.cli 26 | nitpick.compat 27 | nitpick.config 28 | nitpick.constants 29 | nitpick.core 30 | nitpick.exceptions 31 | nitpick.fields 32 | nitpick.flake8 33 | nitpick.generic 34 | nitpick.schemas 35 | nitpick.style 36 | nitpick.tomlkit_ext 37 | nitpick.typedefs 38 | nitpick.violations 39 | -------------------------------------------------------------------------------- /docs/source/nitpick.schemas.rst: -------------------------------------------------------------------------------- 1 | nitpick.schemas module 2 | ====================== 3 | 4 | .. automodule:: nitpick.schemas 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.style.rst: -------------------------------------------------------------------------------- 1 | nitpick.style module 2 | ==================== 3 | 4 | .. automodule:: nitpick.style 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.tomlkit_ext.rst: -------------------------------------------------------------------------------- 1 | nitpick.tomlkit\_ext module 2 | =========================== 3 | 4 | .. automodule:: nitpick.tomlkit_ext 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.typedefs.rst: -------------------------------------------------------------------------------- 1 | nitpick.typedefs module 2 | ======================= 3 | 4 | .. automodule:: nitpick.typedefs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/nitpick.violations.rst: -------------------------------------------------------------------------------- 1 | nitpick.violations module 2 | ========================= 3 | 4 | .. automodule:: nitpick.violations 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/targets.rst: -------------------------------------------------------------------------------- 1 | .. Keep items sorted alphabetically from here (using Pycharm, even tough it's case-sensitive): 2 | 3 | .. _Bash: https://www.gnu.org/software/bash/ 4 | .. _Django: https://github.com/django/django 5 | .. _EditorConfig: https://editorconfig.org 6 | .. _Flask CLI: https://flask.palletsprojects.com/en/1.1.x/cli/ 7 | .. _Flask: https://github.com/pallets/flask 8 | .. _Homebrew: https://github.com/Homebrew/brew 9 | .. _IPython: https://github.com/ipython/ipython 10 | .. _Invoke: https://github.com/pyinvoke/invoke 11 | .. _Nitpick: https://github.com/andreoliwa/nitpick 12 | .. _Pipenv: https://github.com/pypa/pipenv 13 | .. _Poetry: https://github.com/python-poetry/poetry 14 | .. _Pylint: https://github.com/PyCQA/pylint 15 | .. _ReadTheDocs: https://readthedocs.org/ 16 | .. _TOML: https://github.com/toml-lang/toml 17 | .. _autoflake: https://github.com/myint/autoflake 18 | .. _bandit: https://github.com/PyCQA/bandit 19 | .. _bashate: https://github.com/openstack/bashate 20 | .. _black: https://github.com/psf/black 21 | .. _codeclimate: https://codeclimate.com/ 22 | .. _commitizen: https://github.com/commitizen-tools/commitizen 23 | .. _commitlint: https://commitlint.js.org/ 24 | .. _flake8: https://github.com/PyCQA/flake8 25 | .. _git-legal: https://docs.codeclimate.com/docs/git-legal 26 | .. _isort: https://github.com/PyCQA/isort 27 | .. _markdownlint: https://github.com/markdownlint/markdownlint 28 | .. _mypy: https://github.com/python/mypy 29 | .. _package.json: https://docs.npmjs.com/files/package.json 30 | .. _pipx: https://github.com/pipxproject/pipx 31 | .. _pre-commit: https://github.com/pre-commit/pre-commit 32 | .. _prettier: https://github.com/prettier/prettier 33 | .. _pytest: https://github.com/pytest-dev/pytest 34 | .. _radon: https://github.com/rubik/radon 35 | .. _shellcheck: https://github.com/koalaman/shellcheck 36 | .. _sonar-python: https://github.com/SonarSource/sonar-python 37 | .. _tox: https://github.com/tox-dev/tox 38 | -------------------------------------------------------------------------------- /docs/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | .. include:: targets.rst 2 | 3 | Troubleshooting 4 | =============== 5 | 6 | Crash on multi-threading 7 | ------------------------ 8 | 9 | On macOS, flake8_ might raise this error when calling ``requests.get(url)``: 10 | 11 | .. code-block:: shell 12 | 13 | objc[93329]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. 14 | objc[93329]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug. 15 | 16 | To solve this issue, add this environment variable to ``.bashrc`` (or the initialization file for your favorite shell): 17 | 18 | .. code-block:: shell 19 | 20 | export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES 21 | 22 | Thanks to `this StackOverflow answer `_. 23 | 24 | ModuleNotFoundError: No module named 'nitpick.plugins.XXX' 25 | ---------------------------------------------------------- 26 | 27 | When upgrading to new versions, old plugins might be renamed in `setuptools entry points `_. 28 | 29 | But they might still be present in the `entry_points.txt plugin metadata `_ in your virtualenv. 30 | 31 | .. code-block:: 32 | 33 | $ rg nitpick.plugins.setup ~/Library/Caches/pypoetry/ 34 | /Users/john.doe/Library/Caches/pypoetry/virtualenvs/nitpick-UU_pZ5zs-py3.7/lib/python3.7/site-packages/nitpick-0.24.1.dist-info/entry_points.txt 35 | 11:setup_cfg=nitpick.plugins.setup_cfg 36 | 37 | Remove and recreate the virtualenv; this should fix it. 38 | 39 | During development, you can run ``invoke clean --venv install --dry``. 40 | It will display the commands that would be executed; remove ``--dry`` to actually run them. 41 | 42 | :ref:`Read this page on how to install Invoke `. 43 | 44 | Executable ``.tox/lint/bin/pylint`` not found 45 | --------------------------------------------- 46 | 47 | You might get this error while running ``make`` locally. 48 | 49 | 1. Run ``invoke lint`` (or ``tox -e lint`` directly) to create this tox_ environment. 50 | 2. Run ``make`` again. 51 | 52 | Missing ``rev`` key when using the default ``pre-commit`` styles 53 | ---------------------------------------------------------------- 54 | 55 | If you're using the default ``pre-commit`` styles, you might get this error: 56 | 57 | .. code-block:: shell 58 | 59 | An error has occurred: InvalidConfigError: 60 | ==> File .pre-commit-config.yaml 61 | ==> At Config() 62 | ==> At key: repos 63 | ==> At Repository(repo='https://github.com/PyCQA/bandit') 64 | =====> Missing required key: rev 65 | Check the log at /Users/your-name/.cache/pre-commit/pre-commit.log 66 | 67 | This happens because the default styles don't have a ``rev`` key. 68 | Currently, this is not possible because the pre-commit plugin doesn't support it. 69 | 70 | To solve this, you can run ``pre-commit autoupdate`` to update the styles to the latest version, as `recommended in the official docs `_. 71 | 72 | For more details, `check out this comment on the GitHub issue `_. 73 | -------------------------------------------------------------------------------- /mega-linter-plugin-nitpick/nitpick.megalinter-descriptor.yml: -------------------------------------------------------------------------------- 1 | descriptor_id: NITPICK 2 | descriptor_type: tooling_format 3 | descriptor_flavors: 4 | - all_flavors 5 | file_extensions: 6 | - "*" 7 | active_only_if_file_found: 8 | - ".nitpick.toml" 9 | - "pyproject.toml" 10 | linters: 11 | - linter_name: nitpick 12 | linter_url: https://nitpick.readthedocs.io/ 13 | name: NITPICK 14 | install: 15 | dockerfile: 16 | - RUN pip install nitpick==0.38.0 17 | examples: 18 | - "nitpick check" 19 | - "nitpick fix" 20 | cli_help_arg_name: --help 21 | cli_lint_mode: project 22 | cli_lint_errors_count: regex_sum 23 | cli_lint_errors_regex: "Violations:.*([0-9]+)" 24 | cli_lint_extra_args: 25 | - "check" 26 | cli_lint_fix_arg_name: "fix" 27 | cli_lint_fix_remove_args: 28 | - "check" 29 | cli_lint_extra_args_after: 30 | - "--verbose" 31 | -------------------------------------------------------------------------------- /nitpick-style.toml: -------------------------------------------------------------------------------- 1 | # Default style file for nitpick 2 | # https://github.com/andreoliwa/nitpick/blob/v0.38.0/nitpick-style.toml 3 | # Kept here for compatibility, if someone is still accessing the file via GitHub URL. 4 | # This style just includes the built-in preset shipped with Nitpick. 5 | 6 | [nitpick.styles] 7 | include = [ 8 | "py://nitpick/resources/presets/nitpick", 9 | ] 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nitpick", 3 | "version": "0.38.0", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/andreoliwa/nitpick.git" 7 | }, 8 | "release": { 9 | "plugins": [ 10 | "@semantic-release/commit-analyzer", 11 | "@semantic-release/release-notes-generator", 12 | [ 13 | "@semantic-release/changelog", 14 | { 15 | "changelogFile": "CHANGELOG.md" 16 | } 17 | ], 18 | [ 19 | "@semantic-release/exec", 20 | { 21 | "prepareCmd": "bash ./ci-prepare-cmd.sh ${nextRelease.version}", 22 | "publishCmd": "poetry build && poetry publish --username __token__ --password $PYPI_PASSWORD" 23 | } 24 | ], 25 | "@semantic-release/github", 26 | [ 27 | "@semantic-release/git", 28 | { 29 | "assets": [ 30 | ".bumpversion.cfg", 31 | "CHANGELOG.md", 32 | "README.rst", 33 | "docs/conf.py", 34 | "docs/configuration.rst", 35 | "docs/quickstart.rst", 36 | "mega-linter-plugin-nitpick/nitpick.megalinter-descriptor.yml", 37 | "nitpick-style.toml", 38 | "package.json", 39 | "pyproject.toml", 40 | "src/nitpick/__init__.py" 41 | ] 42 | } 43 | ] 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /poetry.toml: -------------------------------------------------------------------------------- 1 | [virtualenvs] 2 | # https://python-poetry.org/docs/configuration/#virtualenvscreate 3 | create = true 4 | in-project = true 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | # https://mypy.readthedocs.io/en/stable/config_file.html 3 | ignore_missing_imports = True 4 | # https://mypy.readthedocs.io/en/stable/running_mypy.html#follow-imports 5 | follow_imports = normal 6 | strict_optional = True 7 | warn_no_return = True 8 | warn_redundant_casts = True 9 | # False positives when running on local machine... it works on pre-commit.ci ¯\_(ツ)_/¯ 10 | warn_unused_ignores = false 11 | exclude = 12 | src/nitpick/compat.py 13 | -------------------------------------------------------------------------------- /src/nitpick/__init__.py: -------------------------------------------------------------------------------- 1 | """Main module.""" 2 | 3 | from loguru import logger 4 | 5 | from nitpick.constants import PROJECT_NAME 6 | from nitpick.core import Nitpick 7 | 8 | __all__ = ("Nitpick",) 9 | __version__ = "0.38.0" 10 | 11 | logger.disable(PROJECT_NAME) 12 | -------------------------------------------------------------------------------- /src/nitpick/__main__.py: -------------------------------------------------------------------------------- 1 | """Entrypoint module, in case you use ``python -mnitpick``. 2 | 3 | Why does this file exist, and why __main__? For more info, read: 4 | 5 | - https://www.python.org/dev/peps/pep-0338/ 6 | - https://docs.python.org/3/using/cmdline.html#cmdoption-m 7 | """ 8 | 9 | from nitpick.cli import nitpick_cli # pragma: no cover 10 | from nitpick.constants import PROJECT_NAME # pragma: no cover 11 | 12 | 13 | def main() -> None: # pragma: no cover 14 | """Entry point for the application script.""" 15 | nitpick_cli(auto_envvar_prefix=PROJECT_NAME) 16 | 17 | 18 | if __name__ == "__main__": # pragma: no cover 19 | main() 20 | -------------------------------------------------------------------------------- /src/nitpick/compat.py: -------------------------------------------------------------------------------- 1 | """Handle import compatibility issues.""" 2 | 3 | # pylint: skip-file 4 | import sys 5 | from importlib.resources import files # type: ignore[attr-defined] 6 | 7 | try: 8 | # Python 3.11+ moved Traversable to importlib.resources.abc 9 | from importlib.resources.abc import Traversable # type: ignore[attr-defined] 10 | except ImportError: 11 | # Python 3.9-3.13 12 | from importlib.abc import Traversable # type: ignore[no-redef] 13 | -------------------------------------------------------------------------------- /src/nitpick/config.py: -------------------------------------------------------------------------------- 1 | """Special configurations.""" 2 | 3 | from attr import Factory, define # type: ignore[attr-defined] 4 | 5 | from nitpick.typedefs import JsonDict 6 | 7 | 8 | @define 9 | class OverridableConfig: # pylint: disable=too-few-public-methods 10 | """Configs formed from defaults from the plugin that can be overridden by the style.""" 11 | 12 | from_plugin: JsonDict = Factory(dict) 13 | from_style: JsonDict = Factory(dict) 14 | value: JsonDict = Factory(dict) 15 | 16 | 17 | @define 18 | class SpecialConfig: # pylint: disable=too-few-public-methods 19 | """Special configurations for plugins.""" 20 | 21 | list_keys: OverridableConfig = Factory(OverridableConfig) 22 | -------------------------------------------------------------------------------- /src/nitpick/exceptions.py: -------------------------------------------------------------------------------- 1 | """Nitpick exceptions.""" 2 | 3 | from __future__ import annotations 4 | 5 | import warnings 6 | from typing import TYPE_CHECKING, Any 7 | 8 | from more_itertools import always_iterable 9 | 10 | from nitpick.constants import PRE_COMMIT_CONFIG_YAML, PROJECT_NAME 11 | 12 | if TYPE_CHECKING: 13 | from nitpick.violations import Fuss 14 | 15 | 16 | class QuitComplainingError(Exception): 17 | """Quit complaining and exit the application.""" 18 | 19 | def __init__(self, violations: Fuss | list[Fuss]) -> None: 20 | super().__init__() 21 | self.violations: list[Fuss] = list(always_iterable(violations)) 22 | 23 | 24 | class Deprecation: 25 | """All deprecation messages in a single class. 26 | 27 | When it's time to break compatibility, remove a method/warning below, 28 | and older config files will trigger validation errors on Nitpick. 29 | """ 30 | 31 | @staticmethod 32 | def pre_commit_without_dash(path_from_root: str) -> bool: 33 | """The pre-commit config should start with a dot on the config file.""" 34 | if path_from_root == PRE_COMMIT_CONFIG_YAML[1:]: 35 | warnings.warn( 36 | f'The section name for dotfiles should start with a dot: [".{path_from_root}"]', 37 | DeprecationWarning, 38 | stacklevel=2, 39 | ) 40 | return True 41 | 42 | return False 43 | 44 | @staticmethod 45 | def jsonfile_section(style_errors: dict[str, Any]) -> bool: 46 | """The [nitpick.JSONFile] is not needed anymore; JSON files are now detected by the extension.""" 47 | has_nitpick_jsonfile_section = style_errors.get(PROJECT_NAME, {}).pop("JSONFile", None) 48 | if has_nitpick_jsonfile_section: 49 | style_errors.pop(PROJECT_NAME) 50 | warnings.warn( 51 | "The [nitpick.JSONFile] section is not needed anymore; just declare your JSON files directly", 52 | DeprecationWarning, 53 | stacklevel=2, 54 | ) 55 | return True 56 | return False 57 | 58 | @staticmethod 59 | def pre_commit_repos_with_yaml_key() -> bool: 60 | """The pre-commit config should not have the "repos.yaml" key anymore; this is the old style. 61 | 62 | Slight breaking change in the TOML config format: ditching the old TOML config. 63 | """ 64 | from nitpick.plugins.yaml import KEY_REPOS, KEY_YAML # pylint: disable=import-outside-toplevel # noqa: PLC0415 65 | 66 | warnings.warn( 67 | f"The {KEY_REPOS}.{KEY_YAML} key is not supported anymore." 68 | " Check the documentation and please update your YAML styles", 69 | DeprecationWarning, 70 | stacklevel=2, 71 | ) 72 | return True 73 | 74 | 75 | def pretty_exception(err: Exception, message: str = ""): 76 | """Return a pretty error message with the full path of the Exception.""" 77 | return f"{message} ({err.__module__}.{err.__class__.__name__}: {err!s})" 78 | -------------------------------------------------------------------------------- /src/nitpick/fields.py: -------------------------------------------------------------------------------- 1 | """Custom Marshmallow fields and validators.""" 2 | 3 | import json 4 | 5 | from marshmallow import ValidationError, fields 6 | from marshmallow.fields import URL, Dict, Field, List, Nested, String 7 | from marshmallow.validate import Length 8 | from more_itertools import always_iterable 9 | 10 | from nitpick.constants import DOT 11 | from nitpick.exceptions import pretty_exception 12 | 13 | __all__ = ("Dict", "Field", "List", "Nested", "String", "URL") # noqa: RUF022 14 | 15 | MAX_PARTS = 2 16 | 17 | 18 | def is_valid_json(json_string: str) -> bool: 19 | """Validate the string as JSON.""" 20 | try: 21 | json.loads(json_string) 22 | except json.JSONDecodeError as err: 23 | raise ValidationError(pretty_exception(err, "Invalid JSON")) from err 24 | return True 25 | 26 | 27 | class TrimmedLength(Length): # pylint: disable=too-few-public-methods 28 | """Trim the string before validating the length.""" 29 | 30 | def __call__(self, value): 31 | """Validate the trimmed string.""" 32 | return super().__call__(value.strip()) 33 | 34 | 35 | class NonEmptyString(fields.String): 36 | """A string field that must not be empty even after trimmed.""" 37 | 38 | def __init__(self, **kwargs) -> None: 39 | validate = list(always_iterable(kwargs.pop("validate", None))) 40 | validate.append(TrimmedLength(min=1)) 41 | super().__init__(validate=validate, **kwargs) 42 | 43 | 44 | class JsonString(fields.String): 45 | """A string field with valid JSON content.""" 46 | 47 | def __init__(self, **kwargs) -> None: 48 | validate = kwargs.pop("validate", []) 49 | validate.append(is_valid_json) 50 | super().__init__(validate=validate, **kwargs) 51 | 52 | 53 | def string_or_list_field(object_dict, parent_object_dict): # pylint: disable=unused-argument # noqa: ARG001 54 | """Detect if the field is a string or a list.""" 55 | if isinstance(object_dict, list): 56 | return fields.List(NonEmptyString(required=True, allow_none=False)) 57 | return NonEmptyString() 58 | 59 | 60 | def validate_section_dot_field(section_field: str) -> bool: 61 | """Validate if the combination section/field has a dot separating them.""" 62 | common = "Use ." 63 | msg = "" 64 | if DOT not in section_field: 65 | msg = f"Dot is missing. {common}" 66 | else: 67 | parts = section_field.split(DOT) 68 | if len(parts) > MAX_PARTS: 69 | msg = f"There's more than one dot. {common}" 70 | elif not parts[0].strip(): 71 | msg = f"Empty section name. {common}" 72 | elif not parts[1].strip(): 73 | msg = f"Empty field name. {common}" 74 | if msg: 75 | raise ValidationError(msg) 76 | return True 77 | 78 | 79 | def boolean_or_dict_field(object_dict, parent_object_dict): # pylint: disable=unused-argument # noqa: ARG001 80 | """Detect if the field is a boolean or a dict.""" 81 | if isinstance(object_dict, dict): 82 | return fields.Dict 83 | return fields.Bool 84 | -------------------------------------------------------------------------------- /src/nitpick/flake8.py: -------------------------------------------------------------------------------- 1 | """Flake8 plugin to check files.""" 2 | 3 | import logging 4 | from collections.abc import Iterator 5 | from functools import lru_cache 6 | from pathlib import Path 7 | 8 | import attr 9 | from flake8.options.manager import OptionManager 10 | from loguru import logger 11 | 12 | from nitpick import __version__ 13 | from nitpick.constants import FLAKE8_PREFIX, PROJECT_NAME, Flake8OptionEnum 14 | from nitpick.core import Nitpick, find_main_python_file 15 | from nitpick.exceptions import QuitComplainingError 16 | from nitpick.typedefs import Flake8Error 17 | from nitpick.violations import Fuss 18 | 19 | 20 | @attr.s(hash=False) 21 | class NitpickFlake8Extension: 22 | """Main class for the flake8 extension.""" 23 | 24 | # Plugin config 25 | name = PROJECT_NAME 26 | version = __version__ 27 | 28 | # Plugin arguments passed by Flake8 29 | tree = attr.ib(default=None) 30 | filename = attr.ib(default="(none)") 31 | 32 | def run(self) -> Iterator[Flake8Error]: 33 | """Run the check plugin.""" 34 | try: 35 | for collected_fuss in self.collect_errors(): 36 | yield self.build_flake8_error(collected_fuss) 37 | except QuitComplainingError as err: 38 | for error_fuss in err.violations: 39 | yield self.build_flake8_error(error_fuss) 40 | 41 | def build_flake8_error(self, obj: Fuss) -> Flake8Error: 42 | """Return a flake8 error from a fuss.""" 43 | prefix = f"File {obj.filename}" if obj.filename else "" 44 | line = f"{FLAKE8_PREFIX}{obj.code:03} {prefix}{obj.message}{obj.colored_suggestion}" 45 | return 0, 0, line, self.__class__ 46 | 47 | def collect_errors(self) -> Iterator[Fuss]: 48 | """Collect all possible Nitpick errors.""" 49 | nit = Nitpick.singleton() 50 | 51 | current_python_file = Path(self.filename) 52 | main_python_file: Path = find_main_python_file(nit.project.root) 53 | if current_python_file.absolute() != main_python_file.absolute(): 54 | # Only report warnings once, for the main Python file of this project. 55 | logger.debug("Ignoring other Python file: {}", self.filename) 56 | return 57 | 58 | logger.debug("Nitpicking file through flake8: {}", self.filename) 59 | yield from nit.run() 60 | return 61 | 62 | @staticmethod 63 | @lru_cache # To avoid calling this function twice in the same process 64 | def add_options(option_manager: OptionManager): 65 | """Add the offline option.""" 66 | option_manager.add_option( 67 | Flake8OptionEnum.OFFLINE.as_flake8_flag(), action="store_true", help=Flake8OptionEnum.OFFLINE.value 68 | ) 69 | 70 | @staticmethod 71 | def parse_options(option_manager: OptionManager, options, args): # pylint: disable=unused-argument # noqa: ARG004 72 | """Create the Nitpick app, set logging from the verbose flags, set offline mode. 73 | 74 | This function is called only once by flake8, so it's a good place to create the app. 75 | """ 76 | log_mapping = {1: logging.INFO, 2: logging.DEBUG} 77 | logging.basicConfig(level=log_mapping.get(options.verbose, logging.WARNING)) 78 | 79 | nit = Nitpick.singleton().init(offline=bool(options.nitpick_offline or Flake8OptionEnum.OFFLINE.get_environ())) 80 | logger.info("Offline mode: {}", nit.offline) 81 | -------------------------------------------------------------------------------- /src/nitpick/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | """Hook specifications used by Nitpick plugins. 2 | 3 | .. note:: 4 | 5 | The hook specifications and the plugin classes are still experimental and considered as an internal API. 6 | They might change at any time; use at your own risk. 7 | """ 8 | 9 | from __future__ import annotations 10 | 11 | from typing import TYPE_CHECKING 12 | 13 | import pluggy 14 | 15 | from nitpick.constants import PROJECT_NAME 16 | 17 | if TYPE_CHECKING: 18 | from nitpick.plugins.base import NitpickPlugin 19 | from nitpick.plugins.info import FileInfo 20 | 21 | hookspec = pluggy.HookspecMarker(PROJECT_NAME) 22 | hookimpl = pluggy.HookimplMarker(PROJECT_NAME) 23 | 24 | __all__ = ("hookimpl", "hookspec") 25 | 26 | 27 | @hookspec 28 | def plugin_class() -> type[NitpickPlugin]: # type: ignore[empty-body] 29 | """Return your plugin class here (it should inherit from :py:class:`nitpick.plugins.base.NitpickPlugin`).""" 30 | 31 | 32 | @hookspec 33 | def can_handle(info: FileInfo) -> type[NitpickPlugin] | None: # pylint: disable=unused-argument 34 | """Return a valid :py:class:`nitpick.plugins.base.NitpickPlugin` instance or ``None``. 35 | 36 | :return: A plugin instance if your plugin handles this file info (path or any of its ``identify`` tags). 37 | Return ``None`` if your plugin doesn't handle this file or file type. 38 | """ 39 | -------------------------------------------------------------------------------- /src/nitpick/plugins/info.py: -------------------------------------------------------------------------------- 1 | """Info needed by the plugins.""" 2 | 3 | from __future__ import annotations 4 | 5 | from dataclasses import dataclass, field 6 | from pathlib import Path 7 | from typing import TYPE_CHECKING 8 | 9 | from identify import identify 10 | 11 | from nitpick.constants import DOT 12 | from nitpick.exceptions import Deprecation 13 | 14 | if TYPE_CHECKING: 15 | from nitpick.core import Project 16 | 17 | 18 | @dataclass 19 | class FileInfo: 20 | """File information needed by the plugin.""" 21 | 22 | project: Project 23 | path_from_root: str 24 | tags: set[str] = field(default_factory=set) 25 | 26 | @classmethod 27 | def create(cls, project: Project, path_from_root: str) -> FileInfo: 28 | """Clean the file name and get its tags.""" 29 | if Deprecation.pre_commit_without_dash(path_from_root): 30 | clean_path = DOT + path_from_root 31 | else: 32 | clean_path = DOT + path_from_root[1:] if path_from_root.startswith("-") else path_from_root 33 | 34 | # When we run identify on the actual file we get better tags 35 | if Path(clean_path).exists(): 36 | tags = set(identify.tags_from_path(clean_path)) 37 | else: 38 | tags = set(identify.tags_from_filename(clean_path)) 39 | 40 | return cls(project, clean_path, tags) 41 | -------------------------------------------------------------------------------- /src/nitpick/plugins/text.py: -------------------------------------------------------------------------------- 1 | """Text files.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING, ClassVar 6 | 7 | from marshmallow import Schema 8 | from marshmallow.orderedset import OrderedSet 9 | 10 | from nitpick import fields 11 | from nitpick.plugins import hookimpl 12 | from nitpick.plugins.base import NitpickPlugin 13 | from nitpick.schemas import help_message 14 | from nitpick.violations import Fuss, ViolationEnum 15 | 16 | if TYPE_CHECKING: 17 | from collections.abc import Iterator 18 | 19 | from nitpick.plugins.info import FileInfo 20 | 21 | TEXT_FILE_RTFD_PAGE = "plugins.html#text-files" 22 | KEY_CONTAINS = "contains" 23 | 24 | 25 | class TextItemSchema(Schema): 26 | """Validation schema for the object inside ``contains``.""" 27 | 28 | error_messages = {"unknown": help_message("Unknown configuration", TEXT_FILE_RTFD_PAGE)} # noqa: RUF012 29 | line = fields.NonEmptyString() 30 | 31 | 32 | class TextSchema(Schema): 33 | """Validation schema for the text file TOML configuration.""" 34 | 35 | error_messages = {"unknown": help_message("Unknown configuration", TEXT_FILE_RTFD_PAGE)} # noqa: RUF012 36 | contains = fields.List(fields.Nested(TextItemSchema)) 37 | 38 | 39 | class Violations(ViolationEnum): 40 | """Violations for this plugin.""" 41 | 42 | MISSING_LINES = (352, " has missing lines:") 43 | 44 | 45 | class TextPlugin(NitpickPlugin): 46 | """Enforce configuration on text files. 47 | 48 | To check if ``some.txt`` file contains the lines ``abc`` and ``def`` (in any order): 49 | 50 | .. code-block:: toml 51 | 52 | [["some.txt".contains]] 53 | line = "abc" 54 | 55 | [["some.txt".contains]] 56 | line = "def" 57 | """ 58 | 59 | identify_tags: ClassVar = {"text"} 60 | validation_schema = TextSchema 61 | 62 | #: All other files are also text files, and they already have a suggested content message 63 | # TODO: refactor: rethink the whole schema validation and remove this attribute 64 | skip_empty_suggestion = True 65 | 66 | violation_base_code = 350 67 | 68 | def _expected_lines(self): 69 | return [obj.get("line") for obj in self.expected_config.get(KEY_CONTAINS, {})] 70 | 71 | @property 72 | def initial_contents(self) -> str: 73 | """Suggest the initial content for this missing file.""" 74 | return "\n".join(self._expected_lines()) 75 | 76 | def enforce_rules(self) -> Iterator[Fuss]: 77 | """Enforce rules for missing lines.""" 78 | expected = OrderedSet(self._expected_lines()) 79 | actual = OrderedSet(self.file_path.read_text().split("\n")) 80 | missing = expected - actual 81 | if missing: 82 | yield self.reporter.make_fuss(Violations.MISSING_LINES, "\n".join(sorted(missing))) 83 | 84 | 85 | @hookimpl 86 | def plugin_class() -> type[NitpickPlugin]: 87 | """Handle text files.""" 88 | return TextPlugin 89 | 90 | 91 | @hookimpl 92 | def can_handle(info: FileInfo) -> type[NitpickPlugin] | None: 93 | """Handle text files.""" 94 | if TextPlugin.identify_tags & info.tags: 95 | return TextPlugin 96 | return None 97 | -------------------------------------------------------------------------------- /src/nitpick/plugins/toml.py: -------------------------------------------------------------------------------- 1 | """TOML files.""" 2 | 3 | from __future__ import annotations 4 | 5 | from itertools import chain 6 | from typing import TYPE_CHECKING, ClassVar, cast 7 | 8 | from tomlkit import dumps, parse 9 | 10 | from nitpick.blender import Comparison, TomlDoc, traverse_toml_tree 11 | from nitpick.plugins import hookimpl 12 | from nitpick.plugins.base import NitpickPlugin 13 | from nitpick.violations import Fuss, SharedViolations, ViolationEnum 14 | 15 | if TYPE_CHECKING: 16 | from collections.abc import Iterator 17 | 18 | from tomlkit.toml_document import TOMLDocument 19 | 20 | from nitpick.plugins.info import FileInfo 21 | 22 | 23 | class TomlPlugin(NitpickPlugin): 24 | """Enforce configurations and autofix TOML files. 25 | 26 | E.g.: `pyproject.toml (PEP 518) `_. 27 | 28 | See also `the [tool.poetry] section of the pyproject.toml file 29 | `_. 30 | 31 | Style example: :gitref:`Python 3.10 version constraint `. 32 | There are :ref:`many other examples here `. 33 | """ 34 | 35 | identify_tags: ClassVar = {"toml"} 36 | violation_base_code = 310 37 | fixable = True 38 | 39 | def enforce_rules(self) -> Iterator[Fuss]: 40 | """Enforce rules for missing key/value pairs in the TOML file.""" 41 | toml_doc = TomlDoc(path=self.file_path) 42 | comparison = Comparison(toml_doc, self.expected_config, self.special_config)() 43 | if not comparison.has_changes: 44 | return 45 | 46 | document = parse(toml_doc.as_string) if self.autofix else None 47 | yield from chain( 48 | self.report(SharedViolations.DIFFERENT_VALUES, document, cast("TomlDoc", comparison.diff)), 49 | self.report( 50 | SharedViolations.MISSING_VALUES, 51 | document, 52 | cast("TomlDoc", comparison.missing), 53 | cast("TomlDoc", comparison.replace), 54 | ), 55 | ) 56 | if self.autofix and self.dirty: 57 | self.file_path.write_text(dumps(document)) 58 | 59 | def report( 60 | self, 61 | violation: ViolationEnum, 62 | document: TOMLDocument | None, 63 | change: TomlDoc | None, 64 | replacement: TomlDoc | None = None, 65 | ): 66 | """Report a violation while optionally modifying the TOML document.""" 67 | if not (change or replacement): 68 | return 69 | if self.autofix: 70 | real_change = cast("TomlDoc", replacement or change) 71 | traverse_toml_tree(document, real_change.as_object) 72 | self.dirty = True 73 | 74 | to_display = cast("TomlDoc", change or replacement) 75 | yield self.reporter.make_fuss(violation, to_display.reformatted.strip(), prefix="", fixed=self.autofix) 76 | 77 | @property 78 | def initial_contents(self) -> str: 79 | """Suggest the initial content for this missing file.""" 80 | return self.write_initial_contents(TomlDoc) 81 | 82 | 83 | @hookimpl 84 | def plugin_class() -> type[NitpickPlugin]: 85 | """Handle TOML files.""" 86 | return TomlPlugin 87 | 88 | 89 | @hookimpl 90 | def can_handle(info: FileInfo) -> type[NitpickPlugin] | None: 91 | """Handle TOML files.""" 92 | if TomlPlugin.identify_tags & info.tags: 93 | return TomlPlugin 94 | return None 95 | -------------------------------------------------------------------------------- /src/nitpick/resources/__init__.py: -------------------------------------------------------------------------------- 1 | """A library of Nitpick styles. 2 | 3 | Building blocks that can be combined and reused. 4 | """ 5 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for any language.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/codeclimate.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "CodeClimate" 3 | url = "https://codeclimate.com/" 4 | 5 | # https://docs.codeclimate.com/docs/maintainability#section-checks 6 | # https://docs.codeclimate.com/docs/advanced-configuration#default-checks 7 | [".codeclimate.yml"] 8 | version = "2" 9 | 10 | [".codeclimate.yml".checks.file-lines.config] 11 | # Pylint's default is also 1000: 12 | # https://pylint.readthedocs.io/en/latest/user_guide/configuration/all-options.html#max-module-lines 13 | threshold = 1000 14 | 15 | [".codeclimate.yml".checks.method-complexity.config] 16 | threshold = 10 # Same as [flake8]max-complexity 17 | 18 | [".codeclimate.yml".plugins.fixme] # https://docs.codeclimate.com/docs/fixme 19 | # https://github.com/codeclimate/codeclimate-fixme 20 | enabled = false 21 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/commitizen.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Commitizen (Python)" 3 | url = "https://github.com/commitizen-tools/commitizen" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/commitizen-tools/commitizen" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "commitizen" 10 | stages = ["commit-msg"] 11 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/commitlint.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "commitlint" 3 | url = "https://github.com/conventional-changelog/commitlint" 4 | 5 | ["package.json".contains_json] 6 | commitlint = """ 7 | { 8 | "extends": [ 9 | "@commitlint/config-conventional" 10 | ] 11 | } 12 | """ 13 | 14 | [[".pre-commit-config.yaml".repos]] 15 | repo = "https://github.com/alessandrojcm/commitlint-pre-commit-hook" 16 | 17 | [[".pre-commit-config.yaml".repos.hooks]] 18 | additional_dependencies = ["@commitlint/config-conventional"] 19 | id = "commitlint" 20 | stages = ["commit-msg"] 21 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/editorconfig.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "EditorConfig" 3 | url = "https://editorconfig.org/" 4 | 5 | [".editorconfig"] 6 | # top-most EditorConfig file 7 | root = true 8 | 9 | [".editorconfig"."*"] 10 | # Unix-style newlines with a newline ending every file 11 | charset = "utf-8" 12 | end_of_line = "lf" 13 | indent_size = 4 14 | indent_style = "space" 15 | insert_final_newline = true 16 | trim_trailing_whitespace = true 17 | 18 | [".editorconfig"."*.{bat,cmd,ps1}"] 19 | end_of_line = "crlf" 20 | 21 | [".editorconfig"."*.{js,json,json5,yml,yaml,md,rb}"] 22 | indent_size = 2 23 | 24 | [".editorconfig".Makefile] 25 | indent_style = "tab" 26 | 27 | [".codeclimate.yml".plugins.editorconfig] # https://docs.codeclimate.com/docs/editorconfig 28 | enabled = true 29 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/git-legal.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Git.legal - CodeClimate Community Edition" 3 | url = "https://github.com/kmewhort/git.legal-codeclimate" 4 | 5 | [".codeclimate.yml".plugins.git-legal] # https://docs.codeclimate.com/docs/git-legal 6 | enabled = true 7 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/pre-commit-hooks.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "pre-commit hooks for any project" 3 | url = "https://github.com/pre-commit/pre-commit-hooks" 4 | 5 | # See https://pre-commit.com/hooks.html for more hooks 6 | 7 | [nitpick.files.present] 8 | ".pre-commit-config.yaml" = "Create the file with the contents below, then run 'pre-commit install'" 9 | 10 | [[".pre-commit-config.yaml".repos]] 11 | repo = "https://github.com/pre-commit/pre-commit-hooks" 12 | 13 | [[".pre-commit-config.yaml".repos.hooks]] 14 | id = "end-of-file-fixer" 15 | 16 | [[".pre-commit-config.yaml".repos.hooks]] 17 | id = "trailing-whitespace" 18 | -------------------------------------------------------------------------------- /src/nitpick/resources/any/prettier.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Prettier" 3 | url = "https://github.com/prettier/prettier" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/pre-commit/mirrors-prettier" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "prettier" 10 | stages = ["pre-commit"] 11 | -------------------------------------------------------------------------------- /src/nitpick/resources/javascript/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for JavaScript.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/javascript/package-json.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "package.json" 3 | url = "https://github.com/yarnpkg/website/blob/master/lang/en/docs/package-json.md" 4 | 5 | ["package.json"] 6 | contains_keys = ["name", "version", "repository.type", "repository.url", "release.plugins"] 7 | -------------------------------------------------------------------------------- /src/nitpick/resources/kotlin/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for Kotlin.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/kotlin/ktlint.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "ktlint" 3 | url = "https://github.com/pinterest/ktlint" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/macisamuele/language-formatters-pre-commit-hooks" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "pretty-format-kotlin" 10 | args = ["--autofix"] 11 | stages = ["commit"] 12 | -------------------------------------------------------------------------------- /src/nitpick/resources/markdown/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for Markdown files.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/markdown/markdownlint.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Markdown lint" 3 | url = "https://github.com/markdownlint/markdownlint" 4 | 5 | [".codeclimate.yml".plugins.markdownlint] # https://docs.codeclimate.com/docs/markdownlint # TODO: style: enable markdownlint after configuring it 6 | enabled = false 7 | -------------------------------------------------------------------------------- /src/nitpick/resources/presets/__init__.py: -------------------------------------------------------------------------------- 1 | """Style presets.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/presets/nitpick.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Default style file for Nitpick" 3 | url = "https://nitpick.rtfd.io/" 4 | 5 | [nitpick] 6 | minimum_version = "0.10.0" 7 | 8 | [nitpick.styles] 9 | include = [ 10 | # Suggest the current stable Python version for projects 11 | "py://nitpick/resources/python/313", 12 | 13 | "py://nitpick/resources/python/absent", 14 | "py://nitpick/resources/python/black", 15 | "py://nitpick/resources/python/pre-commit-hooks", 16 | "py://nitpick/resources/python/mypy", 17 | "py://nitpick/resources/python/poetry", 18 | "py://nitpick/resources/python/pylint", 19 | "py://nitpick/resources/python/readthedocs", 20 | "py://nitpick/resources/python/sonar-python", 21 | "py://nitpick/resources/python/tox", 22 | "py://nitpick/resources/python/github-workflow", 23 | 24 | "py://nitpick/resources/any/prettier", 25 | "py://nitpick/resources/any/codeclimate", 26 | "py://nitpick/resources/any/commitizen", 27 | "py://nitpick/resources/any/editorconfig", 28 | "py://nitpick/resources/any/git-legal", 29 | "py://nitpick/resources/any/pre-commit-hooks", 30 | "py://nitpick/resources/markdown/markdownlint", 31 | 32 | "py://nitpick/resources/shell/bashate", 33 | "py://nitpick/resources/shell/shellcheck", 34 | 35 | "py://nitpick/resources/javascript/package-json", 36 | ] 37 | -------------------------------------------------------------------------------- /src/nitpick/resources/proto/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for Protobuf files.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/proto/protolint.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "protolint (Protobuf linter)" 3 | url = "https://github.com/yoheimuta/protolint" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/yoheimuta/protolint" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "protolint-docker" 10 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/310.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Python 3.10" 3 | 4 | ["pyproject.toml".tool.poetry.dependencies] 5 | python = "^3.10" 6 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/311.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Python 3.11" 3 | 4 | ["pyproject.toml".tool.poetry.dependencies] 5 | python = "^3.11" 6 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/312.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Python 3.12" 3 | 4 | ["pyproject.toml".tool.poetry.dependencies] 5 | python = "^3.12" 6 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/313.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Python 3.13" 3 | 4 | ["pyproject.toml".tool.poetry.dependencies] 5 | python = "^3.13" 6 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/314.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Python 3.14" 3 | 4 | ["pyproject.toml".tool.poetry.dependencies] 5 | python = "^3.14" 6 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for Python.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/absent.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Files that should not exist" 3 | 4 | [nitpick.files.absent] 5 | ".isort.cfg" = "Move values to setup.cfg, section [isort]" 6 | ".pyup.yml" = "Configure safety instead: https://github.com/pyupio/safety#using-safety-with-a-ci-service" 7 | "Pipfile" = "Use pyproject.toml instead" 8 | "Pipfile.lock" = "Use pyproject.toml instead" 9 | "requirements.txt" = "Install poetry, run 'poetry init' to create pyproject.toml, and move dependencies to it" 10 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/autoflake.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "autoflake" 3 | url = "https://github.com/myint/autoflake" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/myint/autoflake" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "autoflake" 10 | args = ["--in-place", "--remove-all-unused-imports", "--remove-unused-variables", "--remove-duplicate-keys", "--ignore-init-module-imports"] 11 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/bandit.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Bandit" 3 | url = "https://github.com/PyCQA/bandit" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/PyCQA/bandit" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "bandit" 10 | args = ["--ini", "setup.cfg"] 11 | exclude = "tests/" 12 | 13 | [".codeclimate.yml".plugins.bandit] # https://docs.codeclimate.com/docs/bandit 14 | # https://github.com/PyCQA/bandit 15 | enabled = true 16 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/black.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Black" 3 | url = "https://github.com/psf/black" 4 | 5 | ["pyproject.toml".tool.black] 6 | line-length = 120 7 | 8 | [[".pre-commit-config.yaml".repos]] 9 | # Mirror that's 2x faster, recommended by 10 | # https://github.com/psf/black/blob/58f31a70efe6509ce8213afac998bc5d5bb7e34d/.pre-commit-hooks.yaml#L1-L2 11 | repo = "https://github.com/psf/black-pre-commit-mirror" 12 | 13 | [[".pre-commit-config.yaml".repos.hooks]] 14 | id = "black" 15 | args = ["--safe", "--quiet"] 16 | 17 | [[".pre-commit-config.yaml".repos]] 18 | repo = "https://github.com/asottile/blacken-docs" 19 | 20 | [[".pre-commit-config.yaml".repos.hooks]] 21 | id = "blacken-docs" 22 | additional_dependencies = ["black==23.7.0"] 23 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/flake8.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Flake8" 3 | url = "https://github.com/PyCQA/flake8" 4 | 5 | ["setup.cfg".flake8] 6 | # http://www.pydocstyle.org/en/2.1.1/error_codes.html 7 | # Ignoring W503: https://github.com/python/black#line-breaks--binary-operators 8 | # Ignoring "D202 No blank lines allowed after function docstring": black inserts a blank line. 9 | ignore = "D107,D202,D203,D401,E203,E402,E501,W503" 10 | max-line-length = 120 11 | inline-quotes = "double" 12 | exclude = ".tox,build" 13 | 14 | # Nitpick recommends those plugins as part of the style, but doesn't install them automatically as before. 15 | # This way, the developer has the choice of overriding this style, instead of having lots of plugins installed 16 | # without being asked. 17 | [[".pre-commit-config.yaml".repos]] 18 | repo = "https://github.com/PyCQA/flake8" 19 | 20 | [[".pre-commit-config.yaml".repos.hooks]] 21 | id = "flake8" 22 | additional_dependencies = ["flake8-blind-except", "flake8-bugbear", "flake8-comprehensions", "flake8-debugger", "flake8-docstrings", "flake8-isort", "flake8-polyfill", "flake8-pytest", "flake8-quotes", "flake8-typing-imports", "yesqa"] 23 | 24 | [".codeclimate.yml".plugins.pep8] # https://docs.codeclimate.com/docs/pep8 PEP8 already being checked by flake8 plugins on pre-commit 25 | enabled = false 26 | 27 | [nitpick.files."setup.cfg"] 28 | comma_separated_values = ["flake8.ignore", "flake8.exclude"] 29 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/github-workflow.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "GitHub Workflow for Python" 3 | url = "https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions" 4 | 5 | [".github/workflows/python.yaml"] 6 | name = "Python" 7 | on = ["push", "pull_request"] 8 | 9 | [".github/workflows/python.yaml".jobs.build.strategy] 10 | fail-fast = false 11 | 12 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 13 | os = ["ubuntu-latest", "windows-latest", "macos-latest"] 14 | python-version = ["3.14", "3.13", "3.12", "3.11", "3.10"] 15 | 16 | [".github/workflows/python.yaml".jobs.build] 17 | name = "${{ matrix.python-version }} ${{ matrix.os }}" 18 | runs-on = "${{ matrix.os }}" 19 | 20 | [".github/workflows/python.yaml".jobs.build.env] 21 | PYTHONUNBUFFERED = 1 22 | 23 | [[".github/workflows/python.yaml".jobs.build.steps]] 24 | name = "Checkout" 25 | uses = "actions/checkout@v5" 26 | 27 | [[".github/workflows/python.yaml".jobs.build.steps]] 28 | name = "Set up Python ${{ matrix.python-version }}" 29 | uses = "actions/setup-python@v6" 30 | 31 | [".github/workflows/python.yaml".jobs.build.steps.with] 32 | python-version = "${{ matrix.python-version }}" 33 | 34 | [[".github/workflows/python.yaml".jobs.build.steps]] 35 | name = "Install tox" 36 | run = "python -m pip install tox" 37 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/ipython.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "IPython" 3 | url = "https://github.com/ipython/ipython" 4 | 5 | ["pyproject.toml".tool.poetry.group.dev.dependencies] 6 | ipython = "*" 7 | ipdb = "*" 8 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/isort.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "isort" 3 | url = "https://github.com/PyCQA/isort" 4 | 5 | ["setup.cfg".isort] 6 | line_length = 120 7 | skip = ".tox,build" 8 | known_first_party = "tests" 9 | 10 | # The configuration below is needed for compatibility with black. 11 | # https://github.com/python/black#how-black-wraps-lines 12 | # https://github.com/PyCQA/isort#multi-line-output-modes 13 | multi_line_output = 3 14 | include_trailing_comma = true 15 | force_grid_wrap = 0 16 | combine_as_imports = true 17 | 18 | [[".pre-commit-config.yaml".repos]] 19 | repo = "https://github.com/PyCQA/isort" 20 | 21 | [[".pre-commit-config.yaml".repos.hooks]] 22 | id = "isort" 23 | 24 | [nitpick.files."setup.cfg"] 25 | comma_separated_values = ["isort.skip", "isort.known_first_party"] 26 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/mypy.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Mypy" 3 | url = "https://github.com/python/mypy" 4 | 5 | # https://mypy.readthedocs.io/en/latest/config_file.html 6 | ["setup.cfg".mypy] 7 | ignore_missing_imports = true 8 | 9 | # https://mypy.readthedocs.io/en/stable/running_mypy.html#follow-imports 10 | follow_imports = "normal" 11 | 12 | # Treat Optional per PEP 484 13 | strict_optional = true 14 | 15 | # Ensure all execution paths are returning 16 | warn_no_return = true 17 | 18 | # Lint-style cleanliness for typing 19 | warn_redundant_casts = true 20 | # False positives when running on local machine... it works on pre-commit.ci ¯\_(ツ)_/¯ 21 | warn_unused_ignores = false 22 | 23 | [[".pre-commit-config.yaml".repos]] 24 | repo = "https://github.com/pre-commit/mirrors-mypy" 25 | 26 | [[".pre-commit-config.yaml".repos.hooks]] 27 | id = "mypy" 28 | args = ["--show-error-codes"] 29 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/poetry-editable.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Poetry (editable projects; PEP 600 support)" 3 | url = "https://github.com/python-poetry/poetry" 4 | 5 | ["pyproject.toml".build-system] 6 | requires = ["poetry-core>=1.0.8"] 7 | build-backend = "poetry.core.masonry.api" 8 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/poetry-venv.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Poetry (virtualenv in project)" 3 | url = "https://github.com/python-poetry/poetry" 4 | 5 | ["poetry.toml"] 6 | # https://python-poetry.org/docs/configuration/#virtualenvscreate 7 | virtualenvs.create = true 8 | virtualenvs.in-project = true 9 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/poetry.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Poetry" 3 | url = "https://github.com/python-poetry/poetry" 4 | 5 | ["pyproject.toml".build-system] 6 | requires = ["poetry-core>=1.0.8"] 7 | build-backend = "poetry.core.masonry.api" 8 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/pre-commit-hooks.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "pre-commit hooks for Python projects" 3 | url = "https://pre-commit.com/hooks" 4 | 5 | [".pre-commit-config.yaml".default_language_version] 6 | # https://pre-commit.com/#top_level-default_language_version 7 | python = "python3.13" 8 | 9 | [[".pre-commit-config.yaml".repos]] 10 | repo = "https://github.com/pre-commit/pygrep-hooks" 11 | 12 | [[".pre-commit-config.yaml".repos.hooks]] 13 | id = "python-check-mock-methods" 14 | 15 | [[".pre-commit-config.yaml".repos.hooks]] 16 | id = "rst-backticks" 17 | 18 | [[".pre-commit-config.yaml".repos]] 19 | repo = "https://github.com/pre-commit/pre-commit-hooks" 20 | 21 | [[".pre-commit-config.yaml".repos.hooks]] 22 | id = "debug-statements" 23 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/pylint.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Pylint" 3 | url = "https://github.com/PyCQA/pylint" 4 | 5 | ["pyproject.toml".tool.poetry.dependencies] 6 | pylint = {version = "*", optional = true} 7 | 8 | ["pyproject.toml".tool.poetry.extras] 9 | lint = ["pylint"] 10 | 11 | # pylint needs to be installed in the same venv as the project, to be more useful 12 | # https://github.com/pre-commit/mirrors-pylint#using-pylint-with-pre-commit 13 | [[".pre-commit-config.yaml".repos]] 14 | repo = "local" 15 | 16 | [[".pre-commit-config.yaml".repos.hooks]] 17 | id = "pylint" 18 | name = "pylint" 19 | language = "system" 20 | exclude = "tests/" 21 | types = ["python"] 22 | 23 | [".pylintrc".MASTER] 24 | # Use multiple processes to speed up Pylint. 25 | jobs = 1 26 | 27 | # https://github.com/samuelcolvin/pydantic/issues/1961#issuecomment-759522422 28 | extension-pkg-whitelist = "pydantic" 29 | 30 | [".pylintrc".REPORTS] 31 | # Set the output format. Available formats are text, parseable, colorized, msvs (visual studio) and html. 32 | # You can also give a reporter class, eg mypackage.mymodule.MyReporterClass. 33 | output-format = "colorized" 34 | 35 | [".pylintrc"."MESSAGES CONTROL"] 36 | # TODO: fix: deal with character separated INI options in https://github.com/andreoliwa/nitpick/issues/271 37 | # The "nitpick.files" section doesn't work out of the box for .pylintrc: 38 | # [nitpick.files.".pylintrc"] 39 | # comma_separated_values = ["MESSAGES CONTROL.disable"] 40 | # This syntax will be deprecated anyway, so I won't make it work now 41 | # Configurations for the black formatter 42 | #disable = "bad-continuation,bad-whitespace,fixme,cyclic-import,line-too-long" 43 | 44 | [".pylintrc".BASIC] 45 | # List of builtins function names that should not be used, separated by a comma 46 | bad-functions = "map,filter" 47 | # Good variable names which should always be accepted, separated by a comma 48 | good-names = "i,j,k,e,ex,Run,_,id,rv,c" 49 | 50 | [".pylintrc".FORMAT] 51 | # Maximum number of characters on a single line. 52 | max-line-length = 120 53 | # Maximum number of lines in a module 54 | max-module-lines = 1000 55 | # TODO: fix: deal with empty options (strings with spaces and quotes); maybe it's a ConfigParser/ConfigUpdater thing 56 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 tab). 57 | #indent-string = " " 58 | # Number of spaces of indent required inside a hanging or continued line. 59 | indent-after-paren = 4 60 | 61 | [".pylintrc".SIMILARITIES] 62 | # Minimum lines number of a similarity. 63 | min-similarity-lines = 4 64 | # Ignore comments when computing similarities. 65 | ignore-comments = "yes" 66 | # Ignore docstrings when computing similarities. 67 | ignore-docstrings = "yes" 68 | # Ignore imports when computing similarities. 69 | ignore-imports = "no" 70 | 71 | [".pylintrc".VARIABLES] 72 | # A regular expression matching the name of dummy variables (i.e. expectedly not used). 73 | dummy-variables-rgx = "_$|dummy" 74 | 75 | [".codeclimate.yml".plugins.pylint] # https://docs.codeclimate.com/docs/pylint Already checked by pre-commit 76 | enabled = false 77 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/radon.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Radon" 3 | url = "https://github.com/rubik/radon" 4 | 5 | [".codeclimate.yml".plugins.radon] # https://docs.codeclimate.com/docs/radon 6 | enabled = true 7 | 8 | [".codeclimate.yml".plugins.radon.config] 9 | # https://radon.readthedocs.io/en/latest/commandline.html#the-cc-command 10 | threshold = "C" 11 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/readthedocs.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Read the Docs" 3 | url = "https://github.com/readthedocs/readthedocs.org" 4 | 5 | # https://docs.readthedocs.io/en/stable/config-file/v2.html 6 | [".readthedocs.yaml"] 7 | version = 2 8 | formats = "all" 9 | 10 | [".readthedocs.yaml".build] 11 | os = "ubuntu-22.04" 12 | 13 | [".readthedocs.yaml".build.tools] 14 | python = "3.11" 15 | 16 | [".readthedocs.yaml".sphinx] 17 | configuration = "docs/conf.py" 18 | 19 | [[".readthedocs.yaml".python.install]] 20 | method = "pip" 21 | path = "." 22 | extra_requirements = ["doc"] 23 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/sonar-python.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "SonarQube Python plugin" 3 | url = "https://github.com/SonarSource/sonar-python" 4 | 5 | [".codeclimate.yml".plugins.sonar-python] # https://docs.codeclimate.com/docs/sonar-python 6 | enabled = true 7 | -------------------------------------------------------------------------------- /src/nitpick/resources/python/tox.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "tox" 3 | url = "https://github.com/tox-dev/tox" 4 | 5 | ["tox.ini".tox] 6 | # https://tox.readthedocs.io/en/latest/config.html 7 | isolated_build = true 8 | 9 | ["tox.ini".testenv] 10 | description = "Run tests with pytest and coverage" 11 | extras = "test" 12 | 13 | ["tox.ini"."coverage:run"] 14 | # https://coverage.readthedocs.io/en/latest/config.html#run 15 | branch = true 16 | parallel = true 17 | source = "src/" 18 | # TODO: fix: deal with multiline INI values in https://github.com/andreoliwa/nitpick/issues/271 19 | #omit = """tests/* 20 | #.tox/* 21 | #*/pypoetry/virtualenvs/* 22 | #""" 23 | # This config is needed by https://github.com/marketplace/actions/coveralls-python#usage 24 | relative_files = true 25 | 26 | ["tox.ini"."coverage:report"] 27 | # https://coverage.readthedocs.io/en/latest/config.html#report 28 | show_missing = true 29 | precision = 2 30 | skip_covered = true 31 | skip_empty = true 32 | sort = "Cover" 33 | -------------------------------------------------------------------------------- /src/nitpick/resources/shell/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for shell scripts.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/shell/bashate.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "bashate (code style for Bash)" 3 | url = "https://github.com/openstack/bashate" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/openstack/bashate" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "bashate" 10 | 11 | # https://docs.openstack.org/bashate/latest/man/bashate.html#options 12 | args = ["-i", "E006"] 13 | -------------------------------------------------------------------------------- /src/nitpick/resources/shell/shellcheck.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "ShellCheck (static analysis for shell scripts)" 3 | url = "https://github.com/koalaman/shellcheck" 4 | 5 | [".codeclimate.yml".plugins.shellcheck] # https://docs.codeclimate.com/docs/shellcheck 6 | # https://github.com/koalaman/shellcheck 7 | enabled = true 8 | 9 | [[".pre-commit-config.yaml".repos]] 10 | # This repo installs the "shellcheck" executable, and this is needed in order to run it on https://pre-commit.ci. 11 | # The previous hook I used (https://github.com/jumanjihouse/pre-commit-hooks) didn't do that, and fails with the error 12 | # "This check needs shellcheck from https://github.com/koalaman/shellcheck" 13 | repo = "https://github.com/shellcheck-py/shellcheck-py" 14 | 15 | [[".pre-commit-config.yaml".repos.hooks]] 16 | id = "shellcheck" 17 | -------------------------------------------------------------------------------- /src/nitpick/resources/shell/shfmt.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "shfmt (shell script formatter)" 3 | url = "https://github.com/mvdan/sh" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/jumanjihouse/pre-commit-hooks" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | # https://github.com/jumanjihouse/pre-commit-hooks#shfmt 10 | id = "shfmt" 11 | -------------------------------------------------------------------------------- /src/nitpick/resources/toml/__init__.py: -------------------------------------------------------------------------------- 1 | """Styles for TOML files.""" 2 | -------------------------------------------------------------------------------- /src/nitpick/resources/toml/toml-sort.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "TOML sort" 3 | url = "https://github.com/pappasam/toml-sort" 4 | 5 | [[".pre-commit-config.yaml".repos]] 6 | repo = "https://github.com/pappasam/toml-sort" 7 | 8 | [[".pre-commit-config.yaml".repos.hooks]] 9 | id = "toml-sort-fix" 10 | 11 | ["pyproject.toml".tool.tomlsort] 12 | all = true 13 | ignore_case = true 14 | in_place = true 15 | trailing_comma_inline_array = true 16 | -------------------------------------------------------------------------------- /src/nitpick/schemas.py: -------------------------------------------------------------------------------- 1 | """Marshmallow schemas.""" 2 | 3 | from __future__ import annotations 4 | 5 | from marshmallow import Schema 6 | from marshmallow_polyfield import PolyField 7 | from sortedcontainers import SortedDict 8 | 9 | from nitpick import fields 10 | from nitpick.blender import flatten_quotes 11 | from nitpick.constants import PYTHON_SETUP_CFG, READ_THE_DOCS_URL 12 | 13 | 14 | def flatten_marshmallow_errors(errors: dict) -> str: 15 | """Flatten Marshmallow errors to a string.""" 16 | formatted = [] 17 | for field, data in SortedDict(flatten_quotes(errors)).items(): 18 | if isinstance(data, (list, tuple)): 19 | messages_per_field = [f"{field}: {', '.join(data)}"] 20 | else: 21 | # This should not happen; if it does, let's just convert to a string 22 | messages_per_field = [f"{field}: {data}"] 23 | formatted.append("\n".join(messages_per_field)) 24 | return "\n".join(formatted) 25 | 26 | 27 | def help_message(sentence: str, help_page: str) -> str: 28 | """Show help with the documentation URL on validation errors.""" 29 | clean_sentence = sentence.strip(" .") 30 | return f"{clean_sentence}. See {READ_THE_DOCS_URL}{help_page}." 31 | 32 | 33 | class BaseNitpickSchema(Schema): 34 | """Base schema for all others, with default error messages.""" 35 | 36 | error_messages = {"unknown": help_message("Unknown configuration", "nitpick_section.html")} # noqa: RUF012 37 | 38 | 39 | class NitpickStylesSectionSchema(BaseNitpickSchema): 40 | """Validation schema for the ``[nitpick.styles]`` section on the style file.""" 41 | 42 | error_messages = { # noqa: RUF012 43 | "unknown": help_message("Unknown configuration", "nitpick_section.html#nitpick-styles") 44 | } 45 | 46 | include = PolyField(deserialization_schema_selector=fields.string_or_list_field) 47 | 48 | 49 | class IniSchema(BaseNitpickSchema): 50 | """Validation schema for INI files.""" 51 | 52 | error_messages = { # noqa: RUF012 53 | "unknown": help_message("Unknown configuration", "nitpick_section.html#comma-separated-values") 54 | } 55 | 56 | comma_separated_values = fields.List(fields.String(validate=fields.validate_section_dot_field)) 57 | 58 | 59 | class NitpickFilesSectionSchema(BaseNitpickSchema): 60 | """Validation schema for the ``[nitpick.files]`` section on the style file.""" 61 | 62 | error_messages = {"unknown": help_message("Unknown file", "nitpick_section.html#nitpick-files")} # noqa: RUF012 63 | 64 | absent = fields.Dict(fields.NonEmptyString, fields.String()) 65 | present = fields.Dict(fields.NonEmptyString, fields.String()) 66 | # TODO: refactor: load this schema dynamically, then add this next field setup_cfg 67 | setup_cfg = fields.Nested(IniSchema, data_key=PYTHON_SETUP_CFG) 68 | 69 | 70 | class NitpickMetaSchema(BaseNitpickSchema): 71 | """Meta info about a specific TOML style file.""" 72 | 73 | name = fields.String() 74 | url = fields.URL() 75 | 76 | 77 | class NitpickSectionSchema(BaseNitpickSchema): 78 | """Validation schema for the ``[nitpick]`` section on the style file.""" 79 | 80 | meta = fields.Nested(NitpickMetaSchema) 81 | minimum_version = fields.NonEmptyString() 82 | styles = fields.Nested(NitpickStylesSectionSchema) 83 | files = fields.Nested(NitpickFilesSectionSchema) 84 | 85 | 86 | class BaseStyleSchema(Schema): 87 | """Base validation schema for style files. 88 | 89 | Dynamic fields will be added to it later. 90 | """ 91 | 92 | error_messages = {"unknown": help_message("Unknown file", "plugins.html")} # noqa: RUF012 93 | 94 | nitpick = fields.Nested(NitpickSectionSchema) 95 | -------------------------------------------------------------------------------- /src/nitpick/typedefs.py: -------------------------------------------------------------------------------- 1 | """Type definitions.""" 2 | 3 | from collections.abc import Iterable 4 | from pathlib import Path 5 | from typing import Any 6 | 7 | from ruamel.yaml.comments import CommentedMap, CommentedSeq 8 | 9 | JsonDict = dict[str, Any] # https://github.com/python/typing/issues/182#issuecomment-185996450 10 | 11 | # keep-sorted start 12 | ElementData = JsonDict | str | int | float | CommentedMap | list[Any] 13 | Flake8Error = tuple[int, int, str, type] 14 | ListOrCommentedSeq = list[Any] | CommentedSeq 15 | PathOrStr = Path | str 16 | StrOrIterable = str | Iterable[str] 17 | StrOrList = str | list[str] 18 | YamlObject = CommentedSeq | CommentedMap 19 | YamlValue = JsonDict | list[Any] | str | float 20 | # keep-sorted end 21 | 22 | # Decorated property not supported · Issue #1362 · python/mypy 23 | # https://github.com/python/mypy/issues/1362#issuecomment-562141376 24 | mypy_property: Any = property 25 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Tests.""" 2 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | """Pytest fixtures. 2 | 3 | Imports from ``nitpick`` have to be here within the fixtures, otherwise they raise an error on tox: 4 | 5 | $ tox -e clean,py38,report 6 | (...) 7 | Coverage.py warning: No data was collected. (no-data-collected) 8 | .tox/py38/lib/python3.8/site-packages/pytest_cov/plugin.py:271: 9 | PytestWarning: Failed to generate report: No data to report. 10 | """ 11 | 12 | import logging 13 | from pathlib import Path 14 | from textwrap import dedent 15 | 16 | import pytest 17 | from _pytest.logging import caplog as _caplog # noqa: F401 18 | from loguru import logger 19 | from responses import RequestsMock 20 | 21 | 22 | @pytest.fixture 23 | def project_default(tmp_path): 24 | """Project with the default Nitpick style.""" 25 | from nitpick.constants import NITPICK_STYLE_TOML # noqa: PLC0415 26 | from tests.helpers import ProjectMock, tomlstring # noqa: PLC0415 27 | 28 | nitpick_style = Path(__file__).parent.parent / NITPICK_STYLE_TOML 29 | return ProjectMock(tmp_path).pyproject_toml( 30 | f""" 31 | [tool.nitpick] 32 | style = {tomlstring(nitpick_style)} 33 | """ 34 | ) 35 | 36 | 37 | @pytest.fixture 38 | def project_remote(request, tmp_path): 39 | """Project with a remote style (loaded from a URL).""" 40 | from tests.helpers import ProjectMock, tomlstring # noqa: PLC0415 41 | 42 | remote_url = "https://example.com/remote-style.toml" 43 | remote_style = """ 44 | ["pyproject.toml".tool.black] 45 | line-length = 100 46 | """ 47 | # https://docs.pytest.org/en/stable/fixture.html#using-markers-to-pass-data-to-fixtures 48 | marker = request.node.get_closest_marker("tool_nitpick") 49 | tool_nitpick = marker.args[0] if marker else "" 50 | 51 | with RequestsMock() as mocked_response: 52 | mocked_response.add(mocked_response.GET, remote_url, dedent(remote_style), status=200) 53 | 54 | project = ProjectMock(tmp_path) 55 | project.pyproject_toml( 56 | f""" 57 | [tool.nitpick] 58 | style = {tomlstring(remote_url)} 59 | {tool_nitpick} 60 | 61 | [tool.black] 62 | line-length = 100 63 | """ 64 | ).remote(mocked_response, remote_url) 65 | yield project 66 | 67 | 68 | @pytest.fixture 69 | def caplog(_caplog): # noqa: F811 70 | """Override the caplog fixture to make pytest work with loguru. 71 | 72 | More info: 73 | https://loguru.readthedocs.io/en/stable/resources/migration.html#making-things-work-with-pytest-and-caplog 74 | """ 75 | 76 | class PropogateHandler(logging.Handler): 77 | def emit(self, record): 78 | logging.getLogger(record.name).handle(record) 79 | 80 | handler_id = logger.add(PropogateHandler(), format="{message} {extra}") 81 | from nitpick import PROJECT_NAME # noqa: PLC0415 82 | 83 | logger.enable(PROJECT_NAME) 84 | yield _caplog 85 | logger.remove(handler_id) 86 | logger.disable(PROJECT_NAME) 87 | -------------------------------------------------------------------------------- /tests/data/hello.py: -------------------------------------------------------------------------------- 1 | """Some empty Python file.""" 2 | 3 | x = 1 4 | print(x) 5 | -------------------------------------------------------------------------------- /tests/data/pre-commit-config-with-old-repos-yaml-key.toml: -------------------------------------------------------------------------------- 1 | [[".pre-commit-config.yaml".repos]] 2 | yaml = """ 3 | - repo: https://github.com/user/repo 4 | rev: 1.2.3 5 | hooks: 6 | - id: my-hook 7 | args: [--expected, arguments] 8 | """ 9 | -------------------------------------------------------------------------------- /tests/data/typed-style-dir/any/editorconfig.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "EditorConfig" 3 | url = "https://editorconfig.org/" 4 | 5 | [".editorconfig"] 6 | # top-most EditorConfig file 7 | root = true 8 | 9 | [".editorconfig"."*"] 10 | # Unix-style newlines with a newline ending every file 11 | end_of_line = "lf" 12 | insert_final_newline = true 13 | indent_style = "space" 14 | indent_size = 4 15 | trim_trailing_whitespace = true 16 | -------------------------------------------------------------------------------- /tests/data/typed-style-dir/markdown/markdownlint.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Markdown lint" 3 | url = "https://github.com/markdownlint/markdownlint" 4 | 5 | [".codeclimate.yml".plugins.markdownlint] # https://docs.codeclimate.com/docs/markdownlint # TODO: style: enable markdownlint after configuring it 6 | enabled = false 7 | -------------------------------------------------------------------------------- /tests/data/typed-style-dir/python/black.toml: -------------------------------------------------------------------------------- 1 | [nitpick.meta] 2 | name = "Black" 3 | url = "https://github.com/psf/black" 4 | 5 | ["pyproject.toml".tool.black] 6 | line-length = 120 7 | -------------------------------------------------------------------------------- /tests/resources/__init__.py: -------------------------------------------------------------------------------- 1 | """To test ``PythonPackageURL``.""" 2 | -------------------------------------------------------------------------------- /tests/resources/empty-style.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreoliwa/nitpick/186571b1e06c5f386d0c6b59cebdfa8711cc2560/tests/resources/empty-style.toml -------------------------------------------------------------------------------- /tests/resources/nested_package/__init__.py: -------------------------------------------------------------------------------- 1 | """To test ``PythonPackageURL``.""" 2 | -------------------------------------------------------------------------------- /tests/resources/nested_package/empty_style.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreoliwa/nitpick/186571b1e06c5f386d0c6b59cebdfa8711cc2560/tests/resources/nested_package/empty_style.toml -------------------------------------------------------------------------------- /tests/test_builtin/any/codeclimate/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | checks: 3 | file-lines: 4 | config: 5 | threshold: 1000 6 | method-complexity: 7 | config: 8 | threshold: 10 9 | plugins: 10 | fixme: 11 | enabled: false 12 | -------------------------------------------------------------------------------- /tests/test_builtin/any/commitizen/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/commitizen-tools/commitizen 3 | hooks: 4 | - id: commitizen 5 | stages: 6 | - commit-msg 7 | -------------------------------------------------------------------------------- /tests/test_builtin/any/commitlint/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook 3 | hooks: 4 | - additional_dependencies: 5 | - '@commitlint/config-conventional' 6 | id: commitlint 7 | stages: 8 | - commit-msg 9 | -------------------------------------------------------------------------------- /tests/test_builtin/any/commitlint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "commitlint": { 3 | "extends": [ 4 | "@commitlint/config-conventional" 5 | ] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/test_builtin/any/editorconfig/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | editorconfig: 3 | enabled: true 4 | -------------------------------------------------------------------------------- /tests/test_builtin/any/editorconfig/.editorconfig: -------------------------------------------------------------------------------- 1 | root = True 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = True 9 | trim_trailing_whitespace = True 10 | 11 | [*.{bat,cmd,ps1}] 12 | end_of_line = crlf 13 | 14 | [*.{js,json,json5,yml,yaml,md,rb}] 15 | indent_size = 2 16 | 17 | [Makefile] 18 | indent_style = tab 19 | -------------------------------------------------------------------------------- /tests/test_builtin/any/git-legal/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | git-legal: 3 | enabled: true 4 | -------------------------------------------------------------------------------- /tests/test_builtin/any/pre-commit-hooks/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | hooks: 4 | - id: end-of-file-fixer 5 | - id: trailing-whitespace 6 | -------------------------------------------------------------------------------- /tests/test_builtin/any/prettier/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/mirrors-prettier 3 | hooks: 4 | - id: prettier 5 | stages: 6 | - pre-commit 7 | -------------------------------------------------------------------------------- /tests/test_builtin/javascript/package-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "release": { 4 | "plugins": "" 5 | }, 6 | "repository": { 7 | "type": "", 8 | "url": "" 9 | }, 10 | "version": "" 11 | } 12 | -------------------------------------------------------------------------------- /tests/test_builtin/kotlin/ktlint/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks 3 | hooks: 4 | - id: pretty-format-kotlin 5 | args: 6 | - --autofix 7 | stages: 8 | - commit 9 | -------------------------------------------------------------------------------- /tests/test_builtin/markdown/markdownlint/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | markdownlint: 3 | enabled: false 4 | -------------------------------------------------------------------------------- /tests/test_builtin/preset/nitpick/.editorconfig: -------------------------------------------------------------------------------- 1 | ../../any/editorconfig/.editorconfig -------------------------------------------------------------------------------- /tests/test_builtin/preset/nitpick/.pylintrc: -------------------------------------------------------------------------------- 1 | ../../python/pylint/.pylintrc -------------------------------------------------------------------------------- /tests/test_builtin/preset/nitpick/setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | ignore_missing_imports = True 3 | follow_imports = normal 4 | strict_optional = True 5 | warn_no_return = True 6 | warn_redundant_casts = True 7 | warn_unused_ignores = False 8 | -------------------------------------------------------------------------------- /tests/test_builtin/preset/nitpick/tox.ini: -------------------------------------------------------------------------------- 1 | ../../python/tox/tox.ini -------------------------------------------------------------------------------- /tests/test_builtin/proto/protolint/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/yoheimuta/protolint 3 | hooks: 4 | - id: protolint-docker 5 | -------------------------------------------------------------------------------- /tests/test_builtin/python/310/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.dependencies] 2 | python = "^3.10" 3 | -------------------------------------------------------------------------------- /tests/test_builtin/python/311/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.dependencies] 2 | python = "^3.11" 3 | -------------------------------------------------------------------------------- /tests/test_builtin/python/312/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.dependencies] 2 | python = "^3.12" 3 | -------------------------------------------------------------------------------- /tests/test_builtin/python/313/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.dependencies] 2 | python = "^3.13" 3 | -------------------------------------------------------------------------------- /tests/test_builtin/python/314/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.dependencies] 2 | python = "^3.14" 3 | -------------------------------------------------------------------------------- /tests/test_builtin/python/autoflake/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/myint/autoflake 3 | hooks: 4 | - id: autoflake 5 | args: 6 | - --in-place 7 | - --remove-all-unused-imports 8 | - --remove-unused-variables 9 | - --remove-duplicate-keys 10 | - --ignore-init-module-imports 11 | -------------------------------------------------------------------------------- /tests/test_builtin/python/bandit/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | bandit: 3 | enabled: true 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/bandit/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/PyCQA/bandit 3 | hooks: 4 | - id: bandit 5 | args: 6 | - --ini 7 | - setup.cfg 8 | exclude: tests/ 9 | -------------------------------------------------------------------------------- /tests/test_builtin/python/black/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/psf/black-pre-commit-mirror 3 | hooks: 4 | - id: black 5 | args: 6 | - --safe 7 | - --quiet 8 | - repo: https://github.com/asottile/blacken-docs 9 | hooks: 10 | - id: blacken-docs 11 | additional_dependencies: 12 | - black==23.7.0 13 | -------------------------------------------------------------------------------- /tests/test_builtin/python/black/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 120 3 | -------------------------------------------------------------------------------- /tests/test_builtin/python/flake8/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | pep8: 3 | enabled: false 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/flake8/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/PyCQA/flake8 3 | hooks: 4 | - id: flake8 5 | additional_dependencies: 6 | - flake8-blind-except 7 | - flake8-bugbear 8 | - flake8-comprehensions 9 | - flake8-debugger 10 | - flake8-docstrings 11 | - flake8-isort 12 | - flake8-polyfill 13 | - flake8-pytest 14 | - flake8-quotes 15 | - flake8-typing-imports 16 | - yesqa 17 | -------------------------------------------------------------------------------- /tests/test_builtin/python/flake8/setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = D107,D202,D203,D401,E203,E402,E501,W503 3 | max-line-length = 120 4 | inline-quotes = double 5 | exclude = .tox,build 6 | -------------------------------------------------------------------------------- /tests/test_builtin/python/github-workflow/.github/workflows/python.yaml: -------------------------------------------------------------------------------- 1 | name: Python 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | os: 11 | - ubuntu-latest 12 | - windows-latest 13 | - macos-latest 14 | python-version: 15 | - '3.14' 16 | - '3.13' 17 | - '3.12' 18 | - '3.11' 19 | - '3.10' 20 | name: ${{ matrix.python-version }} ${{ matrix.os }} 21 | runs-on: ${{ matrix.os }} 22 | env: 23 | PYTHONUNBUFFERED: 1 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v5 27 | - name: Set up Python ${{ matrix.python-version }} 28 | uses: actions/setup-python@v6 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | - name: Install tox 32 | run: python -m pip install tox 33 | -------------------------------------------------------------------------------- /tests/test_builtin/python/ipython/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.group.dev.dependencies] 2 | ipython = "*" 3 | ipdb = "*" 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/isort/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/PyCQA/isort 3 | hooks: 4 | - id: isort 5 | -------------------------------------------------------------------------------- /tests/test_builtin/python/isort/setup.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | line_length = 120 3 | skip = .tox,build 4 | known_first_party = tests 5 | multi_line_output = 3 6 | include_trailing_comma = True 7 | force_grid_wrap = 0 8 | combine_as_imports = True 9 | -------------------------------------------------------------------------------- /tests/test_builtin/python/mypy/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/mirrors-mypy 3 | hooks: 4 | - id: mypy 5 | args: 6 | - --show-error-codes 7 | -------------------------------------------------------------------------------- /tests/test_builtin/python/mypy/setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | ignore_missing_imports = True 3 | follow_imports = normal 4 | strict_optional = True 5 | warn_no_return = True 6 | warn_redundant_casts = True 7 | warn_unused_ignores = False 8 | -------------------------------------------------------------------------------- /tests/test_builtin/python/poetry-editable/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ "poetry-core>=1.0.8",] 3 | build-backend = "poetry.core.masonry.api" 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/poetry-venv/poetry.toml: -------------------------------------------------------------------------------- 1 | [virtualenvs] 2 | create = true 3 | in-project = true 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/poetry/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ "poetry-core>=1.0.8",] 3 | build-backend = "poetry.core.masonry.api" 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/pre-commit-hooks/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_language_version: 2 | python: python3.13 3 | repos: 4 | - repo: https://github.com/pre-commit/pygrep-hooks 5 | hooks: 6 | - id: python-check-mock-methods 7 | - id: rst-backticks 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | hooks: 10 | - id: debug-statements 11 | -------------------------------------------------------------------------------- /tests/test_builtin/python/pylint/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | pylint: 3 | enabled: false 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/pylint/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: pylint 5 | name: pylint 6 | language: system 7 | exclude: tests/ 8 | types: 9 | - python 10 | -------------------------------------------------------------------------------- /tests/test_builtin/python/pylint/.pylintrc: -------------------------------------------------------------------------------- 1 | [BASIC] 2 | bad-functions = map,filter 3 | good-names = i,j,k,e,ex,Run,_,id,rv,c 4 | 5 | [FORMAT] 6 | max-line-length = 120 7 | max-module-lines = 1000 8 | indent-after-paren = 4 9 | 10 | [MASTER] 11 | jobs = 1 12 | extension-pkg-whitelist = pydantic 13 | 14 | [REPORTS] 15 | output-format = colorized 16 | 17 | [SIMILARITIES] 18 | min-similarity-lines = 4 19 | ignore-comments = yes 20 | ignore-docstrings = yes 21 | ignore-imports = no 22 | 23 | [VARIABLES] 24 | dummy-variables-rgx = _$|dummy 25 | -------------------------------------------------------------------------------- /tests/test_builtin/python/pylint/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry.extras] 2 | lint = [ "pylint",] 3 | 4 | [tool.poetry.dependencies.pylint] 5 | version = "*" 6 | optional = true 7 | -------------------------------------------------------------------------------- /tests/test_builtin/python/radon/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | radon: 3 | enabled: true 4 | config: 5 | threshold: C 6 | -------------------------------------------------------------------------------- /tests/test_builtin/python/readthedocs/.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | formats: all 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: '3.11' 7 | sphinx: 8 | configuration: docs/conf.py 9 | python: 10 | install: 11 | - method: pip 12 | path: . 13 | extra_requirements: 14 | - doc 15 | -------------------------------------------------------------------------------- /tests/test_builtin/python/sonar-python/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | sonar-python: 3 | enabled: true 4 | -------------------------------------------------------------------------------- /tests/test_builtin/python/tox/tox.ini: -------------------------------------------------------------------------------- 1 | [coverage:report] 2 | show_missing = True 3 | precision = 2 4 | skip_covered = True 5 | skip_empty = True 6 | sort = Cover 7 | 8 | [coverage:run] 9 | branch = True 10 | parallel = True 11 | source = src/ 12 | relative_files = True 13 | 14 | [testenv] 15 | description = Run tests with pytest and coverage 16 | extras = test 17 | 18 | [tox] 19 | isolated_build = True 20 | -------------------------------------------------------------------------------- /tests/test_builtin/real.toml: -------------------------------------------------------------------------------- 1 | [nitpick] 2 | minimum_version = "0.10.0" 3 | 4 | [nitpick.styles] 5 | include = [ 6 | # Suggest the current stable Python version for projects 7 | "py://nitpick/resources/python/310", 8 | 9 | "py://nitpick/resources/python/absent", 10 | "py://nitpick/resources/python/bandit", 11 | "py://nitpick/resources/python/black", 12 | "py://nitpick/resources/python/flake8", 13 | "py://nitpick/resources/python/pre-commit-hooks", 14 | "py://nitpick/resources/python/isort", 15 | "py://nitpick/resources/python/mypy", 16 | "py://nitpick/resources/python/poetry", 17 | "py://nitpick/resources/python/pylint", 18 | "py://nitpick/resources/python/radon", 19 | "py://nitpick/resources/python/readthedocs", 20 | "py://nitpick/resources/python/sonar-python", 21 | "py://nitpick/resources/python/tox", 22 | "py://nitpick/resources/python/github-workflow", 23 | "py://nitpick/resources/python/autoflake", 24 | 25 | "py://nitpick/resources/any/prettier", 26 | "py://nitpick/resources/any/codeclimate", 27 | "py://nitpick/resources/any/commitizen", 28 | "py://nitpick/resources/any/editorconfig", 29 | "py://nitpick/resources/any/git-legal", 30 | "py://nitpick/resources/any/pre-commit-hooks", 31 | "py://nitpick/resources/markdown/markdownlint", 32 | 33 | "py://nitpick/resources/shell/bashate", 34 | "py://nitpick/resources/shell/shellcheck", 35 | 36 | "py://nitpick/resources/javascript/package-json", 37 | ] 38 | 39 | [nitpick.files."setup.cfg"] 40 | comma_separated_values = ["flake8.ignore", "flake8.exclude", "isort.skip", "isort.known_first_party"] 41 | -------------------------------------------------------------------------------- /tests/test_builtin/shell/bashate/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/openstack/bashate 3 | hooks: 4 | - id: bashate 5 | args: 6 | - -i 7 | - E006 8 | -------------------------------------------------------------------------------- /tests/test_builtin/shell/shellcheck/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | shellcheck: 3 | enabled: true 4 | -------------------------------------------------------------------------------- /tests/test_builtin/shell/shellcheck/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/shellcheck-py/shellcheck-py 3 | hooks: 4 | - id: shellcheck 5 | -------------------------------------------------------------------------------- /tests/test_builtin/shell/shfmt/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/jumanjihouse/pre-commit-hooks 3 | hooks: 4 | - id: shfmt 5 | -------------------------------------------------------------------------------- /tests/test_builtin/toml/toml-sort/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pappasam/toml-sort 3 | hooks: 4 | - id: toml-sort-fix 5 | -------------------------------------------------------------------------------- /tests/test_builtin/toml/toml-sort/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.tomlsort] 2 | all = true 3 | ignore_case = true 4 | in_place = true 5 | trailing_comma_inline_array = true 6 | -------------------------------------------------------------------------------- /tests/test_ini/2-actual-editorconfig.ini: -------------------------------------------------------------------------------- 1 | # Comments should be kept 2 | root = false 3 | some_other = "value without a section" 4 | 5 | [*] 6 | ; Another comment that should be kept 7 | end_of_line = cr 8 | insert_final_newline = false 9 | indent_style = space 10 | tab_width = 2 11 | indent_size = tab 12 | 13 | [*.{js,json}] 14 | charset = utf-8 15 | -------------------------------------------------------------------------------- /tests/test_ini/2-expected-editorconfig.ini: -------------------------------------------------------------------------------- 1 | # Comments should be kept 2 | root = true 3 | some_other = "value without a section" 4 | missing = value 5 | another_missing = 100 6 | 7 | [*] 8 | ; Another comment that should be kept 9 | end_of_line = lf 10 | insert_final_newline = true 11 | indent_style = space 12 | tab_width = 4 13 | indent_size = tab 14 | 15 | [*.{js,json}] 16 | charset = utf-8 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /tests/test_ini/2-style.toml: -------------------------------------------------------------------------------- 1 | [".editorconfig"] 2 | root = true 3 | missing = "value" 4 | another_missing = 100 5 | 6 | [".editorconfig"."*"] 7 | end_of_line = "lf" 8 | insert_final_newline = true 9 | tab_width = 4 10 | 11 | [".editorconfig"."*.{js,json}"] 12 | charset = "utf-8" 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /tests/test_ini/3-actual-setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = 3 | # Trash and cache: 4 | .git 5 | __pycache__ 6 | .venv 7 | .eggs 8 | *.egg 9 | temp 10 | # Bad code that I write to test things: 11 | ex.py 12 | another = 13 | A valid line 14 | ; Now a comment with semicolon 15 | Another valid line 16 | -------------------------------------------------------------------------------- /tests/test_ini/3-expected-setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = 3 | # Trash and cache: 4 | .git 5 | __pycache__ 6 | .venv 7 | .eggs 8 | *.egg 9 | temp 10 | # Bad code that I write to test things: 11 | ex.py 12 | another = 13 | A valid line 14 | ; Now a comment with semicolon 15 | Another valid line 16 | new = value 17 | -------------------------------------------------------------------------------- /tests/test_json/1-expected-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "commitlint": { 3 | "extends": [ 4 | "@commitlint/config-conventional" 5 | ] 6 | }, 7 | "name": "", 8 | "release": { 9 | "plugins": "" 10 | }, 11 | "repository": { 12 | "type": "", 13 | "url": "" 14 | }, 15 | "version": "" 16 | } 17 | -------------------------------------------------------------------------------- /tests/test_json/2-actual-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myproject", 3 | "version": "0.0.1", 4 | "something": "else", 5 | "commitlint": { 6 | "extends": ["wrong-plugin-should-be-replaced", "another-wrong-plugin"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/test_json/2-expected-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "commitlint": { 3 | "extends": [ 4 | "@commitlint/config-conventional" 5 | ] 6 | }, 7 | "name": "myproject", 8 | "release": { 9 | "plugins": "" 10 | }, 11 | "repository": { 12 | "type": "", 13 | "url": "" 14 | }, 15 | "something": "else", 16 | "version": "0.0.1" 17 | } 18 | -------------------------------------------------------------------------------- /tests/test_json/3-expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatting": { 3 | "doesnt": "matter", 4 | "here": true, 5 | "on.the": "config file" 6 | }, 7 | "name": "myproject", 8 | "some.dotted.root.key": { 9 | "content": [ 10 | "should", 11 | "be", 12 | "here" 13 | ], 14 | "dotted.subkeys": [ 15 | "should be preserved", 16 | { 17 | "complex.weird.sub": { 18 | "objects": true 19 | }, 20 | "even.with": 1 21 | } 22 | ], 23 | "valid": "JSON" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/test_json/3-style.toml: -------------------------------------------------------------------------------- 1 | ["my.json".contains_json] 2 | "some.dotted.root.key" = """ 3 | { "valid": "JSON", "content": ["should", "be", "here"] , "dotted.subkeys" : ["should be preserved", 4 | {"even.with": 1, "complex.weird.sub":{"objects":true}}] } 5 | """ 6 | formatting = """ {"doesnt":"matter","here":true,"on.the": "config file"} """ 7 | -------------------------------------------------------------------------------- /tests/test_json/4-style.toml: -------------------------------------------------------------------------------- 1 | ["another.json".contains_json] 2 | some_field = """ 3 | { "this": "is missing the end... 4 | """ 5 | 6 | ["another.json".with] 7 | extra = "key" 8 | -------------------------------------------------------------------------------- /tests/test_json/package-json-style.toml: -------------------------------------------------------------------------------- 1 | ["package.json"] 2 | contains_keys = ["name", "version", "repository.type", "repository.url", "release.plugins"] 3 | 4 | ["package.json".contains_json] 5 | commitlint = """ 6 | { "extends": [ "@commitlint/config-conventional" ] } 7 | """ 8 | -------------------------------------------------------------------------------- /tests/test_meta.py: -------------------------------------------------------------------------------- 1 | """Meta tests for sanity check purposes.""" 2 | 3 | import json 4 | from configparser import ConfigParser 5 | from pathlib import Path 6 | 7 | from testfixtures import compare 8 | 9 | from nitpick.constants import JAVASCRIPT_PACKAGE_JSON 10 | 11 | REPO_ROOT = Path(__file__).parent.parent 12 | 13 | 14 | def test_bumpversion_files_match_package_json(): 15 | """Files changed by bumpversion should be present in package.json Git assets. 16 | 17 | So they are committed when a new release is created. 18 | """ 19 | bumpversion_cfg = ConfigParser() 20 | bumpversion_cfg.read(REPO_ROOT / ".bumpversion.cfg") 21 | bumpversion_files = {section.split(":")[2] for section in bumpversion_cfg.sections() if ":file:" in section} 22 | 23 | package_json = Path(REPO_ROOT / JAVASCRIPT_PACKAGE_JSON) 24 | package_json_dict = json.loads(package_json.read_text()) 25 | package_json_git_files = set( 26 | next( 27 | obj[1]["assets"] 28 | for obj in package_json_dict["release"]["plugins"] 29 | if isinstance(obj, list) and "/git" in obj[0] 30 | ) 31 | ) 32 | 33 | package_json_git_files.remove(".bumpversion.cfg") 34 | package_json_git_files.remove("CHANGELOG.md") 35 | compare(bumpversion_files, package_json_git_files) 36 | -------------------------------------------------------------------------------- /tests/test_text.py: -------------------------------------------------------------------------------- 1 | """Text file tests.""" 2 | 3 | from nitpick.constants import READ_THE_DOCS_URL 4 | from nitpick.violations import Fuss 5 | from tests.helpers import NBSP, SUGGESTION_BEGIN, SUGGESTION_END, ProjectMock 6 | 7 | 8 | def test_suggest_initial_contents(tmp_path): 9 | """Suggest initial contents for a text file.""" 10 | ProjectMock(tmp_path).style( 11 | """ 12 | [["requirements.txt".contains]] 13 | # File contains this exact line anywhere 14 | line = "sphinx>=1.3.0" 15 | 16 | [["requirements.txt".contains]] 17 | line = "some-package==1.0.0" 18 | """ 19 | ).api_check_then_fix( 20 | Fuss( 21 | False, 22 | "requirements.txt", 23 | 351, 24 | " was not found. Create it with this content:", 25 | """ 26 | sphinx>=1.3.0 27 | some-package==1.0.0 28 | """, 29 | ) 30 | ) 31 | 32 | 33 | def test_text_configuration(tmp_path): 34 | """Test configuration for text files.""" 35 | # pylint: disable=line-too-long 36 | ProjectMock(tmp_path).style( 37 | """ 38 | [["abc.txt".contains]] 39 | invalid = "key" 40 | line = ["it", "should", "be", "a", "string"] 41 | 42 | ["def.txt".contains] 43 | should_be = "inside an array" 44 | 45 | ["ghi.txt".whatever] 46 | wrong = "everything" 47 | """ 48 | ).flake8().assert_errors_contain( 49 | f""" 50 | NIP001 File nitpick-style.toml has an incorrect style. Invalid config:{SUGGESTION_BEGIN} 51 | "abc.txt".contains.0.invalid: Unknown configuration. See {READ_THE_DOCS_URL}plugins.html#text-files. 52 | "abc.txt".contains.0.line: Not a valid string. 53 | "def.txt".contains: Not a valid list. 54 | "ghi.txt".whatever: Unknown configuration. See {READ_THE_DOCS_URL}plugins.html#text-files.{SUGGESTION_END} 55 | """, 56 | 1, 57 | ) 58 | 59 | 60 | def test_text_file_contains_line(tmp_path): 61 | """Test if the text file contains a line.""" 62 | ProjectMock(tmp_path).style( 63 | """ 64 | [["my.txt".contains]] 65 | line = "qqq" 66 | [["my.txt".contains]] 67 | line = "abc" 68 | [["my.txt".contains]] 69 | line = "www" 70 | """ 71 | ).save_file("my.txt", "def\nghi\nwww").api_check_then_fix( 72 | Fuss( 73 | False, 74 | "my.txt", 75 | 352, 76 | " has missing lines:", 77 | """ 78 | abc 79 | qqq 80 | """, 81 | ) 82 | ) 83 | 84 | 85 | def test_yaml_file_as_text(tmp_path): 86 | """A YAML file is also a text file, so it could be checked with the text plugin.""" 87 | ProjectMock(tmp_path).style( 88 | """ 89 | [[".gitlab-ci.yml".contains]] 90 | line = " - mypy -p ims --junit-xml report-mypy.xml" 91 | """ 92 | ).save_file(".gitlab-ci.yml", "def\nghi\nwww").api_check_then_fix( 93 | Fuss( 94 | False, ".gitlab-ci.yml", 352, " has missing lines:", f"{NBSP * 4}- mypy -p ims --junit-xml report-mypy.xml" 95 | ) 96 | ) 97 | -------------------------------------------------------------------------------- /tests/test_violations.py: -------------------------------------------------------------------------------- 1 | """Violations.""" 2 | 3 | from textwrap import dedent 4 | 5 | import pytest 6 | from marshmallow import ValidationError 7 | from testfixtures import compare 8 | 9 | from nitpick.constants import EmojiEnum 10 | from nitpick.schemas import flatten_marshmallow_errors 11 | from nitpick.violations import Fuss, Reporter 12 | from tests.helpers import SUGGESTION_BEGIN, SUGGESTION_END 13 | 14 | 15 | @pytest.mark.parametrize("fixed", [False, True]) 16 | def test_fuss_pretty(fixed): 17 | """Test Fuss' pretty formatting.""" 18 | examples = [ 19 | (Fuss(fixed, "abc.txt", 2, "message"), "abc.txt:1: NIP002 message"), 20 | (Fuss(fixed, "abc.txt", 2, "message", "", 15), "abc.txt:15: NIP002 message"), 21 | ( 22 | Fuss(fixed, "abc.txt", 1, "message", "\tsuggestion\n\t "), 23 | f"abc.txt:1: NIP001 message{SUGGESTION_BEGIN}\n\tsuggestion{SUGGESTION_END}", 24 | ), 25 | (Fuss(fixed, " ", 3, "no filename"), "NIP003 no filename"), 26 | ] 27 | for fuss, expected in examples: 28 | compare(actual=fuss.pretty, expected=dedent(expected)) 29 | 30 | 31 | def test_reporter(): 32 | """Test error reporter.""" 33 | reporter = Reporter() 34 | reporter.reset() 35 | assert reporter.manual == 0 36 | assert reporter.fixed == 0 37 | assert reporter.get_counts() == f"No violations found. {EmojiEnum.STAR_CAKE.value}" 38 | 39 | reporter.increment() 40 | assert reporter.manual == 1 41 | assert reporter.fixed == 0 42 | assert reporter.get_counts() == f"Violations: {EmojiEnum.X_RED_CROSS.value} 1 to fix manually." 43 | 44 | reporter.increment(True) 45 | assert reporter.manual == 1 46 | assert reporter.fixed == 1 47 | assert ( 48 | reporter.get_counts() 49 | == f"Violations: {EmojiEnum.GREEN_CHECK.value} 1 fixed, {EmojiEnum.X_RED_CROSS.value} 1 to fix manually." 50 | ) 51 | 52 | reporter.reset() 53 | assert reporter.manual == 0 54 | assert reporter.fixed == 0 55 | 56 | reporter.increment(True) 57 | assert reporter.manual == 0 58 | assert reporter.fixed == 1 59 | assert reporter.get_counts() == f"Violations: {EmojiEnum.GREEN_CHECK.value} 1 fixed." 60 | 61 | 62 | def test_flatten_marshmallow_errors(): 63 | """Flatten Marshmallow errors.""" 64 | examples = [ 65 | ({"list": ["multi", "part", "message"]}, "list: multi, part, message"), 66 | ({"dict": {"a": "blargh", "b": "blergh"}}, "dict.a: blargh\ndict.b: blergh"), 67 | ({"dict": {"a": ["x", "y"], "b": "blergh"}}, "dict.a: x, y\ndict.b: blergh"), 68 | ({"tuple": ("c", "meh")}, "tuple: c, meh"), 69 | ({"err": ValidationError("some error")}, "err: some error"), 70 | ] 71 | for error, expected in examples: 72 | compare(actual=flatten_marshmallow_errors(error), expected=expected) 73 | -------------------------------------------------------------------------------- /tests/test_yaml/existing-actual.yaml: -------------------------------------------------------------------------------- 1 | # Root comment 2 | python: 3 | version: 3.8 # This comment should be kept 4 | install: 5 | - method: pip 6 | path: . 7 | extra_requirements: 8 | - doc 9 | mixed: 10 | - 1 11 | - string 12 | - c: 1 13 | b: 2 14 | a: 3 15 | - and the remaining items are untouched 16 | - [ 5,3,1 ] 17 | -------------------------------------------------------------------------------- /tests/test_yaml/existing-desired.toml: -------------------------------------------------------------------------------- 1 | ["me/deep/rooted.yaml".python] 2 | version = "3.9" 3 | 4 | [["me/deep/rooted.yaml".python.install]] 5 | # There is no __list_keys defined for this list, so a new element with "extra_requirements" will be added 6 | # instead of replacing the existing "extra_requirements" 7 | extra_requirements = ["some", "nice", "package"] 8 | 9 | [["me/deep/rooted.yaml".root_key.a_dict]] 10 | c = "3.1" 11 | 12 | [["me/deep/rooted.yaml".root_key.a_dict]] 13 | b = 2 14 | 15 | [["me/deep/rooted.yaml".mixed]] 16 | lets = { ruin = "this", with = ["weird", "1", "crap"] } 17 | 18 | [["me/deep/rooted.yaml".mixed]] 19 | "second item" = "also a dict" 20 | 21 | [["me/deep/rooted.yaml".mixed]] 22 | c = 1 23 | b = 2 24 | a = 3 25 | 26 | [["me/deep/rooted.yaml".root_key.a_dict]] 27 | a = "string value" 28 | 29 | ["me/deep/rooted.yaml".root_key.a_nested] 30 | list = [0, 2, 1] 31 | int = 10 32 | -------------------------------------------------------------------------------- /tests/test_yaml/existing-expected.yaml: -------------------------------------------------------------------------------- 1 | # Root comment 2 | python: 3 | version: '3.9' # This comment should be kept 4 | install: 5 | - method: pip 6 | path: . 7 | extra_requirements: 8 | - doc 9 | - extra_requirements: 10 | - some 11 | - nice 12 | - package 13 | mixed: 14 | - 1 15 | - string 16 | - c: 1 17 | b: 2 18 | a: 3 19 | - and the remaining items are untouched 20 | - [5, 3, 1] 21 | - lets: 22 | ruin: this 23 | with: 24 | - weird 25 | - '1' 26 | - crap 27 | - second item: also a dict 28 | root_key: 29 | a_dict: 30 | - c: '3.1' 31 | - b: 2 32 | - a: string value 33 | a_nested: 34 | list: 35 | - 0 36 | - 2 37 | - 1 38 | int: 10 39 | -------------------------------------------------------------------------------- /tests/test_yaml/jmes-list-key-desired.toml: -------------------------------------------------------------------------------- 1 | ["an/arbitrary/file.yaml".__list_keys] 2 | my.list.with.dicts = "name" 3 | # TODO: fix: this raises a KeyError: 'regions.cities.people'; try dpath-python 4 | # root = "regions.cities.people.name" 5 | 6 | [["an/arbitrary/file.yaml".my.list.with.dicts]] 7 | name = "Will" 8 | age = 50 9 | 10 | [["an/arbitrary/file.yaml".root]] 11 | country = "ENG" 12 | [["an/arbitrary/file.yaml".root.regions]] 13 | region = "West Midlands" 14 | [["an/arbitrary/file.yaml".root.regions.cities]] 15 | city = "Birmingham" 16 | [["an/arbitrary/file.yaml".root.regions.cities.people]] 17 | name = "Ann" 18 | age = 27 19 | from = "Liverpool" 20 | -------------------------------------------------------------------------------- /tests/test_yaml/jmes-list-key-expected.yaml: -------------------------------------------------------------------------------- 1 | my: 2 | list: 3 | with: 4 | dicts: 5 | - name: John 6 | age: 50 7 | - name: Mary 8 | age: 40 9 | - name: Frank 10 | age: 55 11 | - name: Will 12 | age: 50 13 | - name: Carrie 14 | age: 38 15 | root: 16 | - country: GER 17 | regions: 18 | - region: Bayern 19 | cities: 20 | - city: Muenchen # TODO: fix: umlaut UTF-8 is failing on Windows CI 21 | people: 22 | - name: Fritz 23 | age: 60 24 | - age: 45 25 | name: Helga 26 | - name: Otto 27 | age: 67 28 | - country: ENG 29 | regions: 30 | - region: West Midlands 31 | cities: 32 | - city: Birmingham 33 | people: 34 | - name: Judy 35 | age: 36 36 | - name: Ann 37 | age: 32 38 | - name: Mildred 39 | age: 47 40 | - country: ENG 41 | regions: 42 | - region: West Midlands 43 | cities: 44 | - city: Birmingham 45 | people: 46 | - name: Ann 47 | age: 27 48 | from: Liverpool 49 | -------------------------------------------------------------------------------- /tests/test_yaml/list-by-hash-desired.toml: -------------------------------------------------------------------------------- 1 | [["some/nice/config.yaml".my.list.with.dicts]] 2 | age = 56 3 | name = "Will" 4 | 5 | [["some/nice/config.yaml".my.list.with.dicts]] 6 | age = 35 7 | name = "Silly" 8 | 9 | [["some/nice/config.yaml".my.list.with.dicts]] 10 | age = 38 11 | name = "Carrie" 12 | 13 | [["some/nice/config.yaml".my.list.with.dicts]] 14 | age = 40 15 | name = "Mary" 16 | -------------------------------------------------------------------------------- /tests/test_yaml/list-by-hash-expected.yaml: -------------------------------------------------------------------------------- 1 | my: 2 | list: 3 | with: 4 | dicts: 5 | - name: John 6 | age: 50 7 | - name: Mary 8 | age: 40 9 | - name: Frank 10 | age: 55 11 | - name: Will 12 | age: 56 13 | - name: Carrie 14 | age: 38 15 | - age: 35 16 | name: Silly 17 | root: 18 | - country: GER 19 | regions: 20 | - region: Bayern 21 | cities: 22 | - city: Muenchen # TODO: fix: umlaut UTF-8 is failing on Windows CI 23 | people: 24 | - name: Fritz 25 | age: 60 26 | - age: 45 27 | name: Helga 28 | - name: Otto 29 | age: 67 30 | - country: ENG 31 | regions: 32 | - region: West Midlands 33 | cities: 34 | - city: Birmingham 35 | people: 36 | - name: Judy 37 | age: 36 38 | - name: Ann 39 | age: 32 40 | - name: Mildred 41 | age: 47 42 | -------------------------------------------------------------------------------- /tests/test_yaml/multiple-lists.yaml: -------------------------------------------------------------------------------- 1 | my: 2 | list: 3 | with: 4 | dicts: 5 | - name: John 6 | age: 50 7 | - name: Mary 8 | age: 40 9 | - name: Frank 10 | age: 55 11 | - name: Will 12 | age: 56 13 | - name: Carrie 14 | age: 38 15 | root: 16 | - country: GER 17 | regions: 18 | - region: Bayern 19 | cities: 20 | - city: Muenchen # TODO: fix: umlaut UTF-8 is failing on Windows CI 21 | people: 22 | - name: Fritz 23 | age: 60 24 | - age: 45 25 | name: Helga 26 | - name: Otto 27 | age: 67 28 | - country: ENG 29 | regions: 30 | - region: West Midlands 31 | cities: 32 | - city: Birmingham 33 | people: 34 | - name: Judy 35 | age: 36 36 | - name: Ann 37 | age: 32 38 | - name: Mildred 39 | age: 47 40 | -------------------------------------------------------------------------------- /tests/test_yaml/new-desired.toml: -------------------------------------------------------------------------------- 1 | # TOML tables to represent YAML lists 2 | [[".github/workflows/python.yaml".jobs.build.steps]] 3 | uses = "actions/checkout@v2" 4 | 5 | [[".github/workflows/python.yaml".jobs.build.steps]] 6 | name = "Set up Python ${{ matrix.python-version }}" 7 | uses = "actions/setup-python@v2" 8 | 9 | # A dynamic inline table; this causes issues with the TOML decoder 10 | # See https://github.com/uiri/toml/issues/362 11 | with = {"python-version" = "${{ matrix.python-version }}"} 12 | 13 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 14 | os = ["ubuntu-latest", "macos-latest", "windows-latest"] 15 | "python-version" = ["3.12", "3.11", "3.10", "3.9", "3.8"] 16 | 17 | [".github/workflows/python.yaml".jobs.build] 18 | "runs-on" = "${{ matrix.os }}" 19 | -------------------------------------------------------------------------------- /tests/test_yaml/new-expected.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | steps: 4 | - uses: actions/checkout@v2 5 | - name: Set up Python ${{ matrix.python-version }} 6 | uses: actions/setup-python@v2 7 | with: 8 | python-version: ${{ matrix.python-version }} 9 | strategy: 10 | matrix: 11 | os: 12 | - ubuntu-latest 13 | - macos-latest 14 | - windows-latest 15 | python-version: 16 | - '3.12' 17 | - '3.11' 18 | - '3.10' 19 | - '3.9' 20 | - '3.8' 21 | runs-on: ${{ matrix.os }} 22 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/any-order.toml: -------------------------------------------------------------------------------- 1 | [[".github/workflows/any-order.yaml".jobs.release.steps]] 2 | name = "D" 3 | uses = "D" 4 | 5 | [[".github/workflows/any-order.yaml".jobs.release.steps]] 6 | name = "B" 7 | uses = "B" 8 | 9 | [[".github/workflows/any-order.yaml".jobs.release.steps]] 10 | name = "Semantic Release" 11 | uses = "cycjimmy/semantic-release-action@v2" 12 | 13 | [".github/workflows/any-order.yaml".jobs.release.steps.env] 14 | GITHUB_TOKEN = "${{ secrets.GITHUB_TOKEN }}" 15 | TWINE_PASSWORD = "${{ secrets.TWINE_PASSWORD }}" 16 | TWINE_TEST_PASSWORD = "${{ secrets.TWINE_TEST_PASSWORD }}" 17 | TWINE_USERNAME = "${{ secrets.TWINE_USERNAME }}" 18 | 19 | [".github/workflows/any-order.yaml".jobs.release.steps.with] 20 | extra_plugins = "@semantic-release/changelog@5.0.1\n@semantic-release/git@9.0.0\n@semantic-release/exec@5.0.0\n" 21 | semantic_version = "17.3.9" 22 | 23 | [[".github/workflows/any-order.yaml".jobs.release.steps]] 24 | name = "A" 25 | uses = "A" 26 | 27 | [[".github/workflows/any-order.yaml".jobs.release.steps]] 28 | if = "steps.semantic.outputs.new_release_published == 'true'" 29 | name = "New release published" 30 | run = "echo ${{ steps.semantic.outputs.new_release_version }}\necho ${{ steps.semantic.outputs.new_release_major_version }}\necho ${{ steps.semantic.outputs.new_release_minor_version }}\necho ${{ steps.semantic.outputs.new_release_patch_version }}\necho ${{ steps.semantic.outputs.new_release_channel }}\necho ${{ steps.semantic.outputs.new_release_notes }}\n" 31 | 32 | [[".github/workflows/any-order.yaml".jobs.release.steps]] 33 | name = "C" 34 | uses = "C" 35 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/any-order.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | release: 3 | steps: 4 | - name: C 5 | uses: C 6 | - name: D 7 | uses: D 8 | - name: New release published 9 | if: steps.semantic.outputs.new_release_published == 'true' 10 | run: | 11 | echo ${{ steps.semantic.outputs.new_release_version }} 12 | echo ${{ steps.semantic.outputs.new_release_major_version }} 13 | echo ${{ steps.semantic.outputs.new_release_minor_version }} 14 | echo ${{ steps.semantic.outputs.new_release_patch_version }} 15 | echo ${{ steps.semantic.outputs.new_release_channel }} 16 | echo ${{ steps.semantic.outputs.new_release_notes }} 17 | - name: A 18 | uses: A 19 | - name: Semantic Release 20 | uses: cycjimmy/semantic-release-action@v2 21 | with: 22 | semantic_version: 17.3.9 23 | extra_plugins: | 24 | @semantic-release/changelog@5.0.1 25 | @semantic-release/git@9.0.0 26 | @semantic-release/exec@5.0.0 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} 30 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} 31 | TWINE_TEST_PASSWORD: ${{ secrets.TWINE_TEST_PASSWORD }} 32 | - name: B 33 | uses: B 34 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/dict-search-by-key-actual.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | steps: 4 | - name: Before checkout 5 | - name: Checkout 6 | uses: some-wrong-action/checkout@v2 7 | - name: Right after checkout 8 | run: echo yeah yeah yeah 9 | - name: Another step after checkout 10 | run: echo die die die 11 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/dict-search-by-key-desired.toml: -------------------------------------------------------------------------------- 1 | [[".github/workflows/any-language.yaml".jobs.build.steps]] 2 | name = "Checkout" 3 | uses = "actions/checkout@v2" 4 | 5 | [[".github/workflows/any-language.yaml".jobs.build.steps]] 6 | name = "Set up Python ${{ matrix.python-version }}" 7 | uses = "actions/setup-python@v2" 8 | 9 | [".github/workflows/any-language.yaml".jobs.build.steps.with] 10 | python-version = "${{ matrix.python-version }}" 11 | 12 | [[".github/workflows/any-language.yaml".jobs.build.steps]] 13 | name = "Install tox" 14 | run = "python -m pip install tox" 15 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/dict-search-by-key-expected.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | steps: 4 | - name: Before checkout 5 | - name: Checkout 6 | uses: actions/checkout@v2 7 | - name: Right after checkout 8 | run: echo yeah yeah yeah 9 | - name: Another step after checkout 10 | run: echo die die die 11 | - name: Set up Python ${{ matrix.python-version }} 12 | uses: actions/setup-python@v2 13 | with: 14 | python-version: ${{ matrix.python-version }} 15 | - name: Install tox 16 | run: python -m pip install tox 17 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/same-key-actual.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | whatever: 3 | steps: 4 | - name: Some step 5 | - name: Same key 6 | uses: actions/first-element-will-be-replaced@v2 7 | - name: Another step 8 | - name: Next step has the same key as another one above 9 | - name: Same key 10 | uses: actions/duplicated-element-will-be-kept@v2 11 | - name: Step after the duplicated one 12 | - name: And the final step 13 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/same-key-desired.toml: -------------------------------------------------------------------------------- 1 | [[".github/workflows/something.yaml".jobs.whatever.steps]] 2 | name = "Same key" 3 | uses = "actions/replacing-duplicated-element@v2" 4 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/same-key-expected.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | whatever: 3 | steps: 4 | - name: Some step 5 | - name: Same key 6 | uses: actions/replacing-duplicated-element@v2 7 | - name: Another step 8 | - name: Next step has the same key as another one above 9 | - name: Same key 10 | uses: actions/duplicated-element-will-be-kept@v2 11 | - name: Step after the duplicated one 12 | - name: And the final step 13 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/scalar-add-elements-that-do-not-exist-actual.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | name: "${{ matrix.python-version }} ${{ matrix.os }}" 4 | strategy: 5 | fail-fast: false 6 | matrix: 7 | # ubuntu-latest is being moved from ubuntu-18.04 to ubuntu-20.04 8 | # See https://github.com/actions/virtual-environments/issues/1816 9 | os: [windows-latest, gentoo, macos-latest, arch-linux] 10 | python-version: ["3.8", "3.9", "2.7"] 11 | runs-on: ${{ matrix.os }} 12 | env: 13 | PYTHONUNBUFFERED: 1 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/scalar-add-elements-that-do-not-exist-desired.toml: -------------------------------------------------------------------------------- 1 | [".github/workflows/python.yaml".jobs.build.strategy.matrix] 2 | os = ["ubuntu-latest", "windows-latest", "macos-latest"] 3 | python-version = ["3.8", "3.9", "3.10", "3.11", "3.12"] 4 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/scalar-add-elements-that-do-not-exist-expected.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | name: "${{ matrix.python-version }} ${{ matrix.os }}" 4 | strategy: 5 | fail-fast: false 6 | matrix: 7 | # ubuntu-latest is being moved from ubuntu-18.04 to ubuntu-20.04 8 | # See https://github.com/actions/virtual-environments/issues/1816 9 | os: [windows-latest, gentoo, macos-latest, arch-linux, ubuntu-latest] 10 | python-version: ["3.8", "3.9", "2.7", '3.10', '3.11', '3.12'] 11 | runs-on: ${{ matrix.os }} 12 | env: 13 | PYTHONUNBUFFERED: 1 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/wildcard-actual.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | steps: 4 | - name: Before checkout 5 | - name: Checkout 6 | uses: wrong/checkout@v2 7 | - name: This should be the last step 8 | test: 9 | steps: 10 | - name: Wrong checkout as well 11 | - name: Checkout 12 | uses: wrong-as-well 13 | - name: This should be the last step 14 | release: 15 | steps: 16 | - name: Wrong checkout once again 17 | - name: Checkout 18 | uses: bad-copy-paste 19 | - name: This should be the last step 20 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/wildcard-desired.toml: -------------------------------------------------------------------------------- 1 | [[".github/workflows/anything.yaml".jobs.build.steps]] 2 | name = "Checkout" 3 | uses = "actions/checkout@v2" 4 | 5 | [[".github/workflows/anything.yaml".jobs.test.steps]] 6 | name = "Checkout" 7 | uses = "actions/checkout@v2" 8 | 9 | [[".github/workflows/anything.yaml".jobs.release.steps]] 10 | name = "Checkout" 11 | uses = "actions/checkout@v2" 12 | -------------------------------------------------------------------------------- /tests/test_yaml_github_workflows/wildcard-expected.yaml: -------------------------------------------------------------------------------- 1 | jobs: 2 | build: 3 | steps: 4 | - name: Before checkout 5 | - name: Checkout 6 | uses: actions/checkout@v2 7 | - name: This should be the last step 8 | test: 9 | steps: 10 | - name: Wrong checkout as well 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | - name: This should be the last step 14 | release: 15 | steps: 16 | - name: Wrong checkout once again 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | - name: This should be the last step 20 | -------------------------------------------------------------------------------- /tests/test_yaml_old_pre_commit/1-black.toml: -------------------------------------------------------------------------------- 1 | ["pyproject.toml".tool.black] 2 | line-length = 120 3 | 4 | [[".pre-commit-config.yaml".repos]] 5 | yaml = """ 6 | - repo: https://github.com/psf/black 7 | rev: 21.5b2 8 | hooks: 9 | - id: black 10 | args: [--safe, --quiet] 11 | - repo: https://github.com/asottile/blacken-docs 12 | rev: v1.10.0 13 | hooks: 14 | - id: blacken-docs 15 | additional_dependencies: [black==21.5b2] 16 | """ 17 | -------------------------------------------------------------------------------- /tests/test_yaml_old_pre_commit/1-isort.toml: -------------------------------------------------------------------------------- 1 | ["setup.cfg".isort] 2 | line_length = 120 3 | skip = ".tox,build" 4 | known_first_party = "tests" 5 | 6 | # The configuration below is needed for compatibility with black. 7 | # https://github.com/python/black#how-black-wraps-lines 8 | # https://github.com/PyCQA/isort#multi-line-output-modes 9 | multi_line_output = 3 10 | include_trailing_comma = true 11 | force_grid_wrap = 0 12 | combine_as_imports = true 13 | 14 | [[".pre-commit-config.yaml".repos]] 15 | yaml = """ 16 | - repo: https://github.com/PyCQA/isort 17 | rev: 5.8.0 18 | hooks: 19 | - id: isort 20 | """ 21 | -------------------------------------------------------------------------------- /tests/test_yaml_old_pre_commit/2-untouched-pre-commit.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pygrep-hooks 3 | rev: v1.1.0 4 | hooks: 5 | - id: python-check-blanket-noqa 6 | - id: missing-hook-in-this-position 7 | - id: python-no-eval 8 | - id: python-no-log-warn 9 | - id: rst-backticks 10 | - repo: https://github.com/pre-commit/pre-commit-hooks 11 | rev: v4.0.1 12 | hooks: 13 | - id: debug-statements 14 | - repo: https://github.com/asottile/pyupgrade 15 | rev: v2.16.0 16 | hooks: 17 | - id: pyupgrade 18 | - repo: https://github.com/openstack/bashate 19 | rev: 0.5.0 20 | hooks: 21 | - id: extra-hook-before-should-be-ignored 22 | - id: bashate 23 | args: [extra, arguments, should, --not, --throw, errors] 24 | - id: extra-hook-after-should-be-ignored 25 | - repo: https://github.com/user/repo 26 | rev: 1.2.3 27 | hooks: 28 | - id: my-hook 29 | args: [--different, args, --should, throw, errors] 30 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/hook-args-add.toml: -------------------------------------------------------------------------------- 1 | [[".pre-commit-config.yaml".repos]] 2 | repo = "https://github.com/pre-commit/pygrep-hooks" 3 | 4 | [[".pre-commit-config.yaml".repos.hooks]] 5 | id = "python-no-eval" 6 | args = ["--first", "--second"] 7 | another = "value" 8 | last = "key" 9 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/hook-args-add.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/myint/autoflake 9 | rev: v1.4 10 | hooks: 11 | - id: autoflake 12 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 13 | args: [--in-place, --remove-all-unused-imports, 14 | --remove-unused-variables, --remove-duplicate-keys, 15 | --ignore-init-module-imports, --exclude, compat.py] 16 | - repo: https://github.com/psf/black 17 | rev: 21.12b0 18 | hooks: 19 | - id: black 20 | args: [--safe, --quiet] 21 | - repo: https://github.com/asottile/blacken-docs 22 | rev: v1.12.0 23 | hooks: 24 | - id: blacken-docs 25 | additional_dependencies: [black==21.5b2] 26 | - repo: https://github.com/pre-commit/pygrep-hooks 27 | rev: v1.9.0 28 | hooks: 29 | - id: python-check-blanket-noqa 30 | - id: python-check-mock-methods 31 | - id: python-no-eval 32 | args: 33 | - --first 34 | - --second 35 | another: value 36 | last: key 37 | - id: python-no-log-warn 38 | - id: rst-backticks 39 | - repo: https://github.com/pre-commit/mirrors-prettier 40 | rev: v2.5.1 41 | hooks: 42 | - id: prettier 43 | stages: [commit] 44 | - repo: https://github.com/PyCQA/flake8 45 | rev: 4.0.1 46 | hooks: 47 | - id: flake8 48 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 49 | additional_dependencies: [flake8-blind-except, flake8-bugbear, 50 | flake8-comprehensions, flake8-debugger, flake8-docstrings, 51 | flake8-isort, flake8-polyfill, flake8-pytest, flake8-quotes, 52 | flake8-typing-imports, yesqa] 53 | - repo: https://github.com/pre-commit/mirrors-mypy 54 | rev: v0.930 55 | hooks: 56 | - id: mypy 57 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 58 | args: [--show-error-codes] 59 | # Install additional types to fix new warnings that appeared on v0.910: 60 | # https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports 61 | # "using --install-types is problematic" 62 | # see https://github.com/pre-commit/mirrors-mypy#using-mypy-with-pre-commit 63 | additional_dependencies: [types-freezegun, types-toml, types-attrs, 64 | types-requests, types-python-slugify, types-dataclasses] 65 | - repo: https://github.com/PyCQA/bandit 66 | rev: 1.7.1 67 | hooks: 68 | - id: bandit 69 | args: [--ini, setup.cfg] 70 | exclude: tests/ 71 | - repo: https://github.com/openstack/bashate 72 | rev: 2.1.0 73 | hooks: 74 | - id: bashate 75 | # https://docs.openstack.org/bashate/latest/man/bashate.html#options 76 | args: [-i, E006] 77 | - repo: https://github.com/commitizen-tools/commitizen 78 | rev: v2.20.3 79 | hooks: 80 | - id: commitizen 81 | stages: [commit-msg] 82 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/hook-args-change.toml: -------------------------------------------------------------------------------- 1 | [[".pre-commit-config.yaml".repos]] 2 | repo = "https://github.com/psf/black" 3 | 4 | [[".pre-commit-config.yaml".repos.hooks]] 5 | id = "black" 6 | args = ["--safe", "--custom", "--loud"] 7 | 8 | [[".pre-commit-config.yaml".repos]] 9 | repo = "https://github.com/asottile/blacken-docs" 10 | 11 | [[".pre-commit-config.yaml".repos.hooks]] 12 | id = "blacken-docs" 13 | additional_dependencies = ["black==22.1"] 14 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/hook-args-change.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/myint/autoflake 9 | rev: v1.4 10 | hooks: 11 | - id: autoflake 12 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 13 | args: [--in-place, --remove-all-unused-imports, 14 | --remove-unused-variables, --remove-duplicate-keys, 15 | --ignore-init-module-imports, --exclude, compat.py] 16 | - repo: https://github.com/psf/black 17 | rev: 21.12b0 18 | hooks: 19 | - id: black 20 | args: 21 | - --safe 22 | - --custom 23 | - --loud 24 | - repo: https://github.com/asottile/blacken-docs 25 | rev: v1.12.0 26 | hooks: 27 | - id: blacken-docs 28 | additional_dependencies: 29 | - black==22.1 30 | - repo: https://github.com/pre-commit/pygrep-hooks 31 | rev: v1.9.0 32 | hooks: 33 | - id: python-check-blanket-noqa 34 | - id: python-check-mock-methods 35 | - id: python-no-eval 36 | - id: python-no-log-warn 37 | - id: rst-backticks 38 | - repo: https://github.com/pre-commit/mirrors-prettier 39 | rev: v2.5.1 40 | hooks: 41 | - id: prettier 42 | stages: [commit] 43 | - repo: https://github.com/PyCQA/flake8 44 | rev: 4.0.1 45 | hooks: 46 | - id: flake8 47 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 48 | additional_dependencies: [flake8-blind-except, flake8-bugbear, 49 | flake8-comprehensions, flake8-debugger, flake8-docstrings, 50 | flake8-isort, flake8-polyfill, flake8-pytest, flake8-quotes, 51 | flake8-typing-imports, yesqa] 52 | - repo: https://github.com/pre-commit/mirrors-mypy 53 | rev: v0.930 54 | hooks: 55 | - id: mypy 56 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 57 | args: [--show-error-codes] 58 | # Install additional types to fix new warnings that appeared on v0.910: 59 | # https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports 60 | # "using --install-types is problematic" 61 | # see https://github.com/pre-commit/mirrors-mypy#using-mypy-with-pre-commit 62 | additional_dependencies: [types-freezegun, types-toml, types-attrs, 63 | types-requests, types-python-slugify, types-dataclasses] 64 | - repo: https://github.com/PyCQA/bandit 65 | rev: 1.7.1 66 | hooks: 67 | - id: bandit 68 | args: [--ini, setup.cfg] 69 | exclude: tests/ 70 | - repo: https://github.com/openstack/bashate 71 | rev: 2.1.0 72 | hooks: 73 | - id: bashate 74 | # https://docs.openstack.org/bashate/latest/man/bashate.html#options 75 | args: [-i, E006] 76 | - repo: https://github.com/commitizen-tools/commitizen 77 | rev: v2.20.3 78 | hooks: 79 | - id: commitizen 80 | stages: [commit-msg] 81 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/hook-args.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/myint/autoflake 9 | rev: v1.4 10 | hooks: 11 | - id: autoflake 12 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 13 | args: 14 | [ 15 | --in-place, 16 | --remove-all-unused-imports, 17 | --remove-unused-variables, 18 | --remove-duplicate-keys, 19 | --ignore-init-module-imports, 20 | --exclude, 21 | compat.py, 22 | ] 23 | - repo: https://github.com/psf/black 24 | rev: 21.12b0 25 | hooks: 26 | - id: black 27 | args: [--safe, --quiet] 28 | - repo: https://github.com/asottile/blacken-docs 29 | rev: v1.12.0 30 | hooks: 31 | - id: blacken-docs 32 | additional_dependencies: [black==21.5b2] 33 | - repo: https://github.com/pre-commit/pygrep-hooks 34 | rev: v1.9.0 35 | hooks: 36 | - id: python-check-blanket-noqa 37 | - id: python-check-mock-methods 38 | - id: python-no-eval 39 | - id: python-no-log-warn 40 | - id: rst-backticks 41 | - repo: https://github.com/pre-commit/mirrors-prettier 42 | rev: v2.5.1 43 | hooks: 44 | - id: prettier 45 | stages: [commit] 46 | - repo: https://github.com/PyCQA/flake8 47 | rev: 4.0.1 48 | hooks: 49 | - id: flake8 50 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 51 | additional_dependencies: 52 | [ 53 | flake8-blind-except, 54 | flake8-bugbear, 55 | flake8-comprehensions, 56 | flake8-debugger, 57 | flake8-docstrings, 58 | flake8-isort, 59 | flake8-polyfill, 60 | flake8-pytest, 61 | flake8-quotes, 62 | flake8-typing-imports, 63 | yesqa, 64 | ] 65 | - repo: https://github.com/pre-commit/mirrors-mypy 66 | rev: v0.930 67 | hooks: 68 | - id: mypy 69 | # KNOWN ISSUE: this list will be joined in a single line and comments from items will be removed 70 | args: [ 71 | # https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-show-error-codes 72 | --show-error-codes, 73 | ] 74 | # Install additional types to fix new warnings that appeared on v0.910: 75 | # https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports 76 | # "using --install-types is problematic" 77 | # see https://github.com/pre-commit/mirrors-mypy#using-mypy-with-pre-commit 78 | additional_dependencies: 79 | [types-freezegun, types-toml, types-attrs, types-requests, types-python-slugify, types-dataclasses] 80 | - repo: https://github.com/PyCQA/bandit 81 | rev: 1.7.1 82 | hooks: 83 | - id: bandit 84 | args: [--ini, setup.cfg] 85 | exclude: tests/ 86 | - repo: https://github.com/openstack/bashate 87 | rev: 2.1.0 88 | hooks: 89 | - id: bashate 90 | # https://docs.openstack.org/bashate/latest/man/bashate.html#options 91 | args: [-i, E006] 92 | - repo: https://github.com/commitizen-tools/commitizen 93 | rev: v2.20.3 94 | hooks: 95 | - id: commitizen 96 | stages: [commit-msg] 97 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-actual.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/psf/black 9 | rev: 21.12b0 10 | hooks: 11 | - id: black 12 | args: [--safe, --quiet] 13 | - repo: https://github.com/asottile/blacken-docs 14 | rev: v1.12.0 15 | hooks: 16 | - id: blacken-docs 17 | additional_dependencies: [black==21.5b2] 18 | - repo: https://github.com/PyCQA/isort 19 | rev: 5.10.1 20 | hooks: 21 | - id: isort 22 | - repo: https://github.com/pre-commit/pygrep-hooks 23 | rev: v1.9.0 24 | hooks: 25 | - id: python-check-blanket-noqa 26 | - id: python-check-mock-methods 27 | - id: python-no-eval 28 | - id: python-no-log-warn 29 | - id: rst-backticks 30 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-default-expected.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/psf/black 9 | rev: 21.12b0 10 | hooks: 11 | - id: black 12 | args: [--safe, --quiet] 13 | - repo: https://github.com/asottile/blacken-docs 14 | rev: v1.12.0 15 | hooks: 16 | - id: blacken-docs 17 | additional_dependencies: [black==21.5b2] 18 | - repo: https://github.com/PyCQA/isort 19 | rev: 5.10.1 20 | hooks: 21 | - id: isort 22 | - repo: https://github.com/pre-commit/pygrep-hooks 23 | rev: v1.9.0 24 | hooks: 25 | - id: python-check-blanket-noqa 26 | - id: python-check-mock-methods 27 | - id: python-no-eval 28 | - id: python-no-log-warn 29 | - id: rst-backticks 30 | - repo: https://github.com/myint/autoflake 31 | hooks: 32 | - id: autoflake 33 | args: 34 | - --in-place 35 | - --remove-all-unused-imports 36 | - --remove-unused-variables 37 | - --remove-duplicate-keys 38 | - --ignore-init-module-imports 39 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-default.toml: -------------------------------------------------------------------------------- 1 | [[".pre-commit-config.yaml".repos]] 2 | repo = "https://github.com/myint/autoflake" 3 | 4 | [[".pre-commit-config.yaml".repos.hooks]] 5 | id = "autoflake" 6 | args = ["--in-place", "--remove-all-unused-imports", "--remove-unused-variables", "--remove-duplicate-keys", "--ignore-init-module-imports"] 7 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-empty-expected.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/psf/black 9 | rev: 21.12b0 10 | hooks: 11 | - id: black 12 | args: [--safe, --quiet] 13 | - repo: https://github.com/asottile/blacken-docs 14 | rev: v1.12.0 15 | hooks: 16 | - id: blacken-docs 17 | additional_dependencies: [black==21.5b2] 18 | - repo: https://github.com/PyCQA/isort 19 | rev: 5.10.1 20 | hooks: 21 | - id: isort 22 | - repo: https://github.com/pre-commit/pygrep-hooks 23 | rev: v1.9.0 24 | hooks: 25 | - id: python-check-blanket-noqa 26 | - id: python-check-mock-methods 27 | - id: python-no-eval 28 | - id: python-no-log-warn 29 | - id: rst-backticks 30 | - repo: https://github.com/myint/autoflake 31 | hooks: 32 | - id: autoflake 33 | args: 34 | - --in-place 35 | - --remove-all-unused-imports 36 | - --remove-unused-variables 37 | - --remove-duplicate-keys 38 | - --ignore-init-module-imports 39 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-empty.toml: -------------------------------------------------------------------------------- 1 | [".pre-commit-config.yaml".__list_keys] 2 | repos = "" 3 | 4 | [[".pre-commit-config.yaml".repos]] 5 | repo = "https://github.com/myint/autoflake" 6 | 7 | # [Enforce presence of keys (with any values) · Issue #218 · andreoliwa/nitpick](https://github.com/andreoliwa/nitpick/issues/218) 8 | #rev__exists = true 9 | # Should generate: 10 | # rev: 11 | 12 | [[".pre-commit-config.yaml".repos.hooks]] 13 | id = "autoflake" 14 | args = ["--in-place", "--remove-all-unused-imports", "--remove-unused-variables", "--remove-duplicate-keys", "--ignore-init-module-imports"] 15 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-override-expected.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.1.0 4 | hooks: 5 | - id: debug-statements 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/psf/black 9 | rev: 21.12b0 10 | hooks: 11 | - id: autoflake 12 | args: [--wrong-id-for-the-black-repo, --wont-be-validated-by-nitpick] 13 | - repo: https://github.com/asottile/blacken-docs 14 | rev: v1.12.0 15 | hooks: 16 | - id: blacken-docs 17 | additional_dependencies: [black==21.5b2] 18 | - repo: https://github.com/PyCQA/isort 19 | rev: 5.10.1 20 | hooks: 21 | - id: isort 22 | - repo: https://github.com/pre-commit/pygrep-hooks 23 | rev: v1.9.0 24 | hooks: 25 | - id: python-check-blanket-noqa 26 | - id: python-check-mock-methods 27 | - id: python-no-eval 28 | - id: python-no-log-warn 29 | - id: rst-backticks 30 | -------------------------------------------------------------------------------- /tests/test_yaml_pre_commit/uk-override.toml: -------------------------------------------------------------------------------- 1 | [".pre-commit-config.yaml".__list_keys] 2 | repos = "repo" 3 | 4 | [[".pre-commit-config.yaml".repos]] 5 | repo = "https://github.com/psf/black" 6 | 7 | [[".pre-commit-config.yaml".repos.hooks]] 8 | id = "autoflake" 9 | args = ["--wrong-id-for-the-black-repo", "--wont-be-validated-by-nitpick"] 10 | --------------------------------------------------------------------------------