Add markdownlint and dev Ruff to pre-commit (#2303)

This commit is contained in:
Jonathan Plasse 2023-02-02 22:29:07 +01:00 committed by GitHub
parent ec8b827d26
commit bdcab87d2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 277 additions and 236 deletions

View file

@ -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: If you're filing a bug report, please consider including the following information:
- A minimal code snippet that reproduces the bug. * 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 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 settings (any relevant sections from your `pyproject.toml`).
- The current Ruff version (`ruff --version`). * The current Ruff version (`ruff --version`).
--> -->

View file

@ -56,7 +56,7 @@ jobs:
cargo-test: cargo-test:
strategy: strategy:
matrix: matrix:
os: [ ubuntu-latest, windows-latest ] os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: "cargo test | ${{ matrix.os }}" name: "cargo test | ${{ matrix.os }}"
steps: steps:
@ -95,8 +95,8 @@ jobs:
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint - run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
- run: cargo check - run: cargo check
- run: | - run: |
./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST ./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_rule.py --name FirstRule --code TST001 --linter test
- run: cargo check - run: cargo check
maturin-build: maturin-build:
@ -118,7 +118,7 @@ jobs:
name: "spell check" name: "spell check"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: crate-ci/typos@master - uses: crate-ci/typos@master
with: with:
files: . files: .

View file

@ -6,10 +6,9 @@ on:
- README.md - README.md
- mkdocs.template.yml - mkdocs.template.yml
- .github/workflows/docs.yaml - .github/workflows/docs.yaml
branches: [ main ] branches: [main]
workflow_dispatch: workflow_dispatch:
jobs: jobs:
mkdocs: mkdocs:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View file

@ -15,7 +15,7 @@ jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }} CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: "Install Rust toolchain" - name: "Install Rust toolchain"

View file

@ -1,16 +1,19 @@
repos: 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 - repo: https://github.com/abravalheri/validate-pyproject
rev: v0.10.1 rev: v0.10.1
hooks: hooks:
- id: validate-pyproject - 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 - repo: local
hooks: hooks:
- id: cargo-fmt - id: cargo-fmt
@ -23,9 +26,19 @@ repos:
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic entry: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic
language: rust language: rust
pass_filenames: false 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 - id: dev-generate-all
name: dev-generate-all name: dev-generate-all
entry: cargo dev generate-all entry: cargo dev generate-all
language: rust language: rust
pass_filenames: false pass_filenames: false
exclude: target exclude: target
ci:
skip: [cargo-fmt, clippy, dev-generate-all]

View file

