From bdcab87d2ff3851d2583e116bd095e2853140de5 Mon Sep 17 00:00:00 2001 From: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com> Date: Thu, 2 Feb 2023 22:29:07 +0100 Subject: [PATCH] Add `markdownlint` and dev Ruff to `pre-commit` (#2303) --- .github/ISSUE_TEMPLATE.md | 8 +- .github/workflows/ci.yaml | 14 +- .github/workflows/docs.yaml | 3 +- .github/workflows/playground.yaml | 2 +- .pre-commit-config.yaml | 27 +- BREAKING_CHANGES.md | 22 +- CODE_OF_CONDUCT.md | 10 +- README.md | 294 +++++++++++---------- playground/README.md | 6 +- playground/index.html | 2 +- pyproject.toml | 48 ++-- python/ruff/__main__.py | 3 +- resources/test/project/README.md | 14 +- ruff.schema.json | 14 +- ruff_dev/src/generate_cli_help.rs | 8 +- ruff_dev/src/generate_options.rs | 2 +- ruff_dev/src/generate_rules_table.rs | 3 +- scripts/add_rule.py | 2 +- setup.py | 2 +- src/rules/flake8_annotations/settings.rs | 4 +- src/rules/flake8_pytest_style/settings.rs | 15 +- src/rules/flake8_type_checking/settings.rs | 2 +- src/settings/options.rs | 8 +- 23 files changed, 277 insertions(+), 236 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4c37cea22c..7db3627dc6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,8 +3,8 @@ Thank you for taking the time to report an issue! We're glad to have you involve If you're filing a bug report, please consider including the following information: -- A minimal code snippet that reproduces the bug. -- The command you invoked (e.g., `ruff /path/to/file.py --fix`), ideally including the `--isolated` flag. -- The current Ruff settings (any relevant sections from your `pyproject.toml`). -- The current Ruff version (`ruff --version`). +* A minimal code snippet that reproduces the bug. +* The command you invoked (e.g., `ruff /path/to/file.py --fix`), ideally including the `--isolated` flag. +* The current Ruff settings (any relevant sections from your `pyproject.toml`). +* The current Ruff version (`ruff --version`). --> diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bf88c0dce9..0a0f8854d8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -56,7 +56,7 @@ jobs: cargo-test: strategy: matrix: - os: [ ubuntu-latest, windows-latest ] + os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} name: "cargo test | ${{ matrix.os }}" steps: @@ -95,8 +95,8 @@ jobs: - run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint - run: cargo check - run: | - ./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST - ./scripts/add_rule.py --name FirstRule --code TST001 --linter test + ./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST + ./scripts/add_rule.py --name FirstRule --code TST001 --linter test - run: cargo check maturin-build: @@ -118,7 +118,7 @@ jobs: name: "spell check" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: crate-ci/typos@master - with: - files: . + - uses: actions/checkout@v3 + - uses: crate-ci/typos@master + with: + files: . diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 71021e8287..f3e48d468f 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -6,10 +6,9 @@ on: - README.md - mkdocs.template.yml - .github/workflows/docs.yaml - branches: [ main ] + branches: [main] workflow_dispatch: - jobs: mkdocs: runs-on: ubuntu-latest diff --git a/.github/workflows/playground.yaml b/.github/workflows/playground.yaml index e4fc5efa3f..02eea99203 100644 --- a/.github/workflows/playground.yaml +++ b/.github/workflows/playground.yaml @@ -15,7 +15,7 @@ jobs: publish: runs-on: ubuntu-latest env: - CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }} + CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }} steps: - uses: actions/checkout@v3 - name: "Install Rust toolchain" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 058892fc1a..9b012f90f0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,19 @@ repos: - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.240 - hooks: - - id: ruff - args: [--fix] - exclude: ^resources - - repo: https://github.com/abravalheri/validate-pyproject rev: v0.10.1 hooks: - id: validate-pyproject + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.33.0 + hooks: + - id: markdownlint-fix + args: + - --disable + - MD013 # line-length + - MD033 # no-inline-html + - -- + - repo: local hooks: - id: cargo-fmt @@ -23,9 +26,19 @@ repos: entry: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic language: rust pass_filenames: false + - id: ruff + name: ruff + entry: cargo run -- --no-cache --fix + language: rust + types_or: [python, pyi] + require_serial: true + exclude: ^resources - id: dev-generate-all name: dev-generate-all entry: cargo dev generate-all language: rust pass_filenames: false exclude: target + +ci: + skip: [cargo-fmt, clippy, dev-generate-all] diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 3dbd91a9a1..532583c80f 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -43,16 +43,18 @@ upgrades. `--explain`, `--clean`, and `--generate-shell-completion` are now implemented as subcommands: - ruff . # Still works! And will always work. - ruff check . # New! Also works. +```console +ruff . # Still works! And will always work. +ruff check . # New! Also works. - ruff --explain E402 # Still works. - ruff rule E402 # New! Also works. (And preferred.) +ruff --explain E402 # Still works. +ruff rule E402 # New! Also works. (And preferred.) - # Oops! The command has to come first. - ruff --format json --explain E402 # No longer works. - ruff --explain E402 --format json # Still works! - ruff rule E402 --format json # Works! (And preferred.) +# Oops! The command has to come first. +ruff --format json --explain E402 # No longer works. +ruff --explain E402 --format json # Still works! +ruff rule E402 --format json # Works! (And preferred.) +``` This change is largely backwards compatible -- most users should experience no change in behavior. However, please note the following exceptions: @@ -60,7 +62,9 @@ no change in behavior. However, please note the following exceptions: * Subcommands will now fail when invoked with unsupported arguments, instead of silently ignoring them. For example, the following will now fail: - ruff --clean --respect-gitignore + ```console + ruff --clean --respect-gitignore + ``` (the `clean` command doesn't support `--respect-gitignore`.) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d809ca6b1e..71074c4faa 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within @@ -115,14 +115,12 @@ the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +version 2.0, available [here](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html). Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +For answers to common questions about this code of conduct, see the [FAQ](https://www.contributor-covenant.org/faq). +Translations are available [here](https://www.contributor-covenant.org/translations). diff --git a/README.md b/README.md index 67bbb2e5c7..421d08c815 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,16 @@ An extremely fast Python linter, written in Rust. Linting the CPython codebase from scratch.

-- ⚡️ 10-100x faster than existing linters -- 🐍 Installable via `pip` -- 🤝 Python 3.11 compatibility -- 🛠️ `pyproject.toml` support -- 📦 Built-in caching, to avoid re-analyzing unchanged files -- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports) -- ⚖️ [Near-parity](#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set -- 🔌 Native re-implementations of dozens of Flake8 plugins, like [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) -- ⌨️ First-party editor integrations for [VS Code](https://github.com/charliermarsh/ruff-vscode) and [more](https://github.com/charliermarsh/ruff-lsp) -- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](#pyprojecttoml-discovery) +* ⚡️ 10-100x faster than existing linters +* 🐍 Installable via `pip` +* 🤝 Python 3.11 compatibility +* 🛠️ `pyproject.toml` support +* 📦 Built-in caching, to avoid re-analyzing unchanged files +* 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports) +* ⚖️ [Near-parity](#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set +* 🔌 Native re-implementations of dozens of Flake8 plugins, like [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) +* ⌨️ First-party editor integrations for [VS Code](https://github.com/charliermarsh/ruff-vscode) and [more](https://github.com/charliermarsh/ruff-lsp) +* 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](#pyprojecttoml-discovery) Ruff aims to be orders of magnitude faster than alternative tools while integrating more functionality behind a single, common interface. @@ -46,32 +46,32 @@ all while executing tens or hundreds of times faster than any individual tool. Ruff is extremely actively developed and used in major open-source projects like: -- [pandas](https://github.com/pandas-dev/pandas) -- [FastAPI](https://github.com/tiangolo/fastapi) -- [Apache Airflow](https://github.com/apache/airflow) -- [SciPy](https://github.com/scipy/scipy) -- [Bokeh](https://github.com/bokeh/bokeh) -- [Zulip](https://github.com/zulip/zulip) -- [Pydantic](https://github.com/pydantic/pydantic) -- [Dagster](https://github.com/dagster-io/dagster) -- [Dagger](https://github.com/dagger/dagger) -- [Sphinx](https://github.com/sphinx-doc/sphinx) -- [Hatch](https://github.com/pypa/hatch) -- [Jupyter](https://github.com/jupyter-server/jupyter_server) -- [Great Expectations](https://github.com/great-expectations/great_expectations) -- [Polars](https://github.com/pola-rs/polars) -- [Ibis](https://github.com/ibis-project/ibis) -- [Synapse (Matrix)](https://github.com/matrix-org/synapse) -- [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli) -- [Saleor](https://github.com/saleor/saleor) -- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal) -- [Home Assistant](https://github.com/home-assistant/core) -- [Cryptography (PyCA)](https://github.com/pyca/cryptography) -- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel) -- [build (PyPA)](https://github.com/pypa/build) -- [Babel](https://github.com/python-babel/babel) -- [featuretools](https://github.com/alteryx/featuretools) -- [meson-python](https://github.com/mesonbuild/meson-python) +* [pandas](https://github.com/pandas-dev/pandas) +* [FastAPI](https://github.com/tiangolo/fastapi) +* [Apache Airflow](https://github.com/apache/airflow) +* [SciPy](https://github.com/scipy/scipy) +* [Bokeh](https://github.com/bokeh/bokeh) +* [Zulip](https://github.com/zulip/zulip) +* [Pydantic](https://github.com/pydantic/pydantic) +* [Dagster](https://github.com/dagster-io/dagster) +* [Dagger](https://github.com/dagger/dagger) +* [Sphinx](https://github.com/sphinx-doc/sphinx) +* [Hatch](https://github.com/pypa/hatch) +* [Jupyter](https://github.com/jupyter-server/jupyter_server) +* [Great Expectations](https://github.com/great-expectations/great_expectations) +* [Polars](https://github.com/pola-rs/polars) +* [Ibis](https://github.com/ibis-project/ibis) +* [Synapse (Matrix)](https://github.com/matrix-org/synapse) +* [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli) +* [Saleor](https://github.com/saleor/saleor) +* [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal) +* [Home Assistant](https://github.com/home-assistant/core) +* [Cryptography (PyCA)](https://github.com/pyca/cryptography) +* [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel) +* [build (PyPA)](https://github.com/pypa/build) +* [Babel](https://github.com/python-babel/babel) +* [featuretools](https://github.com/alteryx/featuretools) +* [meson-python](https://github.com/mesonbuild/meson-python) Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster) or the most recent [project update](https://notes.crmarsh.com/ruff-the-first-200-releases). @@ -89,7 +89,7 @@ co-creator of [GraphQL](https://graphql.org/): > Why is Ruff a gamechanger? Primarily because it is nearly 1000x faster. Literally. Not a typo. On > our largest module (dagster itself, 250k LOC) pylint takes about 2.5 minutes, parallelized across 4 -> cores on my M1. Running ruff against our *entire* codebase takes .4 seconds. +> cores on my M1. Running ruff against our _entire_ codebase takes .4 seconds. [**Bryan Van de Ven**](https://github.com/bokeh/bokeh/pull/12605), co-creator of [Bokeh](https://github.com/bokeh/bokeh/), original author @@ -340,13 +340,13 @@ for the pydocstyle plugin. If you're wondering how to configure Ruff, here are some **recommended guidelines**: -- Prefer `select` and `ignore` over `extend-select` and `extend-ignore`, to make your rule set +* Prefer `select` and `ignore` over `extend-select` and `extend-ignore`, to make your rule set explicit. -- Use `ALL` with discretion. Enabling `ALL` will implicitly enable new rules whenever you upgrade. -- Start with a small set of rules (`select = ["E", "F"]`) and add a category at-a-time. For example, +* Use `ALL` with discretion. Enabling `ALL` will implicitly enable new rules whenever you upgrade. +* Start with a small set of rules (`select = ["E", "F"]`) and add a category at-a-time. For example, you might consider expanding to `select = ["E", "F", "B"]` to enable the popular flake8-bugbear extension. -- By default, Ruff's autofix is aggressive. If you find that it's too aggressive for your liking, +* By default, Ruff's autofix is aggressive. If you find that it's too aggressive for your liking, consider turning off autofix for specific rules or categories (see: [FAQ](#ruff-tried-to-fix-something-but-it-broke-my-code-what-should-i-do)). As an alternative to `pyproject.toml`, Ruff will also respect a `ruff.toml` file, which implements @@ -383,7 +383,8 @@ ruff path/to/code/ --select F401 --select F403 --quiet See `ruff help` for more on Ruff's top-level commands: -``` + +```text Ruff: An extremely fast Python linter. Usage: ruff [OPTIONS] @@ -406,12 +407,14 @@ Log levels: For help with a specific command, see: `ruff help `. ``` + Or `ruff help check` for more on the linting command: -``` + +```text Run Ruff on the given files or directories (default) Usage: ruff check [OPTIONS] [FILES]... @@ -480,6 +483,7 @@ Log levels: -q, --quiet Print lint violations, but nothing else -s, --silent Disable all logging (but still exit with status code "1" upon detecting lint violations) ``` + ### `pyproject.toml` discovery @@ -639,6 +643,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com + ### Pyflakes (F) For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI. @@ -694,6 +699,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI. For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI. #### Error (E) + | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | E101 | mixed-spaces-and-tabs | Indentation contains mixed spaces and tabs | | @@ -714,6 +720,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI. | E999 | syntax-error | SyntaxError: {message} | | #### Warning (W) + | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | W292 | no-new-line-at-end-of-file | No newline at end of file | 🛠 | @@ -1315,12 +1322,14 @@ For more, see [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) on GitH For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI. #### Convention (PLC) + | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | PLC0414 | useless-import-alias | Import alias does not rename original package | 🛠 | | PLC3002 | unnecessary-direct-lambda-call | Lambda expression called directly. Execute the expression inline instead. | | #### Error (PLE) + | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | PLE0117 | nonlocal-without-binding | Nonlocal name `{name}` found without binding | | @@ -1330,6 +1339,7 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI. | PLE1142 | await-outside-async | `await` should be used within an async function | | #### Refactor (PLR) + | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | PLR0133 | constant-comparison | Two constants compared in a comparison, consider replacing `{left_constant} {op} {right_constant}` | | @@ -1342,6 +1352,7 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI. | PLR2004 | magic-value-comparison | Magic value used in comparison, consider replacing {value} with a constant variable | | #### Warning (PLW) + | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | PLW0120 | useless-else-on-loop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | | @@ -1402,7 +1413,7 @@ For more, see [flake8-self](https://pypi.org/project/flake8-self/) on PyPI. Download the [Ruff VS Code extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff), which supports autofix actions, import sorting, and more. -![](https://user-images.githubusercontent.com/1309177/205175763-cf34871d-5c05-4abf-9916-440afc82dbf8.gif) +![Ruff VS Code extension](https://user-images.githubusercontent.com/1309177/205175763-cf34871d-5c05-4abf-9916-440afc82dbf8.gif) ### Language Server Protocol (Official) @@ -1547,13 +1558,14 @@ let g:ale_fixers = { ```yaml tools: python-ruff: &python-ruff - lint-command: 'ruff --config ~/myconfigs/linters/ruff.toml --quiet ${INPUT}' + lint-command: "ruff --config ~/myconfigs/linters/ruff.toml --quiet ${INPUT}" lint-stdin: true lint-formats: - - '%f:%l:%c: %m' - format-command: 'ruff --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -' + - "%f:%l:%c: %m" + format-command: "ruff --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -" format-stdin: true ``` +
@@ -1570,8 +1582,8 @@ null_ls.setup({ } }) ``` -
+ ### PyCharm (External Tool) @@ -1644,47 +1656,47 @@ implements all of the `F` rules (which originate from Pyflakes), along with a su Ruff also re-implements some of the most popular Flake8 plugins and related code quality tools natively, including: -- [autoflake](https://pypi.org/project/autoflake/) ([#1647](https://github.com/charliermarsh/ruff/issues/1647)) -- [eradicate](https://pypi.org/project/eradicate/) -- [flake8-2020](https://pypi.org/project/flake8-2020/) -- [flake8-annotations](https://pypi.org/project/flake8-annotations/) -- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646)) -- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/) -- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) -- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) -- [flake8-builtins](https://pypi.org/project/flake8-builtins/) -- [flake8-commas](https://pypi.org/project/flake8-commas/) -- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) -- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) -- [flake8-debugger](https://pypi.org/project/flake8-debugger/) -- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) -- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) -- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) -- [flake8-executable](https://pypi.org/project/flake8-executable/) -- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) -- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) -- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) -- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) -- [flake8-pie](https://pypi.org/project/flake8-pie/) -- [flake8-print](https://pypi.org/project/flake8-print/) -- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) -- [flake8-quotes](https://pypi.org/project/flake8-quotes/) -- [flake8-raise](https://pypi.org/project/flake8-raise/) -- [flake8-return](https://pypi.org/project/flake8-return/) -- [flake8-self](https://pypi.org/project/flake8-self/) -- [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998)) -- [flake8-super](https://pypi.org/project/flake8-super/) -- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) -- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) -- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) -- [isort](https://pypi.org/project/isort/) -- [mccabe](https://pypi.org/project/mccabe/) -- [pandas-vet](https://pypi.org/project/pandas-vet/) -- [pep8-naming](https://pypi.org/project/pep8-naming/) -- [pydocstyle](https://pypi.org/project/pydocstyle/) -- [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980)) -- [pyupgrade](https://pypi.org/project/pyupgrade/) ([#827](https://github.com/charliermarsh/ruff/issues/827)) -- [yesqa](https://github.com/asottile/yesqa) +* [autoflake](https://pypi.org/project/autoflake/) ([#1647](https://github.com/charliermarsh/ruff/issues/1647)) +* [eradicate](https://pypi.org/project/eradicate/) +* [flake8-2020](https://pypi.org/project/flake8-2020/) +* [flake8-annotations](https://pypi.org/project/flake8-annotations/) +* [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646)) +* [flake8-blind-except](https://pypi.org/project/flake8-blind-except/) +* [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) +* [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) +* [flake8-builtins](https://pypi.org/project/flake8-builtins/) +* [flake8-commas](https://pypi.org/project/flake8-commas/) +* [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) +* [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) +* [flake8-debugger](https://pypi.org/project/flake8-debugger/) +* [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) +* [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) +* [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) +* [flake8-executable](https://pypi.org/project/flake8-executable/) +* [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) +* [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) +* [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) +* [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) +* [flake8-pie](https://pypi.org/project/flake8-pie/) +* [flake8-print](https://pypi.org/project/flake8-print/) +* [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) +* [flake8-quotes](https://pypi.org/project/flake8-quotes/) +* [flake8-raise](https://pypi.org/project/flake8-raise/) +* [flake8-return](https://pypi.org/project/flake8-return/) +* [flake8-self](https://pypi.org/project/flake8-self/) +* [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998)) +* [flake8-super](https://pypi.org/project/flake8-super/) +* [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) +* [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) +* [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) +* [isort](https://pypi.org/project/isort/) +* [mccabe](https://pypi.org/project/mccabe/) +* [pandas-vet](https://pypi.org/project/pandas-vet/) +* [pep8-naming](https://pypi.org/project/pep8-naming/) +* [pydocstyle](https://pypi.org/project/pydocstyle/) +* [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980)) +* [pyupgrade](https://pypi.org/project/pyupgrade/) ([#827](https://github.com/charliermarsh/ruff/issues/827)) +* [yesqa](https://github.com/asottile/yesqa) Note that, in some cases, Ruff uses different rule codes and prefixes than would be found in the originating Flake8 plugins. For example, Ruff uses `TID252` to represent the `I252` rule from @@ -1700,8 +1712,8 @@ Beyond the rule set, Ruff suffers from the following limitations vis-à-vis Flak There are a few other minor incompatibilities between Ruff and the originating Flake8 plugins: -- Ruff doesn't implement all the "opinionated" lint rules from flake8-bugbear. -- Depending on your project structure, Ruff and isort can differ in their detection of first-party +* Ruff doesn't implement all the "opinionated" lint rules from flake8-bugbear. +* Depending on your project structure, Ruff and isort can differ in their detection of first-party code. (This is often solved by modifying the `src` property, e.g., to `src = ["src"]`, if your code is nested in a `src` directory.) @@ -1743,41 +1755,41 @@ feedback on type errors. Today, Ruff can be used to replace Flake8 when used with any of the following plugins: -- [flake8-2020](https://pypi.org/project/flake8-2020/) -- [flake8-annotations](https://pypi.org/project/flake8-annotations/) -- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646)) -- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/) -- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) -- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) -- [flake8-builtins](https://pypi.org/project/flake8-builtins/) -- [flake8-commas](https://pypi.org/project/flake8-commas/) -- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) -- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) -- [flake8-debugger](https://pypi.org/project/flake8-debugger/) -- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) -- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) -- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) -- [flake8-executable](https://pypi.org/project/flake8-executable/) -- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) -- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) -- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) -- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) -- [flake8-pie](https://pypi.org/project/flake8-pie/) -- [flake8-print](https://pypi.org/project/flake8-print/) -- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) -- [flake8-quotes](https://pypi.org/project/flake8-quotes/) -- [flake8-raise](https://pypi.org/project/flake8-raise/) -- [flake8-return](https://pypi.org/project/flake8-return/) -- [flake8-self](https://pypi.org/project/flake8-self/) -- [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998)) -- [flake8-super](https://pypi.org/project/flake8-super/) -- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) -- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) -- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) -- [mccabe](https://pypi.org/project/mccabe/) -- [pandas-vet](https://pypi.org/project/pandas-vet/) -- [pep8-naming](https://pypi.org/project/pep8-naming/) -- [pydocstyle](https://pypi.org/project/pydocstyle/) +* [flake8-2020](https://pypi.org/project/flake8-2020/) +* [flake8-annotations](https://pypi.org/project/flake8-annotations/) +* [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646)) +* [flake8-blind-except](https://pypi.org/project/flake8-blind-except/) +* [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) +* [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) +* [flake8-builtins](https://pypi.org/project/flake8-builtins/) +* [flake8-commas](https://pypi.org/project/flake8-commas/) +* [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) +* [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) +* [flake8-debugger](https://pypi.org/project/flake8-debugger/) +* [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) +* [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) +* [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) +* [flake8-executable](https://pypi.org/project/flake8-executable/) +* [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) +* [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) +* [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) +* [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) +* [flake8-pie](https://pypi.org/project/flake8-pie/) +* [flake8-print](https://pypi.org/project/flake8-print/) +* [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) +* [flake8-quotes](https://pypi.org/project/flake8-quotes/) +* [flake8-raise](https://pypi.org/project/flake8-raise/) +* [flake8-return](https://pypi.org/project/flake8-return/) +* [flake8-self](https://pypi.org/project/flake8-self/) +* [flake8-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998)) +* [flake8-super](https://pypi.org/project/flake8-super/) +* [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) +* [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) +* [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) +* [mccabe](https://pypi.org/project/mccabe/) +* [pandas-vet](https://pypi.org/project/pandas-vet/) +* [pep8-naming](https://pypi.org/project/pep8-naming/) +* [pydocstyle](https://pypi.org/project/pydocstyle/) Ruff can also replace [isort](https://pypi.org/project/isort/), [yesqa](https://github.com/asottile/yesqa), [eradicate](https://pypi.org/project/eradicate/), @@ -2084,6 +2096,7 @@ Benchmark 1: find . -type f -name "*.py" | xargs -P 0 pyupgrade --py311-plus + #### [`allowed-confusables`](#allowed-confusables) A list of allowed "confusable" Unicode characters to ignore when @@ -2174,10 +2187,10 @@ A list of file patterns to exclude from linting. Exclusions are based on globs, and can be either: -- Single-path patterns, like `.mypy_cache` (to exclude any directory +* Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). -- Relative patterns, like `directory/foo.py` (to exclude that specific +* Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`). @@ -2233,10 +2246,10 @@ specified by `exclude`. Exclusions are based on globs, and can be either: -- Single-path patterns, like `.mypy_cache` (to exclude any directory +* Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). -- Relative patterns, like `directory/foo.py` (to exclude that specific +* Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`). @@ -2810,8 +2823,8 @@ suppress-dummy-args = true Whether to suppress `ANN200`-level violations for functions that meet either of the following criteria: -- Contain no `return` statement. -- Explicit `return` statement(s) all return `None` (explicitly or +* Contain no `return` statement. +* Explicit `return` statement(s) all return `None` (explicitly or implicitly). **Default value**: `false` @@ -3063,10 +3076,11 @@ mark-parentheses = true Expected type for multiple argument names in `@pytest.mark.parametrize`. The following values are supported: + * `csv` — a comma-separated list, e.g. `@pytest.mark.parametrize('name1,name2', ...)` -* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), - ...)` +* `tuple` (default) — e.g. + `@pytest.mark.parametrize(('name1', 'name2'), ...)` * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)` **Default value**: `tuple` @@ -3086,10 +3100,11 @@ parametrize-names-type = "list" Expected type for each row of values in `@pytest.mark.parametrize` in case of multiple parameters. The following values are supported: -* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), - [(1, 2), (3, 4)])` -* `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], - [3, 4]])` + +* `tuple` (default) — e.g. + `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])` +* `list` — e.g. + `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])` **Default value**: `tuple` @@ -3108,6 +3123,7 @@ parametrize-values-row-type = "list" Expected type for the list of values rows in `@pytest.mark.parametrize`. The following values are supported: + * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` * `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])` @@ -3307,7 +3323,7 @@ exempt-modules = ["typing", "typing_extensions"] Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module. -See: https://github.com/snok/flake8-type-checking#strict. +See flake8-type-checking's [strict](https://github.com/snok/flake8-type-checking#strict) option. **Default value**: `false` diff --git a/playground/README.md b/playground/README.md index b60817f87d..ffd031b1c5 100644 --- a/playground/README.md +++ b/playground/README.md @@ -4,10 +4,10 @@ In-browser playground for Ruff. Available [https://ruff.pages.dev/](https://ruff ## Getting started -- To build the WASM module, run `wasm-pack build --target web --out-dir playground/src/pkg` from the +* To build the WASM module, run `wasm-pack build --target web --out-dir playground/src/pkg` from the root directory. -- Install TypeScript dependencies with: `npm install`. -- Start the development server with: `npm run dev`. +* Install TypeScript dependencies with: `npm install`. +* Start the development server with: `npm run dev`. ## Implementation diff --git a/playground/index.html b/playground/index.html index d116aa23d1..4719d71b9b 100644 --- a/playground/index.html +++ b/playground/index.html @@ -1,4 +1,4 @@ - + diff --git a/pyproject.toml b/pyproject.toml index e0cb401107..6523db3ee6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,31 +9,34 @@ build-backend = "maturin" name = "ruff" version = "0.0.240" description = "An extremely fast Python linter, written in Rust." -authors = [ - { name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }, -] -maintainers = [ - { name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }, -] +authors = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }] +maintainers = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }] readme = "README.md" requires-python = ">=3.7" license = { file = "LICENSE" } -keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"] +keywords = [ + "automation", + "flake8", + "pycodestyle", + "pyflakes", + "pylint", + "clippy", +] classifiers = [ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3 :: Only", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Software Development :: Quality Assurance", + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Quality Assurance", ] urls = { repository = "https://github.com/charliermarsh/ruff" } @@ -42,3 +45,6 @@ bindings = "bin" manifest-path = "ruff_cli/Cargo.toml" python-source = "python" strip = true + +[tool.ruff.per-file-ignores] +"setup.py" = ["INP001"] diff --git a/python/ruff/__main__.py b/python/ruff/__main__.py index 947caea0a9..1c30d2b596 100644 --- a/python/ruff/__main__.py +++ b/python/ruff/__main__.py @@ -1,7 +1,8 @@ import os import sys import sysconfig +from pathlib import Path if __name__ == "__main__": - ruff = os.path.join(sysconfig.get_path("scripts"), "ruff") + ruff = Path(sysconfig.get_path("scripts")) / "ruff" sys.exit(os.spawnv(os.P_WAIT, ruff, [ruff, *sys.argv[1:]])) diff --git a/resources/test/project/README.md b/resources/test/project/README.md index e985823b33..e5993e537d 100644 --- a/resources/test/project/README.md +++ b/resources/test/project/README.md @@ -7,7 +7,7 @@ behaviors. Running from the repo root should pick up and enforce the appropriate settings for each package: -``` +```console ∴ cargo run resources/test/project/ resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused @@ -22,7 +22,7 @@ Found 7 errors. Running from the project directory itself should exhibit the same behavior: -``` +```console ∴ (cd resources/test/project/ && cargo run .) examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused @@ -38,7 +38,7 @@ Found 7 errors. Running from the sub-package directory should exhibit the same behavior, but omit the top-level files: -``` +```console ∴ (cd resources/test/project/examples/docs && cargo run .) docs/file.py:1:1: I001 Import block is un-sorted or un-formatted docs/file.py:8:5: F841 Local variable `x` is assigned to but never used @@ -49,7 +49,7 @@ Found 2 errors. `--config` should force Ruff to use the specified `pyproject.toml` for all files, and resolve file paths from the current working directory: -``` +```console ∴ (cargo run -- --config=resources/test/project/pyproject.toml resources/test/project/) resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused @@ -67,7 +67,7 @@ Found 9 errors. Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets included in the output): -``` +```console ∴ (cd resources/test/project/examples && cargo run -- --config=docs/ruff.toml .) docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted @@ -79,7 +79,7 @@ Found 4 errors. Passing an excluded directory directly should report errors in the contained files: -``` +```console ∴ cargo run resources/test/project/examples/excluded/ resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused Found 1 error. @@ -88,7 +88,7 @@ Found 1 error. Unless we `--force-exclude`: -``` +```console ∴ cargo run resources/test/project/examples/excluded/ --force-exclude warning: No Python files found under the given path(s) ∴ cargo run resources/test/project/examples/excluded/script.py --force-exclude diff --git a/ruff.schema.json b/ruff.schema.json index 303ee250f5..205785d1ca 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -40,7 +40,7 @@ ] }, "exclude": { - "description": "A list of file patterns to exclude from linting.\n\nExclusions are based on globs, and can be either:\n\n- Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). - Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`).\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).\n\nNote that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify the excluded paths.", + "description": "A list of file patterns to exclude from linting.\n\nExclusions are based on globs, and can be either:\n\n* Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). * Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`).\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).\n\nNote that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify the excluded paths.", "type": [ "array", "null" @@ -57,7 +57,7 @@ ] }, "extend-exclude": { - "description": "A list of file patterns to omit from linting, in addition to those specified by `exclude`.\n\nExclusions are based on globs, and can be either:\n\n- Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). - Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`).\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).", + "description": "A list of file patterns to omit from linting, in addition to those specified by `exclude`.\n\nExclusions are based on globs, and can be either:\n\n* Single-path patterns, like `.mypy_cache` (to exclude any directory named `.mypy_cache` in the tree), `foo.py` (to exclude any file named `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). * Relative patterns, like `directory/foo.py` (to exclude that specific file) or `directory/*.py` (to exclude any Python files in `directory`). Note that these paths are relative to the project root (e.g., the directory containing your `pyproject.toml`).\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).", "type": [ "array", "null" @@ -556,7 +556,7 @@ ] }, "suppress-none-returning": { - "description": "Whether to suppress `ANN200`-level violations for functions that meet either of the following criteria:\n\n- Contain no `return` statement. - Explicit `return` statement(s) all return `None` (explicitly or implicitly).", + "description": "Whether to suppress `ANN200`-level violations for functions that meet either of the following criteria:\n\n* Contain no `return` statement. * Explicit `return` statement(s) all return `None` (explicitly or implicitly).", "type": [ "boolean", "null" @@ -702,7 +702,7 @@ ] }, "parametrize-names-type": { - "description": "Expected type for multiple argument names in `@pytest.mark.parametrize`. The following values are supported: * `csv` — a comma-separated list, e.g. `@pytest.mark.parametrize('name1,name2', ...)` * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), ...)` * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`", + "description": "Expected type for multiple argument names in `@pytest.mark.parametrize`. The following values are supported:\n\n* `csv` — a comma-separated list, e.g. `@pytest.mark.parametrize('name1,name2', ...)` * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), ...)` * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`", "anyOf": [ { "$ref": "#/definitions/ParametrizeNameType" @@ -713,7 +713,7 @@ ] }, "parametrize-values-row-type": { - "description": "Expected type for each row of values in `@pytest.mark.parametrize` in case of multiple parameters. The following values are supported: * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])` * `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`", + "description": "Expected type for each row of values in `@pytest.mark.parametrize` in case of multiple parameters. The following values are supported:\n\n* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])` * `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`", "anyOf": [ { "$ref": "#/definitions/ParametrizeValuesRowType" @@ -724,7 +724,7 @@ ] }, "parametrize-values-type": { - "description": "Expected type for the list of values rows in `@pytest.mark.parametrize`. The following values are supported: * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` * `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`", + "description": "Expected type for the list of values rows in `@pytest.mark.parametrize`. The following values are supported:\n\n* `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` * `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`", "anyOf": [ { "$ref": "#/definitions/ParametrizeValuesType" @@ -844,7 +844,7 @@ } }, "strict": { - "description": "Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module. See: https://github.com/snok/flake8-type-checking#strict.", + "description": "Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module. See flake8-type-checking's [strict](https://github.com/snok/flake8-type-checking#strict) option.", "type": [ "boolean", "null" diff --git a/ruff_dev/src/generate_cli_help.rs b/ruff_dev/src/generate_cli_help.rs index d137eb47c5..704cde435e 100644 --- a/ruff_dev/src/generate_cli_help.rs +++ b/ruff_dev/src/generate_cli_help.rs @@ -4,10 +4,10 @@ use crate::utils::replace_readme_section; use anyhow::Result; use std::str; -const COMMAND_HELP_BEGIN_PRAGMA: &str = ""; +const COMMAND_HELP_BEGIN_PRAGMA: &str = "\n"; const COMMAND_HELP_END_PRAGMA: &str = ""; -const SUBCOMMAND_HELP_BEGIN_PRAGMA: &str = ""; +const SUBCOMMAND_HELP_BEGIN_PRAGMA: &str = "\n"; const SUBCOMMAND_HELP_END_PRAGMA: &str = ""; #[derive(clap::Args)] @@ -33,12 +33,12 @@ pub fn main(args: &Args) -> Result<()> { print!("{subcommand_help}"); } else { replace_readme_section( - &format!("```\n{command_help}\n```\n"), + &format!("```text\n{command_help}\n```\n\n"), COMMAND_HELP_BEGIN_PRAGMA, COMMAND_HELP_END_PRAGMA, )?; replace_readme_section( - &format!("```\n{subcommand_help}\n```\n"), + &format!("```text\n{subcommand_help}\n```\n\n"), SUBCOMMAND_HELP_BEGIN_PRAGMA, SUBCOMMAND_HELP_END_PRAGMA, )?; diff --git a/ruff_dev/src/generate_options.rs b/ruff_dev/src/generate_options.rs index 32d4855f03..7576b096b3 100644 --- a/ruff_dev/src/generate_options.rs +++ b/ruff_dev/src/generate_options.rs @@ -7,7 +7,7 @@ use ruff::settings::options_base::{ConfigurationOptions, OptionEntry, OptionFiel use crate::utils::replace_readme_section; -const BEGIN_PRAGMA: &str = ""; +const BEGIN_PRAGMA: &str = "\n"; const END_PRAGMA: &str = ""; #[derive(clap::Args)] diff --git a/ruff_dev/src/generate_rules_table.rs b/ruff_dev/src/generate_rules_table.rs index b5685f4212..d8c05f8a36 100644 --- a/ruff_dev/src/generate_rules_table.rs +++ b/ruff_dev/src/generate_rules_table.rs @@ -7,7 +7,7 @@ use strum::IntoEnumIterator; use crate::utils::replace_readme_section; -const TABLE_BEGIN_PRAGMA: &str = ""; +const TABLE_BEGIN_PRAGMA: &str = "\n"; const TABLE_END_PRAGMA: &str = ""; const TOC_BEGIN_PRAGMA: &str = ""; @@ -97,6 +97,7 @@ pub fn main(args: &Args) -> Result<()> { for LinterCategory(prefix, name, selector) in categories { table_out.push_str(&format!("#### {name} ({prefix})")); table_out.push('\n'); + table_out.push('\n'); generate_table(&mut table_out, selector); } } else { diff --git a/scripts/add_rule.py b/scripts/add_rule.py index 8e7ee84d02..f5b9223656 100755 --- a/scripts/add_rule.py +++ b/scripts/add_rule.py @@ -21,7 +21,7 @@ def snake_case(name: str) -> str: ).lstrip("_") -def main(*, name: str, code: str, linter: str) -> None: +def main(*, name: str, code: str, linter: str) -> None: # noqa: PLR0915 """Generate boilerplate for a new rule.""" # Create a test fixture. with (ROOT_DIR / "resources/test/fixtures" / dir_name(linter) / f"{code}.py").open( diff --git a/setup.py b/setup.py index a8d82c4a0a..115c9e361d 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ Unsupported installation method =============================== ruff no longer supports installation with `python setup.py install`. Please use `python -m pip install .` instead. -""" +""", ) sys.exit(1) diff --git a/src/rules/flake8_annotations/settings.rs b/src/rules/flake8_annotations/settings.rs index 41340b1592..0789d90066 100644 --- a/src/rules/flake8_annotations/settings.rs +++ b/src/rules/flake8_annotations/settings.rs @@ -37,8 +37,8 @@ pub struct Options { /// Whether to suppress `ANN200`-level violations for functions that meet /// either of the following criteria: /// - /// - Contain no `return` statement. - /// - Explicit `return` statement(s) all return `None` (explicitly or + /// * Contain no `return` statement. + /// * Explicit `return` statement(s) all return `None` (explicitly or /// implicitly). pub suppress_none_returning: Option, #[option( diff --git a/src/rules/flake8_pytest_style/settings.rs b/src/rules/flake8_pytest_style/settings.rs index fb85267dcd..029db61e3d 100644 --- a/src/rules/flake8_pytest_style/settings.rs +++ b/src/rules/flake8_pytest_style/settings.rs @@ -47,10 +47,11 @@ pub struct Options { )] /// Expected type for multiple argument names in `@pytest.mark.parametrize`. /// The following values are supported: + /// /// * `csv` — a comma-separated list, e.g. /// `@pytest.mark.parametrize('name1,name2', ...)` - /// * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), - /// ...)` + /// * `tuple` (default) — e.g. + /// `@pytest.mark.parametrize(('name1', 'name2'), ...)` /// * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)` pub parametrize_names_type: Option, #[option( @@ -60,6 +61,7 @@ pub struct Options { )] /// Expected type for the list of values rows in `@pytest.mark.parametrize`. /// The following values are supported: + /// /// * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` /// * `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])` pub parametrize_values_type: Option, @@ -70,10 +72,11 @@ pub struct Options { )] /// Expected type for each row of values in `@pytest.mark.parametrize` in /// case of multiple parameters. The following values are supported: - /// * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), - /// [(1, 2), (3, 4)])` - /// * `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], - /// [3, 4]])` + /// + /// * `tuple` (default) — e.g. + /// `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])` + /// * `list` — e.g. + /// `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])` pub parametrize_values_row_type: Option, #[option( default = r#"["BaseException", "Exception", "ValueError", "OSError", "IOError", "EnvironmentError", "socket.error"]"#, diff --git a/src/rules/flake8_type_checking/settings.rs b/src/rules/flake8_type_checking/settings.rs index 862ecf1b1b..49dcc7ffcb 100644 --- a/src/rules/flake8_type_checking/settings.rs +++ b/src/rules/flake8_type_checking/settings.rs @@ -22,7 +22,7 @@ pub struct Options { )] /// Enforce TC001, TC002, and TC003 rules even when valid runtime imports /// are present for the same module. - /// See: https://github.com/snok/flake8-type-checking#strict. + /// See flake8-type-checking's [strict](https://github.com/snok/flake8-type-checking#strict) option. pub strict: Option, #[option( default = "[\"typing\"]", diff --git a/src/settings/options.rs b/src/settings/options.rs index c2fbf6eebb..d1594a07b1 100644 --- a/src/settings/options.rs +++ b/src/settings/options.rs @@ -80,10 +80,10 @@ pub struct Options { /// /// Exclusions are based on globs, and can be either: /// - /// - Single-path patterns, like `.mypy_cache` (to exclude any directory + /// * Single-path patterns, like `.mypy_cache` (to exclude any directory /// named `.mypy_cache` in the tree), `foo.py` (to exclude any file named /// `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). - /// - Relative patterns, like `directory/foo.py` (to exclude that specific + /// * Relative patterns, like `directory/foo.py` (to exclude that specific /// file) or `directory/*.py` (to exclude any Python files in /// `directory`). Note that these paths are relative to the project root /// (e.g., the directory containing your `pyproject.toml`). @@ -124,10 +124,10 @@ pub struct Options { /// /// Exclusions are based on globs, and can be either: /// - /// - Single-path patterns, like `.mypy_cache` (to exclude any directory + /// * Single-path patterns, like `.mypy_cache` (to exclude any directory /// named `.mypy_cache` in the tree), `foo.py` (to exclude any file named /// `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). - /// - Relative patterns, like `directory/foo.py` (to exclude that specific + /// * Relative patterns, like `directory/foo.py` (to exclude that specific /// file) or `directory/*.py` (to exclude any Python files in /// `directory`). Note that these paths are relative to the project root /// (e.g., the directory containing your `pyproject.toml`).