# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks minimum_pre_commit_version: '2.8.2' default_language_version: python: python3 default_stages: [commit] repos: # General file checks and fixers - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: mixed-line-ending name: "Normalize mixed line endings" args: [--fix=lf] - id: file-contents-sorter name: "Sort codespell ignore list" files: '.codespell/ignore-words.txt' - id: check-case-conflict name: "Check for case conflicts" - id: check-merge-conflict name: "Check for merge conflict markers" - id: check-executables-have-shebangs name: "Check that executables have shebangs" - id: check-shebang-scripts-are-executable name: "Check that shebangs are executable" - id: check-vcs-permalinks name: "Check that VCS links are permalinks" # - id: check-ast # name: "Check Python AST" - id: check-json name: "Check JSON" - id: check-toml name: "Check TOML" - id: check-yaml name: "Check YAML" - repo: https://github.com/psf/black rev: 23.7.0 hooks: - id: black name: "Format with Black" args: - '--target-version=py39' - '--target-version=py310' files: 'pep_sphinx_extensions/tests/.*' - repo: https://github.com/PyCQA/isort rev: 5.12.0 hooks: - id: isort name: "Sort imports with isort" args: ['--profile=black', '--atomic'] files: 'pep_sphinx_extensions/tests/.*' - repo: https://github.com/tox-dev/tox-ini-fmt rev: 1.3.1 hooks: - id: tox-ini-fmt name: "Format tox.ini" - repo: https://github.com/sphinx-contrib/sphinx-lint rev: v0.6.8 hooks: - id: sphinx-lint name: "Sphinx lint" args: ["--disable=trailing-whitespace"] # RST checks - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.10.0 hooks: - id: rst-backticks name: "Check RST: No single backticks" files: '^pep-\d+\.(rst|txt)$' types: [text] - id: rst-inline-touching-normal name: "Check RST: No backticks touching text" files: '^pep-\d+\.(rst|txt)$' types: [text] - id: rst-directive-colons name: "Check RST: 2 colons after directives" files: '^pep-\d+\.(rst|txt)$' types: [text] # Manual codespell check - repo: https://github.com/codespell-project/codespell rev: v2.2.5 hooks: - id: codespell name: "Check for common misspellings in text files" stages: [manual] # Local checks for PEP headers and more - repo: local hooks: # # Hook to run "check-peps.py" # - id: "check-peps" # name: "Check PEPs for metadata and content enforcement" # entry: "python check-peps.py" # language: "system" # files: "^pep-\d{4}\.(rst|txt)$" # require_serial: true - id: check-no-tabs name: "Check tabs not used in PEPs" language: pygrep entry: '\t' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: check-required-headers name: "PEPs must have all required headers" language: pygrep entry: '(?-m:^PEP:(?=[\s\S]*\nTitle:)(?=[\s\S]*\nAuthor:)(?=[\s\S]*\nStatus:)(?=[\s\S]*\nType:)(?=[\s\S]*\nContent-Type:)(?=[\s\S]*\nCreated:))' args: ['--negate', '--multiline'] files: '^pep-\d+\.(rst|txt)$' types: [text] - id: check-header-order name: "PEP header order must follow PEP 12" language: pygrep entry: '^PEP:[^\n]+\nTitle:[^\n]+\n(Version:[^\n]+\n)?(Last-Modified:[^\n]+\n)?Author:[^\n]+\n( +\S[^\n]+\n)*(Sponsor:[^\n]+\n)?((PEP|BDFL)-Delegate:[^\n]*\n)?(Discussions-To:[^\n]*\n)?Status:[^\n]+\nType:[^\n]+\n(Topic:[^\n]+\n)?Content-Type:[^\n]+\n(Requires:[^\n]+\n)?Created:[^\n]+\n(Python-Version:[^\n]*\n)?(Post-History:[^\n]*\n( +\S[^\n]*\n)*)?(Replaces:[^\n]+\n)?(Superseded-By:[^\n]+\n)?(Resolution:[^\n]*\n)?\n' args: ['--negate', '--multiline'] files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-pep-number name: "'PEP' header must be a number 1-9999" language: pygrep entry: '(?-m:^PEP:(?:(?! +(0|[1-9][0-9]{0,3})\n)))' args: ['--multiline'] files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-title name: "'Title' must be 1-79 characters" language: pygrep entry: '(?<=\n)Title:(?:(?! +\S.{1,78}\n(?=[A-Z])))' args: ['--multiline'] files: '^pep-\d+\.(rst|txt)$' exclude: '^pep-(0499)\.(rst|txt)$' types: [text] - id: validate-author name: "'Author' must be list of 'Name , ...'" language: pygrep entry: '(?<=\n)Author:(?:(?!((( +|\n {1,8})[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?)(,|(?=\n[^ ])))+\n(?=[A-Z])))' args: [--multiline] files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-sponsor name: "'Sponsor' must have format 'Name '" language: pygrep entry: '^Sponsor:(?: (?! *[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-delegate name: "'Delegate' must have format 'Name '" language: pygrep entry: '^(PEP|BDFL)-Delegate: (?:(?! *[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?$))' files: '^pep-\d+\.(rst|txt)$' exclude: '^pep-(0451)\.(rst|txt)$' types: [text] - id: validate-discussions-to name: "'Discussions-To' must be a thread URL" language: pygrep entry: '^Discussions-To: (?:(?!([\w\-]+@(python\.org|googlegroups\.com))|https://((discuss\.python\.org/t/([\w\-]+/)?\d+/?)|(mail\.python\.org/pipermail/[\w\-]+/\d{4}-[A-Za-z]+/[A-Za-z0-9]+\.html)|(mail\.python\.org/archives/list/[\w\-]+@python\.org/thread/[A-Za-z0-9]+/?))$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-status name: "'Status' must be a valid PEP status" language: pygrep entry: '^Status:(?:(?! +(Draft|Withdrawn|Rejected|Accepted|Final|Active|Provisional|Deferred|Superseded|April Fool!)$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-type name: "'Type' must be a valid PEP type" language: pygrep entry: '^Type:(?:(?! +(Standards Track|Informational|Process)$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-topic name: "'Topic' must be for a valid sub-index" language: pygrep entry: '^Topic:(?:(?! +(Governance|Packaging|Typing|Release)(, (Governance|Packaging|Typing|Release))*$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-content-type name: "'Content-Type' must be 'text/x-rst'" language: pygrep entry: '^Content-Type:(?:(?! +text/x-rst$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-pep-references name: "`Requires`/`Replaces`/`Superseded-By` must be 'NNN' PEP IDs" language: pygrep entry: '^(Requires|Replaces|Superseded-By):(?:(?! *( (0|[1-9][0-9]{0,3})(,|$))+$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-created name: "'Created' must be a 'DD-mmm-YYYY' date" language: pygrep entry: '^Created:(?:(?! +([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9])$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-python-version name: "'Python-Version' must be a 'X.Y[.Z]` version" language: pygrep entry: '^Python-Version:(?:(?! *( [1-9]\.([0-9][0-9]?|x)(\.[1-9][0-9]?)?(,|$))+$))' files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-post-history name: "'Post-History' must be '`DD-mmm-YYYY `__, ...'" language: pygrep entry: '(?<=\n)Post-History:(?:(?! ?\n|((( +|\n {1,14})(([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9])|`([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9]) `__)(,|(?=\n[^ ])))+\n(?=[A-Z\n]))))' args: [--multiline] files: '^pep-\d+\.(rst|txt)$' types: [text] - id: validate-resolution name: "'Resolution' must be a direct thread/message URL" language: pygrep entry: '(?