@ -43,16 +43,18 @@ upgrades.
`--explain`, `--clean`, and `--generate-shell-completion` are now implemented as subcommands: `--explain`, `--clean`, and `--generate-shell-completion` are now implemented as subcommands:
ruff . # Still works! And will always work. ```console
ruff check . # New! Also works. ruff . # Still works! And will always work.
ruff check . # New! Also works.
ruff --explain E402 # Still works. ruff --explain E402 # Still works.
ruff rule E402 # New! Also works. (And preferred.) ruff rule E402 # New! Also works. (And preferred.)
# Oops! The command has to come first. # Oops! The command has to come first.
ruff --format json --explain E402 # No longer works. ruff --format json --explain E402 # No longer works.
ruff --explain E402 --format json # Still works! ruff --explain E402 --format json # Still works!
ruff rule E402 --format json # Works! (And preferred.) ruff rule E402 --format json # Works! (And preferred.)
```
This change is largely backwards compatible -- most users should experience This change is largely backwards compatible -- most users should experience
no change in behavior. However, please note the following exceptions: 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 * Subcommands will now fail when invoked with unsupported arguments, instead
of silently ignoring them. For example, the following will now fail: 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`.) (the `clean` command doesn't support `--respect-gitignore`.)

View file

@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
### 4. Permanent Ban ### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community **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. individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within **Consequence**: A permanent ban from any sort of public interaction within
@ -115,14 +115,12 @@ the community.
## Attribution ## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at version 2.0, available [here](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity). enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org [homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at For answers to common questions about this code of conduct, see the [FAQ](https://www.contributor-covenant.org/faq).
https://www.contributor-covenant.org/faq. Translations are available at Translations are available [here](https://www.contributor-covenant.org/translations).
https://www.contributor-covenant.org/translations.

294
README.md
View file

@ -24,16 +24,16 @@ An extremely fast Python linter, written in Rust.
<i>Linting the CPython codebase from scratch.</i> <i>Linting the CPython codebase from scratch.</i>
</p> </p>
- ⚡️ 10-100x faster than existing linters * ⚡️ 10-100x faster than existing linters
- 🐍 Installable via `pip` * 🐍 Installable via `pip`
- 🤝 Python 3.11 compatibility * 🤝 Python 3.11 compatibility
- 🛠️ `pyproject.toml` support * 🛠️ `pyproject.toml` support
- 📦 Built-in caching, to avoid re-analyzing unchanged files * 📦 Built-in caching, to avoid re-analyzing unchanged files
- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports) * 🔧 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 * ⚖️ [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/) * 🔌 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) * ⌨️ 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) * 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](#pyprojecttoml-discovery)
Ruff aims to be orders of magnitude faster than alternative tools while integrating more Ruff aims to be orders of magnitude faster than alternative tools while integrating more
functionality behind a single, common interface. 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: Ruff is extremely actively developed and used in major open-source projects like:
- [pandas](https://github.com/pandas-dev/pandas) * [pandas](https://github.com/pandas-dev/pandas)
- [FastAPI](https://github.com/tiangolo/fastapi) * [FastAPI](https://github.com/tiangolo/fastapi)
- [Apache Airflow](https://github.com/apache/airflow) * [Apache Airflow](https://github.com/apache/airflow)
- [SciPy](https://github.com/scipy/scipy) * [SciPy](https://github.com/scipy/scipy)
- [Bokeh](https://github.com/bokeh/bokeh) * [Bokeh](https://github.com/bokeh/bokeh)
- [Zulip](https://github.com/zulip/zulip) * [Zulip](https://github.com/zulip/zulip)
- [Pydantic](https://github.com/pydantic/pydantic) * [Pydantic](https://github.com/pydantic/pydantic)
- [Dagster](https://github.com/dagster-io/dagster) * [Dagster](https://github.com/dagster-io/dagster)
- [Dagger](https://github.com/dagger/dagger) * [Dagger](https://github.com/dagger/dagger)
- [Sphinx](https://github.com/sphinx-doc/sphinx) * [Sphinx](https://github.com/sphinx-doc/sphinx)
- [Hatch](https://github.com/pypa/hatch) * [Hatch](https://github.com/pypa/hatch)
- [Jupyter](https://github.com/jupyter-server/jupyter_server) * [Jupyter](https://github.com/jupyter-server/jupyter_server)
- [Great Expectations](https://github.com/great-expectations/great_expectations) * [Great Expectations](https://github.com/great-expectations/great_expectations)
- [Polars](https://github.com/pola-rs/polars) * [Polars](https://github.com/pola-rs/polars)
- [Ibis](https://github.com/ibis-project/ibis) * [Ibis](https://github.com/ibis-project/ibis)
- [Synapse (Matrix)](https://github.com/matrix-org/synapse) * [Synapse (Matrix)](https://github.com/matrix-org/synapse)
- [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli) * [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli)
- [Saleor](https://github.com/saleor/saleor) * [Saleor](https://github.com/saleor/saleor)
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal) * [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
- [Home Assistant](https://github.com/home-assistant/core) * [Home Assistant](https://github.com/home-assistant/core)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography) * [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel) * [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [build (PyPA)](https://github.com/pypa/build) * [build (PyPA)](https://github.com/pypa/build)
- [Babel](https://github.com/python-babel/babel) * [Babel](https://github.com/python-babel/babel)
- [featuretools](https://github.com/alteryx/featuretools) * [featuretools](https://github.com/alteryx/featuretools)
- [meson-python](https://github.com/mesonbuild/meson-python) * [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 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). 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 > 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 > 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 [**Bryan Van de Ven**](https://github.com/bokeh/bokeh/pull/12605), co-creator
of [Bokeh](https://github.com/bokeh/bokeh/), original author 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**: 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. explicit.
- Use `ALL` with discretion. Enabling `ALL` will implicitly enable new rules whenever you upgrade. * 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, * 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 you might consider expanding to `select = ["E", "F", "B"]` to enable the popular flake8-bugbear
extension. 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)). 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 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: See `ruff help` for more on Ruff's top-level commands:
<!-- Begin auto-generated command help. --> <!-- Begin auto-generated command help. -->
```
```text
Ruff: An extremely fast Python linter. Ruff: An extremely fast Python linter.
Usage: ruff [OPTIONS] <COMMAND> Usage: ruff [OPTIONS] <COMMAND>
@ -406,12 +407,14 @@ Log levels:
For help with a specific command, see: `ruff help <command>`. For help with a specific command, see: `ruff help <command>`.
``` ```
<!-- End auto-generated command help. --> <!-- End auto-generated command help. -->
Or `ruff help check` for more on the linting command: Or `ruff help check` for more on the linting command:
<!-- Begin auto-generated subcommand help. --> <!-- Begin auto-generated subcommand help. -->
```
```text
Run Ruff on the given files or directories (default) Run Ruff on the given files or directories (default)
Usage: ruff check [OPTIONS] [FILES]... Usage: ruff check [OPTIONS] [FILES]...
@ -480,6 +483,7 @@ Log levels:
-q, --quiet Print lint violations, but nothing else -q, --quiet Print lint violations, but nothing else
-s, --silent Disable all logging (but still exit with status code "1" upon detecting lint violations) -s, --silent Disable all logging (but still exit with status code "1" upon detecting lint violations)
``` ```
<!-- End auto-generated subcommand help. --> <!-- End auto-generated subcommand help. -->
### `pyproject.toml` discovery ### `pyproject.toml` discovery
@ -639,6 +643,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
<!-- Sections automatically generated by `cargo dev generate-rules-table`. --> <!-- Sections automatically generated by `cargo dev generate-rules-table`. -->
<!-- Begin auto-generated sections. --> <!-- Begin auto-generated sections. -->
### Pyflakes (F) ### Pyflakes (F)
For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI. 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. For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI.
#### Error (E) #### Error (E)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| E101 | mixed-spaces-and-tabs | Indentation contains mixed spaces and tabs | | | 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} | | | E999 | syntax-error | SyntaxError: {message} | |
#### Warning (W) #### Warning (W)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| W292 | no-new-line-at-end-of-file | No newline at end of file | 🛠 | | 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. For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
#### Convention (PLC) #### Convention (PLC)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| PLC0414 | useless-import-alias | Import alias does not rename original package | 🛠 | | 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. | | | PLC3002 | unnecessary-direct-lambda-call | Lambda expression called directly. Execute the expression inline instead. | |
#### Error (PLE) #### Error (PLE)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| PLE0117 | nonlocal-without-binding | Nonlocal name `{name}` found without binding | | | 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 | | | PLE1142 | await-outside-async | `await` should be used within an async function | |
#### Refactor (PLR) #### Refactor (PLR)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| PLR0133 | constant-comparison | Two constants compared in a comparison, consider replacing `{left_constant} {op} {right_constant}` | | | 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 | | | PLR2004 | magic-value-comparison | Magic value used in comparison, consider replacing {value} with a constant variable | |
#### Warning (PLW) #### Warning (PLW)
| Code | Name | Message | Fix | | 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 | | | 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), Download the [Ruff VS Code extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff),
which supports autofix actions, import sorting, and more. 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) ### Language Server Protocol (Official)
@ -1547,13 +1558,14 @@ let g:ale_fixers = {
```yaml ```yaml
tools: tools:
python-ruff: &python-ruff 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-stdin: true
lint-formats: lint-formats:
- '%f:%l:%c: %m' - "%f:%l:%c: %m"
format-command: 'ruff --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -' format-command: "ruff --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -"
format-stdin: true format-stdin: true
``` ```
</details> </details>
<details> <details>
@ -1570,8 +1582,8 @@ null_ls.setup({
} }
}) })
``` ```
</details>
</details>
### PyCharm (External Tool) ### 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 Ruff also re-implements some of the most popular Flake8 plugins and related code quality tools
natively, including: natively, including:
- [autoflake](https://pypi.org/project/autoflake/) ([#1647](https://github.com/charliermarsh/ruff/issues/1647)) * [autoflake](https://pypi.org/project/autoflake/) ([#1647](https://github.com/charliermarsh/ruff/issues/1647))
- [eradicate](https://pypi.org/project/eradicate/) * [eradicate](https://pypi.org/project/eradicate/)
- [flake8-2020](https://pypi.org/project/flake8-2020/) * [flake8-2020](https://pypi.org/project/flake8-2020/)
- [flake8-annotations](https://pypi.org/project/flake8-annotations/) * [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-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-blind-except](https://pypi.org/project/flake8-blind-except/)
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) * [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) * [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
- [flake8-builtins](https://pypi.org/project/flake8-builtins/) * [flake8-builtins](https://pypi.org/project/flake8-builtins/)
- [flake8-commas](https://pypi.org/project/flake8-commas/) * [flake8-commas](https://pypi.org/project/flake8-commas/)
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) * [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) * [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
- [flake8-debugger](https://pypi.org/project/flake8-debugger/) * [flake8-debugger](https://pypi.org/project/flake8-debugger/)
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) * [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) * [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) * [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/) * [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) * [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) * [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) * [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) * [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
- [flake8-pie](https://pypi.org/project/flake8-pie/) * [flake8-pie](https://pypi.org/project/flake8-pie/)
- [flake8-print](https://pypi.org/project/flake8-print/) * [flake8-print](https://pypi.org/project/flake8-print/)
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) * [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
- [flake8-quotes](https://pypi.org/project/flake8-quotes/) * [flake8-quotes](https://pypi.org/project/flake8-quotes/)
- [flake8-raise](https://pypi.org/project/flake8-raise/) * [flake8-raise](https://pypi.org/project/flake8-raise/)
- [flake8-return](https://pypi.org/project/flake8-return/) * [flake8-return](https://pypi.org/project/flake8-return/)
- [flake8-self](https://pypi.org/project/flake8-self/) * [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-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998))
- [flake8-super](https://pypi.org/project/flake8-super/) * [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) * [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) * [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) * [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [isort](https://pypi.org/project/isort/) * [isort](https://pypi.org/project/isort/)
- [mccabe](https://pypi.org/project/mccabe/) * [mccabe](https://pypi.org/project/mccabe/)
- [pandas-vet](https://pypi.org/project/pandas-vet/) * [pandas-vet](https://pypi.org/project/pandas-vet/)
- [pep8-naming](https://pypi.org/project/pep8-naming/) * [pep8-naming](https://pypi.org/project/pep8-naming/)
- [pydocstyle](https://pypi.org/project/pydocstyle/) * [pydocstyle](https://pypi.org/project/pydocstyle/)
- [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980)) * [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)) * [pyupgrade](https://pypi.org/project/pyupgrade/) ([#827](https://github.com/charliermarsh/ruff/issues/827))
- [yesqa](https://github.com/asottile/yesqa) * [yesqa](https://github.com/asottile/yesqa)
Note that, in some cases, Ruff uses different rule codes and prefixes than would be found in the 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 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: 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. * 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 * 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. (This is often solved by modifying the `src` property, e.g., to `src = ["src"]`, if your
code is nested in a `src` directory.) 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: 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-2020](https://pypi.org/project/flake8-2020/)
- [flake8-annotations](https://pypi.org/project/flake8-annotations/) * [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-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-blind-except](https://pypi.org/project/flake8-blind-except/)
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) * [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) * [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
- [flake8-builtins](https://pypi.org/project/flake8-builtins/) * [flake8-builtins](https://pypi.org/project/flake8-builtins/)
- [flake8-commas](https://pypi.org/project/flake8-commas/) * [flake8-commas](https://pypi.org/project/flake8-commas/)
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) * [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) * [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
- [flake8-debugger](https://pypi.org/project/flake8-debugger/) * [flake8-debugger](https://pypi.org/project/flake8-debugger/)
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) * [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) * [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) * [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/) * [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) * [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) * [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) * [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) * [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
- [flake8-pie](https://pypi.org/project/flake8-pie/) * [flake8-pie](https://pypi.org/project/flake8-pie/)
- [flake8-print](https://pypi.org/project/flake8-print/) * [flake8-print](https://pypi.org/project/flake8-print/)
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) * [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
- [flake8-quotes](https://pypi.org/project/flake8-quotes/) * [flake8-quotes](https://pypi.org/project/flake8-quotes/)
- [flake8-raise](https://pypi.org/project/flake8-raise/) * [flake8-raise](https://pypi.org/project/flake8-raise/)
- [flake8-return](https://pypi.org/project/flake8-return/) * [flake8-return](https://pypi.org/project/flake8-return/)
- [flake8-self](https://pypi.org/project/flake8-self/) * [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-simplify](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998))
- [flake8-super](https://pypi.org/project/flake8-super/) * [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) * [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) * [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) * [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [mccabe](https://pypi.org/project/mccabe/) * [mccabe](https://pypi.org/project/mccabe/)
- [pandas-vet](https://pypi.org/project/pandas-vet/) * [pandas-vet](https://pypi.org/project/pandas-vet/)
- [pep8-naming](https://pypi.org/project/pep8-naming/) * [pep8-naming](https://pypi.org/project/pep8-naming/)
- [pydocstyle](https://pypi.org/project/pydocstyle/) * [pydocstyle](https://pypi.org/project/pydocstyle/)
Ruff can also replace [isort](https://pypi.org/project/isort/), Ruff can also replace [isort](https://pypi.org/project/isort/),
[yesqa](https://github.com/asottile/yesqa), [eradicate](https://pypi.org/project/eradicate/), [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
<!-- Sections automatically generated by `cargo dev generate-options`. --> <!-- Sections automatically generated by `cargo dev generate-options`. -->
<!-- Begin auto-generated options sections. --> <!-- Begin auto-generated options sections. -->
#### [`allowed-confusables`](#allowed-confusables) #### [`allowed-confusables`](#allowed-confusables)
A list of allowed "confusable" Unicode characters to ignore when 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: 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 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` ). `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 file) or `directory/*.py` (to exclude any Python files in
`directory`). Note that these paths are relative to the project root `directory`). Note that these paths are relative to the project root
(e.g., the directory containing your `pyproject.toml`). (e.g., the directory containing your `pyproject.toml`).
@ -2233,10 +2246,10 @@ specified by `exclude`.
Exclusions are based on globs, and can be either: 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 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` ). `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 file) or `directory/*.py` (to exclude any Python files in
`directory`). Note that these paths are relative to the project root `directory`). Note that these paths are relative to the project root
(e.g., the directory containing your `pyproject.toml`). (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 Whether to suppress `ANN200`-level violations for functions that meet
either of the following criteria: either of the following criteria:
- Contain no `return` statement. * Contain no `return` statement.
- Explicit `return` statement(s) all return `None` (explicitly or * Explicit `return` statement(s) all return `None` (explicitly or
implicitly). implicitly).
**Default value**: `false` **Default value**: `false`
@ -3063,10 +3076,11 @@ mark-parentheses = true
Expected type for multiple argument names in `@pytest.mark.parametrize`. Expected type for multiple argument names in `@pytest.mark.parametrize`.
The following values are supported: The following values are supported:
* `csv` — a comma-separated list, e.g. * `csv` — a comma-separated list, e.g.
`@pytest.mark.parametrize('name1,name2', ...)` `@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'], ...)` * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`
**Default value**: `tuple` **Default value**: `tuple`
@ -3086,10 +3100,11 @@ parametrize-names-type = "list"
Expected type for each row of values in `@pytest.mark.parametrize` in Expected type for each row of values in `@pytest.mark.parametrize` in
case of multiple parameters. The following values are supported: case of multiple parameters. The following values are supported:
* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
[(1, 2), (3, 4)])` * `tuple` (default) — e.g.
* `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])`
[3, 4]])` * `list` — e.g.
`@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`
**Default value**: `tuple` **Default value**: `tuple`
@ -3108,6 +3123,7 @@ parametrize-values-row-type = "list"
Expected type for the list of values rows in `@pytest.mark.parametrize`. Expected type for the list of values rows in `@pytest.mark.parametrize`.
The following values are supported: The following values are supported:
* `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))`
* `list` (default) — 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 Enforce TC001, TC002, and TC003 rules even when valid runtime imports
are present for the same module. 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` **Default value**: `false`

View file

@ -4,10 +4,10 @@ In-browser playground for Ruff. Available [https://ruff.pages.dev/](https://ruff
## Getting started ## 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. root directory.
- Install TypeScript dependencies with: `npm install`. * Install TypeScript dependencies with: `npm install`.
- Start the development server with: `npm run dev`. * Start the development server with: `npm run dev`.
## Implementation ## Implementation

View file

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />

View file

@ -9,31 +9,34 @@ build-backend = "maturin"
name = "ruff" name = "ruff"
version = "0.0.240" version = "0.0.240"
description = "An extremely fast Python linter, written in Rust." description = "An extremely fast Python linter, written in Rust."
authors = [ authors = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }]
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }, maintainers = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }]
]
maintainers = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
]
readme = "README.md" readme = "README.md"
requires-python = ">=3.7" requires-python = ">=3.7"
license = { file = "LICENSE" } license = { file = "LICENSE" }
keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"] keywords = [
"automation",
"flake8",
"pycodestyle",
"pyflakes",
"pylint",
"clippy",
]
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Environment :: Console", "Environment :: Console",
"Intended Audience :: Developers", "Intended Audience :: Developers",
"License :: OSI Approved :: MIT License", "License :: OSI Approved :: MIT License",
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Quality Assurance",
] ]
urls = { repository = "https://github.com/charliermarsh/ruff" } urls = { repository = "https://github.com/charliermarsh/ruff" }
@ -42,3 +45,6 @@ bindings = "bin"
manifest-path = "ruff_cli/Cargo.toml" manifest-path = "ruff_cli/Cargo.toml"
python-source = "python" python-source = "python"
strip = true strip = true
[tool.ruff.per-file-ignores]
"setup.py" = ["INP001"]

View file

@ -1,7 +1,8 @@
import os import os
import sys import sys
import sysconfig import sysconfig
from pathlib import Path
if __name__ == "__main__": 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:]])) sys.exit(os.spawnv(os.P_WAIT, ruff, [ruff, *sys.argv[1:]]))

View file

@ -7,7 +7,7 @@ behaviors.
Running from the repo root should pick up and enforce the appropriate settings for each package: Running from the repo root should pick up and enforce the appropriate settings for each package:
``` ```console
∴ cargo run resources/test/project/ ∴ 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:1: I001 Import block is un-sorted or un-formatted
resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused 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: Running from the project directory itself should exhibit the same behavior:
``` ```console
∴ (cd resources/test/project/ && cargo run .) ∴ (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:1: I001 Import block is un-sorted or un-formatted
examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused 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 Running from the sub-package directory should exhibit the same behavior, but omit the top-level
files: files:
``` ```console
∴ (cd resources/test/project/examples/docs && cargo run .) ∴ (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: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 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 `--config` should force Ruff to use the specified `pyproject.toml` for all files, and resolve
file paths from the current working directory: file paths from the current working directory:
``` ```console
∴ (cargo run -- --config=resources/test/project/pyproject.toml resources/test/project/) ∴ (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:1:8: F401 `numpy` imported but unused
resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` 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 Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets
included in the output): included in the output):
``` ```console
∴ (cd resources/test/project/examples && cargo run -- --config=docs/ruff.toml .) ∴ (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/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 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: Passing an excluded directory directly should report errors in the contained files:
``` ```console
∴ cargo run resources/test/project/examples/excluded/ ∴ cargo run resources/test/project/examples/excluded/
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
Found 1 error. Found 1 error.
@ -88,7 +88,7 @@ Found 1 error.
Unless we `--force-exclude`: Unless we `--force-exclude`:
``` ```console
∴ cargo run resources/test/project/examples/excluded/ --force-exclude ∴ cargo run resources/test/project/examples/excluded/ --force-exclude
warning: No Python files found under the given path(s) warning: No Python files found under the given path(s)
∴ cargo run resources/test/project/examples/excluded/script.py --force-exclude ∴ cargo run resources/test/project/examples/excluded/script.py --force-exclude

View file

@ -40,7 +40,7 @@
] ]
}, },
"exclude": { "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": [ "type": [
"array", "array",
"null" "null"
@ -57,7 +57,7 @@
] ]
}, },
"extend-exclude": { "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": [ "type": [
"array", "array",
"null" "null"
@ -556,7 +556,7 @@
] ]
}, },
"suppress-none-returning": { "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": [ "type": [
"boolean", "boolean",
"null" "null"
@ -702,7 +702,7 @@
] ]
}, },
"parametrize-names-type": { "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": [ "anyOf": [
{ {
"$ref": "#/definitions/ParametrizeNameType" "$ref": "#/definitions/ParametrizeNameType"
@ -713,7 +713,7 @@
] ]
}, },
"parametrize-values-row-type": { "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": [ "anyOf": [
{ {
"$ref": "#/definitions/ParametrizeValuesRowType" "$ref": "#/definitions/ParametrizeValuesRowType"
@ -724,7 +724,7 @@
] ]
}, },
"parametrize-values-type": { "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": [ "anyOf": [
{ {
"$ref": "#/definitions/ParametrizeValuesType" "$ref": "#/definitions/ParametrizeValuesType"
@ -844,7 +844,7 @@
} }
}, },
"strict": { "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": [ "type": [
"boolean", "boolean",
"null" "null"

View file

@ -4,10 +4,10 @@ use crate::utils::replace_readme_section;
use anyhow::Result; use anyhow::Result;
use std::str; use std::str;
const COMMAND_HELP_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated command help. -->"; const COMMAND_HELP_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated command help. -->\n";
const COMMAND_HELP_END_PRAGMA: &str = "<!-- End auto-generated command help. -->"; const COMMAND_HELP_END_PRAGMA: &str = "<!-- End auto-generated command help. -->";
const SUBCOMMAND_HELP_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated subcommand help. -->"; const SUBCOMMAND_HELP_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated subcommand help. -->\n";
const SUBCOMMAND_HELP_END_PRAGMA: &str = "<!-- End auto-generated subcommand help. -->"; const SUBCOMMAND_HELP_END_PRAGMA: &str = "<!-- End auto-generated subcommand help. -->";
#[derive(clap::Args)] #[derive(clap::Args)]
@ -33,12 +33,12 @@ pub fn main(args: &Args) -> Result<()> {
print!("{subcommand_help}"); print!("{subcommand_help}");
} else { } else {
replace_readme_section( replace_readme_section(
&format!("```\n{command_help}\n```\n"), &format!("```text\n{command_help}\n```\n\n"),
COMMAND_HELP_BEGIN_PRAGMA, COMMAND_HELP_BEGIN_PRAGMA,
COMMAND_HELP_END_PRAGMA, COMMAND_HELP_END_PRAGMA,
)?; )?;
replace_readme_section( replace_readme_section(
&format!("```\n{subcommand_help}\n```\n"), &format!("```text\n{subcommand_help}\n```\n\n"),
SUBCOMMAND_HELP_BEGIN_PRAGMA, SUBCOMMAND_HELP_BEGIN_PRAGMA,
SUBCOMMAND_HELP_END_PRAGMA, SUBCOMMAND_HELP_END_PRAGMA,
)?; )?;

View file

@ -7,7 +7,7 @@ use ruff::settings::options_base::{ConfigurationOptions, OptionEntry, OptionFiel
use crate::utils::replace_readme_section; use crate::utils::replace_readme_section;
const BEGIN_PRAGMA: &str = "<!-- Begin auto-generated options sections. -->"; const BEGIN_PRAGMA: &str = "<!-- Begin auto-generated options sections. -->\n";
const END_PRAGMA: &str = "<!-- End auto-generated options sections. -->"; const END_PRAGMA: &str = "<!-- End auto-generated options sections. -->";
#[derive(clap::Args)] #[derive(clap::Args)]

View file

@ -7,7 +7,7 @@ use strum::IntoEnumIterator;
use crate::utils::replace_readme_section; use crate::utils::replace_readme_section;
const TABLE_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated sections. -->"; const TABLE_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated sections. -->\n";
const TABLE_END_PRAGMA: &str = "<!-- End auto-generated sections. -->"; const TABLE_END_PRAGMA: &str = "<!-- End auto-generated sections. -->";
const TOC_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated table of contents. -->"; const TOC_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated table of contents. -->";
@ -97,6 +97,7 @@ pub fn main(args: &Args) -> Result<()> {
for LinterCategory(prefix, name, selector) in categories { for LinterCategory(prefix, name, selector) in categories {
table_out.push_str(&format!("#### {name} ({prefix})")); table_out.push_str(&format!("#### {name} ({prefix})"));
table_out.push('\n'); table_out.push('\n');
table_out.push('\n');
generate_table(&mut table_out, selector); generate_table(&mut table_out, selector);
} }
} else { } else {

View file

@ -21,7 +21,7 @@ def snake_case(name: str) -> str:
).lstrip("_") ).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.""" """Generate boilerplate for a new rule."""
# Create a test fixture. # Create a test fixture.
with (ROOT_DIR / "resources/test/fixtures" / dir_name(linter) / f"{code}.py").open( with (ROOT_DIR / "resources/test/fixtures" / dir_name(linter) / f"{code}.py").open(

View file

@ -9,7 +9,7 @@ Unsupported installation method
=============================== ===============================
ruff no longer supports installation with `python setup.py install`. ruff no longer supports installation with `python setup.py install`.
Please use `python -m pip install .` instead. Please use `python -m pip install .` instead.
""" """,
) )
sys.exit(1) sys.exit(1)

View file

@ -37,8 +37,8 @@ pub struct Options {
/// Whether to suppress `ANN200`-level violations for functions that meet /// Whether to suppress `ANN200`-level violations for functions that meet
/// either of the following criteria: /// either of the following criteria:
/// ///
/// - Contain no `return` statement. /// * Contain no `return` statement.
/// - Explicit `return` statement(s) all return `None` (explicitly or /// * Explicit `return` statement(s) all return `None` (explicitly or
/// implicitly). /// implicitly).
pub suppress_none_returning: Option<bool>, pub suppress_none_returning: Option<bool>,
#[option( #[option(

View file

@ -47,10 +47,11 @@ pub struct Options {
)] )]
/// Expected type for multiple argument names in `@pytest.mark.parametrize`. /// Expected type for multiple argument names in `@pytest.mark.parametrize`.
/// The following values are supported: /// The following values are supported:
///
/// * `csv` — a comma-separated list, e.g. /// * `csv` — a comma-separated list, e.g.
/// `@pytest.mark.parametrize('name1,name2', ...)` /// `@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'], ...)` /// * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`
pub parametrize_names_type: Option<types::ParametrizeNameType>, pub parametrize_names_type: Option<types::ParametrizeNameType>,
#[option( #[option(
@ -60,6 +61,7 @@ pub struct Options {
)] )]
/// Expected type for the list of values rows in `@pytest.mark.parametrize`. /// Expected type for the list of values rows in `@pytest.mark.parametrize`.
/// The following values are supported: /// The following values are supported:
///
/// * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` /// * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))`
/// * `list` (default) — 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<types::ParametrizeValuesType>, pub parametrize_values_type: Option<types::ParametrizeValuesType>,
@ -70,10 +72,11 @@ pub struct Options {
)] )]
/// Expected type for each row of values in `@pytest.mark.parametrize` in /// Expected type for each row of values in `@pytest.mark.parametrize` in
/// case of multiple parameters. The following values are supported: /// case of multiple parameters. The following values are supported:
/// * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), ///
/// [(1, 2), (3, 4)])` /// * `tuple` (default) — e.g.
/// * `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], /// `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])`
/// [3, 4]])` /// * `list` — e.g.
/// `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`
pub parametrize_values_row_type: Option<types::ParametrizeValuesRowType>, pub parametrize_values_row_type: Option<types::ParametrizeValuesRowType>,
#[option( #[option(
default = r#"["BaseException", "Exception", "ValueError", "OSError", "IOError", "EnvironmentError", "socket.error"]"#, default = r#"["BaseException", "Exception", "ValueError", "OSError", "IOError", "EnvironmentError", "socket.error"]"#,

View file

@ -22,7 +22,7 @@ pub struct Options {
)] )]
/// Enforce TC001, TC002, and TC003 rules even when valid runtime imports /// Enforce TC001, TC002, and TC003 rules even when valid runtime imports
/// are present for the same module. /// 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<bool>, pub strict: Option<bool>,
#[option( #[option(
default = "[\"typing\"]", default = "[\"typing\"]",

View file

@ -80,10 +80,10 @@ pub struct Options {
/// ///
/// Exclusions are based on globs, and can be either: /// 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 /// 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` ). /// `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 /// file) or `directory/*.py` (to exclude any Python files in
/// `directory`). Note that these paths are relative to the project root /// `directory`). Note that these paths are relative to the project root
/// (e.g., the directory containing your `pyproject.toml`). /// (e.g., the directory containing your `pyproject.toml`).
@ -124,10 +124,10 @@ pub struct Options {
/// ///
/// Exclusions are based on globs, and can be either: /// 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 /// 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` ). /// `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 /// file) or `directory/*.py` (to exclude any Python files in
/// `directory`). Note that these paths are relative to the project root /// `directory`). Note that these paths are relative to the project root
/// (e.g., the directory containing your `pyproject.toml`). /// (e.g., the directory containing your `pyproject.toml`).